[MCP Bundle] Publish the registry's changes to the configured notification bus - #2458
Merged
chr-hertel merged 1 commit intoAug 30, 2026
Merged
Conversation
chr-hertel
force-pushed
the
mcp-bundle-registry-publishes-to-bus
branch
from
August 29, 2026 23:15
bb27414 to
f04b10e
Compare
…tion bus `subscriptions:` configures a notification bus, and the 2026-07-28 protocol reads it: every `subscriptions/listen` stream polls it for the list-changed notifications it agreed to carry. Nothing ever writes to it. The SDK wires the publishing half itself — `Builder` wraps the event dispatcher in a `PublishingEventDispatcher` when a bus is configured, so that a runtime `registerTool()` reaches a listening client without the caller knowing a bus exists. But it can only wrap a registry it constructs, and a registry handed in through `setRegistry()` is already built. This bundle always supplies one, so the wrapping never happens: the bus is read by every stream and written to by nothing. From a client that is worse than an error. The stream opens, the acknowledgment names the types the server agreed to carry, keep-alives arrive for the configured lifetime, and it closes gracefully having carried nothing — whatever changed on the server. Every observable part of the mechanism works except the one that matters. Give the registry the publishing dispatcher where it is registered, which is the only place the bundle knows both it and the bus. Per server rather than one publisher on the shared `event_dispatcher`, because the registries are per server too: a tool appearing on one of them is not news to a client subscribed to another. Requires mcp/sdk 0.8.1. Until modelcontextprotocol/php-sdk#490 the SDK loaded a supplied registry without its `loading` guard, so publishing from the registry also published every element the load registered — one `list_changed` each, on every build, for a registry that did not change.
chr-hertel
force-pushed
the
mcp-bundle-registry-publishes-to-bus
branch
from
August 29, 2026 23:39
f04b10e to
283b19a
Compare
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.
subscriptions:configures a notification bus, and the 2026-07-28 protocol reads it: everysubscriptions/listenstream polls it for the list-changed notifications it agreed to carry. Nothing ever writes to it.The SDK wires the publishing half itself —
Builderwraps the event dispatcher in aPublishingEventDispatcherwhen a bus is configured. But it can only wrap a registry it constructs, and this bundle always supplies one (mcp.server.<name>.registry, built with Symfony'sevent_dispatcher), so the wrapping never happens. The two halves are each individually right and never meet.From a client that is worse than an error: the stream opens, the acknowledgment names the types the server agreed to carry, keep-alives arrive for the configured lifetime, and it closes gracefully having carried nothing — whatever changed on the server.
Gives the registry the publishing dispatcher where it is registered, which is the only place the bundle knows both it and the bus. Per server, because the registries are per server.
Requires mcp/sdk 0.8.1. Below that the SDK loads a supplied registry without its
loadingguard (modelcontextprotocol/php-sdk#490), so publishing from the registry also publishes every element the load registers — this patch would turn an inert bus into a noisy one.Found by a demo application that drives its own MCP servers with its own MCP client over a real transport (chr-hertel/mcp-demo).