HTTP MCP transport does not auto-reinitialize after server restart (404 "Session not found" is not handled)

Resolved 💬 4 comments Opened May 20, 2026 by rogenmoserdavid-design Closed May 23, 2026

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

  1. Configure a local HTTP MCP server (e.g. a Gmail HTTP MCP service on 127.0.0.1:8761).
  2. Start a Claude Code session. Confirm MCP tools work (e.g. get_gmail_profile).
  3. In another terminal, fully restart the MCP server process (new PID, port re-binds).
  4. 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 curl against the same MCP server completes the full handshake: initialize returns a new Mcp-Session-Id, tools/list works, tools/call returns 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 Found with 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:

  1. Discard the stored Mcp-Session-Id.
  2. Re-issue initialize against the same server URL.
  3. Capture the new session ID.
  4. Transparently retry the original tool call once.
  5. Only surface a failure to the model/UI if the re-initialize itself 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.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗