[BUG] MCP tool parameters with type: number are sent as strings to MCP servers
Environment
- Claude Code version: 2.1.71
- OS: macOS (Darwin 25.3.0)
- MCP Server: @mobilenext/mobile-mcp v0.0.46 (MCP SDK v1.26.0)
Description
When Claude Code calls an MCP tool that declares parameters with "type": "number" in its JSON Schema, the values are sent as strings in the JSON-RPC call. MCP servers using strict Zod validation (z.number()) rightfully reject these with "expected number, received string".
Root Cause Analysis
The issue is in the XML-to-JSON-RPC pipeline:
- MCP server exposes
tools/listwith JSON Schema declaring"type": "number"for parameters - Claude Code presents the schema to the Claude model
- Claude model generates tool calls in XML format:
<parameter name="x">330</parameter> - Claude Code parses the XML and sends JSON-RPC to the MCP server
The problem is at step 4. Everything in XML is inherently a string — there's no type distinction. Claude Code needs to use the JSON Schema from step 1 to coerce parameter values to their declared types before sending the JSON-RPC request. Currently, it passes raw strings through without coercion.
Reproduction
- Configure
@mobilenext/mobile-mcpin.mcp.json:
{
"mobile-mcp": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@mobilenext/mobile-mcp@latest"]
}
}
- Call
mobile_click_on_screen_at_coordinateswith any numeric x/y values
- Expected: Parameters sent as JSON numbers (
{"x": 330, "y": 200}) - Actual: Parameters sent as JSON strings (
{"x": "330", "y": "200"})
Error from MCP Server
MCP error -32602: Input validation error: Invalid arguments for tool mobile_click_on_screen_at_coordinates: [
{
"expected": "number",
"code": "invalid_type",
"path": ["x"],
"message": "Invalid input: expected number, received string"
},
{
"expected": "number",
"code": "invalid_type",
"path": ["y"],
"message": "Invalid input: expected number, received string"
}
]
MCP Server Schema
The server uses Zod (z.number()) which converts to JSON Schema {"type": "number"} via zodToJsonSchema. The schema is correct — the server properly declares these as numbers.
// From mobile-mcp server.ts
x: z.number().describe("The x coordinate to click on the screen, in pixels"),
y: z.number().describe("The y coordinate to click on the screen, in pixels"),
Suggested Fix
When constructing the JSON-RPC arguments object for an MCP tool call, Claude Code should walk the tool's JSON Schema and coerce values to their declared types:
"type": "number"→parseFloat(value)"type": "integer"→parseInt(value, 10)"type": "boolean"→value === "true""type": "string"→ no change (default)"type": "array"/"type": "object"→JSON.parse(value)
This is similar to how the existing $ref serialization bug (#18260) manifests, but affects plain primitive types.
Impact
This breaks any MCP tool that uses z.number(), z.boolean(), or z.integer() for parameters, which is extremely common. Affected tools include coordinate-based interactions (click, swipe, long press), pagination parameters, numeric configuration values, etc.
Workaround
MCP server authors can use z.coerce.number() instead of z.number() to accept both strings and numbers, but this shouldn't be necessary — the client should honor the schema.
This issue has 11 comments on GitHub. Read the full discussion on GitHub ↗