mcp: preserve JSON number precision in tool argument schemas - #1244
mcp: preserve JSON number precision in tool argument schemas#1244jstar0 wants to merge 3 commits into
Conversation
5e24747 to
78592ba
Compare
|
Rebased onto The bug survives that restructuring on both paths — confirmed on for an input of Two things changed from the first version:
Added
|
applySchema decoded tool arguments into a map[string]any, which represents every JSON number as a float64, and re-marshalled the value when schema defaults were applied. Integers outside the IEEE-754 safe range were silently rounded before the typed handler decoded them: a tool taking an int64 ID received 9007199254740992 for an argument of 9007199254740993. Decode with UseNumber so the re-marshalled JSON reproduces each number's original literal text. UnmarshalUseNumber applies the same nesting-depth check as Unmarshal. Validation cannot run on that value directly. A json.Number has reflect.Kind String, so jsonschema's type check reports it as a JSON string and rejects it against "type": "integer". Validate a copy whose numbers are converted back to float64, which is exactly the representation this code has always validated, so validation semantics are unchanged. A number too large for a float64 is still rejected, as it was when decoding produced the error. This covers the output schema path as well, so an object-rooted structured result keeps its precision on the wire. Fixes modelcontextprotocol#1201
78592ba to
485e284
Compare
This reverts commit 485e284.
|
Scope update: this PR is limited to issue #1201. I removed the separate StructuredContent precision follow-up so the diff stays focused on schema-processed tool arguments and outputs. On exact head fd4681d, local go test ./..., go vet ./..., formatting/diff checks, and all 9 hosted checks pass. The PR description now reflects this scope; please review this head when convenient. |
Fixes #1201.
The bug
Tool arguments and schema-validated outputs pass through
applySchema. Decoding JSON numbers intomap[string]anywith the defaultencoding/jsonbehavior converts them tofloat64; when defaults require a re-marshal, integers outside the exactfloat64range can be silently rounded. Usingjson.Numberdirectly for schema validation is not compatible with the currentjsonschema-gotype classification, so the original number must be preserved separately from the validation representation.The fix
internal/json.UnmarshalUseNumber, retaining the existing nesting-depth guard.float64-converted copy to preserve current JSON Schema behavior.float64values.Verification
go test ./...— passed on the narrowed headfd4681d.go vet ./...— passed.gofmt -d internal/json/json.go mcp/server_test.go mcp/tool.go mcp/tool_test.go— no changes.git diff --check— passed.TestApplySchemaNumberPrecisioncovers unsafe integers, nested data, arrays, and precise numbers when defaults force a re-marshal.TestApplySchemaOutputNumberPrecisioncovers the output-schema default path.TestApplySchemaNumberErrorspreserves errors for unrepresentable values and invalid types.TestToolArgumentIntegerPrecisionexercises the typed handler through an in-memory client/server call.Hosted checks for exact head
fd4681dd320c08e0e3fcc86db77fbf2b9183777cpassed: CodeQL, Analyze (actions/go), client and server conformance, lint, race-test, and Test on Go 1.25 and 1.26.