Repository navigation
Consult the resources_subscribe_handler for listen resource URIs - #632
Merged
koic merged 1 commit intoOct 26, 2026
Conversation
## Motivation and Context In the 2026-07-28 lifecycle `subscriptions/listen` takes the place of `resources/subscribe`, but the URIs it names in `resourceSubscriptions` were honored on the `subscribe` capability alone. The `resources_subscribe_handler`, the hook an application uses to decide which resources a client may follow, was never called for them, so a decision it made for `resources/subscribe` did not carry over to a modern client. Each distinct URI is now passed to that handler with the params a `resources/subscribe` request for it would carry, together with the listen request's envelope and `auth_info` when the handler declares `server_context:`. A URI the handler raises for is reported to the exception reporter and left out of the acknowledgement, and the stream receives no `notifications/resources/updated` for it. The spec lets the acknowledgement honor a subset of the requested filter, so this needs no new error on the wire, and the field is omitted when no URI remains. The decision is made once when the stream opens, before it is registered; the stream already closes when its token expires. The params also carry the listen request's `_meta`, as those of a `resources/subscribe` request would, while the `server_context` has no session, so session-scoped helpers do nothing there. Any value the handler returns accepts the URI. The TypeScript and Python SDKs copy the requested URIs into the acknowledgement as well; the TypeScript SDK leaves authorization to the middleware layer. In the Ruby SDK the handler was already the documented place for this decision, so it is reused instead of adding a second hook that existing applications would have to discover. `resources_unsubscribe_handler` is not called when a listen stream ends: the subscription lasts as long as the stream. `Server#subscribable_resource_uris` is public only so that the transport can call it; it is marked `@api private` and is not part of the published API. ## How Has This Been Tested? - test/mcp/server/transports/streamable_http_transport_test.rb - test/mcp/server/transports/streamable_http_transport_oauth_test.rb - test/mcp/server_test.rb The two transport tests and the OAuth test fail against the previous `lib`, which acknowledged every requested URI. The `_meta` transport test fails against it too. ## Breaking Changes A `resources_subscribe_handler` that raises for a URI now narrows the listen acknowledgement for that URI, and a handler that records subscriptions is now also called for listen streams, without a matching `resources_unsubscribe_handler` call. Servers without a custom handler are unaffected.
atesgoral
approved these changes
Oct 25, 2026
koic
deleted the
authorize_the_resource_subscriptions_of_a_listen_stream
branch
October 26, 2026 06:17
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
In the 2026-07-28 lifecycle
subscriptions/listentakes the place ofresources/subscribe, but the URIs it names inresourceSubscriptionswere honored on thesubscribecapability alone. Theresources_subscribe_handler, the hook an application uses to decide which resources a client may follow, was never called for them, so a decision it made forresources/subscribedid not carry over to a modern client.Each distinct URI is now passed to that handler with the params a
resources/subscriberequest for it would carry, together with the listen request's envelope andauth_infowhen the handler declaresserver_context:. A URI the handler raises for is reported to the exception reporter and left out of the acknowledgement, and the stream receives nonotifications/resources/updatedfor it. The spec lets the acknowledgement honor a subset of the requested filter, so this needs no new error on the wire, and the field is omitted when no URI remains. The decision is made once when the stream opens, before it is registered; the stream already closes when its token expires.The params also carry the listen request's
_meta, as those of aresources/subscriberequest would, while theserver_contexthas no session, so session-scoped helpers do nothing there. Any value the handler returns accepts the URI.The TypeScript and Python SDKs copy the requested URIs into the acknowledgement as well; the TypeScript SDK leaves authorization to the middleware layer. In the Ruby SDK the handler was already the documented place for this decision, so it is reused instead of adding a second hook that existing applications would have to discover.
resources_unsubscribe_handleris not called when a listen stream ends: the subscription lasts as long as the stream.Server#subscribable_resource_urisis public only so that the transport can call it; it is marked@api privateand is not part of the published API.How Has This Been Tested?
The two transport tests and the OAuth test fail against the previous
lib, which acknowledged every requested URI. The_metatransport test fails against it too.Breaking Changes
A
resources_subscribe_handlerthat raises for a URI now narrows the listen acknowledgement for that URI, and a handler that records subscriptions is now also called for listen streams, without a matchingresources_unsubscribe_handlercall. Servers without a custom handler are unaffected.Types of changes
Checklist