Give Claude custom tools
기준일: 2026-07-26
공식 기준: Give Claude custom tools
Give Claude custom tools 문서는 Claude Code 공식 문서(agent-sdk/custom-tools)를 한국어로 정리한 가이드입니다. Define custom tools with the Claude Agent SDK's in-process MCP server so Claude can call your functions, hit your APIs, and perform domain-specific operations. 명령·설정 키·코드 예시는 공식 문서를 그대로 보존하며, 해석과 절차 안내는 한국어로 제공합니다. 최종 동작은 설치 버전과 공식 원문을 확인하세요.
핵심 요약
Define custom tools with the Claude Agent SDK's in-process MCP server so Claude can call your functions, hit your APIs, and perform domain-specific operations.
한국어 가이드 범위: agent-sdk/custom-tools 경로의 설정·명령·제약·예시를 학습용으로 재구성합니다.
문서 구성
공식 문서의 주요 섹션은 다음과 같습니다.
- Give Claude custom tools
- Quick reference
- Create a custom tool
- Weather tool example
- Call a custom tool
- Add more tools
- Add tool annotations
- Control tool access
- Tool name format
- Configure allowed tools
- Handle errors
- Return images and resources
- Images
- Resources
- Return structured data
- Example: unit converter
- 다음 단계
- Related documentation
상세 내용
Give Claude custom tools
Define custom tools with the Claude Agent SDK's in-process MCP server so Claude can call your functions, hit your APIs, and perform domain-specific operations.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
Quick reference
| If you want to... | Do this |
|---|---|
| Define a tool | Use @tool (Python) or tool() (TypeScript) with a name, description, schema, and handler. See Create a custom tool. |
| Register a tool with Claude | Wrap in create_sdk_mcp_server / createSdkMcpServer and pass to mcpServers in query(). See Call a custom tool. |
| Pre-approve a tool | Add to your allowed tools. See Configure allowed tools. |
| Remove a built-in tool from Claude's context | Pass a tools array listing only the built-ins you want. See Configure allowed tools. |
| Let Claude call tools in parallel | Set readOnlyHint: true on tools with no side effects. See Add tool annotations. |
| Control the error message Claude reads | Return isError: true to compose the message instead of surfacing the raw exception. See Handle errors. |
| Return images or files | Use image or resource blocks in the content array. See Return images and resources. |
| Return a machine-readable JSON result | Set structuredContent on the result. See Return structured data. |
| Scale to many tools | Use tool search to load tools on demand. |
Create a custom tool
A tool is defined by four parts, passed as arguments to the tool() helper in TypeScript or the @tool decorator in Python:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
주요 항목:
- Name: a unique identifier Claude uses to call the tool.
- Description: what the tool does. Claude reads this to decide when to call it.
- Input schema: the arguments Claude must provide. In TypeScript this is always a Zod schema, and the handler's
argsare 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 dict directly when you need enums, ranges, optional fields, or nested objects. - Handler: the async function that runs when Claude calls the tool. It receives the validated arguments and must return an object with:
content(required): an array of result blocks, each with atypeof"text","image","audio","resource", or"resource_link". See Return images and resources for non-text blocks.structuredContent(optional): a JSON object holding the result as machine-readable data, returned alongsidecontent. See Return structured data.isError(optional): set totrueto signal a tool failure so Claude can react to it. See Handle errors.
Weather tool example
This 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 below.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
Call a custom tool
Pass 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.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
Add more tools
A 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.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
Add tool annotations
Tool annotations are optional metadata describing how a tool behaves. Pass them as the fifth argument to tool() helper in TypeScript or via the annotations keyword argument for the @tool decorator in Python. All hint fields are Booleans.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
| Field | Default | Meaning |
|---|---|---|
readOnlyHint |
false |
Tool does not modify its environment. Controls whether the tool can be called in parallel with other read-only tools. |
destructiveHint |
true |
Tool may perform destructive updates. Informational only. |
idempotentHint |
false |
Repeated calls with the same arguments have no additional effect. Informational only. |
openWorldHint |
true |
Tool reaches systems outside your process. Informational only. |
Control tool access
The weather tool example registered a server and listed tools in allowedTools. This section covers how tool names are constructed and how to scope access when you have multiple tools or want to restrict built-ins.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
Tool name format
When MCP tools are exposed to Claude, their names follow a specific format:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
주요 항목:
- Pattern:
mcp__{server_name}__{tool_name} - Example: A tool named
get_temperaturein serverweatherbecomesmcp__weather__get_temperature
Configure allowed tools
The tools option and the allowed/disallowed lists affect two layers: availability, which controls whether a tool appears in Claude's context, and permission, which controls whether a call is approved once Claude attempts it. tools and bare-name disallowedTools entries change availability. allowedTools and scoped disallowedTools rules change permission only.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
| Option | Layer | Effect |
|---|---|---|
tools: ["Read", "Grep"] |
Availability | Only the listed built-ins are in Claude's context. Unlisted built-ins are removed. MCP tools are unaffected. |
tools: [] |
Availability | All built-ins are removed. Claude can only use your MCP tools. |
| allowed tools | Permission | Listed tools run without a permission prompt. Unlisted tools remain available; calls go through the permission flow. |
| disallowed tools | Both | A bare tool name such as "Bash" removes the tool from Claude's context, the same as omitting it from tools. A scoped rule such as "Bash(rm *)" leaves the tool in context and denies only matching calls. |
Handle errors
A handler error doesn't stop the agent loop. The SDK's in-process MCP server catches uncaught exceptions and returns them as error results, so how you report an error determines what Claude reads, not whether the query fails:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
| What happens | Result |
|---|---|
| Handler throws an uncaught exception | The MCP server converts it to an error result carrying the raw exception message. Claude sees that message, and the agent loop continues. |
Handler catches the error and returns isError: true (TS) / "is_error": True (Python) |
Claude sees the message you compose. You can add context the raw exception lacks, such as which request failed or what to try instead. |
Return images and resources
The content array in a tool result accepts text, image, audio, resource, and resource_link blocks. You can mix them in the same response. In TypeScript, audio blocks are saved to disk and Claude receives a text block with the saved file path; in Python, the SDK drops audio blocks from the tool result and logs a warning. Resource link blocks are converted to a text block containing the link's name, URI, and description.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
Images
An image block carries the image bytes inline, encoded as base64. There is no URL field. To return an image that lives at a URL, fetch it in the handler, read the response bytes, and base64-encode them before returning. The result is processed as visual input.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
| Field | Type | Notes |
|---|---|---|
type |
"image" |
|
data |
string |
Base64-encoded bytes. Raw base64 only, no data:image/...;base64, prefix |
mimeType |
string |
Required. For example image/png, image/jpeg, image/webp, image/gif |
Resources
A resource block embeds a piece of content identified by a URI. The URI is a label for Claude to reference; the actual content rides in the block's text or blob field. Use this when your tool produces something that makes sense to address by name later, such as a generated file or a record from an external system.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
| Field | Type | Notes |
|---|---|---|
type |
"resource" |
|
resource.uri |
string |
Identifier for the content. Any URI scheme |
resource.text |
string |
The content, if it's text. Provide this or blob, not both |
resource.blob |
string |
The content base64-encoded, if it's binary. TypeScript only: the Python SDK drops binary resources from the tool result and logs a warning |
resource.mimeType |
string |
Optional |
Return structured data
structuredContent is an optional JSON object on the result, separate from the content array. Use it to return raw values that Claude can read as exact fields instead of parsing them out of a text string or image.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
Example: unit converter
This tool converts values between units of length, temperature, and weight. A user can ask "convert 100 kilometers to miles" or "what is 72°F in Celsius," and Claude picks the right unit type and units from the request.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
주요 항목:
- Enum schemas:
unit_typeis constrained to a fixed set of values. In TypeScript, usez.enum(). In Python, the dict schema doesn't support enums, so the full JSON Schema dict is required. - Unsupported input handling: when a conversion pair isn't found, the handler returns
isError: trueso Claude can tell the user what went wrong rather than treating a failure as a normal result.
Once the server is defined, pass it to `query` the same way as the weather example. This example sends three different prompts in a loop to show the same tool handling different unit types. For each response, it inspects `AssistantMessage` objects (which contain the tool calls Claude made during that turn) and prints each `ToolUseBlock` before printing the final `ResultMessage` text. This lets you see when Claude is using the tool versus answering from its own knowledge.
Because [tool search](/docs/en/agent-sdk/tool-search) is on by default, the output may also include a `ToolSearch` call as Claude loads the deferred tool schema.
다음 단계
Custom tools wrap async functions in a standard interface. You can mix the patterns on this page in the same server: a single server can hold a database tool, an API gateway tool, and an image renderer alongside each other.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문을 확인하세요.
주요 항목:
- If your server grows to dozens of tools, see tool search to defer loading them until Claude needs them.
- To connect to external MCP servers (filesystem, GitHub, Slack) instead of building your own, see Connect MCP servers.
- To control which tools run automatically versus requiring approval, see Configure permissions.
Related documentation
주요 항목:
- TypeScript SDK Reference
- Python SDK Reference
- MCP Documentation
- SDK Overview
실습 체크리스트
- 공식 문서와 로컬/SDK 버전을 대조합니다.
- 관련 CLI·SDK 옵션은 공식 페이지와
--help로 교차 확인합니다. - Agent SDK 예시는 TypeScript/Python 패키지 최신 API를 우선합니다.
- 권한·호스팅·보안 설정 변경 후 통합 테스트를 실행합니다.
자주 쓰는 명령·설정 예시
See 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.
To make a parameter optional: in TypeScript, add `.default()` to the Zod field. 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.
### Call a custom tool
Pass 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.
These snippets reuse the `weatherServer` from the [example above](#weather-tool-example) to ask Claude what the weather is in a specific location.
Combine 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.
### Add more tools
A 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.
The example below defines a second tool, `get_precipitation_chance`, and replaces the `weatherServer` definition from the [weather tool example](#weather-tool-example) with one that lists both tools in the array.
[Tool search](/docs/en/agent-sdk/tool-search) is on by default and defers SDK MCP tools: Claude sees each tool's name in a compact list and loads its full schema on demand. With tool search disabled, every tool in this array consumes context window space on every turn. In TypeScript, pass `alwaysLoad: true` in the `extras` argument of [`tool()`](/docs/en/agent-sdk/typescript#tool) or in the options of [`createSdkMcpServer()`](/docs/en/agent-sdk/typescript#createsdkmcpserver) to keep a tool's full schema in the initial prompt.
### Add tool annotations
[Tool annotations](https://modelcontextprotocol.io/docs/concepts/tools#tool-annotations) are optional metadata describing how a tool behaves. Pass them as the fifth argument to `tool()` helper in TypeScript or via the `annotations` keyword argument for the `@tool` decorator in Python. All hint fields are Booleans.
| Field | Default | Meaning |
| :---------------- | :------ | :-------------------------------------------------------------------------------------------------------------------- |
| `readOnlyHint` | `false` | Tool does not modify its environment. Controls whether the tool can be called in parallel with other read-only tools. |
| `destructiveHint` | `true` | Tool may perform destructive updates. Informational only. |
| `idempotentHint` | `false` | Repeated calls with the same arguments have no additional effect. Informational only. |
| `openWorldHint` | `true` | Tool reaches systems outside your process. Informational only. |
Annotations are metadata, not enforcement. A tool marked `readOnlyHint: true` can still write to disk if that's what the handler does. Keep the annotation accurate to the handler.
This example adds `readOnlyHint` to the `get_temperature` tool from the [weather tool example](#weather-tool-example).
See `ToolAnnotations` in the [TypeScript](/docs/en/agent-sdk/typescript#toolannotations) or [Python](/docs/en/agent-sdk/python#toolannotations) reference.
## Control tool access
The [weather tool example](#weather-tool-example) registered a server and listed tools in `allowedTools`. This section covers how tool names are constructed and how to scope access when you have multiple tools or want to restrict built-ins.
### Tool name format
When MCP tools are exposed to Claude, their names follow a specific format:
* Pattern: `mcp__{server_name}__{tool_name}`
* Example: A tool named `get_temperature` in server `weather` becomes `mcp__weather__get_temperature`
### Configure allowed tools
The `tools` option and the allowed/disallowed lists affect two layers: availability, which controls whether a tool appears in Claude's context, and permission, which controls whether a call is approved once Claude attempts it. `tools` and bare-name `disallowedTools` entries change availability. `allowedTools` and scoped `disallowedTools` rules change permission only.
| Option | Layer | Effect |
| :------------------------ | :----------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tools: ["Read", "Grep"]` | Availability | Only the listed built-ins are in Claude's context. Unlisted built-ins are removed. MCP tools are unaffected. |
| `tools: []` | Availability | All built-ins are removed. Claude can only use your MCP tools. |
| allowed tools | Permission | Listed tools run without a permission prompt. Unlisted tools remain available; calls go through the [permission flow](/docs/en/agent-sdk/permissions). |
| disallowed tools | Both | A bare tool name such as `"Bash"` removes the tool from Claude's context, the same as omitting it from `tools`. A scoped rule such as `"Bash(rm *)"` leaves the tool in context and denies only matching calls. |
To remove a built-in entirely, omit it from `tools` or list its bare name in `disallowedTools` (Python: `disallowed_tools`); both keep the tool out of context so Claude never attempts it. A scoped `disallowedTools` rule blocks matching calls but leaves the tool visible, so Claude may waste a turn trying it. See [Configure permissions](/docs/en/agent-sdk/permissions) for the full evaluation order.
## Handle errors
A handler error doesn't stop the agent loop. The SDK's in-process MCP server catches uncaught exceptions and returns them as error results, so how you report an error determines what Claude reads, not whether the query fails:
| What happens | Result |
| :--------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------- |
| Handler throws an uncaught exception | The MCP server converts it to an error result carrying the raw exception message. Claude sees that message, and the agent loop continues. |
| Handler catches the error and returns `isError: true` (TS) / `"is_error": True` (Python) | Claude sees the message you compose. You can add context the raw exception lacks, such as which request failed or what to try instead. |
In both cases Claude can retry, try a different tool, or explain the failure. Catch errors yourself when the raw exception message isn't enough for Claude to act on.
The example below catches two kinds of failures inside the handler and composes the error message Claude reads. A non-200 HTTP status is caught from the response and returned as an error result. A network error or invalid JSON is caught by the surrounding `try/except` (Python) or `try/catch` (TypeScript) and also returned as an error result. In both cases Claude receives a message that describes the failure instead of a bare exception string.
관련 링크
- 공식 원문: agent-sdk/custom-tools
- 문서 홈
이 가이드는 공식 문서를 한국어 학습용으로 재구성한 것입니다. 옵션 기본값·API 이름은 설치 버전에 따라 달라질 수 있습니다.