MCP tool call arguments may not be serialised with correct types — integers and arrays arrive at server as strings
Description
When calling MCP tools via Cowork, typed arguments (integers, arrays) appear to arrive at the MCP server as strings rather than their correct JSON types. This causes server-side validation failures and silent drops of structured parameters like filter conditions.
We may be using Cowork incorrectly — raising this in case it is a genuine serialisation issue on the client side.
How we found it
We were using Cowork to explore an ash_ai-backed MCP server (diffo_example). The server exposes a fully typed inputSchema for its tools, for example list_nnis:
{
"type": "object",
"properties": {
"filter": { "type": "array", "items": { "...": "..." } },
"limit": { "type": "integer", "default": 25 },
"offset": { "type": "integer", "default": 0 }
}
}
When we passed arguments via Cowork:
offset: 0caused the server to returnAsh.Error.Query.InvalidOffset: "0" is not a valid offset— the integer0appeared to arrive as the string"0"filter: [{"field": "rsp_id", "operator": "eq", "value": "0002"}]was silently dropped — the server receivedfilter: niland returned all records unfiltered
Curling the server directly with a correctly typed JSON-RPC payload worked perfectly:
curl -X POST http://localhost:4000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "list_nnis",
"arguments": {
"filter": [{"field": "rsp_id", "operator": "eq", "value": "0002"}]
}
},
"id": 1
}'
This returned the correct 4 filtered results. The Ash actions and AshNeo4j data layer are all working correctly — we verified this independently via iex. The server tools/list response also returns a complete, correctly typed inputSchema.
What we observed in Cowork
When tool schemas are loaded via ToolSearch, all parameters appear as {} — untyped. For example:
"filter": {}
"limit": {}
"offset": {}
Our hypothesis is that Claude is making tool calls without the type information needed to correctly serialise values, because the deferred schemas don't carry the real inputSchema from the server. Whether this is a Cowork issue, a usage issue on our side, or something else entirely, we're not sure.
What we'd expect
filter: [{"field": "rsp_id", "operator": "eq", "value": "0002"}] should arrive at the server as a JSON array, and limit: 25 should arrive as a JSON integer, consistent with the server's published inputSchema.
Context
- Cowork on macOS
- MCP server: ash_ai v0.7.1 over HTTP, protocol version
2024-11-05 - The server and all upstream Ash/AshNeo4j layers are confirmed working via direct curl and iex
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗