Claude Desktop drops the MCP tool argument named `session_id` (only that token) from tools/call

Open 💬 1 comment Opened Jul 13, 2026 by jgilfoil

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-remote 0.1.37 → stateless Streamable-HTTP MCP server
  • Server SDK: @modelcontextprotocol/sdk 1.26.0 via mcp-handler 1.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.

View original on GitHub ↗

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