Hataları ele alma
Makine çevirisi
Bu sayfa İngilizce dokümantasyondan otomatik olarak çevrildi; esas alınması gereken sürüm İngilizce sayfadır. Yanlış görünen bir şey varsa, nasıl bildireceğinizi Çeviriler sayfası açıklar.
Bir araç üç şekilde başarısız olabilir ve SDK her birini farklı ele alır.
ToolError fırlatırsanız mesajınızı model görür. MCPError fırlatırsanız bunu protokol görür. Başka herhangi bir şey fırlatırsanız bu bir çökmedir: model yalnızca çağrının başarısız olduğunu öğrenir, traceback ise log'unuza düşer.
Bu sayfa, hangisini seçeceğinizle ilgili.
Modelin düzeltebileceği bir hata
Bir şeyi arayıp bulan bir araç düşünün; arama sonuçsuz kalsın:
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 içindeki ToolError, bir aracın modele bir şeylerin ters gittiğini söyleme yoludur.
Katalogda olmayan bir başlıkla çağırın ve sonuca bakın:
result.is_error # True
result.content # [TextContent(text="Error executing tool get_author: No book titled 'Nothing' in the catalog.")]
result.structured_content # None
- İstek başarılı oldu. Ortada bir sonuç var; çağıran tarafta hiçbir şey fırlatılmadı.
is_errordeğeriTrue; mesajınız (başına araç adı eklenmiş olarak)content'te, tam da modelin okuduğu yerde.structured_contentdeğeriNone. Başarısız bir çağrının yapılandırılacak bir dönüş değeri yoktur.
Bu bir araç hatasıdır ve neredeyse her zaman istediğiniz şey de budur.
Aracınızı çağıran modeldir. Argümanları o seçti. Bu yüzden araç hatası, konuşmada bir tur demektir: model "No book titled 'Nothing' in the catalog." mesajını okur, başlığı yanlış tahmin ettiğini anlar ve daha iyi bir başlıkla tekrar çağırır. Tek bir raise yazdınız ve kendi kendini düzelten bir ajan elde ettiniz.
Sunucuda bir ToolError, log'da tek bir INFO satırıdır; traceback yoktur. Bunu zaten bekliyordunuz, bu yüzden araştırılacak bir şey yok.
Tip
Bir araçtan hata mesajını asla return ile döndürmeyin. Döndürülen bir dizenin is_error=False
değeri vardır; bu yüzden modele (ve her istemci arayüzüne) araç çalışmış ve yanıt o dizeymiş gibi görünür.
raise kullanın. Sinyali veren bayraktır.
Modelin düzeltemeyeceği bir hata
Şimdi ToolError yerine MCPError koyun.
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'nın protokol hatasıdır. Araç sarmalayıcısının yakalamadığı tek istisna budur: yayılır ve tools/call isteğinin tamamı bir sonuç yerine JSON-RPC hatasıyla başarısız olur.
{
"code": -32602,
"message": "No book titled 'Nothing' in the catalog."
}
- Sonuç yoktur.
contentyok,is_erroryok: modelin okuyacağı hiçbir şey yok. - Hatayı bunun yerine host uygulama alır; tıpkı araç hiç var olmasaydı alacağı gibi.
code,messagevedatabozulmadan ulaşır.INVALID_PARAMSsabiti-32602değerini taşır;mcp.typesonu ve diğer JSON-RPC hata kodlarını (INVALID_REQUEST,INTERNAL_ERROR, ...) sabit olarak dışa aktarır, böylece hiçbir zaman sihirli bir sayı yazmazsınız.
Check
Aynı arama, aynı sonuçsuzluk; ama bu kez çağrı istemci tarafında döndürmek yerine fırlatır:
mcp.shared.exceptions.MCPError: No book titled 'Nothing' in the catalog.
İlk sürüm modele tepki verebileceği bir cümle vermişti. Bu sürüm ona hiçbir şey vermez.
get_author için bu kesinlikle daha kötüdür; bir sonraki bölümün konusu da budur.
Hangisini fırlatmalı
İki yol, iki farklı soruyu yanıtlar.
- Yürütme başarısızlığı için
ToolErrorfırlatın: aracınızın yapmaya çalıştığı şey işe yaramadı. Çağrıyı model seçti, bu yüzden sonucunu da model görmeli ve toparlanma şansı bulmalı. Yanlış yazılmış bir başlık, zaman aşımına uğrayan bir dış API, var olmayan bir satır: hepsi araç hatası. - İsteğin kendisi reddedilmesi gerektiğinde
MCPErrorfırlatın: istemcide aracınızın bağımlı olduğu bir yetenek eksik, sunucu kimseye hizmet verecek durumda değil, çağıran taraf zorunlu bir adımı atlamış. Modelin hiçbir yeniden denemesi bunları düzeltmez; bu yüzden mesajı ona vermenin bir kazancı yok.
Kararı tek bir soru verir: daha akıllı bir model bundan kaçınabilir miydi? Evet -> ToolError. Hayır -> MCPError.
Bu ölçüte göre get_author'ın ikinci sürümü yanlış seçim yaptı: daha iyi bir başlık sorunu çözer, yani model mesajı görmeyi hak ediyordu. O sürüm size mekanizmayı göstermek için orada, onu önermek için değil.
Info
MCPError, from mcp import MCPError ile içe aktarılır ve code, message ile isteğe bağlı
bir data yükü alır. Bunlara ne koyarsanız istemci onu alır: SDK, fırlatılan bir
MCPError'ı temizlemek yerine olduğu gibi iletir.
Başka herhangi bir istisna
Şimdi denetimi çıkarın ve sözlük aramasının kendi kendine başarısız olmasına izin verin:
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 fırlatır. Bunu planlamadınız, bu yüzden SDK onu bir çökme olarak ele alır:
result.is_error # True
result.content # [TextContent(text="Error executing tool get_author")]
Çağrı yine is_error=True döndürür; yani model başarısız olduğunu bilir ve yoluna devam edebilir. Almadığı şey istisnanın metnidir: kodunuzdan gelen bir KeyError ya da üç kütüphane alttaki bir sürücüden gelen bir yığın SQL, sunucunuzun iç yapısını ele verebilir; bu yüzden sunucudan asla çıkmaz.
Onu siz alırsınız. Sunucu çökmeyi tam traceback ile ERROR düzeyinde, Tool 'get_author' raised an unexpected exception olarak log'a yazar. Bu yüzden WARNING düzeyindeki bir üretim log'u her ToolError boyunca sessiz kalır ve bir şey gerçekten bozulduğu anda sesini çıkarır.
Var olmayan bir kaynak
Kaynaklar da aynı çizgiyi çeker ve yaygın durum için adlandırılmış bir istisna sunar.
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} bir şablondur. Her başlıkla eşleşir; bu yüzden "URI düzgün biçimli" ile "kitap var" iki farklı sorudur ve ikincisini yalnızca fonksiyonunuz yanıtlayabilir.
Yanıtlayamadığında ResourceNotFoundError fırlatın. SDK bunu, spesifikasyonun eksik bir kaynağa atadığı protokol hatasına dönüştürür: data'da istenen URI ile birlikte -32602; böylece istemci hangi okumanın başarısız olduğunu bilir.
{
"code": -32602,
"message": "No book titled 'Nothing' in the catalog.",
"data": {"uri": "books://Nothing"}
}
Burada is_error=True taşıyan yarım bir sonuç olmadığına dikkat edin. Bir kaynak okuması ya içerik döndürür ya da başarısız olur: kaynakların yalnızca protokol yolu vardır. ResourceError, "bulunamadı" olmayan bir başarısızlık için aynı şeydir (-32603, sizin mesajınız); ikisi de log'unuzda tek bir INFO satırıdır. MCPError dışındaki diğer her istisna bir çökmedir: istemci yalnızca URI'yi belirten -32603 alır, traceback ise ERROR düzeyinde log'unuza gider. Şablonlar ve kaynaklarla ilgili diğer her şey Kaynaklar sayfasında.
Hiç fırlatmadığınız hatalar
Hatalı bir argüman fonksiyonunuza asla ulaşmaz.
get_author'a dize olmayan bir title gönderin; SDK sizi çağırmadan önce onu girdi şemasına göre reddeder. Bu da modelin okuyup düzeltebileceği türden, aynı is_error=True araç hatasıdır. Araçlar sayfası aynı reddi bir Field(le=50) kısıtıyla gösterir.
Bu, yazmadığınız koca bir raise ifadesi sınıfı demektir: kendi tür ipuçlarınızı yeniden doğrulamayın.
Info
Bu sayfada bir istemcinin gördüğü her şeyi, testleri yazarken kullanacağınız bellek içi
Client da görür. raise_exceptions=True bile başarısız olan bir
aracın istisnasını çağırana geri vermez: o bayrak devreye girebilecek noktaya geldiğinde istisnanız çoktan
is_error=True sonucuna dönüşmüştür. Doğrulamayı sonuç üzerinde yapın. Bir çökmenin traceback'ine ihtiyacınız varsa o
sunucunun log'undadır ve pytest'in caplog'u onu yakalar. Test etme sayfası bu kalıbı anlatır.
Özet
- Bir araçta
ToolErrorfırlatın -> çağrı, mesajınızcontent'te olacak şekildeis_error=Truedöndürür. Model bunu okur ve yeniden deneyebilir. MCPErrorfırlatın -> çağrının kendisi bir JSON-RPC hatasıyla başarısız olur. Model hiçbir şey görmez; bununla host ilgilenir.code,messagevedatabozulmadan ulaşır.- Belirleyici soru: daha akıllı bir model bundan kaçınabilir miydi? Evet ->
ToolError. Hayır ->MCPError. - Diğer her istisna bir çökmedir -> model için yalnızca
Error executing tool <name>içerenis_error=True, sizin için ise traceback'li birERRORkaydı. - Bir kaynak işleyicisinden
ResourceNotFoundError-> protokolün-32602kodu, URIdata'da. - Hatalı argümanlar, fonksiyonunuz çalışmadan önce şemaya göre reddedilir; bunlar için
raiseyazmazsınız. - İçe aktarmalar:
from mcp import MCPError,from mcp.server.mcpserver.exceptions import ToolError, ResourceError, ResourceNotFoundErrorvemcp.types'tan hata kodu sabitleri.
Hatalar halloldu. Bir sunucunun sunduğu her şey bu kadar. Her işleyicinin çalışırken neleri okuyabildiği ve istemciye geri neler yapabildiği bir sonraki bölümde: İşleyicinin içinde.
En sık karşılaşacağınız SDK hatalarının tam metni, her birinin ne anlama geldiği ve her biri için tek hamlelik çözüm Sorun giderme sayfasında.