MCP tool call arguments may not be serialised with correct types — integers and arrays arrive at server as strings

Resolved 💬 1 comment Opened Jun 3, 2026 by matt-beanland Closed Jul 8, 2026

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: 0 caused the server to return Ash.Error.Query.InvalidOffset: "0" is not a valid offset — the integer 0 appeared to arrive as the string "0"
  • filter: [{"field": "rsp_id", "operator": "eq", "value": "0002"}] was silently dropped — the server received filter: nil and 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

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗