-
Notifications
You must be signed in to change notification settings - Fork 362
Closed
Labels
documentationImprovements or additions to documentation or error messagesImprovements or additions to documentation or error messages
Milestone
Description
I have an MCP server that only servers JSON over HTTP POST in a stateless fashion. It works like so:
❯ curl http://localhost:3000/mcp \
-X POST \
-H 'accept: application/json, text/event-stream' \
-H 'content-type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "ping"
}' -vvv
Note: Unnecessary use of -X or --request, POST is already inferred.
* Host localhost:3000 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:3000...
* Connected to localhost (::1) port 3000
> POST /mcp HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/8.7.1
> accept: application/json, text/event-stream
> content-type: application/json
> Content-Length: 55
>
* upload completely sent off: 55 bytes
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 38
< Date: Tue, 02 Sep 2025 19:49:45 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
<
* Connection #0 to host localhost left intact
{"jsonrpc":"2.0","id":"1","result":{}}
But when attempting to us a very simple go-sdk with this like so:
package main
import (
"context"
"log"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
func main() {
ctx := context.Background()
// Create a new client, with no features.
client := mcp.NewClient(&mcp.Implementation{Name: "mcp-client", Version: "v1.0.0"}, nil)
// Connect to a server over stdin/stdout
transport := &mcp.StreamableClientTransport{Endpoint: "http://localhost:3000/mcp"}
session, err := client.Connect(ctx, transport, nil)
if err != nil {
log.Fatal(err)
}
defer session.Close()
err = session.Ping(ctx, nil)
if err != nil {
log.Fatalf("could not ping: %v", err)
}
}I get this error:
❯ go run main.go
2025/09/02 15:54:35 could not ping: calling "ping": failed to reconnect: Not Found
exit status 1
It seems that this client successfully connects and initializes (as I see a log in my server that Received notification: notifications/initialized) but does not reuse the connection:
Lines 1309 to 1313 in 07b65d7
| if resp.StatusCode < 200 || resp.StatusCode >= 300 { | |
| resp.Body.Close() | |
| c.fail(fmt.Errorf("failed to reconnect: %v", http.StatusText(resp.StatusCode))) | |
| return | |
| } |
Since the error message is Not found, I'm wondering if my server is returning a 404 for some reason.
But, a very similar program works fine with mark3labs/mcp-go:
package main
import (
"context"
"fmt"
"log"
"github.com/mark3labs/mcp-go/client"
"github.com/mark3labs/mcp-go/client/transport"
"github.com/mark3labs/mcp-go/mcp"
)
func main() {
ctx := context.Background()
// Create HTTP transport directly
httpTransport, err := transport.NewStreamableHTTP(
"http://localhost:3000/mcp",
)
if err != nil {
log.Fatalf("Failed to create HTTP transport: %v", err)
}
defer httpTransport.Close()
// Create client with sampling support
mcpClient := client.NewClient(
httpTransport,
)
err = mcpClient.Start(ctx)
if err != nil {
log.Fatalf("Failed to start client: %v", err)
}
// Initialize the MCP session
initRequest := mcp.InitializeRequest{
Params: mcp.InitializeParams{
ProtocolVersion: mcp.LATEST_PROTOCOL_VERSION,
Capabilities: mcp.ClientCapabilities{},
ClientInfo: mcp.Implementation{
Name: "http-client",
Version: "0.0.1",
},
},
}
_, err = mcpClient.Initialize(ctx, initRequest)
if err != nil {
log.Fatalf("Failed to initialize MCP session: %v", err)
}
toolsResult, err := mcpClient.ListTools(ctx, mcp.ListToolsRequest{})
if err != nil {
log.Fatalf("Failed to list tools: %v", err)
}
for i, tool := range toolsResult.Tools {
fmt.Printf(" %d. %s - %s\n", i+1, tool.Name, tool.Description)
}
}❯ go run main.go
1. add - Adds two numbers together and returns the result.
2. subtract - Subtracts the second number from the first and returns the result.
3. multiply - Multiplies two numbers together and returns the result.
4. divide - Divides the first number by the second and returns the result.
5. power - Raises the first number to the power of the second number.
6. sqrt - Calculates the square root of the given number.
7. modulo - Returns the remainder of dividing the first number by the second.
8. factorial - Calculates the factorial of the given integer.
This also works fine with inspector:
I'm at abit of a loss as to what is going on here. My main questions are:
- Does
go-sdksupport new HTTP connections when the server closes the connection? I.e., can it churn the connection to do a new method after initialization? - What steps can I take to debug this further? For the curious, this is the server I'm using: https://github.com/zuplo/mcp/tree/main/examples/calculator
- What is the code path that a "Not found" would be surfaced here? Very curious!
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
documentationImprovements or additions to documentation or error messagesImprovements or additions to documentation or error messages