diff --git a/docs/concepts/tools.mdx b/docs/concepts/tools.mdx index 45eb4ec..36b1dd3 100644 --- a/docs/concepts/tools.mdx +++ b/docs/concepts/tools.mdx @@ -30,6 +30,13 @@ Each tool is defined with the following structure: inputSchema: { // JSON Schema for the tool's parameters type: "object", properties: { ... } // Tool-specific parameters + }, + annotations?: { // Optional hints about tool behavior + title?: string; // Human-readable title for the tool + readOnlyHint?: boolean; // If true, the tool does not modify its environment + destructiveHint?: boolean; // If true, the tool may perform destructive updates + idempotentHint?: boolean; // If true, repeated calls with same args have no additional effect + openWorldHint?: boolean; // If true, tool interacts with external entities } } ``` @@ -302,6 +309,163 @@ Here's an example of proper error handling for tools: This approach allows the LLM to see that an error occurred and potentially take corrective action or request human intervention. +## Tool annotations + +Tool annotations provide additional metadata about a tool's behavior, helping clients understand how to present and manage tools. These annotations are hints that describe the nature and impact of a tool, but should not be relied upon for security decisions. + +### Purpose of tool annotations + +Tool annotations serve several key purposes: + +1. Provide UX-specific information without affecting model context +2. Help clients categorize and present tools appropriately +3. Convey information about a tool's potential side effects +4. Assist in developing intuitive interfaces for tool approval + +### Available tool annotations + +The MCP specification defines the following annotations for tools: + +| Annotation | Type | Default | Description | +|------------|------|---------|-------------| +| `title` | string | - | A human-readable title for the tool, useful for UI display | +| `readOnlyHint` | boolean | false | If true, indicates the tool does not modify its environment | +| `destructiveHint` | boolean | true | If true, the tool may perform destructive updates (only meaningful when `readOnlyHint` is false) | +| `idempotentHint` | boolean | false | If true, calling the tool repeatedly with the same arguments has no additional effect (only meaningful when `readOnlyHint` is false) | +| `openWorldHint` | boolean | true | If true, the tool may interact with an "open world" of external entities | + +### Example usage + +Here's how to define tools with annotations for different scenarios: + +```typescript +// A read-only search tool +{ + name: "web_search", + description: "Search the web for information", + inputSchema: { + type: "object", + properties: { + query: { type: "string" } + }, + required: ["query"] + }, + annotations: { + title: "Web Search", + readOnlyHint: true, + openWorldHint: true + } +} + +// A destructive file deletion tool +{ + name: "delete_file", + description: "Delete a file from the filesystem", + inputSchema: { + type: "object", + properties: { + path: { type: "string" } + }, + required: ["path"] + }, + annotations: { + title: "Delete File", + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, + openWorldHint: false + } +} + +// A non-destructive database record creation tool +{ + name: "create_record", + description: "Create a new record in the database", + inputSchema: { + type: "object", + properties: { + table: { type: "string" }, + data: { type: "object" } + }, + required: ["table", "data"] + }, + annotations: { + title: "Create Database Record", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, + openWorldHint: false + } +} +``` + +### Integrating annotations in server implementation + + + + ```typescript + server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: [{ + name: "calculate_sum", + description: "Add two numbers together", + inputSchema: { + type: "object", + properties: { + a: { type: "number" }, + b: { type: "number" } + }, + required: ["a", "b"] + }, + annotations: { + title: "Calculate Sum", + readOnlyHint: true, + openWorldHint: false + } + }] + }; + }); + ``` + + + ```python + @app.list_tools() + async def list_tools() -> list[types.Tool]: + return [ + types.Tool( + name="calculate_sum", + description="Add two numbers together", + inputSchema={ + "type": "object", + "properties": { + "a": {"type": "number"}, + "b": {"type": "number"} + }, + "required": ["a", "b"] + }, + annotations={ + "title": "Calculate Sum", + "readOnlyHint": True, + "openWorldHint": False + } + ) + ] + ``` + + + +### Best practices for tool annotations + +1. **Be accurate about side effects**: Clearly indicate whether a tool modifies its environment and whether those modifications are destructive. + +2. **Use descriptive titles**: Provide human-friendly titles that clearly describe the tool's purpose. + +3. **Indicate idempotency properly**: Mark tools as idempotent only if repeated calls with the same arguments truly have no additional effect. + +4. **Set appropriate open/closed world hints**: Indicate whether a tool interacts with a closed system (like a database) or an open system (like the web). + +5. **Remember annotations are hints**: All properties in ToolAnnotations are hints and not guaranteed to provide a faithful description of tool behavior. Clients should never make security-critical decisions based solely on annotations. + ## Testing tools A comprehensive testing strategy for MCP tools should cover: