Files
Max Isbey 1b74b06753 Tighten comments and docstrings repo-wide
Cut comment and docstring volume roughly in half across src, tests,
examples, and docs_src: removed comments that restate the adjacent code,
leftover development narration, section banners, and self-evident
Args/Returns blocks, and compressed the remaining docstrings to a
Google-style summary line plus only the detail that earns its place.

Kept (and tightened) the load-bearing content: Raises sections,
deprecation and version-availability notes, spec/RFC/issue references,
why-comments for non-obvious decisions, and all coverage pragmas. The
generated mcp_types.v* wire modules are untouched.
2026-06-29 15:10:27 +00:00
..

error-handling

Tool execution failures travel as a successful CallToolResult with is_error=True so the LLM can read the message and self-correct. Protocol failures travel as a JSON-RPC error that the client catches as MCPError. This story shows how to produce each from a tool body — raise ToolError(...) vs raise MCPError(...) on MCPServer; an explicit is_error=True return vs raise MCPError on lowlevel.Server — and how a client tells them apart.

Run it

# stdio (default — the client spawns the server as a subprocess)
uv run python -m stories.error_handling.client

# HTTP — the client self-hosts the server on a free port, runs, then tears it down
uv run python -m stories.error_handling.client --http
# same, against the lowlevel-API server variant
uv run python -m stories.error_handling.client --http --server server_lowlevel

What to look at

  • client.py main — opens with async with Client(target, mode=mode) as client:. Inside it, await returns for is_error results and except MCPError catches protocol errors; the client never auto-raises on is_error.
  • server.pyraise ToolError(...) vs raise MCPError(...): same raise keyword, opposite wire channel. The tool wrapper re-raises MCPError verbatim and wraps everything else as an is_error result.
  • server_lowlevel.py — no wrapper: you build CallToolResult(is_error=True) yourself, and MCPError is the only way to pick a JSON-RPC error code.

Caveats

  • The "any other exception → is_error result" contract on MCPServer and the "uncaught exception → code=0" behaviour on lowlevel.Server are not shown — the contract is under design and the legacy code is a known spec divergence. This story will grow those cases once the contract lands.
  • MCPServer prefixes the execution-error message with "Error executing tool {name}: "; build a CallToolResult directly from a lowlevel handler if you need verbatim control.

Spec

Tools — error handling

See also

tools/ (the happy path), streaming/ (cancellation as a third error-adjacent surface).