Skip to content

Commit 761500d

Browse files
committed
Tighten dispatcher abandon-path writes and response invariants
- Bound the timeout-path courtesy cancel like the other abandon writes and extract a single _final_write policy: 5s for courtesy cancels, 1s for shutdown responses so closing a session stays fast on a wedged transport - Answer shutdown-interrupted requests with CONNECTION_CLOSED and retire the REQUEST_CANCELLED constant (-32002 collides with resource-not-found) - Key the peer-cancel error response on cancelled_caught so a cancel landing after the handler finished cannot produce a second answer for the same id - Decide outbound metadata and cancel-on-abandon suppression in one place: only resumption hints that actually reach the transport suppress the courtesy cancel - Never send notifications/cancelled for a request whose write never completed - Identity-guard the in-flight pop so a finished handler cannot evict a newer entry that reused its request id - Map request-write stream failures to MCPError(CONNECTION_CLOSED); warn when a bounded final write gives up; mark the Dispatcher lifecycle provisional
1 parent a51357c commit 761500d

5 files changed

Lines changed: 784 additions & 94 deletions

File tree

src/mcp/shared/dispatcher.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,11 @@ class CallOptions(TypedDict, total=False):
6161
A request is abandoned when its `timeout` elapses or the caller's scope is
6262
cancelled while awaiting the response. Defaults to `True`. Set `False` for
6363
requests the protocol forbids cancelling, such as `initialize`. The
64-
notification is also suppressed when resumption hints are present: the
65-
caller intends to resume the request, so the peer's work must keep running.
64+
notification is also suppressed when resumption hints actually reach the
65+
transport (the caller intends to resume the request, so the peer's work
66+
must keep running); hints ignored in favor of dispatch-context routing do
67+
not suppress it. No notification is sent for a request that was never
68+
written to the transport.
6669
"""
6770

6871
on_progress: ProgressFnT
@@ -197,6 +200,10 @@ class Dispatcher(Outbound, Protocol[TransportT_co]):
197200
198201
Implementations own correlation of outbound requests to inbound results, the
199202
receive loop, per-request concurrency, and cancellation/progress wiring.
203+
204+
The protocol's lifecycle surface is provisional and expected to change
205+
before v2 stable (`run()` may be superseded by an `open()`/`wait_closed()`
206+
pair).
200207
"""
201208

202209
async def run(

0 commit comments

Comments
 (0)