[Server] Add MCP stateless mode support - #416
Open
andreybolonin wants to merge 4 commits into
Open
Conversation
andreybolonin
requested review from
CodeWithKyrian,
Nyholm,
chr-hertel and
soyuka
as code owners
August 13, 2026 10:56
Member
|
Hi @andreybolonin, thanks for this - before diving into it, i read that you mostly verified by unit tests? did you also try it with one of the examples and inspector - basically going end to end with the transport? |
Author
|
Hi @chr-hertel, good catch — so far I've only covered it with unit tests. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation and Context
This PR implements MCP 2026-07-28 stateless mode support for the official PHP SDK.
The stateless protocol variant removes the requirement for a persistent session handshake (
initialize/initialized) and theMcp-Session-Idheader. Each HTTP POST request is self-contained: the server creates an ephemeral in-memory session, processes the request, and destroys it at the end of the lifecycle.This enables MCP servers to run in environments where sticky sessions are not available — such as serverless platforms, plain round-robin load balancers, and stateless API gateways.
Key changes:
Protocol: Addedstatelessflag. When enabled, skipsresolveSession()and creates a fresh ephemeral session per request.Builder: AddedsetStateless(bool)to toggle the mode. In stateless mode, it registersServerDiscoverHandlerinstead ofInitializeHandler, and omitsInitializedHandler.ServerDiscoverHandler: New handler forserver/discover— the stateless replacement for the initialize handshake. ReturnsInitializeResultwith capabilities, server info, and instructions.StatelessStreamableHttpTransport: New HTTP transport that accepts POST and OPTIONS only. NoMcp-Session-Idvalidation, no DELETE endpoint.How Has This Been Tested?
StatelessStreamableHttpTransportcovering:ServerDiscoverHandlercovering:server/discovervs others)StreamableHttpTransporttests continue to pass (no regression in stateful mode)Breaking Changes
None. This is an opt-in feature. Existing servers continue to work unchanged. To enable stateless mode:
Types of changes
Checklist
Additional context
Design decisions
Reused existing
Protocolclass instead of creating a separateStatelessProtocol. Thestatelessboolean flag keeps the diff minimal and avoids code duplication for request handling, fiber management, and outgoing message queues.Ephemeral sessions are still created via
SessionManager::create()so that existing handlers (tools, resources, prompts) can use$session->get()/$session->set()without knowing whether the server is stateful or stateless. The session lives only for the duration of one HTTP request.ServerDiscoverHandlerreturnsInitializeResult— the same result type asInitializeHandler. This keeps client compatibility simple: clients receive the same shape of capabilities and server info, just viaserver/discoverinstead ofinitialize.StatelessStreamableHttpTransportextendsBaseTransportand reuses all fiber/SSE logic from the original transport. Only the request routing layer differs (no session ID parsing, no DELETE).