From 208de2052589902155f3239d7910c148a96fefc2 Mon Sep 17 00:00:00 2001 From: Vadym Samoilenko Date: Fri, 17 Apr 2026 12:49:28 +0100 Subject: [PATCH] vault backup: 2026-04-17 12:49:28 --- 99 Daily/2026-04-17.md | 3 + .../Give Claude custom tools.md | 0 wiki/_master-index.md | 2 +- wiki/agent-sdk/_index.md | 1 + wiki/agent-sdk/custom-tools.md | 170 ++++++++++++++++++ 5 files changed, 175 insertions(+), 1 deletion(-) rename raw/{ => _processed}/Give Claude custom tools.md (100%) create mode 100644 wiki/agent-sdk/custom-tools.md diff --git a/99 Daily/2026-04-17.md b/99 Daily/2026-04-17.md index 743f939..d0d3157 100644 --- a/99 Daily/2026-04-17.md +++ b/99 Daily/2026-04-17.md @@ -155,3 +155,6 @@ tags: [daily] - 12:48 (<1min) | `memory-compiler` - **Asked:** File a new article about structured outputs into the agent-SDK wiki section. - **Done:** Created `structured-outputs.md` with schema guides and updated both index files. +- 12:49 (<1min) | `memory-compiler` + - **Asked:** Compile a new raw article into the wiki knowledge base with proper indexing. + - **Done:** Filed article as `wiki/agent-sdk/custom-tools.md` and updated both topic and master indices. diff --git a/raw/Give Claude custom tools.md b/raw/_processed/Give Claude custom tools.md similarity index 100% rename from raw/Give Claude custom tools.md rename to raw/_processed/Give Claude custom tools.md diff --git a/wiki/_master-index.md b/wiki/_master-index.md index 377547c..872ef9a 100644 --- a/wiki/_master-index.md +++ b/wiki/_master-index.md @@ -30,7 +30,7 @@ This 3-hop pattern works for hundreds of articles without vector search. | [[wiki/web-agency/_index\|web-agency/]] | AI-assisted website building & selling: Claude Code, Nanobanana 2, Kling, LaunchPath MCP | 1 | | [[wiki/dotfiles/_index\|dotfiles/]] | Linux terminal ricing: Kitty, Fish, WezTerm CLI, modern Rust CLI tools, LazyVim, unified themes, Tabby | 9 | -| [[wiki/agent-sdk/_index\|agent-sdk/]] | Claude Agent SDK (formerly Claude Code SDK) — build autonomous AI agents in Python and TypeScript | 9 | +| [[wiki/agent-sdk/_index\|agent-sdk/]] | Claude Agent SDK (formerly Claude Code SDK) — build autonomous AI agents in Python and TypeScript | 10 | | [[wiki/llm-models/_index\|llm-models/]] | OpenAI model catalog — GPT-5.x, o-series reasoning, audio/realtime, embeddings, moderation | 1 | | [[wiki/claude-code/_index\|claude-code/]] | Claude Code product docs — install, capabilities, surfaces, MCP, hooks, scheduling, multi-agent, plugins, skills, error recovery | 7 | diff --git a/wiki/agent-sdk/_index.md b/wiki/agent-sdk/_index.md index f794626..c974ea1 100644 --- a/wiki/agent-sdk/_index.md +++ b/wiki/agent-sdk/_index.md @@ -23,3 +23,4 @@ Build production AI agents using the same tools, agent loop, and context managem | [[wiki/agent-sdk/configure-permissions\|configure-permissions]] | Permission modes, allow/deny rules, evaluation order, bypassPermissions caveats, subagent inheritance | raw/Configure permissions.md | 2026-04-17 | | [[wiki/agent-sdk/mcp-integration\|mcp-integration]] | MCP server setup: transport types (stdio/HTTP/SSE), allowedTools, auth, tool search, error handling | raw/Connect to external tools with MCP.md | 2026-04-17 | | [[wiki/agent-sdk/structured-outputs\|structured-outputs]] | Return validated JSON from agent workflows using JSON Schema, Zod, or Pydantic; error subtypes, tips | raw/Get structured output from agents.md | 2026-04-17 | +| [[wiki/agent-sdk/custom-tools\|custom-tools]] | Define custom tools with @tool/@tool(), in-process MCP server, error handling, images, resources, annotations | raw/Give Claude custom tools.md | 2026-04-17 | diff --git a/wiki/agent-sdk/custom-tools.md b/wiki/agent-sdk/custom-tools.md new file mode 100644 index 0000000..6475ac4 --- /dev/null +++ b/wiki/agent-sdk/custom-tools.md @@ -0,0 +1,170 @@ +--- +title: "Custom Tools in the Agent SDK" +aliases: [custom-tools, sdk-custom-tools, mcp-custom-tools] +tags: [agent-sdk, mcp, tools, python, typescript] +sources: [raw/Give Claude custom tools.md] +created: 2026-04-17 +updated: 2026-04-17 +--- + +# Custom Tools in the Agent SDK + +Extend Claude's capabilities by defining your own async functions — wrapped in an in-process MCP server — that Claude can call during any `query()` session. + +## Tool Anatomy + +Every tool has four required parts: + +| Part | Purpose | +|------|---------| +| **Name** | Unique ID Claude uses to call the tool | +| **Description** | What the tool does — Claude reads this to decide when to call it | +| **Input schema** | Arguments Claude must supply (Zod in TS, dict or JSON Schema in Python) | +| **Handler** | `async` function that runs when Claude calls the tool; returns `{ content, isError? }` | + +The `content` array accepts blocks of type `"text"`, `"image"`, or `"resource"`. + +## Defining a Tool + +**Python** — use the `@tool` decorator: + +```python +from claude_agent_sdk import tool, create_sdk_mcp_server + +@tool( + "get_temperature", + "Get the current temperature at a location", + {"latitude": float, "longitude": float}, +) +async def get_temperature(args): + # ... fetch data ... + return {"content": [{"type": "text", "text": "72°F"}]} + +weather_server = create_sdk_mcp_server( + name="weather", version="1.0.0", tools=[get_temperature] +) +``` + +**TypeScript** — use the `tool()` helper with a Zod schema (args are auto-typed). + +## Registering & Calling Tools + +Pass the server to `query()` via `mcpServers`. The tool's fully-qualified name follows: + +``` +mcp__{server_name}__{tool_name} +``` + +List it in `allowedTools` to skip the permission prompt: + +```python +options = ClaudeAgentOptions( + mcp_servers={"weather": weather_server}, + allowed_tools=["mcp__weather__get_temperature"], +) +async for msg in query(prompt="Temp in SF?", options=options): + ... +``` + +Use wildcard `mcp__weather__*` to approve all tools on a server at once. + +## Optional Parameters + +- **TypeScript:** add `.default()` to a Zod field. +- **Python:** omit the key from the schema dict, mention it in the description, read with `args.get("key", default)`. + +## Tool Annotations + +Pass via `annotations=ToolAnnotations(...)` to give Claude hints about side effects: + +| Field | Default | Effect | +|-------|---------|--------| +| `readOnlyHint` | `false` | Allows parallel batching with other read-only tools | +| `destructiveHint` | `true` | Informational — flags potentially destructive ops | +| `idempotentHint` | `false` | Informational — repeated calls are safe | +| `openWorldHint` | `true` | Informational — tool reaches external systems | + +Annotations are metadata only — they do not enforce behavior. + +## Controlling Tool Access + +Two separate layers govern tool availability: + +| Option | Layer | Effect | +|--------|-------|--------| +| `tools: ["Read", "Grep"]` | Availability | Restricts which built-ins appear in Claude's context | +| `tools: []` | Availability | Removes all built-ins; Claude only uses MCP tools | +| `allowedTools` | Permission | Listed tools run without a prompt | +| `disallowedTools` | Permission | Calls denied, but tool stays visible (wastes turns) | + +Prefer `tools` over `disallowedTools` to restrict built-ins — omitting removes it from context entirely. + +## Error Handling + +| Handler behavior | Agent loop | +|-----------------|-----------| +| Throws uncaught exception | **Stops** — `query()` fails, Claude never sees the error | +| Returns `is_error: True` in result | **Continues** — Claude sees error as data, can retry or explain | + +Always `try/except` (Python) or `try/catch` (TS) inside handlers and return `is_error: True` for recoverable failures. + +## Returning Images & Resources + +**Images** — base64-encode raw bytes inline (no URL field, no `data:image/...` prefix): + +```python +return {"content": [{"type": "image", "data": base64_str, "mimeType": "image/png"}]} +``` + +**Resources** — embed content identified by a URI label: + +```python +return {"content": [{"type": "resource", "resource": { + "uri": "file:///tmp/report.md", + "mimeType": "text/markdown", + "text": "# Report\n..." +}}]} +``` + +The URI is a label for Claude — the SDK does not read from that path. + +## Enum / Complex Schemas (Python) + +The dict schema doesn't support enums. Use full JSON Schema when you need enums, ranges, or nested objects: + +```python +@tool("convert_units", "...", { + "type": "object", + "properties": { + "unit_type": {"type": "string", "enum": ["length", "temperature", "weight"]}, + ... + }, + "required": ["unit_type", ...] +}) +``` + +## Scaling Beyond a Few Tools + +Each tool in the server array consumes context window space every turn. For dozens of tools, use [[wiki/agent-sdk/tool-search|tool search]] to load tools on demand instead of all upfront. + +## Key Takeaways + +- Define tools with `@tool` (Python) / `tool()` (TS) → wrap in `create_sdk_mcp_server` → pass to `query()` via `mcpServers` +- Tool names follow `mcp__{server_name}__{tool_name}`; use wildcard `mcp__server__*` to approve all +- Return `is_error: True` (not throw) to keep the agent loop alive on tool failure +- `readOnlyHint: true` lets Claude batch parallel calls — keep annotations accurate +- Use `tools: []` to remove all built-ins; use `tools: ["Read"]` to whitelist specific built-ins +- Images must be base64 inline; resources carry content in `text` or `blob`, URI is just a label +- For enum/complex input schemas in Python, pass a full JSON Schema dict instead of the shorthand dict + +## Related + +- [[wiki/agent-sdk/mcp-integration|MCP Integration]] — connecting to external MCP servers (filesystem, GitHub, Slack) +- [[wiki/agent-sdk/configure-permissions|Configure Permissions]] — full evaluation order for allowed/disallowed tools +- [[wiki/agent-sdk/python-api-reference|Python API Reference]] — `@tool`, `create_sdk_mcp_server`, `ToolAnnotations` signatures +- [[wiki/agent-sdk/typescript-api-reference|TypeScript API Reference]] — `tool()`, Zod schemas, `ToolAnnotations` +- [[wiki/agent-sdk/structured-outputs|Structured Outputs]] — returning validated JSON from agent workflows + +## Sources + +- `raw/Give Claude custom tools.md` — clipped from https://code.claude.com/docs/en/agent-sdk/custom-tools