Skip to content

fix(mcp): notify only the session whose compatibility shim transitioned - #108

Open
carldebilly wants to merge 1 commit into
mainfrom
dev/cdb/mcp-shim-notification-scope
Open

carldebilly wants to merge 1 commit into
mainfrom
dev/cdb/mcp-shim-notification-scope

Conversation

@carldebilly

Copy link
Copy Markdown
Member

Closes #102.

Under DynamicToolCompatibilityMode.DiscoverAndCallShim, an initialize-era session answers its first tools/list with the discover_tools/call_tool pair. It then sends tools/list_changed so the client re-lists and gets the real catalog. That transition belongs to one connection, but the notification went through the handler-wide _toolListChanged collection, and the SDK fans that collection out to every attached session. So each session's transition sent a spurious tools/list_changed to all the others.

The notification is now sent to request.Server only. SignalToolListChanged has no callers left, so it is removed. Its comment about Clear() raising Changed moves to SignalDiscoveryChanged, which still relies on that behaviour.

Test plan

  • When_OneLegacySessionConsumesItsShimIntro_Then_NoOtherSessionIsNotified was red 3/3 before the fix, because session B received the notification caused by session A's transition. The ordering barrier is a ping on B sent after A's own notification arrives. The SDK starts every session's send synchronously inside the single Clear(), so anything bound for B is already queued ahead of the ping's response. B's own transition is the positive control.
  • The existing shim tests still pass, 3 runs each.
  • Repl.Tests 803, Repl.IntegrationTests 641 (+10 skipped), Repl.McpTests 324 (+1 skipped, run twice), Repl.SpectreTests 17.

Under DynamicToolCompatibilityMode.DiscoverAndCallShim, each initialize-era session answers
its first tools/list with the discover_tools/call_tool pair, then signals tools/list_changed
so it re-lists and gets the real catalog. The transition is connection-local — each session
claims its own intro — but the signal cleared _toolListChanged, a handler-wide collection
whose SDK fan-out notifies every attached session. Every other session got a
tools/list_changed for a catalog that had not changed.

The notification now goes to request.Server, the server of the request that made the
transition. SignalToolListChanged lost its only caller and is removed. Its comment, about
Clear() raising Changed on an empty collection, moves to SignalDiscoveryChanged, which still
relies on that.

TDD: the new test is red 3/3 before the fix — session B receives the notification session A's
transition caused. A ping on B, sent after A's own notification arrives, is the ordering
barrier: the SDK starts every session's send synchronously inside that one Clear(), so a
notification bound for B is already queued ahead of the ping's response. B's own transition
is the positive control that the handler observes one when it should.

Refs #102
@carldebilly carldebilly added this to the 0.12.0 milestone Sep 22, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-22T22:14:29.156400Z 308c7c4 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mcp: a connection-local shim transition notifies every session

1 participant