Add HttpServerSessionMode for hybrid stateful/stateless HTTP serving - #1796
Merged
jeffhandley merged 7 commits intoAug 13, 2026
Merged
Conversation
saicharanpardhu
marked this pull request as ready for review
August 5, 2026 21:26
halter73
reviewed
Aug 6, 2026
halter73
reviewed
Aug 10, 2026
Introduces `HttpServerSessionMode` so a single Streamable HTTP endpoint can
serve `initialize`-handshake clients with full sessions while serving
`2026-07-28` and later clients statelessly.
- Add `HttpServerSessionMode { Stateless, Stateful, StatefulForInitializeClients }`
and `HttpServerTransportOptions.SessionMode` (defaults to `Stateless`).
- Obsolete `HttpServerTransportOptions.Stateless` (MCP9008) and keep it as a
compatibility proxy over `SessionMode`: `true` maps to `Stateless`, `false`
maps to `Stateful`, hybrid reads as `false`. Assigning both is allowed and the
last assignment wins.
- Decide the effective mode per request in `StreamableHttpHandler`:
`2026-07-28` requests are refused only in `Stateful` mode, and
`StartNewSessionAsync`/`CreateSessionAsync` now take an explicit
`serveStatelessly` flag so DI and callback lifetimes follow the request.
- Keep GET/DELETE endpoints mapped, legacy SSE permitted, and idle tracking
running in hybrid mode.
Fixes modelcontextprotocol#1777
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reject undefined HttpServerSessionMode values through options validation, cover RunSessionHandler lifetimes in hybrid mode, and repair documentation examples and terminology for the three configuration values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the HttpServerTransportOptions validator, its DI registration, and the undefined-enum regression test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Retain the bool as shorthand for the Stateless and Stateful session modes, while SessionMode remains available for selecting hybrid behavior. Remove the MCP9008 diagnostic and related obsolete documentation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
saicharanpardhu
force-pushed
the
hybrid-session-mode
branch
from
August 10, 2026 21:57
9ceec2f to
592a355
Compare
halter73
previously approved these changes
Aug 11, 2026
jeffhandley
requested changes
Aug 12, 2026
jeffhandley
left a comment
Contributor
There was a problem hiding this comment.
The feature design and implementation are excellent, @saicharanpardhu!
Most of my comments are about cleaning up some wording in code comments, API doc comments, conceptual documentation and samples. I also have some requests for changes in the tests to revert test changes that aren't required and augmenting coverage a little bit.
Co-authored-by: Jeff Handley <jeffhandley@users.noreply.github.com>
Restore bool-based transport configuration coverage, add fallback coverage for both configuration properties, and fix the session mode XML documentation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jeffhandley
reviewed
Aug 13, 2026
Co-authored-by: Jeff Handley <jeffhandley@users.noreply.github.com>
jeffhandley
approved these changes
Aug 13, 2026
jeffhandley
left a comment
Contributor
There was a problem hiding this comment.
Thanks, @saicharanpardhu. Great work!
jeffhandley
merged commit Aug 13, 2026
c6a97d9
into
modelcontextprotocol:main
17 of 18 checks passed
Merged
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.
Closes #1777.
Implements the design @halter73 described, finishing the work from the draft in saicharanpardhu#1.
Problem
Starting with
2026-07-28, Streamable HTTP has no sessions (SEP-2567 removedMcp-Session-Id, SEP-2575 removed theinitializehandshake). Today an ASP.NET Core server must pick one era for the whole endpoint:Stateless = true— no sessions for anyone, so legacy clients lose unsolicited notifications, resource subscriptions, and server-to-client requests.Stateless = false—2026-07-28requests are refused with-32022 UnsupportedProtocolVersionto force a downgrade, so servers can't adopt the new revision until every client has migrated (or is willing to downgrade).Change
New three-value
HttpServerSessionModeonHttpServerTransportOptions:initializeclients (2025-11-25and earlier)2026-07-28and later clientsStateless(default)Stateful-32022so dual-path clients downgradeStatefulForInitializeClientsIn hybrid mode the effective mode is decided per request, so lifetimes follow the request rather than the endpoint:
2026-07-28requests resolve fromHttpContext.RequestServiceswith request scoping disabled;ConfigureSessionOptionsandRunSessionHandlerrun per request.initialize-handshake sessions resolve from the application provider with per-request scoping;ConfigureSessionOptionsandRunSessionHandlerrun once per session.GET/DELETEstay mapped, legacy SSE stays permitted, and idle tracking keeps running — but only legacy sessions can use them;2026-07-28GET/DELETEget405.Statelessremains a convenience proxybool Statelessremains the convenient way to select the two most common modes, whileSessionModeexposes the hybrid value:Stateless = true→SessionMode = Stateless;Stateless = false→SessionMode = StatefulStatelessreturnstrueonly forSessionMode == Stateless(hybrid reads asfalse)Internal call sites, samples, docs samples, and tests use
SessionModeexplicitly so their intended behavior is clear; existing applications can continue using the bool without an obsolete warning.Tests
July2026ProtocolHybridSessionModeTestscovers the pre-merge checklist from the issue:ModernAndLegacyClients_ShareOneEndpoint_AndModernDoesNotDowngrade2026-07-28instead of downgradingLegacyClient_OnHybridServer_StillSupportsServerToClientElicitationModernRequests_UseRequestScopedServices_WhileLegacySessionsUseApplicationServicesConfigureSessionOptions_RunsPerRequestForModernClients_AndOncePerSessionForLegacyClientsConfigureSessionOptionslifetimes match the per-request modeRunSessionHandler_RunsPerRequestForModernClients_AndOncePerSessionForLegacyClientsRunSessionHandlerfollows the same per-request vs. per-session lifetimeModernPost_DoesNotMintSessionId_WhileLegacyInitializeDoes2026-07-28ModernPost_IgnoresMcpSessionIdHeaderMcp-Session-Iddoesn't attach a modern request to a sessionLegacyGetAndDelete_RemainAvailable_WhileModernGetAndDeleteReturn405GET/DELETEstill work while modern ones return405HttpServerTransportOptionsTestscovers theStateless↔SessionModeproxy semantics, including that assigning both doesn't throw and the last assignment wins.Docs
docs/concepts/stateless/stateless.md— new "Hybrid mode (sessions for initialize clients only)" section,SessionModein the property reference, and all samples/prose migrated.docs/concepts/mrtr/mrtr.md,elicitation.md,sampling.md,roots.md— updated the statements that a stateful HTTP endpoint always refuses2026-07-28; hybrid mode serves it statelessly (so those clients use MRTR while legacy sessions keep theinitialize-era flows).docs/list-of-diagnostics.md— rewordsMCP9006for per-request hybrid behavior.ModelContextProtocol.AspNetCore, and references to “both session modes” now distinguish the threeSessionModeconfigurations from the two effective request behaviors.Validation
dotnet build— 0 warnings, 0 errorsdotnet test— all targets pass:Note
This pull request description and the accompanying changes were drafted with GitHub Copilot.