MCP proxy surfaces `-32600 "Invalid content from server"` instead of reinitializing on session-404
MCP proxy surfaces -32600 "Invalid content from server" instead of reinitializing on session-404
Summary
When a remote Streamable-HTTP MCP server returns HTTP 404 to a POST /mcp request whose Mcp-Session-Id is not (or no longer) recognized, the Anthropic MCP proxy surfaces this to the client as a JSON-RPC error:
{"jsonrpc":"2.0","id":<n>,"error":{"code":-32600,"message":"Anthropic Proxy: Invalid content from server","data":null}}
instead of discarding the cached Mcp-Session-Id and re-running the initialize handshake.
This causes the connector to appear permanently stuck after any event that invalidates the server's view of the session (server restart, package upgrade, idle-reap of the rmcp session worker). The end-user experience: every tool call fails with the same -32600 error until they manually run /mcp reconnect, which forces the proxy to drop its cached session id.
Expected behavior
Per the MCP 2025-03-26 Streamable-HTTP transport spec: when the server returns 404 on a request carrying an Mcp-Session-Id, the client must discard that session id and re-issue initialize before retrying the original request. Subsequent retries should succeed transparently.
Actual behavior
The proxy returns -32600 "Invalid content from server" for every retry, with the same dead Mcp-Session-Id still attached. The client never re-initializes on its own; only an explicit /mcp reconnect (which clears the proxy's cached session id) restores functionality.
Reproduction
- Connect to a remote Streamable-HTTP MCP server (any spec-compliant one will do).
- Make at least one successful
tools/callso the proxy caches anMcp-Session-Id. - Cause the server to forget that session id, e.g. by restarting it.
- Issue another
tools/callfrom the connector. - Observe
-32600 "Invalid content from server"on every subsequent request until/mcp reconnect.
Evidence
The remote server in this report is a Rust mcp-gitlab instance running rmcp 1.6 behind Caddy. After a package upgrade (process PID changed), client requests with the pre-upgrade Mcp-Session-Id hit the new process and get a deterministic HTTP 404 in 0 ms:
2026-05-15T14:13:56Z mcp request user_id=5887617 session_id="704c3cdb-3c2f-457b-85e4-d23b3e6a17ab" http_method=POST jsonrpc_method="tools/call" jsonrpc_id="4" body_len=348 status=404 elapsed_ms=0
2026-05-15T14:14:32Z mcp request user_id=5887617 session_id="704c3cdb-3c2f-457b-85e4-d23b3e6a17ab" http_method=POST jsonrpc_method="tools/call" jsonrpc_id="5" body_len=5497 status=404 elapsed_ms=0
2026-05-15T14:14:35Z mcp request user_id=5887617 session_id="704c3cdb-3c2f-457b-85e4-d23b3e6a17ab" http_method=POST jsonrpc_method="tools/call" jsonrpc_id="6" body_len=4688 status=404 elapsed_ms=0
2026-05-15T14:14:47Z mcp request user_id=5887617 session_id="704c3cdb-3c2f-457b-85e4-d23b3e6a17ab" http_method=POST jsonrpc_method="tools/call" jsonrpc_id="7" body_len=348 status=404 elapsed_ms=0
The Mcp-Session-Id 704c3cdb-... was minted by a process that no longer exists; the new process correctly returns 404. The proxy surfaces all four as -32600 "Invalid content from server" to the Claude-Code client. Body size and parallelism are not relevant: 348-byte requests fail identically to 5497-byte ones.
After /mcp reconnect, the next request triggers an initialize handshake against the new process and tool calls succeed immediately.
Impact
Any spec-compliant remote MCP server is affected whenever the server side legitimately invalidates a session, including:
- Routine package upgrades that restart the server.
- The server's transport reaping idle session workers (a common pattern).
- Network conditions that cause the server to lose session state.
For Claude Code users connected to remote MCP servers, this manifests as the connector silently breaking until they realize /mcp reconnect is needed. There is no log line or telemetry on the client side that suggests this is the right action -- the visible error message is Invalid content from server, which sounds like a server-side malformation.
Suggested fix
In the proxy's POST /mcp retry path, treat HTTP 404 with an Mcp-Session-Id request header as "session gone, reinitialize" -- discard the cached session id, run initialize against the same endpoint, and replay the original tool call. This is the behavior the MCP 2025-03-26 Streamable-HTTP transport spec already mandates.
Workaround
/mcp reconnect clears the proxy's cached session id. The next tool call triggers initialize against the server and resumes normal operation.
Related issues -- distinct root cause, same surface error
The error string Anthropic Proxy: Invalid content from server already appears in two open/closed issues:
- #51812 (open) -- Linear MCP, narrow trigger:
mcp__Linear__get_issue(includeRelations: true). The upstream returns valid 200 content; the proxy's response-shape validator rejects it. - #55839 (closed as duplicate of #51812) -- Pendo MCP, every tool call fails identically. Same hypothesis: the proxy's response-validator trips on the upstream's payload shape.
This report is a different root cause. In our case the upstream returns HTTP 404 (correctly, per the MCP 2025-03-26 Streamable-HTTP transport spec) for a request whose Mcp-Session-Id is no longer recognized. The proxy then surfaces that 404 as the same -32600 "Invalid content from server" string instead of following the spec's "discard session id and reinitialize" path. Body sizes here are tiny (348 bytes); response-shape validation is not involved.
Fixing #51812/#55839 (response-validator) and fixing this report (404-on-stale-session handling) are independent changes -- they happen to share an error string because the proxy collapses several distinct failure modes under one user-visible message. The two should probably be tracked separately, and the error string itself would benefit from being more specific so future triage isn't bottlenecked on disambiguating the underlying failure.
Versions
- Claude Code CLI: 2.1.140
- Remote MCP server: rmcp 1.6 (Rust); behaves identically with both
keep_alive=None(reaper disabled) and the default reaper configuration -- the failure is purely client-side proxy behavior in response to the server's 404.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗