Skip to content

bug: after adding tool to server, client's call fails #638

@marigs

Description

@marigs

Description

The server cannot be modified if it is being queried. In the example below:

  1. client is initialized and calls tool
  2. a new tool is added to the server
  3. 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

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions