Route a server notification: validate, run the typed callback, tee to message_handler.
(
self, dctx: DispatchContext[TransportContext], method: str, params: Mapping[str, Any] | None
)
| 824 | return dumped |
| 825 | |
| 826 | async def _on_notify( |
| 827 | self, dctx: DispatchContext[TransportContext], method: str, params: Mapping[str, Any] | None |
| 828 | ) -> None: |
| 829 | """Route a server notification: validate, run the typed callback, tee to message_handler.""" |
| 830 | # Same fallback as `_on_request`: covers pre-handshake and stateless. |
| 831 | version = self._negotiated_version or "2025-11-25" |
| 832 | try: |
| 833 | notification = cast(types.ServerNotification, _methods.parse_server_notification(method, version, params)) |
| 834 | except KeyError: |
| 835 | logger.debug("dropped %r: not defined at %s", method, version) |
| 836 | return |
| 837 | except ValidationError: |
| 838 | logger.warning("Failed to validate notification: %s", method, exc_info=True) |
| 839 | return |
| 840 | if isinstance(notification, types.CancelledNotification): |
| 841 | # The dispatcher already applied the cancellation; not surfaced to message_handler. |
| 842 | return |
| 843 | try: |
| 844 | if isinstance(notification, types.LoggingMessageNotification): |
| 845 | await self._logging_callback(notification.params) |
| 846 | await self._message_handler(notification) |
| 847 | except Exception: |
| 848 | # Contain here, not in the dispatcher: DirectDispatcher awaits this |
| 849 | # handler inline in the peer's notify() call, so a raising callback |
| 850 | # would otherwise fail the peer's send. A raising logging_callback |
| 851 | # skips the message_handler tee for that notification (v1 parity). |
| 852 | logger.exception("notification callback for %r raised", method) |
| 853 | |
| 854 | async def _on_stream_exception(self, exc: Exception) -> None: |
| 855 | """Deliver a transport-level fault to message_handler via a spawned task. |