claude-agent-sdk:custom tools

2 阅读11分钟

Give Claude custom tools 为 Claude 提供自定义工具

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.
通过 Claude Agent SDK 的进程内 (in-process) MCP 服务器定义自定义工具,让 Claude 能够调用您的函数、访问您的 API 并执行特定领域的业务操作。

Custom tools extend the Agent SDK by letting you define your own functions that Claude can call during a conversation. Using the SDK's in-process MCP server, you can give Claude access to databases, external APIs, domain-specific logic, or any other capability your application needs.
自定义工具通过允许您定义 Claude 可以在对话期间调用的函数,扩展了 Agent SDK 的功能。利用 SDK 的进程内 MCP 服务器,您可以赋予 Claude 访问数据库、外部 API、特定领域逻辑或您的应用程序所需的任何其他能力。

This guide covers how to define tools with input schemas and handlers, bundle them into an MCP server, pass them to query, and control which tools Claude can access. It also covers error handling, tool annotations, and returning non-text content like images.
本指南涵盖了如何使用输入模式 (input schemas) 和处理程序 (handlers) 定义工具、如何将它们打包进 MCP 服务器、如何将它们传递给 query 函数,以及如何控制 Claude 可以访问哪些工具。此外,本指南还介绍了错误处理、工具注解以及返回图像等非文本内容的方法。

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.
使用 @tool (Python) 或 tool() (TypeScript),并包含名称、描述、模式 (schema) 和处理程序。参见 创建自定义工具
Register a tool with Claude
向 Claude 注册工具
Wrap in create_sdk_mcp_server / createSdkMcpServer and pass to mcpServers in query(). See Call a custom tool.
将其包装在 create_sdk_mcp_server / createSdkMcpServer 中,并传递给 query() 中的 mcpServers。参见 调用自定义工具
Pre-approve a tool
预批准工具
Add to your allowed tools. See Configure allowed tools.
将其添加到您的允许工具列表中。参见 配置允许的工具
Remove a built-in tool from Claude's context
从 Claude 上下文中移除内置工具
Pass a tools array listing only the built-ins you want. See Configure allowed tools.
传递一个仅包含您所需内置工具的 tools 数组。参见 配置允许的工具
Let Claude call tools in parallel
让 Claude 并行调用工具
Set readOnlyHint: true on tools with no side effects. See Add tool annotations.
为没有副作用的工具设置 readOnlyHint: true。参见 添加工具注解
Handle errors without stopping the loop
在不停止循环的情况下处理错误
Return isError: true instead of throwing. See Handle errors.
返回 isError: true 而不是抛出异常。参见 处理错误
Return images or files
返回图像或文件
Use image or resource blocks in the content array. See Return images and resources.
在内容数组中使用 imageresource 块。参见 返回图像和资源
Scale to many tools
扩展至大量工具
Use tool search to load tools on demand.
使用 工具搜索 (tool search) 按需加载工具。

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:

定义一个工具包含四个部分,在 TypeScript 中作为参数传递给 tool() 辅助函数,或在 Python 中传递给 @tool 装饰器:

  • Name: a unique identifier Claude uses to call the tool.
  • 名称 (Name): 一个 Claude 用于调用该工具的唯一标识符。
  • Description: what the tool does. Claude reads this to decide when to call it.
  • 描述 (Description): 工具的功能。Claude 通过阅读描述来决定何时调用它。
  • Input schema: the arguments Claude must provide. In TypeScript this is always a Zod schema, 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 dict directly when you need enums, ranges, optional fields, or nested objects.
  • 输入模式 (Input schema): Claude 必须提供的参数。在 TypeScript 中,这始终是一个 Zod 模式 (Zod schema),处理程序的 args 参数会自动根据其生成类型。在 Python 中,这是一个将名称映射到类型的字典(例如 {"latitude": float}),SDK 会自动为您将其转换为 JSON Schema。当您需要枚举、范围、可选字段或嵌套对象时,Python 装饰器也直接接受完整的 JSON Schema 字典。
  • Handler: the async function that runs when Claude calls the tool. It receives the validated arguments and must return an object with:
  • 处理程序 (Handler): Claude 调用工具时运行的异步函数。它接收经过验证的参数,并且必须返回一个包含以下内容的对象:
    • content (required): an array of result blocks, each with a type of "text", "image", or "resource". See Return images and resources for non-text blocks.
    • content(必需):结果块数组,每个块的 type"text""image""resource"。非文本块请参见 返回图像和资源
    • isError (optional): set to true to signal a tool failure so Claude can react to it. See Handle errors.
    • isError(可选):设置为 true` 以发出工具调用失败的信号,以便 Claude 做出相应反应。参见 处理错误

After defining a tool, wrap it in a server with createSdkMcpServer (TypeScript) or create_sdk_mcp_server (Python). The server runs in-process inside your application, not as a separate process.
定义工具后,使用 createSdkMcpServer (TypeScript) 或 create_sdk_mcp_server (Python) 将其封装在服务器中。该服务器在您的应用程序内部进程内 (in-process) 运行,而不是作为一个独立的进程运行。

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.
本示例定义了一个 get_temperature 工具并将其封装在 MCP 服务器中。这里仅展示工具的设置步骤;若要将其传递给 query 并运行,请参阅下文的 调用自定义工具

import { tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";

// Define a tool: name, description, input schema, handler
const getTemperature = tool(
  "get_temperature",
  "Get the current temperature at a location",
  {
    latitude: z.number().describe("Latitude coordinate"), // .describe() adds a field description Claude sees
    longitude: z.number().describe("Longitude coordinate")
  },
  async (args) => {
    // args is typed from the schema: { latitude: number; longitude: number }
    const response = await fetch(
      `https://api.open-meteo.com/v1/forecast?latitude=${args.latitude}&longitude=${args.longitude}&current=temperature_2m&temperature_unit=fahrenheit`
    );
    const data: any = await response.json();

    // Return a content array - Claude sees this as the tool result
    return {
      content: [{ type: "text", text: `Temperature: ${data.current.temperature_2m}°F` }]
    };
  }
);

// Wrap the tool in an in-process MCP server
const weatherServer = createSdkMcpServer({
  name: "weather",
  version: "1.0.0",
  tools: [getTemperature]
});

See the tool() TypeScript reference or the @tool Python reference for full parameter details, including JSON Schema input formats and return value structure.
有关参数的完整详细信息(包括 JSON Schema 输入格式和返回值结构),请参阅 tool() TypeScript 参考或 @tool Python 参考。

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 shows both patterns.
如何使参数可选: 在 TypeScript 中,在 Zod 字段中添加 .default()。在 Python 中,字典模式会将每个键都视为必填项,因此请在模式 (schema) 中省略该参数,但在描述字符串中提及它,并在处理程序中使用 args.get() 读取。下文的 get_precipitation_chance 工具展示了这两种模式。

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.
通过 mcpServers 选项将您创建的 MCP 服务器传递给 query 函数。mcpServers 中的键(key)将成为每个工具限定全名 (fully qualified name) 中的 {server_name} 部分:mcp__{server_name}__{tool_name}。在 allowedTools 中列出该名称,即可让工具在运行时无需权限提示。

These snippets reuse the weatherServer from the example above to ask Claude what the weather is in a specific location.
以下代码片段复用了上述示例中的 weatherServer,来向 Claude 询问特定地点的天气。

import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "What's the temperature in San Francisco?",
  options: {
    mcpServers: { weather: weatherServer },
    allowedTools: ["mcp__weather__get_temperature"]
  }
})) {
  // "result" is the final message after all tool calls complete
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}

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.
一个服务器可以包含您在其 tools 数组中列出的任意数量的工具。当服务器包含多个工具时,您可以分别在 allowedTools 中列出每一个,也可以使用通配符 mcp__weather__* 来涵盖该服务器公开的所有工具。

The example below adds a second tool, get_precipitation_chance, to the weatherServer from the weather tool example and rebuilds it with both tools in the array.
下面的示例为天气工具示例中的 weatherServer 添加了第二个工具 get_precipitation_chance,并将其重新构建为包含这两个工具的数组。

// Define a second tool for the same server
const getPrecipitationChance = tool(
  "get_precipitation_chance",
  "Get the hourly precipitation probability for a location",
  {
    latitude: z.number(),
    longitude: z.number(),
    hours: z
      .number()
      .int()
      .min(1)
      .max(24)
      .default(12) // .default() makes the parameter optional
      .describe("How many hours of forecast to return")
  },
  async (args) => {
    const response = await fetch(
      `https://api.open-meteo.com/v1/forecast?latitude=${args.latitude}&longitude=${args.longitude}&hourly=precipitation_probability&forecast_days=1`
    );
    const data: any = await response.json();
    const chances = data.hourly.precipitation_probability.slice(0, args.hours);

    return {
      content: [{ type: "text", text: `Next ${args.hours} hours: ${chances.join("%, ")}%` }]
    };
  }
);

// Rebuild the server with both tools in the array
const weatherServer = createSdkMcpServer({
  name: "weather",
  version: "1.0.0",
  tools: [getTemperature, getPrecipitationChance]
});

Every tool in this array consumes context window space on every turn. If you're defining dozens of tools, see tool search to load them on demand instead.

此数组中的每个工具在每一轮对话中都会占用上下文窗口空间。如果您定义了数十个工具,请参阅工具搜索 (tool search) 以按需加载它们。

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.

工具注解 (Tool annotations) 是描述工具行为的可选元数据。在 TypeScript 中,将它们作为 tool() 辅助函数的第五个参数传递;在 Python 中,通过 @tool 装饰器的 annotations 关键字参数传递。所有提示 (hint) 字段均为布尔值。

FieldDefaultMeaning(含义)
readOnlyHintfalseTool does not modify its environment. Controls whether the tool can be called in parallel with other read-only tools.
工具不会修改其环境。控制该工具是否可以与其他只读工具并行调用。
destructiveHinttrueTool may perform destructive updates. Informational only.
工具可能会执行破坏性更新。仅供参考。
idempotentHintfalseRepeated calls with the same arguments have no additional effect. Informational only.
使用相同参数重复调用不会产生额外影响。仅供参考。
openWorldHinttrueTool 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.

注解是元数据,而非强制约束。即使一个标记为 readOnlyHint: true 的工具,如果其处理程序的逻辑是写入磁盘,它仍然会执行写入操作。请确保注解与处理程序的实际行为保持一致。

This example adds readOnlyHint to the get_temperature tool from the weather tool example.
此示例为天气工具示例中的 get_temperature 工具添加了 readOnlyHint

tool(
  "get_temperature",
  "Get the current temperature at a location",
  { latitude: z.number(), longitude: z.number() },
  async (args) => ({ content: [{ type: "text", text: `...` }] }),
  { annotations: { readOnlyHint: true } } // Lets Claude batch this with other read-only calls
);

See ToolAnnotations in the TypeScript or Python reference.
参见 TypeScriptPython 参考文档中的 ToolAnnotations

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.
天气工具示例注册了一个服务器并在 allowedTools 中列出了工具。本节介绍工具名称是如何构建的,以及当您拥有多个工具或想要限制内置工具时,如何划定访问范围。

Tool name format 工具名称格式

When MCP tools are exposed to Claude, their names follow a specific format:
当 MCP 工具暴露给 Claude 时,它们的名称遵循特定格式:

  • Pattern: mcp__{server_name}__{tool_name}
  • Example: A tool named get_temperature in server weather becomes mcp__weather__get_temperature
  • 示例: weather 服务器中名为 get_temperature 的工具将变为 mcp__weather__get_temperature

Configure allowed tools 配置允许的工具

The tools option and the allowed/disallowed lists operate on separate layers. tools controls which built-in tools appear in Claude's context. Allowed and disallowed tool lists control whether calls are approved or denied once Claude attempts them.

tools 选项与允许/禁止列表运行在不同的层级。tools 控制哪些内置工具出现在 Claude 的上下文中。而允许和禁止工具列表则控制在 Claude 尝试调用工具时,该调用是被批准还是被拒绝。

OptionLayer(层级)Effect 效果
tools: ["Read", "Grep"]Availability 可用性Only the listed built-ins are in Claude's context. Unlisted built-ins are removed. MCP tools are unaffected.
只有列出的内置工具会出现在 Claude 的上下文中。未列出的内置工具将被移除。MCP 工具不受影响。
tools: []Availability 可用性All built-ins are removed. Claude can only use your MCP tools.
移除所有内置工具。Claude 只能使用您的 MCP 工具。
allowed toolsPermission 权限Listed tools run without a permission prompt. Unlisted tools remain available; calls go through the permission flow.
所列工具在运行时无需权限提示。未列出的工具仍然可用,但其调用需经过 权限流程
disallowed toolsPermission 权限Every call to a listed tool is denied. The tool stays in Claude's context, so Claude may still attempt it before the call is rejected.
对所列工具的每一次调用都会被拒绝。该工具仍留在 Claude 的上下文中,因此 Claude 可能仍会尝试调用它,直到调用被拒绝。

To limit which built-ins Claude can use, prefer tools over disallowed tools. Omitting a tool from tools removes it from context so Claude never attempts it; listing it in disallowedTools (Python: disallowed_tools) blocks the call but leaves the tool visible, so Claude may waste a turn trying it. See Configure permissions for the full evaluation order.
若要限制 Claude 可以使用的内置工具,请优先使用 tools 选项而非禁止工具列表。在 tools 中省略某个工具会将其从上下文中移除,从而使 Claude 根本不会尝试调用它;而在 disallowedTools(Python 中为 disallowed_tools)中列出工具虽然会阻止调用,但该工具依然可见,Claude 可能会因为尝试调用它而浪费一轮对话。参见 配置权限 以了解完整的评估顺序。

Handle errors 处理错误

How your handler reports errors determines whether the agent loop continues or stops:
处理程序报告错误的方式决定了 Agent 循环(Agent loop)是继续还是停止:

What happensResult
Handler throws an uncaught exception
处理程序抛出未捕获的异常
Agent loop stops. Claude never sees the error, and the query call fails.
Agent 循环停止。Claude 看不到错误,且 query 调用失败。
Handler catches the error and returns isError: true (TS) / "is_error": True (Python)
处理程序捕获错误并返回
Agent loop continues. Claude sees the error as data and can retry, try a different tool, or explain the failure.
Agent 循环继续。Claude 将错误视为数据,并可以尝试重试、使用其他工具或解释失败原因。

The example below catches two kinds of failures inside the handler instead of letting them throw. 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 the handler returns normally and the agent loop continues.

下面的示例在处理程序内部捕获了两种失败情况,而不是让它们抛出异常。非 200 的 HTTP 状态码从响应中被捕获并作为错误结果返回。网络错误或无效的 JSON 则被外层的 try/except (Python) 或 try/catch (TypeScript) 捕获,同样作为错误结果返回。在这两种情况下,处理程序都会正常返回,Agent 循环也会继续运行。

tool(
  "fetch_data",
  "Fetch data from an API",
  {
    endpoint: z.string().url().describe("API endpoint URL")
  },
  async (args) => {
    try {
      const response = await fetch(args.endpoint);

      if (!response.ok) {
        // Return the failure as a tool result so Claude can react to it.
        // isError marks this as a failed call rather than odd-looking data.
        return {
          content: [
            {
              type: "text",
              text: `API error: ${response.status} ${response.statusText}`
            }
          ],
          isError: true
        };
      }

      const data = await response.json();
      return {
        content: [
          {
            type: "text",
            text: JSON.stringify(data, null, 2)
          }
        ]
      };
    } catch (error) {
      // Catching here keeps the agent loop alive. An uncaught throw
      // would end the whole query() call.
      return {
        content: [
          {
            type: "text",
            text: `Failed to fetch data: ${error instanceof Error ? error.message : String(error)}`
          }
        ],
        isError: true
      };
    }
  }
);

Return images and resources 返回图像和资源

The content array in a tool result accepts text, image, and resource blocks. You can mix them in the same response.

工具结果中的 content 数组接受 text(文本)、image(图像)和 resource(资源)块。您可以在同一个响应中混合使用它们。

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.
图像块以内联方式携带图像字节,并使用 base64 编码。这里没有 URL 字段。 若要返回位于某个 URL 的图像,请在处理程序中获取该图像,读取响应字节,并在返回前对其进行 base64 编码。结果将作为视觉输入被处理。

FieldTypeNotes
type"image"
datastringBase64-encoded bytes. Raw base64 only, no data:image/...;base64, prefix
Base64 编码的字节。仅包含原始 base64,不含 data:image/...;base64, 前缀。
mimeTypestringRequired. For example image/png, image/jpeg, image/webp, image/gif
必需。 例如 image/png, image/jpeg, image/webp, image/gif
tool(
  "fetch_image",
  "Fetch an image from a URL and return it to Claude",
  {
    url: z.string().url()
  },
  async (args) => {
    const response = await fetch(args.url); // Fetch the image bytes
    const buffer = Buffer.from(await response.arrayBuffer()); // Read into a Buffer for base64 encoding
    const mimeType = response.headers.get("content-type") ?? "image/png";

    return {
      content: [
        {
          type: "image",
          data: buffer.toString("base64"), // Base64-encode the raw bytes
          mimeType
        }
      ]
    };
  }
);

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.
资源块嵌入了一段由 URI 标识的内容。该 URI 是供 Claude 引用的标签;实际内容则承载在块的 textblob 字段中。当您的工具生成了一些适合稍后按名称引用的内容(例如生成的文件或来自外部系统的记录)时,请使用此方式。

FieldTypeNotes
type"resource"
resource.uristringIdentifier for the content. Any URI scheme
内容标识符。支持任何 URI 方案。
resource.textstringThe content, if it's text. Provide this or blob, not both
如果是文本内容,请使用此字段。提供此项或 blob,不可同时提供。
resource.blobstringThe content base64-encoded, if it's binary
如果是二进制内容,请使用此字段(Base64 编码)。
resource.mimeTypestringOptional

This example shows a resource block returned from inside a tool handler. The URI file:///tmp/report.md is a label that Claude can reference later; the SDK does not read from that path.
此示例展示了从工具处理程序内部返回的资源块。URI file:///tmp/report.md 只是一个供 Claude 稍后引用的标签;SDK 实际上并不会从该磁盘路径读取文件。

return {
  content: [
    {
      type: "resource",
      resource: {
        uri: "file:///tmp/report.md", // Label for Claude to reference, not a path the SDK reads
        mimeType: "text/markdown",
        text: "# Report\n..." // The actual content, inline
      }
    }
  ]
};

These block shapes come from the MCP CallToolResult type. See the MCP specification for the full definition.
这些数据块的结构源自 MCP 的 CallToolResult 类型。完整定义请参阅 MCP 规范

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.
此工具可在长度、温度和重量单位之间转换数值。用户可以询问“将 100 公里转换为英里”或“72 华氏度是多少摄氏度”,Claude 会根据请求选择正确的单位类型和单位。

It demonstrates two patterns:
该示例演示了两种模式:

  • Enum schemas: unit_type is constrained to a fixed set of values. In TypeScript, use z.enum(). In Python, the dict schema doesn't support enums, so the full JSON Schema dict is required.
  • 枚举模式 (Enum schemas): unit_type 被限制在一组固定的值中。在 TypeScript 中,使用 z.enum()。在 Python 中,由于字典模式不支持枚举,因此需要提供完整的 JSON Schema 字典。
  • Unsupported input handling: when a conversion pair isn't found, the handler returns isError: true so Claude can tell the user what went wrong rather than treating a failure as a normal result.
  • 不支持的输入处理: 当找不到对应的转换对时,处理程序会返回 isError: true,以便 Claude 能够告知用户出了什么问题,而不是将失败视为正常结果。
import { tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";

const convert = tool(
  "convert_units",
  "Convert a value from one unit to another",
  {
    unit_type: z.enum(["length", "temperature", "weight"]).describe("Category of unit"),
    from_unit: z
      .string()
      .describe("Unit to convert from, e.g. kilometers, fahrenheit, pounds"),
    to_unit: z.string().describe("Unit to convert to"),
    value: z.number().describe("Value to convert")
  },
  async (args) => {
    type Conversions = Record<string, Record<string, (v: number) => number>>;

    const conversions: Conversions = {
      length: {
        kilometers_to_miles: (v) => v * 0.621371,
        miles_to_kilometers: (v) => v * 1.60934,
        meters_to_feet: (v) => v * 3.28084,
        feet_to_meters: (v) => v * 0.3048
      },
      temperature: {
        celsius_to_fahrenheit: (v) => (v * 9) / 5 + 32,
        fahrenheit_to_celsius: (v) => ((v - 32) * 5) / 9,
        celsius_to_kelvin: (v) => v + 273.15,
        kelvin_to_celsius: (v) => v - 273.15
      },
      weight: {
        kilograms_to_pounds: (v) => v * 2.20462,
        pounds_to_kilograms: (v) => v * 0.453592,
        grams_to_ounces: (v) => v * 0.035274,
        ounces_to_grams: (v) => v * 28.3495
      }
    };

    const key = `${args.from_unit}_to_${args.to_unit}`;
    const fn = conversions[args.unit_type]?.[key];

    if (!fn) {
      return {
        content: [
          {
            type: "text",
            text: `Unsupported conversion: ${args.from_unit} to ${args.to_unit}`
          }
        ],
        isError: true
      };
    }

    const result = fn(args.value);
    return {
      content: [
        {
          type: "text",
          text: `${args.value} ${args.from_unit} = ${result.toFixed(4)} ${args.to_unit}`
        }
      ]
    };
  }
);

const converterServer = createSdkMcpServer({
  name: "converter",
  version: "1.0.0",
  tools: [convert]
});

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.

服务器定义完成后,按照天气示例的相同方式将其传递给 query。此示例在循环中发送三个不同的提示,以展示同一个工具处理不同单位类型的情况。对于每个响应,它会检查 AssistantMessage 对象(其中包含 Claude 在该轮对话中发起的工具调用),并在打印最终的 ResultMessage 文本之前打印每个 ToolUseBlock。这样您可以直观地看到 Claude 何时是在使用工具,何时是根据自身知识进行回答。

import { query } from "@anthropic-ai/claude-agent-sdk";

const prompts = [
  "Convert 100 kilometers to miles.",
  "What is 72°F in Celsius?",
  "How many pounds is 5 kilograms?"
];

for (const prompt of prompts) {
  for await (const message of query({
    prompt,
    options: {
      mcpServers: { converter: converterServer },
      allowedTools: ["mcp__converter__convert_units"]
    }
  })) {
    if (message.type === "assistant") {
      for (const block of message.message.content) {
        if (block.type === "tool_use") {
          console.log(`[tool call] ${block.name}`, block.input);
        }
      }
    } else if (message.type === "result" && message.subtype === "success") {
      console.log(`Q: ${prompt}\nA: ${message.result}\n`);
    }
  }
}

Next steps 后续步骤

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.
自定义工具将异步函数封装在标准接口中。您可以将本页介绍的各种模式混合在同一个服务器中:一个服务器可以同时包含数据库工具、API 网关工具和图像渲染器。

接下来:

  • 如果您的服务器扩展到数十个工具,请参阅 工具搜索 (tool search),以实现按需加载。
  • 若要连接到现有的外部 MCP 服务器(如文件系统、GitHub、Slack)而非自行构建,请参阅 连接 MCP 服务器
  • 若要控制哪些工具可以自动运行以及哪些工具需要人工审批,请参阅 配置权限

Related documentation