Follow Discord
Sweep 22 Oct 2026 · 04:32Z Build v2.1.308 527 read Stable v2.1.308 Latest v2.1.308 Next v2.1.308 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One change · claude-code

Give Claude custom tools changedagent-sdk/custom-tools

Nearest release: v2.1.290, published 2 hours before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.

Upstream edited this page at 5 Oct 2026 20:58 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 5 Oct 2026 21:07 UTC.

Upstream edited
Recorded here
Lines+76added
Lines−12removed
From line 9 where the diff opens
First seen 14 Aug 2026 this site's first read of the page
Recorded edits13to this page, all time

### Make a parameter optional

The whole hunk

from line 9, old and new numbered
/
lines
from line 9
99| What you want to do | Do this |
1010| :- | :- |
1111| Define a tool | Use [`@tool`](/docs/en/agent-sdk/python#tool) (Python) or [`tool()`](/docs/en/agent-sdk/typescript#tool) (TypeScript) with a name, description, schema, and handler. See [Create a custom tool](#create-a-custom-tool). |
12| Make a parameter optional | Declare it optional in the schema and apply the default in the handler. See [Make a parameter optional](#make-a-parameter-optional). |
1213| Register a tool with Claude | Wrap in `create_sdk_mcp_server` / `createSdkMcpServer` and pass to `mcpServers` in `query()`. See [Call a custom tool](#call-a-custom-tool). |
1314| Pre-approve a tool | Add to your allowed tools. See [Configure allowed tools](#configure-allowed-tools). |
1415| Remove a built-in tool from Claude's context | Pass a `tools` array listing only the built-ins you want. See [Configure allowed tools](#configure-allowed-tools). |
from line 25
2425 
2526* **Name:** a unique identifier Claude uses to call the tool.
2627* **Description:** what the tool does. Claude reads this to decide when to call it.
27* **Input schema:** the arguments Claude must provide. In TypeScript this is always a [Zod schema](https://zod.dev/), and the handler's `args` are typed from it automatically. In Python this is a dict mapping names to types, like `{"latitude": float}`, which the SDK converts to JSON Schema for you. The Python decorator also accepts a full [JSON Schema](https://json-schema.org/understanding-json-schema/about) dict directly when you need enums, ranges, optional fields, or nested objects.
28* **Input schema:** the arguments the tool accepts, declared per language:
29 * **TypeScript**: a [Zod schema](https://zod.dev/). The handler's `args` take their types from it. Call `.describe()` on a field to give it a description Claude sees.
30 * **Python**: a dict mapping names to types, like `{"latitude": float}`, which the SDK converts to JSON Schema for you. Wrap a type in `Annotated`, like `{"latitude": Annotated[float, "Latitude coordinate"]}`, to give the field a description Claude sees. The decorator also accepts a full [JSON Schema](https://json-schema.org/understanding-json-schema/about) dict directly when you need enums, ranges, optional fields, or nested objects.
2831* **Handler:** the async function that runs when Claude calls the tool. It receives the validated arguments and must return an object with:
2932 * `content` (required): an array of result blocks, each with a `type` of `"text"`, `"image"`, `"audio"`, `"resource"`, or `"resource_link"`. See [Return images and resources](#return-images-and-resources) for non-text blocks.
3033 * `structuredContent` (optional): a JSON object holding the result as machine-readable data, returned alongside `content`. See [Return structured data](#return-structured-data).
from line 35
3235 
3336After defining a tool, wrap it in a server with [`createSdkMcpServer`](/docs/en/agent-sdk/typescript#createsdkmcpserver) (TypeScript) or [`create_sdk_mcp_server`](/docs/en/agent-sdk/python#create_sdk_mcp_server) (Python). The server runs in-process inside your application, not as a separate process.
3437 
38Python examples on this page that make HTTP requests use [httpx](https://www.python-httpx.org/). Add it with the package manager your project uses:
39 
40<Tabs>
41 <Tab title="Python (uv)">
42 ```bash theme={null}
43 uv add httpx
44 ```
45 </Tab>
46 
47 <Tab title="Python (pip)">
48 ```bash theme={null}
49 pip install httpx
50 ```
51 </Tab>
52</Tabs>
53 
3554### Weather tool example
3655 
37This example defines a `get_temperature` tool and wraps it in an MCP server. It only sets up the tool; to pass it to `query` and run it, see [Call a custom tool](#call-a-custom-tool) below.
56This example defines a `get_temperature` tool and wraps it in an MCP server, without passing the server to `query`. To run the tool, see [Call a custom tool](#call-a-custom-tool) below.
3857 
3958<CodeGroup>
4059 ```python Python theme={null}
41 from typing import Any
60 from typing import Annotated, Any
4261 import httpx
4362 from claude_agent_sdk import tool, create_sdk_mcp_server
4463 
from line 66
4766 @tool(
4867 "get_temperature",
4968 "Get the current temperature at a location",
50 {"latitude": float, "longitude": float},
69 {
70 "latitude": Annotated[float, "Latitude coordinate"],
71 "longitude": Annotated[float, "Longitude coordinate"],
72 },
5173 )
5274 async def get_temperature(args: dict[str, Any]) -> dict[str, Any]:
5375 async with httpx.AsyncClient() as client:
from line 140
118140 
119141See the [`tool()`](/docs/en/agent-sdk/typescript#tool) TypeScript reference or the [`@tool`](/docs/en/agent-sdk/python#tool) Python reference for full parameter details, including JSON Schema input formats and return value structure.
120142 
121<Tip>
122 To make a parameter optional: in TypeScript, add `.optional()` to the Zod field and apply the default in the handler. In Python, the dict schema treats every key as required, so leave the parameter out of the schema, mention it in the description string, and read it with `args.get()` in the handler. The [`get_precipitation_chance` tool below](#add-more-tools) shows both patterns.
123</Tip>
143### Make a parameter optional
124144 
145To make a parameter optional, declare it optional in the schema and apply the default in the handler:
146 
147* **TypeScript**: add `.optional()` to the Zod field.
148* **Python**: the dict schema requires every key. Use the JSON Schema form, leave the parameter out of `required`, and read it with `args.get()`. For a typed schema with optional keys, see [TypedDict class](/docs/en/agent-sdk/python#input-schema-options).
149 
150The [`get_precipitation_chance` tool below](#add-more-tools) shows both patterns.
151 
125152### Call a custom tool
126153 
127154Pass the MCP server you created to `query` via the `mcpServers` option. The key in `mcpServers` becomes the `{server_name}` segment in each tool's fully qualified name: `mcp__{server_name}__{tool_name}`. List that name in `allowedTools` so the tool runs without a permission prompt.
from line 197
170197 ```
171198</CodeGroup>
172199 
173Combine this snippet with the tool and server definitions from the [weather tool example](#weather-tool-example) in one file, then run it with `python weather.py` for Python or `npx tsx weather.ts` for TypeScript. Claude calls `get_temperature` and the script prints a one-line answer with the current temperature in San Francisco.
200Combine this snippet with the tool and server definitions from the [weather tool example](#weather-tool-example) in one file, `weather.py` or `weather.ts`, then run it from your terminal:
174201 
202<Tabs>
203 <Tab title="TypeScript">
204 ```bash theme={null}
205 npx tsx weather.ts
206 ```
207 </Tab>
208 
209 <Tab title="Python (uv)">
210 ```bash theme={null}
211 uv run weather.py
212 ```
213 </Tab>
214 
215 <Tab title="Python (pip)">
216 Activate the virtual environment where you installed the SDK, then run:
217 
218 ```bash theme={null}
219 python weather.py
220 ```
221 </Tab>
222</Tabs>
223 
224Claude calls `get_temperature` and the script prints a one-line answer with the current temperature in San Francisco.
225 
175226### Add more tools
176227 
177228A server holds as many tools as you list in its `tools` array. With more than one tool on a server, you can list each one in `allowedTools` individually or use the wildcard `mcp__weather__*` to cover every tool the server exposes.
from line 234
183234 # Define a second tool for the same server
184235 @tool(
185236 "get_precipitation_chance",
186 "Get the hourly precipitation probability for a location. "
187 "Optionally pass 'hours' (1-24) to control how many hours to return.",
188 {"latitude": float, "longitude": float},
237 "Get the hourly precipitation probability for a location",
238 {
239 "type": "object",
240 "properties": {
241 "latitude": {"type": "number"},
242 "longitude": {"type": "number"},
243 "hours": {
244 "type": "integer",
245 "minimum": 1,
246 "maximum": 24,
247 "description": "How many hours of forecast to return",
248 },
249 },
250 # 'hours' is left out of required, so Claude can omit it
251 "required": ["latitude", "longitude"],
252 },
189253 )
190254 async def get_precipitation_chance(args: dict[str, Any]) -> dict[str, Any]:
191 # 'hours' isn't in the schema - read it with .get() to make it optional
255 # 'hours' isn't in required - read it with .get() to fall back to a default
192256 hours = args.get("hours", 12)
193257 async with httpx.AsyncClient() as client:
194258 response = await client.get(
Feedback