Description
Some MCP clients (including Claude Desktop) send numeric tool arguments as JSON strings instead of numbers. For example, when calling pull_request_read with pullNumber, the client sends "5812" (string) instead of 5812 (number). This causes JSON schema validation to fail with:
Expected number, received string
The tool never executes because the MCP SDK's schema validation rejects the request before it reaches the handler.
Steps to Reproduce
- Use an MCP client that sends numeric parameters as strings (e.g., Claude Desktop)
- Call any tool that has a numeric parameter, such as
pull_request_read with pullNumber
- The client sends:
{"pullNumber": "5812", "owner": "...", "repo": "...", "method": "get"}
- Validation fails with
Expected number, received string for pullNumber
Expected Behavior
The server should accept both 5812 (number) and "5812" (string) for numeric parameters, since MCP clients may serialize integers as strings. The mapstructure.Decode call in the handler already handles type coercion from float64/string to int32, but the request is rejected at the JSON schema validation layer before reaching the handler.
Root Cause Analysis
The JSON schema for numeric parameters is defined with "type": "number":
// pkg/github/pullrequests.go:52-55
"pullNumber": {
Type: "number",
Description: "Pull request number",
},
The MCP SDK validates incoming arguments against this schema before the handler runs. When a client sends "5812" (string), the schema validator rejects it because "number" type does not accept strings.
Affected Parameters
This affects all int32 parameters decoded via mapstructure.Decode across multiple tools:
| File |
Parameter |
Struct Field |
pullrequests.go:1450 |
pullNumber |
PullNumber int32 |
pullrequests.go:1843 |
pullNumber |
PullNumber int32 |
pullrequests.go:1847 |
line |
Line *int32 |
pullrequests.go:1849 |
startLine |
StartLine *int32 |
discussions.go:314 |
discussionNumber |
DiscussionNumber int32 |
discussions.go:418 |
discussionNumber |
DiscussionNumber int32 |
issues.go:1805 |
issue_number |
IssueNumber int32 |
Possible Solutions
-
Use oneOf or custom schema: Define numeric parameters to accept both "number" and "string" types in the JSON schema, e.g., using oneOf: [{type: "number"}, {type: "string", pattern: "^\\d+$"}]
-
Pre-validation coercion: Add a middleware or wrapper that coerces string-encoded numbers to actual numbers in the arguments map before schema validation runs
-
SDK-level fix: If the MCP Go SDK supports custom validators or coercion hooks, configure the server to be lenient with numeric string inputs
-
Use "string" type with pattern: Define these parameters as strings with a numeric pattern, and parse them in the handler (though this changes the API contract)
Environment
- MCP Server: github-mcp-server (latest main)
- MCP Client: Claude Desktop (but likely affects other clients too)
- SDK:
github.com/modelcontextprotocol/go-sdk
Description
Some MCP clients (including Claude Desktop) send numeric tool arguments as JSON strings instead of numbers. For example, when calling
pull_request_readwithpullNumber, the client sends"5812"(string) instead of5812(number). This causes JSON schema validation to fail with:The tool never executes because the MCP SDK's schema validation rejects the request before it reaches the handler.
Steps to Reproduce
pull_request_readwithpullNumber{"pullNumber": "5812", "owner": "...", "repo": "...", "method": "get"}Expected number, received stringforpullNumberExpected Behavior
The server should accept both
5812(number) and"5812"(string) for numeric parameters, since MCP clients may serialize integers as strings. Themapstructure.Decodecall in the handler already handles type coercion fromfloat64/stringtoint32, but the request is rejected at the JSON schema validation layer before reaching the handler.Root Cause Analysis
The JSON schema for numeric parameters is defined with
"type": "number":The MCP SDK validates incoming arguments against this schema before the handler runs. When a client sends
"5812"(string), the schema validator rejects it because"number"type does not accept strings.Affected Parameters
This affects all
int32parameters decoded viamapstructure.Decodeacross multiple tools:pullrequests.go:1450pullNumberPullNumber int32pullrequests.go:1843pullNumberPullNumber int32pullrequests.go:1847lineLine *int32pullrequests.go:1849startLineStartLine *int32discussions.go:314discussionNumberDiscussionNumber int32discussions.go:418discussionNumberDiscussionNumber int32issues.go:1805issue_numberIssueNumber int32Possible Solutions
Use
oneOfor custom schema: Define numeric parameters to accept both"number"and"string"types in the JSON schema, e.g., usingoneOf: [{type: "number"}, {type: "string", pattern: "^\\d+$"}]Pre-validation coercion: Add a middleware or wrapper that coerces string-encoded numbers to actual numbers in the arguments map before schema validation runs
SDK-level fix: If the MCP Go SDK supports custom validators or coercion hooks, configure the server to be lenient with numeric string inputs
Use
"string"type with pattern: Define these parameters as strings with a numeric pattern, and parse them in the handler (though this changes the API contract)Environment
github.com/modelcontextprotocol/go-sdk