You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Docs-only. No production code changes. The intent is to agree the shape of the work before implementation, per CONTRIBUTING.md:
For non-trivial changes, clarify scope with maintainers in an issue before investing in an
implementation.
Why a design document rather than PRs
The SDK currently implements 2024-11-05 through 2025-11-25. Every one of those revisions
shares one structural assumption: an MCP conversation is a session established by an initialize handshake, over which either party may originate JSON-RPC requests.
2026-07-28 removes that assumption. Six of its nine major changes are removals or
inversions of mechanisms mcp-core models as load-bearing types — McpServerSession, McpStreamableServerSession, LifecycleInitializer, McpTransportSession, McpTransportStream, and the client-side request handlers for roots/list, sampling/createMessage and elicitation/create:
#
Change
SEP
1
Remove protocol-level sessions and Mcp-Session-Id
SEP-2567
2
Remove the initialize / notifications/initialized handshake; per-request _meta envelope
SEP-2575
3
Add server/discover (servers MUST implement)
SEP-2575
4
Replace HTTP GET + resources/subscribe with subscriptions/listen
Move tasks to the io.modelcontextprotocol/tasks extension
SEP-2663
7
MRTR replaces server-initiated requests
SEP-2322
8
Required resultType on every result
SEP-2322
9
Remove SSE resumability (Last-Event-ID)
SEP-2575
Three properties make piecemeal delivery actively harmful:
The changes are coupled.resultType is meaningless without MRTR; MRTR is
unimplementable without the _meta envelope; the envelope is unverifiable without header
mirroring. Landing them independently produces intermediate states that are on no protocol
revision at all.
The era boundary must be decided once. Whether "modern vs. legacy" is a runtime flag, a
parallel type hierarchy, or separate modules determines the shape of every subsequent PR.
It is a major version. Per VERSIONING.md, three independent triggers apply, so the
removals must be batched into one release.
The finding the design rests on
This SDK already ships a stateless server.McpStatelessAsyncServer's own Javadoc:
"It allows simple horizontal scalability since it does not maintain a session and does not
require initialization. Each instance of the server can be reached with no prior knowledge
and can serve the clients with the capabilities it supports."
That is close to a verbatim description of the 2026-07-28 server model. The proposal
therefore does not add a parallel server implementation — it promotes the existing
stateless server to be the canonical modern server, and leaves the session-based classes as
a deprecated legacy path. Two additive SPI extensions are needed: answer one request with a stream (subscriptions/listen), and answer one request with "I need more input"
(MRTR).
Without that existing asset, 2026-07-28 support would be a ground-up rewrite. This is the
main reason the proposal is tractable.
What the document contains
Structured as a design proposal (Motivation → Public Interfaces → Proposed Changes →
Security → Compatibility/Migration → Test Plan → Rejected Alternatives → FAQ):
Gap analysis of mcp-core at 8ee8ccbc, requirement by requirement, each classified additive / structural / wire-format / removal.
Full public API surface: ProtocolVersions.MCP_2026_07_28, McpMetaKeys, new ErrorCodes (-32020 / -32021 / -32022), DiscoverResult, InputRequiredResult, InputRequests / InputResponses, ListRootsRequest, SubscriptionsListenRequest, CacheableResult, McpRequestContext, McpSubscription, McpSubscriptionSink, McpRequestStateCodec, McpHeaderCodec, McpParamHeaderExtractor, new exceptions.
Seven keyed design decisions (D1–D7), each with the alternative it rejects.
Five implementation phases, each independently reviewable and each leaving main on a
coherent protocol revision. P1–P2 are non-breaking and could ship in a 2.x minor.
Behaviour matrix resolving the spec's client/server era matrix to concrete SDK
behaviour.
Test plan covering unit, integration and conformance, including per-record cases derived
from the Case A / Case B rules in CONTRIBUTING.md.
Six rejected alternatives with reasoning.
Design decisions worth reviewer attention
D3 — MRTR is resolved inside the client session layer. Sampling / elicitation / roots
handler signatures do not change; the same handlers are invoked from a bounded retry loop
instead of from an inbound-request dispatcher. This keeps callTool() returning CallToolResult rather than a union type, so existing callers recompile unchanged. RA-3
argues the alternative.
D4 — resultType must be a real record component. A default method on Result would not
serialize (Jackson emits record components), so every result the SDK emitted would be
missing a spec-required field. That means ~15 records under the CONTRIBUTING.md Case B
rules. The interface default is still added, for uniform reading across eras.
D1 — era dispatch at the transport front door, not a boolean modern flag on the existing
session types. The spec says a dual-era server "selects its behavior from how the client
opens" — that is a routing decision on the first message and belongs in one place.
D6 — the modern client needs a tool-definition cache, because x-mcp-header mirroring
requires the tool's inputSchema at tools/call time and tools/call does not carry it. The
same cache is what makes ttlMs / cacheScope actionable.
Open questions for maintainers
Is HTTP+SSE removal in scope for the major release? SEP-2596 reclassifies it as Deprecated, not Removed, and the feature-lifecycle policy allows a twelve-month window.
The document proposes removal (the release is already breaking) but explicitly flags
deprecate-now / remove-next-major as the conservative option and does not insist.
Is the dual-era default correct, versus modern-only with legacy behind a flag?
Should mcp-ext-tasks be a new module, or should tasks stay in mcp-core behind the
extension capability?
Should an escape hatch expose InputRequiredResult directly? The document defers it
under CONTRIBUTING.md's "concrete, not speculative" principle, but a real use case would
change that.
Phasing: P1–P2 are non-breaking. Ship them in a 2.x minor to shorten the major-release
critical path, or hold everything for the major?
Known behaviour change
One change cannot be made backward-compatible: on the modern path, notifications/message is
suppressed for requests that omit io.modelcontextprotocol/logLevel. The spec states servers MUST NOT emit it in that case. It leads the migration guide, and logLevel is settable
once on the client builder to restore log flow with a one-line change.
What this PR does not do
No production code, no schema changes, no dependency changes.
Does not commit the project to the proposed API — the naming and shape are a starting point
for discussion.
Does not supersede the spec-revision GitHub Project board referenced in ROADMAP.md; it is
intended to complement it.
Thanks for the thorough write-up — this is the first end-to-end design on the table, and promoting McpStatelessAsyncServer matches what's actually in the Java SDK code today.
Three flags from a Spring Boot-behind-reverse-proxy deployer's perspective:
D1 dual-era default (your Q2): we'd strongly prefer one endpoint serving both eras, selected by how the client opens (initialize → legacy path; server/discover or a request carrying _meta + MCP-Protocol-Version: 2026-07-28 with no session → modern path), with a builder switch to run modern-only. Separate endpoints or a transport-level flag turns this into a deployment change for every existing user behind Tomcat/reverse proxies.
SEP-2567 state: please keep the document explicit that cross-call state travels as server-minted handles passed as ordinary tool arguments, with no SDK-side store. The open McpSessionStore PRs (feat: add McpSessionStore SPI for pluggable session storage #914, Feature/distributed session storage #1048) would then be clearly scoped as 2.x-only under this design — worth stating so contributors stop building against a model 3.x removes.
Two checks while reviewing: the _meta keys should be the namespaced forms (io.modelcontextprotocol/protocolVersion, io.modelcontextprotocol/clientCapabilities) per the changelog, and the Tasks section should reflect the final extension shape — polling tasks/get, tasks/update, unsolicited task handles, no tasks/list.
Happy to help with any of the P1–P2 items if maintainers want to open them up.
slachiewicz
added a commit
to slachiewicz/mcp-java-sdk
that referenced
this pull request
Aug 27, 2026
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
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.
Summary
Adds a design proposal —
docs/design/2026-07-28-spec-support.md— for implementing the2026-07-28MCP specificationrevision in this SDK.
Link for md viewer:
https://github.com/omarmahamid/java-sdk/blob/feat/28-7-mcp-spec/docs/design/2026-07-28-spec-support.md
Docs-only. No production code changes. The intent is to agree the shape of the work
before implementation, per
CONTRIBUTING.md:Why a design document rather than PRs
The SDK currently implements
2024-11-05through2025-11-25. Every one of those revisionsshares one structural assumption: an MCP conversation is a session established by an
initializehandshake, over which either party may originate JSON-RPC requests.2026-07-28removes that assumption. Six of its nine major changes are removals orinversions of mechanisms
mcp-coremodels as load-bearing types —McpServerSession,McpStreamableServerSession,LifecycleInitializer,McpTransportSession,McpTransportStream, and the client-side request handlers forroots/list,sampling/createMessageandelicitation/create:Mcp-Session-Idinitialize/notifications/initializedhandshake; per-request_metaenvelopeserver/discover(servers MUST implement)GET+resources/subscribewithsubscriptions/listenping,logging/setLevel,notifications/roots/list_changedio.modelcontextprotocol/tasksextensionresultTypeon every resultLast-Event-ID)Three properties make piecemeal delivery actively harmful:
resultTypeis meaningless without MRTR; MRTR isunimplementable without the
_metaenvelope; the envelope is unverifiable without headermirroring. Landing them independently produces intermediate states that are on no protocol
revision at all.
parallel type hierarchy, or separate modules determines the shape of every subsequent PR.
VERSIONING.md, three independent triggers apply, so theremovals must be batched into one release.
The finding the design rests on
This SDK already ships a stateless server.
McpStatelessAsyncServer's own Javadoc:That is close to a verbatim description of the
2026-07-28server model. The proposaltherefore does not add a parallel server implementation — it promotes the existing
stateless server to be the canonical modern server, and leaves the session-based classes as
a deprecated legacy path. Two additive SPI extensions are needed: answer one request with a
stream (
subscriptions/listen), and answer one request with "I need more input"(MRTR).
Without that existing asset,
2026-07-28support would be a ground-up rewrite. This is themain reason the proposal is tractable.
What the document contains
Structured as a design proposal (Motivation → Public Interfaces → Proposed Changes →
Security → Compatibility/Migration → Test Plan → Rejected Alternatives → FAQ):
mcp-coreat8ee8ccbc, requirement by requirement, each classifiedadditive / structural / wire-format / removal.
ProtocolVersions.MCP_2026_07_28,McpMetaKeys, newErrorCodes(-32020/-32021/-32022),DiscoverResult,InputRequiredResult,InputRequests/InputResponses,ListRootsRequest,SubscriptionsListenRequest,CacheableResult,McpRequestContext,McpSubscription,McpSubscriptionSink,McpRequestStateCodec,McpHeaderCodec,McpParamHeaderExtractor, new exceptions.mainon acoherent protocol revision. P1–P2 are non-breaking and could ship in a
2.xminor.behaviour.
from the Case A / Case B rules in
CONTRIBUTING.md.Design decisions worth reviewer attention
D3 — MRTR is resolved inside the client session layer. Sampling / elicitation / roots
handler signatures do not change; the same handlers are invoked from a bounded retry loop
instead of from an inbound-request dispatcher. This keeps
callTool()returningCallToolResultrather than a union type, so existing callers recompile unchanged. RA-3argues the alternative.
D4 —
resultTypemust be a real record component. A default method onResultwould notserialize (Jackson emits record components), so every result the SDK emitted would be
missing a spec-required field. That means ~15 records under the
CONTRIBUTING.mdCase Brules. The interface default is still added, for uniform reading across eras.
D1 — era dispatch at the transport front door, not a
boolean modernflag on the existingsession types. The spec says a dual-era server "selects its behavior from how the client
opens" — that is a routing decision on the first message and belongs in one place.
D6 — the modern client needs a tool-definition cache, because
x-mcp-headermirroringrequires the tool's
inputSchemaattools/calltime andtools/calldoes not carry it. Thesame cache is what makes
ttlMs/cacheScopeactionable.Open questions for maintainers
Deprecated, not Removed, and the feature-lifecycle policy allows a twelve-month window.
The document proposes removal (the release is already breaking) but explicitly flags
deprecate-now / remove-next-major as the conservative option and does not insist.
mcp-ext-tasksbe a new module, or should tasks stay inmcp-corebehind theextension capability?
InputRequiredResultdirectly? The document defers itunder
CONTRIBUTING.md's "concrete, not speculative" principle, but a real use case wouldchange that.
2.xminor to shorten the major-releasecritical path, or hold everything for the major?
Known behaviour change
One change cannot be made backward-compatible: on the modern path,
notifications/messageissuppressed for requests that omit
io.modelcontextprotocol/logLevel. The spec states serversMUST NOT emit it in that case. It leads the migration guide, and
logLevelis settableonce on the client builder to restore log flow with a one-line change.
What this PR does not do
for discussion.
ROADMAP.md; it isintended to complement it.
Checklist
./mvnw clean compile -DskipTestsunaffectedspring-javaformatapplies to Java sources only)ROADMAP.mdupdate to retarget the focus area from2025-11-25to2026-07-28— foldedinto this PR or filed as a follow-up, reviewer's preference
modelcontextprotocol.io/specification/2026-07-28(changelog, versioning, MRTR, subscriptions, discover, Streamable HTTP)