errors संभालना
मशीनी अनुवाद
यह page अंग्रेज़ी documentation से अपने-आप अनुवादित किया गया है, और अंग्रेज़ी page ही प्रामाणिक version है। अगर कुछ गलत लगे, तो अनुवाद page बताता है कि इसकी सूचना कैसे दें।
tool तीन तरीकों से fail हो सकता है, और SDK हर एक के साथ अलग बर्ताव करता है।
ToolError raise करें तो आपका message model देखता है। MCPError raise करें तो उसे protocol देखता है। कुछ और raise करें तो वह crash है: model को सिर्फ़ इतना पता चलता है कि call fail हुआ, और traceback आपके log में जाता है।
यह page इनमें से चुनने के बारे में है।
ऐसा error जिसे model ठीक कर सकता है
ऐसा tool लें जो कुछ खोजता है, और खोज को नाकाम होने दें:
from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ToolError
mcp = MCPServer("Bookshop")
CATALOG = {"Dune": "Frank Herbert", "Neuromancer": "William Gibson"}
@mcp.tool()
def get_author(title: str) -> str:
"""Look up the author of a book in the catalog."""
if title not in CATALOG:
raise ToolError(f"No book titled {title!r} in the catalog.")
return CATALOG[title]
mcp.server.mcpserver.exceptions से आने वाला ToolError वह तरीका है जिससे tool model को बताता है कि कुछ गड़बड़ हुई।
इसे ऐसे title से call करें जो catalog में नहीं है और result देखें:
result.is_error # True
result.content # [TextContent(text="Error executing tool get_author: No book titled 'Nothing' in the catalog.")]
result.structured_content # None
- request सफल रही। result मौजूद है; caller की तरफ़ कुछ raise नहीं हुआ।
is_errorTrueहै, और आपका message (आगे tool का नाम लगा हुआ)contentमें है, ठीक वहीं जहाँ model पढ़ता है।structured_contentNoneहै। fail हुए call के पास structure करने को कोई return value नहीं होती।
यह tool error है, और लगभग हमेशा आप यही चाहते हैं।
आपके tool को call करने वाला model ही है। arguments उसी ने चुने। इसलिए tool error बातचीत का एक turn है: model "No book titled 'Nothing' in the catalog." पढ़ता है, समझ जाता है कि उसने title का गलत अंदाज़ा लगाया, और बेहतर title के साथ फिर call करता है। आपने एक raise लिखा और बदले में खुद को सुधारने वाला agent मिल गया।
server पर ToolError log में बस एक INFO line है, बिना traceback के। इसका आपको पहले से अंदाज़ा था, इसलिए जाँचने को कुछ नहीं है।
Tip
tool से कभी error message return न करें। लौटाई गई string का is_error=False होता है, इसलिए
model को (और हर client UI को) लगता है कि tool ठीक चला और वही string जवाब थी।
raise करें। flag ही संकेत है।
ऐसा error जिसे model ठीक नहीं कर सकता
अब ToolError की जगह MCPError रखें।
from mcp import MCPError
from mcp.server import MCPServer
from mcp.types import INVALID_PARAMS
mcp = MCPServer("Bookshop")
CATALOG = {"Dune": "Frank Herbert", "Neuromancer": "William Gibson"}
@mcp.tool()
def get_author(title: str) -> str:
"""Look up the author of a book in the catalog."""
if title not in CATALOG:
raise MCPError(code=INVALID_PARAMS, message=f"No book titled {title!r} in the catalog.")
return CATALOG[title]
MCPError SDK का protocol error है। यही वह एक exception है जिसे tool wrapper catch नहीं करता: यह ऊपर propagate होता है, और पूरी tools/call request result के बजाय JSON-RPC error के साथ fail हो जाती है।
{
"code": -32602,
"message": "No book titled 'Nothing' in the catalog."
}
- कोई result नहीं है। न
content, नis_error: model के पढ़ने के लिए कुछ भी नहीं। - इसके बजाय error host application को मिलता है, ठीक वैसे ही जैसे tool के बिल्कुल मौजूद न होने पर मिलता।
code,message, औरdataजस के तस पहुँचते हैं।INVALID_PARAMS-32602है;mcp.typesइसे और बाकी JSON-RPC error codes (INVALID_REQUEST,INTERNAL_ERROR, ...) को constants के रूप में export करता है, ताकि आपको कभी magic number न लिखना पड़े।
Check
वही lookup, वही चूक, लेकिन अब call client की तरफ़ लौटने के बजाय raise होता है:
mcp.shared.exceptions.MCPError: No book titled 'Nothing' in the catalog.
पहले version ने model को एक वाक्य थमाया जिस पर वह कुछ कर सकता था। यह version उसे कुछ नहीं देता।
get_author के लिए यह साफ़ तौर पर बदतर है, और यही अगले section का मुद्दा है।
कौन सा raise करें
दोनों रास्ते दो अलग-अलग सवालों का जवाब देते हैं।
ToolErrorraise करें जब नाकामी execution की हो: आपके tool ने जो करने की कोशिश की, वह नहीं हुआ। call model ने चुना था, इसलिए नतीजा भी model को दिखना चाहिए और उसे संभलने का मौका मिलना चाहिए। गलत वर्तनी वाला title, timeout हो गया upstream API, ऐसी row जो मौजूद नहीं: सब tool errors।MCPErrorraise करें जब request खुद ठुकराई जानी चाहिए: client के पास वह capability नहीं जिस पर आपका tool निर्भर है, server किसी को भी serve करने की हालत में नहीं है, caller ने कोई ज़रूरी चरण छोड़ दिया। model का कोई retry इनमें से किसी को ठीक नहीं करता, इसलिए उसे message थमाने से कुछ हासिल नहीं।
एक सवाल से फ़ैसला हो जाता है: क्या ज़्यादा समझदार model इससे बच सकता था? हाँ -> ToolError। नहीं -> MCPError।
इस कसौटी पर get_author के दूसरे version ने गलत चुनाव किया: बेहतर title से बात बन जाती है, इसलिए model message देखने का हक़दार था। वह version आपको mechanism दिखाने के लिए है, उसकी सिफ़ारिश करने के लिए नहीं।
Info
MCPError from mcp import MCPError पर मिलता है और code, message, और एक optional
data payload लेता है। इनमें आप जो भी रखें, client को वही मिलता है: SDK raise किए गए
MCPError को sanitise करने के बजाय जस का तस आगे भेज देता है।
कोई और exception
अब check हटा दें और dictionary lookup को अपने आप fail होने दें:
from mcp.server import MCPServer
mcp = MCPServer("Bookshop")
CATALOG = {"Dune": "Frank Herbert", "Neuromancer": "William Gibson"}
@mcp.tool()
def get_author(title: str) -> str:
"""Look up the author of a book in the catalog."""
return CATALOG[title]
CATALOG[title] KeyError raise करता है। आपने इसकी कोई योजना नहीं बनाई थी, इसलिए SDK इसे crash मानता है:
result.is_error # True
result.content # [TextContent(text="Error executing tool get_author")]
call अब भी is_error=True लौटाता है, इसलिए model जानता है कि वह fail हुआ और आगे बढ़ सकता है। जो उसे नहीं मिलता वह है exception का text: आपके code का KeyError, या तीन libraries नीचे के किसी driver से आया SQL का ढेर, आपके server की अंदरूनी बातें बयान कर सकता है, इसलिए वह server से बाहर कभी नहीं जाता।
वह आपको मिलता है। server crash को पूरे traceback के साथ ERROR पर log करता है, Tool 'get_author' raised an unexpected exception के रूप में। इसलिए WARNING पर चलने वाला production log हर ToolError के दौरान चुप रहता है और जैसे ही कुछ सच में टूटता है, बोल उठता है।
ऐसा resource जो मौजूद नहीं है
resources भी यही रेखा खींचते हैं, और आम मामले के लिए एक नाम वाला exception साथ देते हैं।
from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ResourceNotFoundError
mcp = MCPServer("Bookshop")
CATALOG = {"Dune": "Frank Herbert", "Neuromancer": "William Gibson"}
@mcp.resource("books://{title}")
def book(title: str) -> str:
"""The catalog entry for one book."""
if title not in CATALOG:
raise ResourceNotFoundError(f"No book titled {title!r} in the catalog.")
return f"{title} by {CATALOG[title]}"
books://{title} एक template है। यह किसी भी title से match करता है, इसलिए "URI सही बना है" और "किताब मौजूद है" दो अलग सवाल हैं, और दूसरे का जवाब सिर्फ़ आपका function दे सकता है।
जब वह न दे सके, ResourceNotFoundError raise करें। SDK इसे उस protocol error में बदल देता है जो spec ने गायब resource के लिए तय किया है: -32602, और data में माँगा गया URI, ताकि client को पता रहे कि कौन सा read fail हुआ।
{
"code": -32602,
"message": "No book titled 'Nothing' in the catalog.",
"data": {"uri": "books://Nothing"}
}
ध्यान दें, यहाँ कोई is_error=True वाला आधा-अधूरा result नहीं है। resource read या तो contents लौटाता है या fail होता है: resources के पास सिर्फ़ protocol वाला रास्ता है। ResourceError वही चीज़ है ऐसी नाकामी के लिए जो "not found" नहीं है (-32603, आपका message), और दोनों आपके log में एक INFO line हैं। MCPError को छोड़कर कोई भी और exception crash है: client को -32603 मिलता है जिसमें सिर्फ़ URI का नाम होता है, और traceback ERROR पर आपके log में जाता है। templates और resources के बारे में बाकी सब कुछ Resources में है।
ऐसे errors जो आप कभी raise नहीं करते
गलत argument आपके function तक कभी पहुँचता ही नहीं।
get_author को ऐसा title भेजें जो string नहीं है, और SDK आपको call करने से पहले ही उसे input schema के आधार पर ठुकरा देता है, उसी तरह के is_error=True tool error के रूप में जिसे model पढ़ और सुधार सकता है। Tools यही अस्वीकृति Field(le=50) constraint के साथ दिखाता है।
इसका मतलब है raise statements की एक पूरी श्रेणी जो आपको लिखनी नहीं पड़ती: अपने ही type hints को दोबारा validate न करें।
Info
इस page पर जो कुछ client को दिखता है, वह उस in-memory Client को भी दिखता है जिससे आप
tests लिखेंगे। raise_exceptions=True भी fail होते tool का exception caller को वापस नहीं
थमाता: जब तक वह flag कुछ कर पाता, आपका exception पहले ही is_error=True result बन चुका
होता है। result पर assert करें। crash का traceback चाहिए तो वह server के log में है, और
pytest का caplog उसे capture कर लेता है। Testing में यह pattern बताया गया है।
सारांश
- tool में
ToolErrorraise करें -> callis_error=Trueलौटाता है,contentमें आपके message के साथ। model उसे पढ़ता है और retry कर सकता है। MCPErrorraise करें -> call खुद JSON-RPC error के साथ fail हो जाता है। model को कुछ नहीं दिखता; host इससे निपटता है।code,message, औरdataजस के तस बचे रहते हैं।- फ़ैसला करने वाला सवाल: क्या ज़्यादा समझदार model इससे बच सकता था? हाँ ->
ToolError। नहीं ->MCPError। - कोई भी और exception crash है -> model के लिए
is_error=Trueजिसमें सिर्फ़Error executing tool <name>, और आपके लिए traceback वालाERRORrecord। - resource handler से
ResourceNotFoundError-> protocol का-32602,dataमें URI के साथ। - गलत arguments आपका function चलने से पहले ही schema के आधार पर ठुकरा दिए जाते हैं; उनके लिए आप
raiseनहीं करते। - Imports:
from mcp import MCPError,from mcp.server.mcpserver.exceptions import ToolError, ResourceError, ResourceNotFoundError, और error-code constantsmcp.typesसे।
errors संभल गए। server जो कुछ expose करता है, वह सब यही है। हर handler क्या पढ़ सकता है, और चलते-चलते client के साथ वापस क्या कर सकता है, यह अगला section है: आपके handler के अंदर।
जिन SDK errors से आपका सामना होने की सबसे ज़्यादा संभावना है, उनका हूबहू text, हर एक का मतलब, और हर एक का एक-कदम वाला हल Troubleshooting में है।