Document how a handler deals with cancellation (#3625) · modelcontextprotocol/python-sdk@cdf7d33 · GitHub
Skip to content

Commit cdf7d33

Browse files
authored
Document how a handler deals with cancellation (#3625)
1 parent 6513955 commit cdf7d33

9 files changed

Lines changed: 348 additions & 2 deletions

File tree

‎docs/handlers/cancellation.md‎

Lines changed: 55 additions & 0 deletions

‎docs/handlers/index.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ What it can do while it runs:
2222
**[Sampling and roots](sampling-and-roots.md)**, deprecated but still
2323
served.
2424
* Report **[Progress](progress.md)** on something slow.
25+
* Clean up, or stop early, when the client gives up on the call, with
26+
**[Cancellation](cancellation.md)**.
2527
* Write logs (to standard error, for whoever operates the server) with
2628
**[Logging](logging.md)**.
2729
* Tell subscribed clients that something changed with

‎docs/handlers/progress.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,4 @@ The callback receives `total=None`. A client can still show *activity* ("3 impor
115115
* No callback on the call means `report_progress` does nothing. Report unconditionally.
116116
* Omit `total` when you don't know it; the callback gets `None`.
117117

118-
Progress is what a running tool shows the *user*. The lines it logs for *you*, the person operating the server, are a different channel: **[Logging](logging.md)**.
118+
Progress is for a client that is still waiting. What your tool sees when the client stops waiting is **[Cancellation](cancellation.md)**.

‎docs/servers/tools.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ You can mix and match: plain parameters next to model parameters, nested models,
136136

137137
If a tool does I/O (calls an API, reads a file, queries a database), declare it `async def` and `await` inside it. The SDK awaits it.
138138

139-
A plain `def` tool works too: the SDK runs it in a thread so it never blocks the server.
139+
A plain `def` tool works too: the SDK runs it in a thread so it never blocks the server. A long one can check whether the client is still waiting; see **[Cancellation](../handlers/cancellation.md)**.
140140

141141
There is nothing else to configure.
142142

‎docs_src/cancellation/__init__.py‎

Whitespace-only changes.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import anyio
2+
3+
from mcp.server import MCPServer
4+
5+
mcp = MCPServer("Bookshop")
6+
7+
holds: set[str] = set()
8+
9+
10+
async def take_payment(title: str) -> None:
11+
await anyio.sleep(30) # the customer is typing a card number
12+
13+
14+
async def release_hold(title: str) -> None:
15+
await anyio.sleep(0.1) # a round trip to the stock system
16+
holds.discard(title)
17+
18+
19+
@mcp.tool()
20+
async def order_book(title: str) -> str:
21+
"""Hold a copy of a book while the customer pays for it."""
22+
holds.add(title)
23+
try:
24+
await take_payment(title)
25+
return f"Ordered {title!r}."
26+
finally:
27+
with anyio.move_on_after(5, shield=True):
28+
await release_hold(title)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import time
2+
3+
import anyio.from_thread
4+
5+
from mcp.server import MCPServer
6+
7+
mcp = MCPServer("Bookshop")
8+
9+
offline: set[str] = set()
10+
11+
12+
def index_book(title: str) -> None:
13+
time.sleep(1) # slow work with nothing to await
14+
15+
16+
@mcp.tool()
17+
def rebuild_index(titles: list[str]) -> str:
18+
"""Take search offline and rebuild its index, one book at a time."""
19+
offline.add("search")
20+
try:
21+
for title in titles:
22+
anyio.from_thread.check_cancelled()
23+
index_book(title)
24+
return f"Indexed {len(titles)} books."
25+
finally:
26+
offline.discard("search")

‎mkdocs.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ nav:
4040
- Multi-round-trip requests: handlers/multi-round-trip.md
4141
- Sampling and roots: handlers/sampling-and-roots.md
4242
- Progress: handlers/progress.md
43+
- Cancellation: handlers/cancellation.md
4344
- Logging: handlers/logging.md
4445
- Subscriptions: handlers/subscriptions.md
4546
- Running your server:
Lines changed: 234 additions & 0 deletions

0 commit comments

Comments
 (0)