Skip to content

[Server] Serve handshake-era clients without sessions - #645

Open
ruudk wants to merge 1 commit into
modelcontextprotocol:mainfrom
ruudk:sessionless-handshake-era
Open

ruudk wants to merge 1 commit into
modelcontextprotocol:mainfrom
ruudk:sessionless-handshake-era

Conversation

@ruudk

@ruudk ruudk commented Oct 31, 2026

Copy link
Copy Markdown

Closes #644.

A session is optional in the handshake era: a server "MAY assign a session ID at initialization time". The SDK always creates one on initialize and refuses every later request without it, so a horizontally scaled server has to share a session store and lock only to serve handshake-era clients.

Builder::withoutSessions() turns that off for Streamable HTTP:

  • initialize is answered without Mcp-Session-Id, and a session id the client sends anyway is ignored;
  • every request is served on a session of its own that is dropped once it is answered;
  • GET and DELETE are answered with 405, which the spec allows for a server without a stream and for one that does not let clients end sessions.

Requests to the client (elicitation, sampling, roots/list) fail right away in this mode, since the client answers them in a POST of its own that cannot be matched without a session. Progress and other notifications sent during a request still reach the client. The TypeScript SDK serves handshake-era traffic the same way with sessionIdGenerator: undefined.

The option is off by default, so existing servers behave exactly as before. The only API additions are Builder::withoutSessions(), a trailing optional $sessionless argument on Protocol::__construct() and an @internal StreamableHttpTransport::setSessionless(). stdio and the 2026-07-28 era are not affected.

A session is optional in the handshake era, but the SDK always created
one on initialize and refused every later request without it. So a
horizontally scaled server had to share a session store and lock only
to serve those clients.

Builder::withoutSessions() answers initialize without an
Mcp-Session-Id, serves every later request on a session of its own,
and answers GET and DELETE with 405. Requests to the client fail right
away, as their answer cannot be matched without a session. Off by
default; stdio and the 2026-07-28 era are not affected.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Server] Serve handshake-era clients without a session

1 participant