Repository navigation
Conversation
Clients that negotiate 2026-07-28 learn about tool and prompt list changes only through subscriptions/listen. The stdio server did not implement it, so server/discover omitted listChanged and those clients never re-listed after a proxied server changed its tools. - Decode subscriptions/listen (McpCall.Listen with an McpSubscriptionFilter) for 2026-07-28. The engine answers with McpOutcome.Subscribed, carrying the requested notification types the transport can deliver (tools and prompts). - StdioMcpServer keeps a subscription registry per connection. It sends notifications/subscriptions/acknowledged before any notification on a subscription, tags each list-change notification with the subscription id, honors notifications/cancelled, and answers open subscriptions with a complete result on graceful shutdown. - On stdio, server/discover advertises listChanged for tools and prompts. - Untagged list-change notifications, and resource notifications relayed from proxied servers, are sent only to connections that completed initialize. A 2026-07-28 connection receives only what it subscribed to. - HTTP is unchanged: listen is answered with -32601 and discover does not advertise listChanged. - Fix TestOutputStream recording a line twice when a single write ends with a newline.
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?
The stdio MCP server now supports
subscriptions/listenfor clients that negotiate2026-07-28.server/discoveradvertiseslistChanged: truefor tools and prompts on stdio.subscriptions/listenis acknowledged withnotifications/subscriptions/acknowledged. The ack's filter is the subset of the requested types the server can deliver:toolsListChangedandpromptsListChanged. Resource types are dropped from the ack for now._meta["io.modelcontextprotocol/subscriptionId"]. This covers local changes (addService,addRemoteClient,refreshTools) andlist_changednotifications from proxied remote servers.notifications/cancelledfor a listen request id ends that subscription. The id's JSON type must match, so"7"does not cancel7.completeresult.notifications/*/list_changed, and resource notifications relayed from proxied servers, are only written once the connection has completedinitialize. A2026-07-28connection only receives what it subscribed to. Handshake-era clients see the same bytes as before afterinitialize.subscriptions/listenreturns-32601, andserver/discoverdoes not advertiselistChanged. HTTP delivery needs a streaming response, whichMcpHttpHandlercan't produce today.New API, all
@SmithyUnstableApior default methods:McpCall.Listen,McpOutcome.Subscribed,McpSubscriptionFilterMcpOperations.listen(...), which throwsUnsupportedOperationExceptionby defaultMcpTransportContext.supportsSubscriptions(), which defaults tofalse; stdio returnstrueMcpEngine.execute(JsonRpcRequest, ProtocolVersion)returnsnullfor an accepted listen, because the response is only sent when the subscription ends.Why is this change needed?
Since
2026-07-28is the default stdio protocol, a client that negotiates it learns about list changes only throughsubscriptions/listen. Before this change, discover omittedlistChangedand listen was not implemented, so those clients never saw a proxied server's tool list change. Tools added at runtime stayed invisible until the client restarted. #1385 worked around this by keeping stdio on the handshake protocols. This change implements the stateless flow instead, as discussed in #1383.How was this validated?
StdioMcpServerSubscriptionsTest(20 tests) covers:-32602), duplicate active ids (-32600), and listen on a handshake connection (-32601)complete, EOF cleanup, an interceptor rejecting listen, and HTTP neither advertising nor accepting listenStdioSubscriptionsIntegrationTest: an HTTP mock upstream behind the stdio server. A2026-07-28client runs discover, listen, andtools/list, then calls a tool that makes the upstream add a tool. The taggedlist_changedarrives before that call's result, the re-list includes the new tool, the new tool is callable, and shutdown completes the subscription../gradlew :mcp:mcp-server:buildpasses: 259 unit and 125 integration tests, 0 failures, plus spotless and javadoc. I couldn't run the conformance suite locally.list_changed, and called the new tool in the same turn (3/3).main, the client never subscribed and the new tool wasn't visible (2/2).initialize(2/2).TestOutputStreamfixture bug: a singlewriteending in\nrecorded the line twice.What should reviewers focus on?
McpSubscriptionRegistryand its use inStdioMcpServer. The registry shares the output lock, so the ack and the registration happen atomically and no tagged notification can come before its ack. Also review cancellation handling in the reader thread, and shutdown completion before the request executor stops.StdioMcpServer.publishandCatalogEvents, which route handshake and stateless notifications.McpDomainOperations.discoverCapabilitiesandlisten, which tie what discover advertises to what listen accepts.initializecompletes. Before, stdio wrote them as soon as the catalog changed.completeresult, notnotifications/cancelled.Additional Links
initialize-era notifications, and support streaming responses so HTTP can host listen.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.