MCP Removes Protocol-Level Sessions (Mcp-Session-Id)

A terminal window showing the verbatim MCP 2026-07-28 changelog entry: eliminated Mcp-Session-Id header from Streamable HTTP transport, servers use explicit handles for cross-call state
On this page

What’s actually changing

The MCP specification changelog for the 2026-07-28 revision states it directly:

“Eliminated Mcp-Session-Id header from Streamable HTTP transport; list endpoints no longer vary per-connection; servers use explicit handles for cross-call state”

This is tracked as SEP-2567, “Sessionless MCP via Explicit State Handles.” The reasoning: implicit, transport-level session state is invisible to the model and to anyone debugging a multi-step interaction. Making state explicit, an ordinary string the model actually sees and passes around, is the same pattern HTTP APIs have used for years: a basket_id, a browser_id, minted once and referenced afterward.

Structural Comparison Matrix

Operational AspectBefore (protocol-level sessions)After (2026-07-28+)
Where cross-call state livesImplicit, keyed by Mcp-Session-IdExplicit, an ordinary handle string
Visibility to the modelHidden in transport metadataVisible, passed as a normal tool argument
List endpoint behaviorCould vary per connectionNo longer varies per connection
Handle shape (recommended)N/AOpaque, e.g. bsk_a1b2c3, not cart_user42_2026-03-11

Fix it: mint and pass an explicit handle

Keep handles opaque, not descriptive

A handle that encodes internal structure invites clients to parse it or models to guess adjacent ones. Use an opaque token, not something human-readable like a username or a date embedded in the string.

before: implicit session state (removed 2026-07-28)
// Client relied on the Mcp-Session-Id header to keep cart state
// scoped to this connection across multiple tool calls.
after: explicit handle, minted once
{
  "content": [{ "type": "text", "text": "Cart created." }],
  "structuredContent": {
    "basket_id": "bsk_a1b2c3"
  }
}
after: the model passes the handle back on later calls
{
  "name": "add_item_to_cart",
  "arguments": {
    "basket_id": "bsk_a1b2c3",
    "item": "widget-42"
  }
}

The server mints basket_id once, from whatever tool call first needs a piece of persistent state, and returns it in structuredContent. Every subsequent tool call that touches the same state passes it back as an ordinary string argument, no different from any other parameter. A server implementation with connection-scoped in-memory state needs to move that state into whatever store the handle actually looks up, not just stop reading the removed header.

Confirmed version

Sourced from the official Model Context Protocol specification changelog, 2026-07-28 revision, published 2026-07-28, and SEP-2567’s own specification text for the explicit-handle pattern’s recommended shape. Browse more posts like this in the AI Productivity archive.

Frequently asked

Do I need to remove the Mcp-Session-Id header manually from my server?

Yes, if your server implementation reads or sets that header for routing or state lookup. The 2026-07-28 spec eliminates it from the Streamable HTTP transport entirely, so code that depends on it needs the explicit-handle pattern instead, not a header rename.

Is a handle the same thing as an API key or auth token?

No. A handle from this pattern (SEP-2567) identifies a piece of server-side state across calls, like a shopping cart or a browser session, not an identity or credential. It should be opaque and unguessable, but it isn't a security boundary the way an auth token is.

Emitted as FAQPage JSON-LD from the same frontmatter — one source, no duplicated prose.

Recent posts

Full-text search via Pagefind · ↑↓ to navigate · ↵ to open