Repository navigation
Add option to restrict the MCP protocol versions a server serves - #1385
Merged
Merged
Conversation
A server that negotiates 2026-07-28 cannot deliver notifications/tools/list_changed: that revision only delivers list-change notifications on a subscriptions/listen stream, which is not implemented, so server/discover rightly omits listChanged. A stdio server that relays list changes from proxied servers (dynamic tool discovery) therefore stops working for clients that prefer 2026-07-28, even though the same clients work over the handshake versions. Add McpEngine.Builder#protocolVersions and the matching StdioMcpServerBuilder option. When set, only the given registered versions are negotiated and advertised: server/discover and -32022 errors list only them, and initialize falls back to the newest retained handshake version. Clients that support both eras then fall back to initialize and keep receiving list-change notifications. The default protocol used for requests that do not identify a version now falls back to the initialize fallback when the default version is excluded, for stdio sessions and for HTTP requests without a version header. The default behavior is unchanged.
adwsingh
force-pushed
the
mcp-stdio-handshake-only
branch
from
October 12, 2026 19:17
474bc29 to
c42f4b0
Compare
adwsingh
enabled auto-merge (rebase)
October 12, 2026 19:17
adwsingh
approved these changes
Oct 13, 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
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.
What behavior changes?
Adds opt-in
McpEngine.Builder#protocolVersions(ProtocolVersion...)andStdioMcpServerBuilder#protocolVersions(ProtocolVersion...). When set, only the given registered versions are negotiated and advertised:server/discover'ssupportedVersionsand thesupportedlist in-32022errors name only the retained versions.-32022.initializefalls back to the newest retained handshake version.Requests that don't identify a version use the engine's default. That applies to stdio sessions and to HTTP requests without a version header. The default now falls back to the
initializefallback when the default version (2025-03-26) is excluded.Building fails if a version is not registered, or if no retained version supports
initialize.The default behavior is unchanged.
Why is this change needed?
Mitigates #1383. Until
subscriptions/listenis implemented, a 2026-07-28 session cannot receivenotifications/tools/list_changed. As a result, a server that relays list changes from proxied servers (dynamic tool discovery) stops working for clients that prefer 2026-07-28. Restricting such a server to the handshake versions makes those clients fall back toinitialize, where list changes work.How was this validated?
McpArchitectureTest: restricted negotiation and advertisement; retaining an extension protocol; rejecting unregistered versions, an empty list, and a set with noinitialize-capable version; excluding the default version.StdioMcpServerTest: a statelessserver/discoverprobe gets-32022, theninitializelands on 2025-11-25 withtools.listChanged: true; a prebuilt engine combined with the option is rejected.McpHttpHandlerTest: an unversioned request still works when the default version is excluded.RemoteCatalogNotificationIntegrationTestruns an HTTP upstream behind a stdio server restricted to handshake versions. It checks the-32022probe,initializewithlistChanged, the forwardedlist_changedontools/call, that a re-list shows the new tool, and that the new tool is callable../gradlew :mcp:mcp-server:test :mcp:mcp-server:integ :mcp:mcp-server:javadoc :mcp:mcp-server:spotlessCheckall pass (225 unit tests, 128 integration tests).initializeand called the newly discovered tools in the same turn and in later turns, 3 of 3 runs.conformancetask locally. The default configuration is unchanged.What should reviewers focus on?
McpProtocolRegistry.create: the allow-list is applied after override resolution, and every listed id must be registered.McpProtocolRegistry.defaultProtocol: its fallback.McpHttpHandler.resolveProtocolVersion: now uses the engine default.StdioMcpServerBuilder: the prebuilt-engine check.Additional Links
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.