Building Custom Tools for the Claude Agent SDK
Create tools that call external APIs, define their input schemas with Zod, package them into in-process MCP servers, and give your agent capabilities no built-in tool provides.
When built-in tools are not enough
The Agent SDK's built-in tools cover a lot: file operations, web search, bash execution. But real-world agents often need to do something specific — call a proprietary API, fetch live data from a particular source, interact with a service that has no MCP server yet.
Custom tools solve this. They let you define exactly what capability the agent gets, package it in the format the SDK expects, and wire it into your agent's tool list.
Zod: the schema layer
Before writing a custom tool, you need to understand Zod. Zod is a TypeScript schema validation library. The Agent SDK uses it to define what parameters each tool accepts.
The reason Zod works so well here: AI models understand it at a deep level. Once you have written one Zod schema, you can describe the next tool to a coding agent in plain English and it will write the Zod definition correctly. The pattern is highly learnable and highly delegatable.
Install it:
bun add zod
The four parts of a custom tool
Every tool you build has four parts:
1. Name — snakecase identifier (getweather, fetchclientdata) 2. Description — what the tool does and when to use it. The agent reads this to decide whether to call the tool. 3. Zod schema — the input parameters the tool accepts 4. Handler function — the actual code that runs when the agent calls the tool
Here is a complete example — a weather tool that calls a live API:
import { query, tool, createSDKMCPServer } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";
const getWeather = tool(
"get_weather",
"Get the current temperature for a location using latitude and longitude coordinates.",
z.object({
latitude: z.number().describe("Latitude coordinate"),
longitude: z.number().describe("Longitude coordinate"),
}),
async (args) => {
const response = await fetch(
`https://api.open-meteo.com/v1/forecast?latitude=${args.latitude}&longitude=${args.longitude}¤t=temperature_2m`
);
const data = await response.json() as { current: { temperature_2m: number } };
return {
content: [
{
type: "text" as const,
text: `Current temperature: ${data.current.temperature_2m}°C`,
},
],
};
}
);
The handler returns content in the MCP tool format — an array with a type and text field. This is the convention the SDK uses because custom tools follow MCP protocol conventions.
Packaging tools into an in-process MCP server
After creating individual tools, you have to package them into an in-process MCP server before passing them to the agent. This is required by the SDK architecture.
const weatherServer = createSDKMCPServer({
name: "weather",
tools: [getWeather],
});
You can group multiple related tools into one server:
const clientDataServer = createSDKMCPServer({
name: "client-data",
tools: [getClientProfile, getEngagementHistory, getDeliverableStatus],
});
Passing the server to the agent
Add the MCP server to your query options:
for await (const message of query(messages(), {
model: "claude-sonnet-4-5",
mcpServers: {
weather: weatherServer,
},
permissionMode: "bypassPermissions",
dangerouslyAllowBypassPermissions: true,
})) {
if (message.type === "assistant") {
for (const block of message.message.content) {
if (block.type === "text") console.log(block.text);
}
}
}
The agent now sees the get_weather tool in its available tool list. When the prompt asks about weather, it will call the tool, pass the coordinates it determines from context, and get back live temperature data.
> The delegation pattern: You only need to write one custom tool yourself. After that, describe the next tool to your coding agent: "I need a tool that fetches the last 5 invoices for a client ID from our billing API." It knows the Zod schema pattern. It knows the handler format. It will write the correct code. Custom tools are one of those areas where AI coding assistance multiplies your output significantly.
Building tools for operator workflows
The weather example is a teaching pattern. Here is how the same structure maps to actual fractional work:
- CRM tool — fetch a client's account status, last touchpoint date, open opportunities
- Reporting tool — pull weekly metrics from an analytics API and return structured data
- Document tool — read from a specific knowledge base or client folder and return relevant excerpts
- Notification tool — post a message to a Slack channel or send an email when a workflow completes
Each of these follows exactly the same four-part structure. Name, description, Zod schema, handler. The handler is whatever API call or data fetch is specific to your stack.
---
Author: FractionalSkill