Bad Request: Missing session ID
- Spec
2025-11-25 → 2026-07-28- Evidence
- E2Reproducedarm64
- Python SDK
mcp@2.3.0- Verified
What it means
Section titled “What it means”Up to 2025-11-25, a Streamable HTTP server could hand out a session ID in the Mcp-Session-Id header after initialize, and expected it on every later request. 2026-07-28 removed sessions. A server that supports both generations has to decide which one a request belongs to, and in our tests the Python SDK 2.3.0 decided by the MCP-Protocol-Version header.
We sent a 2026-07-28 tools/list request with the version in _meta but without the header, and got:
{"error":{"code":-32600,"message":"Bad Request: Missing session ID"}}The request has no MCP-Protocol-Version header
Section titled “The request has no MCP-Protocol-Version header”The fix for hand-written requests and home-made clients: send the header on every POST, with the same version as in _meta.
-H 'MCP-Protocol-Version: 2026-07-28'With the header, the same request returned the tool list. Clients built on the official SDKs send it automatically.
The request is a GET
Section titled “The request is a GET”A plain GET /mcp to the same server, for example from a browser, also returned 400 with Bad Request: Missing session ID. The endpoint is meant for POST; this response only tells you the server is up. See 405 on GET /mcp.
A 2025 client skipped initialize
Section titled “A 2025 client skipped initialize”A 2025-11-25 client must call initialize first and then send the Mcp-Session-Id the server returned. If you are writing such a client, or a proxy strips the header, the server cannot find the session. Keep the header intact, or move the client to 2026-07-28, which needs no session.
Related
Section titled “Related”- From HTTP+SSE to Streamable HTTP
- Headers and body disagree (-32020): what a TypeScript server says in the same situation.
MCPDev is community documentation. It is not affiliated with the Model Context Protocol project or with the vendors of the clients it covers.