Log MCPServer handler exceptions by kind and keep crash details off the wire (#3314)

Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
This commit is contained in:
Max 2026-08-24 15:51:18 +01:00 • committed by GitHub
commit 56af44727b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 1427 additions and 310 deletions

View file

@ -2,6 +2,7 @@ from pydantic import BaseModel
from mcp import Client
from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ToolError
from mcp.types import TextContent
mcp = MCPServer("Bookshop")
@ -17,7 +18,7 @@ class Book(BaseModel):
def lookup_book(title: str) -> Book:
"""Look up a book by its exact title."""
if title != "Dune":
raise ValueError(f"No book titled {title!r} in the catalog.")
raise ToolError(f"No book titled {title!r} in the catalog.")
return Book(title="Dune", author="Frank Herbert", year=1965)

View file

@ -1,4 +1,5 @@
from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ToolError
mcp = MCPServer("Bookshop")
@ -9,5 +10,5 @@ CATALOG = {"Dune": "Frank Herbert", "Neuromancer": "William Gibson"}
def get_author(title: str) -> str:
"""Look up the author of a book in the catalog."""
if title not in CATALOG:
raise ValueError(f"No book titled {title!r} in the catalog.")
raise ToolError(f"No book titled {title!r} in the catalog.")
return CATALOG[title]

View file

@ -0,0 +1,11 @@
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]

View file

@ -1,4 +1,5 @@
from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ToolError
mcp = MCPServer("Bookshop")
@ -20,7 +21,7 @@ def search_books(query: str) -> list[str]:
def get_author(title: str) -> str:
"""Look up the author of a book in the catalog."""
if title not in CATALOG:
raise ValueError(f"No book titled {title!r} in the catalog.")
raise ToolError(f"No book titled {title!r} in the catalog.")
return CATALOG[title]

View file

@ -1,5 +1,5 @@
from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ResourceNotFoundError
from mcp.server.mcpserver.exceptions import ResourceNotFoundError, ToolError
mcp = MCPServer("Weather")
@ -10,7 +10,7 @@ FORECASTS = {"London": "Rain.", "Cairo": "Sun."}
def forecast(city: str) -> str:
"""Today's forecast for one city."""
if city not in FORECASTS:
raise ValueError(f"No forecast for {city!r}.")
raise ToolError(f"No forecast for {city!r}.")
return FORECASTS[city]

View file

@ -1,6 +1,7 @@
from pathlib import Path
from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ResourceNotFoundError
from mcp.shared.path_security import safe_join
mcp = MCPServer("Bookshop")
@ -11,4 +12,7 @@ DOCS_ROOT = Path("./manuals")
@mcp.resource("manuals://{+path}")
def read_manual(path: str) -> str:
"""A staff manual page, served from a directory on disk."""
return safe_join(DOCS_ROOT, path).read_text(encoding="utf-8")
file = safe_join(DOCS_ROOT, path)
if not file.is_file():
raise ResourceNotFoundError(f"No manual at {path!r}.")
return file.read_text(encoding="utf-8")