Describe the bug
When using the typed mcp.AddTool API, an integer larger than the IEEE-754
safe integer range can be silently rounded before it reaches the tool handler.
The value is accepted as a JSON integer, but the handler receives a different
value.
To Reproduce
Environment:
- Go MCP SDK:
v1.7.0 - Go:
go1.25.7 linux/amd64
Save the following as main.go in a module that requires
github.com/modelcontextprotocol/go-sdk v1.7.0:
package main
import (
"context""fmt""log""github.com/modelcontextprotocol/go-sdk/mcp"
)
typeinputstruct {
IDint64`json:"id"`
}
funcmain() {
constwantint64=9007199254740993// 2^53 + 1server:=mcp.NewServer(
&mcp.Implementation{Name: "server", Version: "repro"}, nil)
mcp.AddTool(server, &mcp.Tool{Name: "echo_id"},
func(_ context.Context, _*mcp.CallToolRequest, ininput) (
*mcp.CallToolResult, input, error) {
fmt.Printf("handler_received=%d\n", in.ID)
returnnil, in, nil
})
clientTransport, serverTransport:=mcp.NewInMemoryTransports()
ctx:=context.Background()
serverSession, err:=server.Connect(ctx, serverTransport, nil)
iferr!=nil {
log.Fatal(err)
}
deferserverSession.Close()
client:=mcp.NewClient(
&mcp.Implementation{Name: "client", Version: "repro"}, nil)
clientSession, err:=client.Connect(ctx, clientTransport, nil)
iferr!=nil {
log.Fatal(err)
}
deferclientSession.Close()
_, err=clientSession.CallTool(ctx, &mcp.CallToolParams{
Name: "echo_id",
Arguments: map[string]any{"id": want},
})
iferr!=nil {
log.Fatal(err)
}
fmt.Printf("want=%d\n", want)
}Run:
go mod init example.com/mcp-int64-repro
go get github.com/modelcontextprotocol/go-sdk@v1.7.0
go run .
Observed output:
handler_received=9007199254740992
want=9007199254740993
The issue is reproducible with the in-memory transport and does not depend on
an external server.
Expected behavior
The typed tool handler should receive exactly the integer sent by the client:
handler_received=9007199254740993
want=9007199254740993
Values representable by Go int64 should not be silently changed during
schema validation or default application.
Logs
No error is returned. The value is silently rounded.
Additional context
The behavior appears to come from the schema application path in
mcp/tool.go: tool arguments are decoded into map[string]any, and the
generic JSON number is then represented as float64. Applying defaults causes
the value to be marshaled again, making the rounding observable before the
typed handler decodes it.
A possible implementation direction is to preserve JSON numbers (for example,
using Decoder.UseNumber()) while applying the schema and defaults, while
retaining strict validation of trailing JSON data. The low-level
Server.AddTool handler path does not have this particular schema round-trip,
but it also does not provide the typed validation/default behavior.
This affects any tool that accepts IDs or counters outside the IEEE-754 safe
integer range, even though those values are valid JSON integers and valid Go
int64 values.
Describe the bug
When using the typed
mcp.AddToolAPI, an integer larger than the IEEE-754safe integer range can be silently rounded before it reaches the tool handler.
The value is accepted as a JSON integer, but the handler receives a different
value.
To Reproduce
Environment:
v1.7.0go1.25.7 linux/amd64Save the following as
main.goin a module that requiresgithub.com/modelcontextprotocol/go-sdk v1.7.0:Run:
go mod init example.com/mcp-int64-repro go get github.com/modelcontextprotocol/go-sdk@v1.7.0 go run .Observed output:
The issue is reproducible with the in-memory transport and does not depend on
an external server.
Expected behavior
The typed tool handler should receive exactly the integer sent by the client:
Values representable by Go
int64should not be silently changed duringschema validation or default application.
Logs
No error is returned. The value is silently rounded.
Additional context
The behavior appears to come from the schema application path in
mcp/tool.go: tool arguments are decoded intomap[string]any, and thegeneric JSON number is then represented as
float64. Applying defaults causesthe value to be marshaled again, making the rounding observable before the
typed handler decodes it.
A possible implementation direction is to preserve JSON numbers (for example,
using
Decoder.UseNumber()) while applying the schema and defaults, whileretaining strict validation of trailing JSON data. The low-level
Server.AddToolhandler path does not have this particular schema round-trip,but it also does not provide the typed validation/default behavior.
This affects any tool that accepts IDs or counters outside the IEEE-754 safe
integer range, even though those values are valid JSON integers and valid Go
int64values.