
This fix is part of MCP troubleshooting, within The MCP Guide. Still stuck? Request a free MCP readiness review.
"Session not found" means the server no longer knows the Mcp-Session-Id your client sent. The session expired, the server restarted, or a load balancer sent you to a different instance. The fastest fix on the client side is to reconnect, which starts a new session. On the server side, either route each session to the same instance or run the server stateless. The 2026-07-28 MCP spec removed sessions entirely, so this error only appears on connections that use the 2025-era Streamable HTTP behavior.
Checked against: the Python SDK troubleshooting page, the 2025-11-25 transports page and the 2026-07-28 Streamable HTTP page on 2 November 2026 (Python SDK mcp 2.3.0). eSEOspace did not run these steps.
Key Takeaways
- In the 2025 spec revisions, a server could assign a session ID and must answer HTTP 404 once that session is terminated.
- On a 404 for a request carrying
Mcp-Session-Id, the 2025-11-25 spec says the client must start a new session with a freshinitialize. - The Python SDK closes idle sessions after 30 minutes by default and returns
{"code": -32600, "message": "Session not found"}with HTTP 404. - Multiple workers without sticky routing is the most common cause when no restart happened.
- Servers on the 2026-07-28 revision should ignore
Mcp-Session-Idand never mint one, so moving to the modern era removes the error.
What this error means
The 2025-11-25 transports page let a Streamable HTTP server assign a session ID in an MCP-Session-Id header at initialization. The client then sends that header on every request. It also says: "The server MAY terminate the session at any time, after which it MUST respond to requests containing that session ID with HTTP 404 Not Found." When a client gets that 404, "it MUST start a new session by sending a new InitializeRequest without a session ID attached."
So the error is the spec working as designed. The real question is why the session disappeared.
The Python SDK troubleshooting page lists the causes: the server restarted, you were routed to a different instance, or the session expired because nothing was in flight for session_idle_timeout (30 minutes by default). It adds: "Sessions live in that one process's memory." The SDK source also rejects a session if the request uses a different credential than the one that created it, and it responds "exactly as if the session did not exist."
The 2026-07-28 changelog removed protocol-level sessions and the Mcp-Session-Id header. A modern-only server that receives the header should ignore it, according to the Streamable HTTP page. Read our stateless protocol explainer for why.
Quick fix
- Reconnect the client. In Claude Code, open
/mcpand reconnect the server. In your own code, close the client and open a new one. - Check for a recent deploy or restart. A burst of these errors right after a deploy is normal, per the Python SDK docs.
- Count your server instances. If you run more than one worker or container, either enable sticky sessions on the load balancer or switch to stateless mode.
- Check the idle timeout. If clients go quiet for long periods, raise
session_idle_timeoutor let clients reconnect. - Plan the move to 2026-07-28. Modern clients and servers have no sessions to lose.
Fix by client / OS
Claude Code
Claude Code's MCP docs say it reconnects a remote server that drops mid-session. You can also reconnect manually from /mcp. Claude Code's v2 client runtime asks HTTP servers whether they support revision 2026-07-28 and uses it with those that do, which avoids sessions with modern servers. If you pinned the older runtime with MCP_SDK_GENERATION=v1 or MCP_PROTOCOL_NEGOTIATION=legacy, every server uses the older handshake.
VS Code
Run MCP: List Servers, pick the server and restart it, as described in VS Code's manage and troubleshoot page. Use Show Output to see whether a 404 came back.
Python server (official SDK)
You have two documented fixes for multi-worker setups: sticky routing, or stateless_http=True. Stateless mode creates a fresh transport per request with no session tracking. If you need sessions for older clients, keep one process per session or route by session ID. The matching server log line is Rejected request with unknown or expired session ID: <id>, logged at INFO, so raise your log level to see it.
TypeScript server (official SDK v2)
The v2 createMcpHandler serves 2025-era clients statelessly by default, according to the SDK's legacy clients page. Under that default a legacy GET or DELETE answers 405. To keep an existing sessionful deployment, the page shows routing with isLegacyRequest in front of a strict handler.
Your own client code
Catch the error and reconnect instead of retrying inside the dead session. The Python SDK docs put it plainly: leave the async with Client(...) block and enter a new one.
Where to find the logs
- Claude Code:
/mcpshows status; runclaude --debug-file /tmp/claude-debug.logfor detail. - VS Code: MCP: List Servers > Show Output.
- Python server: INFO-level
Rejected request with unknown or expired session ID, preceded bySession <id> idle timeoutwhen it expired. - Load balancer: compare which backend served the opening request and which served the failing one.
If it still fails
- 404 on every second request. Your proxy may strip the
Mcp-Session-Idheader, or a browser client cannot read it. Browsers needAccess-Control-Expose-Headers: Mcp-Session-Id; see MCP CORS errors. - 404 after token refresh. The Python SDK binds a session to the credential that created it. A new identity needs a new session.
- Serverless hosting. Each invocation may be a new process, so in-memory sessions cannot survive. Run stateless.
- Unsure which error code you got. Paste it into our MCP error code lookup. Our Streamable HTTP reference shows how the transport changed.
Next step
If your remote MCP server runs on several instances and still uses 2025-era sessions, eSEOspace's MCP readiness audit checks transport, spec version and scaling setup. Related: protocol version mismatch errors.
More in the MCP Guide
Free tools: MCP Error Code Lookup · MCP Config Generator
Latest research: State of MCP: October 2026
Frequently asked questions
Is "Session not found" a bug in my server?
Usually not. The Python SDK docs say "There is no server bug to find" in the common cases: a restart, a different instance, or an idle timeout. It becomes a bug only when sessions vanish without any of those, which points to routing.
Why is the JSON-RPC code -32600 if the HTTP status is 404?
The HTTP 404 comes from the spec's session rule. The Python SDK puts a JSON-RPC error body on that 404 with code -32600 (Invalid Request) and an id of null. Other SDKs may use a different body, so check the HTTP status first.
Does the 2026-07-28 spec still have sessions?
No. The changelog removed protocol-level sessions and the Mcp-Session-Id header. Servers that need state across calls pass explicit handles as normal tool arguments.
Should I just make sessions never expire?
The Python SDK lets you set session_idle_timeout=None, so sessions live until the client deletes them or the manager shuts down. That does not help with restarts or multiple instances, and it holds memory. Stateless mode is usually the better long-term fix.











