ab89da82ba
A tool that crashed used to send the exception's own text to the client as "Error executing tool <name>: <str(exc)>". That text can describe server internals (or, for an output-schema failure, echo the tool's return value), so a crash now reads just "Error executing tool <name>". ToolError, ResourceError, and argument-validation messages still reach the model unchanged, since those are the anticipated failures it can act on. Closes the tool half of the leak that resources already avoided and that prompts stopped doing earlier in this branch. Related tidy-ups in the same direction: - a crashing @mcp.completion() handler is logged once and answered with -32603 "Error completing argument <name>" instead of str(exc) - the legacy resolver path reports a malformed elicitation answer as a ToolError, matching what the input_required path already did - the INFO line for rejected arguments names the fields, not the values Docs now teach ToolError as the way to talk to the model and describe a plain exception as a crash the model sees generically; examples that relied on ValueError text reaching the client raise ToolError instead.
35 lines
861 B
Python
35 lines
861 B
Python
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")
|
|
|
|
|
|
class Book(BaseModel):
|
|
title: str
|
|
author: str
|
|
year: int
|
|
|
|
|
|
@mcp.tool()
|
|
def lookup_book(title: str) -> Book:
|
|
"""Look up a book by its exact title."""
|
|
if title != "Dune":
|
|
raise ToolError(f"No book titled {title!r} in the catalog.")
|
|
return Book(title="Dune", author="Frank Herbert", year=1965)
|
|
|
|
|
|
async def main() -> None:
|
|
async with Client(mcp) as client:
|
|
result = await client.call_tool("lookup_book", {"title": "Dune"})
|
|
|
|
for block in result.content:
|
|
if isinstance(block, TextContent):
|
|
print(block.text)
|
|
|
|
print(result.structured_content)
|
|
print(result.is_error)
|