-
Notifications
You must be signed in to change notification settings - Fork 233
Closed
Labels
documentation/errorsImprovements or additions to documentation or error messages.Improvements 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-sdk
support 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!
Metadata
Metadata
Assignees
Labels
documentation/errorsImprovements or additions to documentation or error messages.Improvements or additions to documentation or error messages.