Claude Desktop drops the MCP tool argument named `session_id` (only that token) from tools/call
Summary
Claude Desktop omits the tool-call argument named session_id when invoking MCP tools over a Streamable-HTTP server (via the mcp-remote stdio bridge). The argument is dropped before it reaches the bridge — and only the token session_id is affected; sibling string arguments on the same server (generation_id, image_id, category_id, name) are delivered correctly. This looks like a collision between the tool argument name session_id and the Streamable-HTTP transport's own session identifier (Mcp-Session-Id).
Environment
- Claude Desktop →
mcp-remote0.1.37 → stateless Streamable-HTTP MCP server - Server SDK:
@modelcontextprotocol/sdk1.26.0 viamcp-handler1.1.0 (SSE disabled) - Observed: 2026-07-12
Actual behavior
A tool with a required session_id: z.string() receives undefined:
MCP error -32602: Input validation error: Invalid arguments for tool get_session:
[ { "code": "invalid_type", "expected": "string", "received": "undefined", "path": ["session_id"], "message": "Required" } ]
When session_id is optional, it is simply absent, so the tool falls back to its default (e.g. auto-creating a new session) — making it look like the passed id is silently ignored.
Expected behavior
The session_id argument the model supplies in a tools/call should reach the MCP server verbatim, like any other argument.
Proof it is the client, not the server or the bridge
The identical call succeeds through every non-Desktop client against the same live server:
| Client path | session_id delivered? |
|---|---|
| Raw MCP SDK Client, in-memory transport | ✅ |
| MCP SDK Client over real HTTP (StreamableHTTPClientTransport) | ✅ |
| mcp-remote 0.1.37 driven by a scripted stdio client | ✅ |
| Claude Desktop (same mcp-remote bridge) | ❌ dropped |
mcp-remote forwards the exact JSON-RPC it receives (verified via its [Local→Remote] tools/call logs — the arguments are intact when it is driven by a non-Desktop client), so the argument is dropped upstream of the bridge, inside Claude Desktop.
Minimal reproduction
Register two tools that differ only in argument name, each echoing its arguments:
server.registerTool("t_session", { inputSchema: { session_id: z.string() } }, echoArgs);
server.registerTool("t_generation", { inputSchema: { generation_id: z.string() } }, echoArgs);
From Claude Desktop, ask it to call each tool with a value. t_generation receives { generation_id: "..." }; t_session receives {} (→ -32602 … received: undefined, path: session_id).
Impact
Any MCP tool whose input uses an argument literally named session_id is uncallable from Claude Desktop. session_id is an extremely common tool-parameter name, so this silently breaks many third-party MCP servers with no error surfaced to the user (for optional params it just does the wrong thing).
Suspected cause
The tool argument name session_id collides with the MCP Streamable-HTTP transport's protocol-level session identifier (Mcp-Session-Id header / sessionId). Related session-id handling issues: #41836, #48557, #99, #27425.
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Update: confirmed via client-side capture — it's the
remote-devicesbridgeA user reproduced this from Claude Desktop / Cowork and captured the client-side request/response, which pins down the strip precisely:
remote-devicesMCP bridge (tools are surfaced asmcp__remote-devices__imggen__*).``
json
``{ "session_id": "e3bdbf73-afa1-4c22-8eaf-16a35c967c4b" }
undefinedand rejected it:``
``MCP error -32602: Input validation error: Invalid arguments for tool list_approved_images:
[ { "code": "invalid_type", "expected": "string", "received": "undefined", "path": ["session_id"], "message": "Required" } ]
get_generation({generation_id})andget_image({image_id})reached the server fine (returnednot_foundfor a probe id).So the argument named
session_idis present in the client's outbound call and absent by the time it reaches the server — theremote-devicesbridge is dropping it, almost certainly a collision with the transport's own session id (Mcp-Session-Id). Renaming the tool parameter to anything else (session_name,gen_session_id) is delivered normally, which is the workaround we've shipped on our side — but it means every third-party server using the very commonsession_idparameter name is silently broken from Desktop.Also for me: The remote-devices bridge strips any MCP tool argument named session_id before it reaches the server — the server receives the call with that key missing while sibling arguments arrive intact (verified differentially; the same calls work over direct stdio). Presumably the bridge reserves session_id for its own routing and pops it from tool arguments. This silently breaks third-party MCP servers that use that parameter name.
Seeing the same behaviour from a different client and a different transport chain,
which suggests this isn't specific to Claude Desktop or to
mcp-remote.Setup: a Claude Code / Cowork cloud agent session calling
CrowdStrike/falcon-mcp tools, proxied
through the Claude desktop bridge to a locally-hosted server — no
mcp-remote, andnot a Streamable-HTTP server of my own. Server-side validation here is Pydantic
rather than Zod.
Same symptom.
falcon_execute_rtr_read_only_command(session_id, base_command,:command_string)
1 validation error for execute_read_only_commandArguments
session_id
Field required [type=missing, input_value={'base_command': 'ls',
'command_string': '...'}, input_type=dict]
The sibling arguments arrive.
session_iddoes not.Cleanest evidence is
falcon_delete_rtr_session, whose only parameter issession_id:1 validation error for delete_sessionArguments
session_id
Field required [type=missing, input_value={}, input_type=dict]
input_value={}— the arguments object arrives empty. Worth noting it's a missingkey rather than a null: Pydantic would report
type=string_typeif it receivedNone. That matches your Zodreceived: "undefined"from an entirely differentvalidation stack.
Parameters that pass fine against the same server, several of them on the same
tools:
ids(an array of RTR session IDs — so it's the exact key name that'saffected, not the concept),
cloud_request_id,device_id,filter,limit,sort,offset.Practical impact: the schema marks
session_idrequired and the transportrefuses to carry it, so no valid invocation of the tool exists. Because the failure
surfaces as a server-side validation error, the natural reading is that the server
is at fault — I spent a while suspecting falcon-mcp before isolating it to the client.
For this server it means Real Time Response command execution is unreachable from an
agent session, which is a meaningful gap in an incident-response workflow.
Given it reproduces outside Desktop, would you reconsider the
invalidlabel?