MCP Streamable HTTP uses one POST endpoint, and Mcp-Session-Id sessions end with 2026-07-28
DrFritzi · Reviewed · Updated 28 Sept 2026 · Markdown
Answer
A Streamable HTTP server exposes one MCP endpoint. The client sends every JSON-RPC message as its own POST with Accept: application/json, text/event-stream. The server answers a request with either Content-Type: application/json or an SSE stream (text/event-stream), and answers an accepted notification with 202 Accepted and no body. In MCP 2025-03-26 to 2025-11-25, a server could also issue an Mcp-Session-Id and offer a GET stream. The latest revision, 2026-07-28, removes both: every request is self-contained. This page covers both eras and marks which is which.
Details
Rules in every revision
- One endpoint path, for example
https://example.com/mcp. - The client MUST send an
Acceptheader that lists bothapplication/jsonandtext/event-stream. The client MUST handle either response type. - When a server replies with SSE, it may send notifications about that request (such as progress) before the final response. The response SHOULD end the stream.
- Since 2025-06-18, clients send an
MCP-Protocol-Versionrequest header. An unsupported value gets400 Bad Request. - Servers MUST validate
Originand MUST answer an invalidOriginwith403 Forbidden. Local servers SHOULD bind to 127.0.0.1, and all servers SHOULD authenticate. These rules defend against DNS rebinding.
Sessions in 2025-11-25 (legacy)
- The server MAY return
MCP-Session-Idon the HTTP response that carries theInitializeResult. The value must be visible ASCII (0x21–0x7E) and SHOULD be cryptographically secure. - The client MUST then send that header on every later request. A server that requires it SHOULD answer requests without it with
400. - Once a session ends, the server MUST answer that ID with
404 Not Found. The client MUST then start over with a newinitializeand no session ID. - A client that is finished SHOULD send
DELETEwith the header. The server MAY answer405.
The optional GET opened a standalone SSE stream for messages the server starts itself. A server that does not offer that stream MUST answer 405 Method Not Allowed. Streams could resume with Last-Event-ID.
Stateless vs stateful (legacy era)
The TypeScript SDK v1 makes this a single option. sessionIdGenerator: () => crypto.randomUUID() gives a stateful server that issues IDs and returns 404 for unknown ones. sessionIdGenerator: undefined gives a stateless server with no session header. The v1 source warns that a stateless transport cannot be reused across requests. Create a new one for each request, or two clients' message IDs can collide.
What 2026-07-28 changed
| Legacy (up to 2025-11-25) | Modern (2026-07-28) |
|---|---|
Optional Mcp-Session-Id, ended with DELETE |
No protocol sessions. State goes in server-issued handles passed as tool arguments |
| GET opens a server-to-client stream | GET is removed. Long-lived notifications use a subscriptions/listen POST |
| Server may send JSON-RPC requests on SSE | Server returns InputRequiredResult, and the client sends the request again with inputResponses |
Resumable via Last-Event-ID |
Not resumable. The client sends a broken request again with a new ID |
Only MCP-Protocol-Version |
Also Mcp-Method (every request) and Mcp-Name (tools/call, resources/read, prompts/get), which must match the body. A mismatch gets 400 with error -32020 |
Cancel with notifications/cancelled |
Close the request's response stream |
A server that speaks only 2026-07-28 SHOULD answer GET and DELETE with 405. It SHOULD ignore Mcp-Session-Id and Last-Event-ID. An unknown method gets 404 with JSON-RPC error -32601. That body tells it apart from a 404 sent by an old HTTP+SSE server.
Example modern request
POST /mcp HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/list
{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientCapabilities":{}}}}
Practical takeaway
If you design a new server today, make it stateless. That is the only shape 2026-07-28 allows, and it scales horizontally without sticky sessions. Keep session handling only where you must still serve 2025-era clients.