Skip to content

fix(private-server): run the MCP endpoint statelessly#275

Merged
passcod merged 1 commit into
mainfrom
mcp-stateless
Jun 25, 2026
Merged

fix(private-server): run the MCP endpoint statelessly#275
passcod merged 1 commit into
mainfrom
mcp-stateless

Conversation

@passcod

@passcod passcod commented Jun 25, 2026

Copy link
Copy Markdown
Member

🤖 Follow-up to #273 and #274. With Host and OAuth-discovery sorted, clients connect but then fail with Not Found: Session not found immediately after initialize — surfaced as "connected · tools fetch failed" / "Connection closed".

Cause

rmcp's default stateful mode keeps each MCP session in the handling process's memory and returns 404 for any later request whose Mcp-Session-Id it doesn't recognise. Behind the multi-replica deployment, the request after initialize is load-balanced to a different pod, which never saw that session → 404. Confirmed from Claude Code's MCP log:

Successfully connected ... capabilities: {"hasTools":true,...}
Error POSTing to endpoint: Not Found: Session not found
MCP session expired (server no longer recognizes session ID)
tools/list failed (MCP error -32000: Connection closed)

(A single curl reusing one HTTP/2 connection lands on one pod, so it worked — which is why this only showed up with a real client opening multiple connections.)

Fix

This is a read-only request/response API with no server-initiated push, so disable sessions:

  • stateful_mode = false — each POST is self-contained; any replica can serve any request, no session affinity needed.
  • json_response = true — return plain application/json per request, so there's no long-lived SSE stream for the ingress to buffer or drop either.

Tests updated for the stateless transport, plus a regression test that a tools/call succeeds with no prior initialize and no session id.

Claude Code (and any client) connected, then got 'Not Found: Session not
found' on the request after initialize. rmcp's default stateful mode keeps
sessions in process memory; behind the multi-replica deployment a follow-up
request routed to a different pod than the one that ran initialize, so the
session was unknown and rmcp 404'd. Clients surface that as a dropped
connection / 'tools fetch failed'.

This is a read-only request/response API with no server-initiated push, so
disable sessions (stateful_mode=false) and return plain application/json
(json_response=true). Each POST is then self-contained and any replica can
serve it; there's also no long-lived SSE stream for the ingress to drop.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@passcod passcod merged commit e5779fd into main Jun 25, 2026
7 checks passed
@passcod passcod deleted the mcp-stateless branch June 25, 2026 05:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant