-
Notifications
You must be signed in to change notification settings - Fork 723
Closed
Description
Description
The server cannot be modified if it is being queried. In the example below:
- client is initialized and calls tool
- a new tool is added to the server
- next client tool fails:
transport error: unexpected nil response
The crucial fact is that the evaluation of query has to take some time (100 * time.Millisecond in function double)
Code Sample
package main
import (
"context"
"fmt"
"github.com/mark3labs/mcp-go/client"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
"log"
"time"
)
func addCalc(s *server.MCPServer, name string) {
// Add a calculator tool
calculatorTool := mcp.NewTool(name,
mcp.WithDescription("Double x"),
mcp.WithNumber("x",
mcp.Required(),
mcp.Description("number"),
),
)
s.AddTool(calculatorTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
x, err := request.RequireFloat("x")
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
time.Sleep(100 * time.Millisecond)
return mcp.NewToolResultText(fmt.Sprintf("%.2f", 2*x)), nil
})
}
func createMCPServer() *server.MCPServer {
s := server.NewMCPServer(
"Calculator Demo",
"1.0.0",
)
addCalc(s, "calculate")
return s
}
func getClient() *client.Client {
c, err := client.NewStreamableHttpClient("http://localhost:7751/mcp")
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
// Create context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := c.Start(ctx); err != nil {
log.Fatalf("Failed to start transport: %v", err)
}
// Initialize the connection
_, err = c.Initialize(ctx, mcp.InitializeRequest{
Params: mcp.InitializeParams{
ProtocolVersion: mcp.LATEST_PROTOCOL_VERSION,
ClientInfo: mcp.Implementation{
Name: "calculator-client",
Version: "1.0.0",
},
Capabilities: mcp.ClientCapabilities{},
},
})
if err != nil {
log.Fatalf("Failed to initialize: %v", err)
}
return c
}
func query(ctx context.Context, c *client.Client) {
result, err := c.CallTool(ctx, mcp.CallToolRequest{
Params: mcp.CallToolParams{
Name: "calculate",
Arguments: map[string]interface{}{
"x": 10,
},
},
})
if err != nil {
fmt.Printf("Error calling tool: %v\n", err)
return
}
if result.IsError {
fmt.Printf(" Error: %s\n", result.Content[0])
} else {
fmt.Printf(" Result: %s\n", result.Content[0])
}
}
func main() {
s := createMCPServer()
sseServer := server.NewStreamableHTTPServer(s)
go func() {
if err := sseServer.Start("localhost:7751"); err != nil {
fmt.Printf("Server error: %v\n", err)
return
}
}()
time.Sleep(100 * time.Millisecond)
cli := getClient()
ctx := context.Background()
query(ctx, cli)
addCalc(s, "calc")
query(ctx, cli)
return
}Logs or Error Messages
$ go run bug/main.go
Result: {{%!s(*mcp.Annotations=<nil>)} %!s(*mcp.Meta=<nil>) text 20.00}
2025/11/19 23:54:35 http: superfluous response.WriteHeader call from github.com/mark3labs/mcp-go/server.(*StreamableHTTPServer).handlePost (streamable_http.go:460)
Error calling tool: transport error: unexpected nil response
Environment
- Go version (see
go.mod): 1.24 - mcp-go version (see
go.mod): v0.43.0
Metadata
Metadata
Assignees
Labels
No labels