Vault / wiki/201/mcp-tools.md
updated 2026-05-28MCP Tools
Actions the LLM can invoke through an MCP server. Same conceptual model as Claude API tool use, with extras.
Definition (Python SDK)
from mcp.server import Server
from mcp.types import Tool
server = Server("my-server")
@server.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="search_tickets",
description="Search Linear tickets by query string. Use when the user asks about tickets, issues, or bugs.",
inputSchema={
"type": "object",
"properties": {
"query": {"type": "string"},
"limit": {"type": "integer", "default": 10},
},
"required": ["query"],
},
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "search_tickets":
results = await linear.search(arguments["query"], arguments.get("limit", 10))
return [{"type": "text", "text": format_results(results)}]
Annotations (trust hints)
Tools can carry annotations that hint at behavior:
readOnlyHint: true— pure read, no side effects.destructiveHint: true— may delete/modify state.idempotentHint: true— safe to retry.openWorldHint: true— interacts with external systems.
Clients use these to decide auto-approval policy. Destructive tools should default to user-confirmation flow.
Return content types
Tool returns are a list of content blocks:
textimage(base64)resource— a pointer to a resource (URI) the model can ask to read.
Returning a resource instead of inlining huge text keeps token usage down — the model fetches only if needed.
Tool description rules (CCA-F)
- State when to use it AND when not to.
- Mention required inputs and their format.
- For destructive tools: explicitly say "Requires user confirmation; do not auto-call."
- Keep under ~500 tokens; long descriptions dilute.