Make custom notifications first-class: typed send, observable drops#3173
Draft
maxisbey wants to merge 1 commit into
Draft
Make custom notifications first-class: typed send, observable drops#3173maxisbey wants to merge 1 commit into
maxisbey wants to merge 1 commit into
Conversation
Widen ClientSession.send_notification and ServerSession.send_notification to accept any Notification subclass, mirroring send_request's open Request arm, so extensions can emit their own methods without casts. Raise dropped-notification logging from debug to a once-per-method warning that names the remedy: on the client when no NotificationBinding observes the method, on the server when a spec notification is not defined at the negotiated version or a custom method has no registered handler (an unserved spec notification stays at debug; repeat drops of a method log at debug so a stream cannot flood the log). Document the message_handler routing change and the binding channel in the migration guide, fix the callbacks page's catch-all claim, and cover the vendor-notification round trip with an interaction test, un-deferring its requirement.
Contributor
📚 Documentation preview
|
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.
Custom (non-spec) notifications get a typed send surface, and dropping one now leaves a trace in the logs.
Motivation and Context
Feedback from a downstream framework: a server-to-client notification whose method isn't in the negotiated version's core tables only reaches a registered
NotificationBinding, and otherwise is dropped atlogger.debug. That drop is silent enough that the fix on the framework's side was found by trial and error, and even once you know the channel,send_notificationon both sessions is typed to the closed spec unions, so emitting a vendor notification needs acast()or# type: ignoreeven though the runtime already sends whatever it's given.Two changes:
ClientSession.send_notificationandServerSession.send_notificationaccept anymcp_types.Notificationsubclass, matching the openRequest[Any, Any]armsend_requestalready has in both classes. The runtime path is unchanged; this legalizes the existing behaviour.debugto a once-per-methodwarningthat names the remedy: the client when no binding observes the method, the server when a spec notification isn't defined at the negotiated version or a custom method has no registered handler. Repeats of the same method fall back todebugso a chatty stream can't flood the log. An unserved spec notification stays atdebug(most servers legitimately ignorenotifications/roots/list_changedand friends).Nothing is teed to
message_handler: its contract is the typed spec union, and v1 dropped unknown methods before it too (atWARNING). The one v1 delivery difference isnotifications/tasks/status, which was a member of v1's union; the migration guide now says where it went and how to observe it.How Has This Been Tested?
New unit tests pin the log levels (first drop
WARNING, repeatDEBUG, unserved spec methodDEBUG) on both sides, plus a wire test for a custom model going throughClientSession.send_notificationunchanged. A new interaction test drives the full loop: anMCPServertool emits vendor notifications throughctx.session.send_notification(..., related_request_id=ctx.request_id)and the declaringClientExtension's binding receives them in order; that un-defers the previously deferredextensions:client:notification-binding-deliveryrequirement. Also exercised end-to-end against a running streamable HTTP server at both2025-11-25and2026-07-28.Breaking Changes
None. The widened annotations only accept more; the log-level change is observability.
Types of changes
Checklist
Additional context
Deliberately out of scope, happy to file follow-ups: a catch-all handler for unobserved notifications, a
Client(notification_bindings=...)kwarg (a one-off binding on the high-levelClientcurrently needs aClientExtension, which also advertises its identifier), anotifications()contribution on the serverExtension, and outbound era-gating for spec notifications.AI Disclaimer