HTTP MCP transport does not auto-reinitialize after server restart (404 "Session not found" is not handled)
Summary
When a Streamable-HTTP MCP server is restarted while a Claude Code session is open, the session's stored MCP session ID becomes stale. The server correctly returns HTTP 404 with Mcp-Session-Id missing (per the MCP spec signal for "session not found"), but Claude Code does not reinitialize the transport. The tools silently stop working for the rest of the session, and /mcp still reports the server as "connected" — stale UI state.
Only a full process exit (Ctrl+D / exit) and relaunch recovers. /load does not restart the underlying process, so it does not fix this.
Environment
- Claude Code: 2.1.145
- macOS: 26.4.1 (darwin 25.4.0)
- Transport: Streamable HTTP MCP (local server on
127.0.0.1)
Reproduction
- Configure a local HTTP MCP server (e.g. a Gmail HTTP MCP service on
127.0.0.1:8761). - Start a Claude Code session. Confirm MCP tools work (e.g.
get_gmail_profile). - In another terminal, fully restart the MCP server process (new PID, port re-binds).
- In the same Claude Code session, call any MCP tool from that server.
Expected: Claude Code detects the 404 "Session not found" response, performs an initialize against the same URL, stores the new Mcp-Session-Id, and retries the original tool call. The session continues to work.
Actual: Tool calls fail. /mcp still shows the server as "connected" because the UI state is not refreshed on transport failure. /mcp reconnect does not actually reinitialize the HTTP transport. The only fix is exit + relaunch.
Evidence
Reproduced cleanly with two parallel paths:
- Direct
curlagainst the same MCP server completes the full handshake:initializereturns a newMcp-Session-Id,tools/listworks,tools/callreturns the live Gmail profile (305k+ messages, correct user). Server is healthy. - Same server, from the stale Claude Code session: the server returns
HTTP 404 Not Foundwith body{"error":"Session not found"}for the stored session ID. Claude Code surfaces this as a tool failure rather than triggering re-initialize.
lsof -p <claude-pid> after the MCP server restart shows zero open connections to the MCP server's port, confirming the transport is dead — but /mcp continues to display "connected."
Impact
Any workflow that restarts a local HTTP MCP server (dependency update, reauth flow, hotfix, automated cron) silently bricks every active Claude Code session until the user notices and fully restarts. The user-visible symptom is "MCP suddenly stopped working" with no clear cause, because the UI lies about connection state.
This is the same class of failure as a TCP socket going stale: the spec already defines the recovery handshake (404 → re-initialize with the same Mcp-Session-Id URL), Claude Code just isn't implementing the client side of it.
Suggested fix
On any HTTP MCP tool call that returns HTTP 404 or includes {"error": "Session not found"} (or equivalent per MCP spec), the Streamable-HTTP transport should:
- Discard the stored
Mcp-Session-Id. - Re-issue
initializeagainst the same server URL. - Capture the new session ID.
- Transparently retry the original tool call once.
- Only surface a failure to the model/UI if the re-
initializeitself fails.
In parallel, /mcp UI state should reflect real transport health (e.g. last successful request), not just "we configured this server at startup."
Workaround
For users running local HTTP MCP servers, do not restart the server mid-session. If a restart is necessary, fully exit Claude Code first, then restart the server, then relaunch Claude Code. /load and /mcp reconnect do not recover the transport.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗