Cancellation
मशीनी अनुवाद
यह page अंग्रेज़ी documentation से अपने-आप अनुवादित किया गया है, और अंग्रेज़ी page ही प्रामाणिक version है। अगर कुछ गलत लगे, तो अनुवाद page बताता है कि इसकी सूचना कैसे दें।
client किसी call को बीच में छोड़ सकता है: user ने stop दबा दिया, या timeout पूरा हो गया।
ऐसा होने पर SDK आपके handler को cancel कर देता है। handler जिस await पर रुका है वह raise करता है, function unwind हो जाता है, और वह जो कुछ भी लौटाता है उसमें से कुछ नहीं भेजा जाता। ज़्यादातर handlers को इस बारे में कुछ करने की ज़रूरत नहीं होती।
दो तरह के handlers को ज़रूरत होती है: वह handler जिसे कुछ cleanup करना हो, और वह handler जो सादा def हो।
async def tool में cleanup करना
cleanup को finally में रखें:
import anyio
from mcp.server import MCPServer
mcp = MCPServer("Bookshop")
holds: set[str] = set()
async def take_payment(title: str) -> None:
await anyio.sleep(30) # the customer is typing a card number
async def release_hold(title: str) -> None:
await anyio.sleep(0.1) # a round trip to the stock system
holds.discard(title)
@mcp.tool()
async def order_book(title: str) -> str:
"""Hold a copy of a book while the customer pays for it."""
holds.add(title)
try:
await take_payment(title)
return f"Ordered {title!r}."
finally:
with anyio.move_on_after(5, shield=True):
await release_hold(title)
- tool चाहे जैसे खत्म हो,
finallyचलता है: tool ने कुछ लौटाया हो, raise किया हो, या cancel हुआ हो। - जिस cleanup को
awaitकरना पड़े, उसेshield=Trueचाहिए। cancel हो चुके handler में आगे का हरawaitभी raise करता है, इसलिए shield के बिनाrelease_holdअपनी पहली line पर ही रुक जाता। - shielded block को कोई cancel नहीं कर सकता, इसलिए उसे समय सीमा दें। यहाँ वह
5सेकंड है।
Tip
except नहीं, finally इस्तेमाल करें। cleanup पूरा होने के बाद cancellation को ऊपर की ओर
बढ़ते रहना होता है, और finally उसे बढ़ने देता है।
सादे def tool में जल्दी रुकना
सादा def tool thread में चलता है, और thread को बाहर से कोई interrupt नहीं कर सकता। tool को खुद पूछना पड़ता है:
import time
import anyio.from_thread
from mcp.server import MCPServer
mcp = MCPServer("Bookshop")
offline: set[str] = set()
def index_book(title: str) -> None:
time.sleep(1) # slow work with nothing to await
@mcp.tool()
def rebuild_index(titles: list[str]) -> str:
"""Take search offline and rebuild its index, one book at a time."""
offline.add("search")
try:
for title in titles:
anyio.from_thread.check_cancelled()
index_book(title)
return f"Indexed {len(titles)} books."
finally:
offline.discard("search")
- जब तक call चालू है,
anyio.from_thread.check_cancelled()कुछ नहीं करता, और call cancel हो जाने के बाद raise करता है। इसे काम की इकाइयों के बीच call करें। - यहाँ भी cleanup
finallyमें जाता है। thread में कुछ भी await नहीं करता, इसलिए इसे shield की ज़रूरत नहीं होती। - जो
deftool कभी नहीं पूछता, वह अंत तक चलता है, और उसका नतीजा फेंक दिया जाता है।
यह कहाँ लागू होता है
prompt और resource functions ठीक tools की तरह cancel होते हैं।
stdio और Streamable HTTP दोनों पर यह एक जैसा काम करता है। इस SDK के Client में call छोड़ने का मतलब है उस task को cancel करना जो call_tool को await कर रहा है, या उसका read_timeout_seconds पूरा हो जाने देना।
Warning
Streamable HTTP के दो options यह खबर handler तक नहीं पहुँचने देते: 2026-07-28 connection पर
json_response=True, और legacy connection पर stateless_http=True। वहाँ client ने चाहे जो
किया हो, handler अंत तक चलता है।
सारांश
- जब client किसी call को छोड़ देता है, तो SDK handler को cancel कर देता है: tool, prompt या resource।
async def: cleanupfinallyमें करें, और जो cleanup await करता है उसेanyio.move_on_after(seconds, shield=True)के अंदर रखें।- सादा
def: काम की इकाइयों के बीचanyio.from_thread.check_cancelled()call करें, नहीं तो tool अंत तक चलता है। सादाfinallycleanup कर देता है। json_response=True(modern connections) औरstateless_http=True(legacy connections) cancellation को बंद कर देते हैं।
progress और cancellation चलते हुए tool और उसके caller के बीच की बात हैं। tool जो lines आपके लिए, यानी server चलाने वाले व्यक्ति के लिए, log करता है, वे एक अलग channel हैं: Logging।