Overview
Custom tools let Claude call your own functions during an Agent SDK session.
Using the SDK's in-process MCP server, you define tools with an input schema and
a handler, bundle them into a server that runs inside your application (not a
separate process), and pass them to query.
Define a tool
A tool has a name, description, input schema, and async handler. Use the tool()
helper (TypeScript, Zod schema) or the @tool decorator (Python, dict or JSON
Schema), then wrap tools in a server.
import { tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";
const getTemperature = tool(
"get_temperature",
"Get the current temperature at a location",
{ latitude: z.number(), longitude: z.number() },
async (args) => ({ content: [{ type: "text", text: `...` }] }),
);
const weatherServer = createSdkMcpServer({
name: "weather",
version: "1.0.0",
tools: [getTemperature],
});
Python uses @tool(...) and create_sdk_mcp_server(...) with the same shape.
Register and allow the tool
Pass the server via mcpServers. The key becomes the {server_name} segment of
the fully qualified name mcp__{server_name}__{tool_name}; list that in
allowedTools so it runs without a prompt.
for await (const message of query({
prompt: "What's the temperature in San Francisco?",
options: {
mcpServers: { weather: weatherServer },
allowedTools: ["mcp__weather__get_temperature"],
},
})) { /* ... */ }
Use the wildcard mcp__weather__* to allow every tool a server exposes.
Handle errors
Return isError: true (TS) / "is_error": True (Python) from the handler when a
call fails. The agent loop continues and Claude can retry or explain. An uncaught
exception stops the loop and fails the query call.
Return images and structured data
A handler's content array accepts text, image (base64, no data URI prefix),
and resource blocks. Set structuredContent to return machine-readable JSON
alongside the content. (In Python, structuredContent requires a standalone MCP
server rather than the in-process @tool decorator.)
Annotations and scaling
Pass annotations like readOnlyHint: true so Claude can batch parallel-safe
calls. Every tool definition consumes context each turn; for dozens of tools, use
tool search to load them on demand.
Source