Skip to content

Commit 9012574

Browse files
committed
Qualify message_handler delivery docs; fix stale README line
IncomingMessage's docstring and the callbacks page said every server notification reaches message_handler, but notifications/cancelled is applied by the dispatcher and a subscription ack for a live listen() stream is consumed by that stream, so neither is delivered. Say so. Also drop the "shared type aliases" mention from the interaction suite's layout guide now that _helpers.py holds only the recording transport. No-Verification-Needed: comment- and doc-only change
1 parent 88b76c6 commit 9012574

3 files changed

Lines changed: 8 additions & 3 deletions

File tree

docs/client/callbacks.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ Two more. Neither declares anything.
135135

136136
`logging_callback` receives every `notifications/message` a server sends, as `LoggingMessageNotificationParams` (`level`, `logger`, `data`). Protocol logging is itself deprecated by the 2026-07-28 spec (**[Logging](../handlers/logging.md)** has what to do instead), so this callback exists for the servers that still emit it.
137137

138-
`message_handler` is the catch-all: every server notification reaches it (as well as its specific callback), and on a stream-backed transport so does every transport-level `Exception`. Annotate its parameter with `IncomingMessage` (`ServerNotification | Exception`, exported from `mcp.client`). The one pattern worth knowing is `if isinstance(message, Exception): raise message`, so a broken connection fails loudly instead of vanishing.
138+
`message_handler` is the catch-all: every server notification the session surfaces reaches it (as well as its specific callback), and on a stream-backed transport so does every transport-level `Exception`. Two never do: `notifications/cancelled` is applied by the SDK rather than surfaced, and a subscription acknowledgment for a live `listen()` stream is consumed by that stream. Annotate the parameter with `IncomingMessage` (`ServerNotification | Exception`, exported from `mcp.client`). The one pattern worth knowing is `if isinstance(message, Exception): raise message`, so a broken connection fails loudly instead of vanishing.
139139

140140
## Recap
141141

src/mcp/client/session.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,12 @@ async def __call__(self, params: types.LoggingMessageNotificationParams) -> None
172172

173173

174174
IncomingMessage: TypeAlias = types.ServerNotification | Exception
175-
"""What `message_handler` receives: every server notification, plus transport-level exceptions."""
175+
"""What `message_handler` receives: the server notifications the session surfaces, plus transport-level exceptions.
176+
177+
`notifications/cancelled` is applied by the dispatcher and never surfaced, and a
178+
`notifications/subscriptions/acknowledged` for a live `listen()` stream is consumed by that
179+
stream, so neither reaches the handler.
180+
"""
176181

177182

178183
class MessageHandlerFnT(Protocol):

tests/interaction/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ flows — with a single subprocess test for stdio.
4040
```text
4141
tests/interaction/
4242
_requirements.py the requirements manifest (see below)
43-
_helpers.py shared type aliases + the wire-recording transport
43+
_helpers.py the wire-recording transport
4444
_connect.py the transport-parametrized connection factories
4545
conftest.py the connect fixture (the transport matrix)
4646
test_coverage.py enforces the manifest ↔ test contract

0 commit comments

Comments
 (0)