You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Warn per event on unbound client notifications; keep server drops at debug
Drop the once-per-method dedup and its per-runner state: the client now
warns on every unbound notification (registering a binding, even a no-op
one, is the silence), and server-side inbound drops return to debug since
the peer is an arbitrary client and warning on its input floods the log.
Revert the ClientSession.send_notification widening: the 2026-07-28
transports do not agree on client-to-server custom notifications yet, so
the closed union stays the accurate type. Carve notifications/cancelled and
listen-owned acks out of the message_handler catch-all claim, add the
imports the notification example was missing, and note that a
json_response answer has no stream to carry request-scoped notifications.
Copy file name to clipboardExpand all lines: docs/advanced/low-level-server.md
+7-2Lines changed: 7 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -166,11 +166,16 @@ The constructor covers the methods MCP defines. `add_request_handler` covers eve
166
166
*`params_type` is the model the incoming `params` are validated against **before** your handler runs, so custom methods *do* get the validation tools don't. Subclass `RequestParams` so the `_meta` field parses like every other method's.
167
167
* The handler returns a `BaseModel`, a `dict`, or `None`. The SDK serialises it into the JSON-RPC result.
168
168
169
-
Notifications have a twin in each direction. Inbound, `add_notification_handler(method, params_type, handler)` registers `async (ctx, params) -> None`. Spec-defined notification methods are validated against the negotiated version's tables before dispatch, and one that does not exist at that version is dropped with a warning. Custom methods skip the version gate; your `params_type` is their validation, and a custom notification nobody registered a handler for is dropped with a warning.
169
+
Notifications have a twin in each direction. Inbound, `add_notification_handler(method, params_type, handler)` registers `async (ctx, params) -> None`. Spec-defined notification methods are validated against the negotiated version's tables before dispatch; custom methods skip the version gate, so your `params_type` is their validation.
170
170
171
171
Outbound, `ctx.session.send_notification(...)` accepts any `mcp_types.Notification` subclass, not just the spec-defined union, so the notifying half of a vendor protocol is one model away:
172
172
173
173
```python
174
+
from typing import Literal
175
+
176
+
from mcp_types import Notification, NotificationParams
Pass `related_request_id` so the notification rides the originating request's stream; the 2026-07-28 wire gives standalone notifications no channel outside `subscriptions/listen`. A python-sdk client observes vendor methods with a `NotificationBinding` (**[Extensions](extensions.md)**) and warns about ones it has no binding for.
195
+
Pass `related_request_id` so the notification rides the originating request's stream; the 2026-07-28 wire gives standalone notifications no channel outside `subscriptions/listen`, and a streamable HTTP response answered with `json_response=True` has no stream, so notifications sent during it are dropped. A python-sdk client observes vendor methods with a `NotificationBinding` (**[Extensions](extensions.md)**) and warns on each one it has no binding for.
191
196
192
197
One honest caveat: the high-level `Client` only has verbs for the methods MCP defines, so there is no `client.reindex()`. A vendor method is for a peer that already knows it exists: a client you also ship, or another service of yours speaking JSON-RPC.
Copy file name to clipboardExpand all lines: docs/client/callbacks.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -135,7 +135,7 @@ Two more. Neither declares anything.
135
135
136
136
`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.
137
137
138
-
`message_handler` is the catch-all for spec traffic: every notification the negotiated protocol version defines reaches it (as well as its specific callback), and on a stream-backed transport so does every transport-level `Exception`. Vendor and extension methods are outside that set; they are delivered only to a matching `NotificationBinding` (**[Extensions](../advanced/extensions.md)**), and without one they are dropped with a warning. 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 for spec traffic: every notification the negotiated protocol version defines reaches it (as well as its specific callback), except `notifications/cancelled`, which the session applies internally, and acknowledgements consumed by an open `listen()` stream. On a stream-backed transport it also receives every transport-level `Exception`. Vendor and extension methods are outside that set; they are delivered only to a matching `NotificationBinding` (**[Extensions](../advanced/extensions.md)**), and without one they are dropped with a warning. The one pattern worth knowing is `if isinstance(message, Exception): raise message`, so a broken connection fails loudly instead of vanishing.
Copy file name to clipboardExpand all lines: docs/migration.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1681,7 +1681,7 @@ session = ClientSession(
1681
1681
)
1682
1682
```
1683
1683
1684
-
On the high-level `Client`, bindings are declared by a `ClientExtension`'s `notifications()`; see [Extensions](advanced/extensions.md). The sending direction also loses its `cast`: `send_notification`on both `ClientSession` and `ServerSession`accepts any `mcp_types.Notification` subclass, where v1 typed it to the closed unions.
1684
+
On the high-level `Client`, bindings are declared by a `ClientExtension`'s `notifications()`; see [Extensions](advanced/extensions.md). The server's sending direction also loses its `cast`: `ServerSession.send_notification` accepts any `mcp_types.Notification` subclass, where v1 typed it to the closed union.
Copy file name to clipboardExpand all lines: docs/whats-new.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -201,7 +201,7 @@ At 2026-07-28 the standalone HTTP GET stream and `resources/subscribe` are repla
201
201
***Requests are routable without parsing bodies.** Modern HTTP requests carry `Mcp-Method` (and, for the three tool-ish calls, `Mcp-Name`); a tool input-schema property annotated with `x-mcp-header` is mirrored into an `Mcp-Param-*` header and cross-checked by the server ([SEP-2243](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2243)). Gateways and rate limiters can route on headers alone; the **[Migration Guide](migration.md#servers-validate-mcp-param-headers-against-the-request-body-sep-2243)** has the rules.
202
202
***Results carry cache hints.** List and read results declare `ttlMs` and `cacheScope` ([SEP-2549](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2549)); you set them per method with `cache_hints=`, and `Client` honors them with a built-in response cache. A server that sends no hints (every pre-2026 server) sees identical, uncached traffic. **[Caching hints](client/caching.md)**.
203
203
***Extensions are first class.** Servers and clients declare optional capability bundles under reverse-DNS identifiers ([SEP-2133](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2133)); the built-in `Apps` extension (MCP Apps) is the reference. **[Extensions](advanced/extensions.md)** and **[MCP Apps](advanced/apps.md)**.
204
-
***Vendor notifications are typed end to end.**`send_notification` on both sessions accepts any `mcp_types.Notification` subclass, and a client observes methods outside the negotiated version's tables with a `NotificationBinding` (on `ClientSession` directly, or declared by a `ClientExtension`); a notification nothing observes is dropped with a warning, not silently. **[Extensions](advanced/extensions.md)**.
204
+
***Vendor notifications are typed end to end.**`ServerSession.send_notification` accepts any `mcp_types.Notification` subclass, and a client observes methods outside the negotiated version's tables with a `NotificationBinding` (on `ClientSession` directly, or declared by a `ClientExtension`); a notification nothing observes is dropped with a warning, not silently. **[Extensions](advanced/extensions.md)**.
205
205
***Error codes got standardized.** A missing resource is `-32602` with the URI in `error.data`, and the new spec-reserved codes appear as `-32020` (header mismatch), `-32021` (missing required capability), and `-32022` (unsupported protocol version). **[Troubleshooting](troubleshooting.md)** is keyed by the exact messages.
206
206
***Authorization got harder to hold wrong.** The client validates the `iss` returned with the authorization code ([RFC 9207](https://datatracker.ietf.org/doc/html/rfc9207); your `callback_handler` now returns an `AuthorizationCodeResult`), sends `application_type` when it registers, and never replays credentials against a different authorization server. New in the enterprise corner: the [SEP-990](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/990) identity-assertion flow. The **[Migration Guide](migration.md)** lists every OAuth change; **[OAuth for clients](client/oauth-clients.md)** and **[Identity assertion](client/identity-assertion.md)** are the pages.
207
207
***Every server is traceable.** OpenTelemetry ships on by default as middleware: every request gets a server span, at no cost until the process configures an exporter. When both ends run the SDK, the client also propagates W3C trace context in `_meta`, so the traces join up. **[OpenTelemetry](run/opentelemetry.md)**.
0 commit comments