@@ -363,12 +363,7 @@ def __init__(
363363 self ._negotiated_version : str | None = None
364364 self ._stamp : Callable [[dict [str , Any ], CallOptions ], None ] = _preconnect_stamp
365365 self ._task_group : anyio .abc .TaskGroup | None = None
366- # subscriptions/listen demux routes, keyed by the listen request's id
367- # (verbatim-typed: a plain dict already keeps 1 and "1" distinct).
368- # Fed by `_intercept_notification` on the dispatcher's receive path;
369- # membership alone decides ack consumption, so a closed subscription
370- # releases its id completely - raw escape-hatch listens (never
371- # registered here) keep receiving their acks via message_handler.
366+ # subscriptions/listen demux routes; membership decides ack consumption (raw listens are never registered)
372367 self ._listen_routes : dict [RequestId , ListenRoute ] = {}
373368 if dispatcher is not None :
374369 if read_stream is not None or write_stream is not None :
@@ -1257,64 +1252,44 @@ def _unregister_listen_route(self, request_id: RequestId) -> None:
12571252 self ._listen_routes .pop (request_id , None )
12581253
12591254 def _settle_listen_routes_closed (self ) -> None :
1260- """End every open subscription as lost: the session is gone.
1261-
1262- Without this, a consumer iterating in a sibling task would park forever -
1263- the driver task dies by cancellation and can never settle its route.
1264- """
1255+ """Settle all open listen routes as lost on session exit; cancelled driver tasks cannot."""
12651256 closed = MCPError (code = CONNECTION_CLOSED , message = "Connection closed" )
12661257 for route in self ._listen_routes .values ():
12671258 route .settle ("lost" , error = closed )
12681259 self ._listen_routes .clear ()
12691260
12701261 def _intercept_notification (self , method : str , params : Mapping [str , Any ] | None ) -> bool :
1271- """Wire-order listen demux, run by the dispatcher on its receive path.
1272-
1273- Route bookkeeping must advance in receive order relative to the listen
1274- request's own result: the result resolves synchronously on this same
1275- path, so an ack or event handled on the spawned `_on_notify` path could
1276- lose the race and be dropped after the stream settled - a graceful
1277- close swallowing the events that preceded it. Only the synchronous
1278- bookkeeping happens here; the user-facing tee (message_handler,
1279- logging) stays on the spawned path.
1280-
1281- Returns True to consume the frame: an ack for a live driver route is
1282- driver state, never surfaced. Raw escape-hatch listens have no route
1283- registered and keep observing their acks via message_handler - as does
1284- a stray ack for an already-closed driver id, whose registration is gone.
1285-
1286- The `as_request_id` guard is not a tripwire: this reads raw wire
1287- dicts, where a non-id (even unhashable) `_meta` value is
1288- constructible and would fail the dict lookup.
1262+ """Wire-order listen demux, run synchronously on the dispatcher's receive path.
1263+
1264+ Bookkeeping must advance in receive order with the listen result (resolved on
1265+ this same path); the spawned `_on_notify` path would race it and drop events.
1266+ Returns True to consume the frame: a live route's ack is driver state, never surfaced.
12891267 """
12901268 if not self ._listen_routes :
12911269 return False
12921270 if method == "notifications/cancelled" :
12931271 request_id = cancelled_request_id_from_params (params )
12941272 if request_id is not None and (listen_route := self ._listen_routes .get (request_id )) is not None :
1295- # A server-sent cancel naming one of our listen requests is
1296- # that stream's teardown signal (the stream-transport spelling).
1273+ # a server-sent cancel naming a listen request is that stream's teardown signal
12971274 listen_route .settle ("lost" )
12981275 return False # _on_notify swallows every cancelled either way (v1 parity)
12991276 if params is None :
13001277 return False
13011278 meta = params .get ("_meta" )
13021279 if not isinstance (meta , Mapping ):
13031280 return False
1281+ # as_request_id is not a tripwire: raw wire _meta can carry a non-id (even unhashable) value
13041282 subscription_id = as_request_id (cast ("Mapping[str, Any]" , meta ).get (SUBSCRIPTION_ID_META_KEY ))
13051283 if subscription_id is None or (listen_route := self ._listen_routes .get (subscription_id )) is None :
13061284 return False
13071285 if method == "notifications/subscriptions/acknowledged" :
13081286 raw_filter = params .get ("notifications" )
13091287 if raw_filter is None :
1310- # The wire shape requires `notifications`; a frame without it is
1311- # malformed, not an empty filter - leave it to the spawned
1312- # path's validation warning rather than fabricating honored={}.
1288+ # malformed, not an empty filter: leave it to the spawned path's validation warning
13131289 return False
13141290 try :
13151291 honored = types .SubscriptionFilter .model_validate (raw_filter )
13161292 except ValidationError :
1317- # Malformed ack: leave it to the spawned path's validation warning.
13181293 return False
13191294 listen_route .set_acked (honored )
13201295 return True
@@ -1356,9 +1331,7 @@ async def _on_notify(
13561331 logger .warning ("Failed to validate notification: %s" , method , exc_info = True )
13571332 return
13581333 if isinstance (notification , types .CancelledNotification ):
1359- # Never surfaced to message_handler (v1 parity): the dispatcher
1360- # already applied any in-flight cancellation, and a cancel naming
1361- # one of our listen streams was settled by the wire-order intercept.
1334+ # Never surfaced (v1 parity): the dispatcher already applied it; listen cancels settled by the intercept.
13621335 return
13631336 try :
13641337 if isinstance (notification , types .LoggingMessageNotification ):
0 commit comments