English ← MyDocs

文档索引

在此获取完整文档索引: https://code.claude.com/docs/llms.txt 使用此文件发现所有可用页面,然后再进一步探索。

为 Claude 提供自定义工具

使用 Claude Agent SDK 的进程内 MCP 服务器定义自定义工具,使 Claude 能够调用您的函数、访问您的 API 并执行特定领域的操作。

自定义工具扩展了 Agent SDK,允许您定义自己的函数,Claude 可以在对话中调用这些函数。使用 SDK 的进程内 MCP 服务器,您可以使 Claude 访问数据库、外部 API、特定领域逻辑或应用程序所需的任何其他功能。

本指南介绍如何使用输入模式和处理程序定义工具、将它们打包到 MCP 服务器中、传递给 query,以及控制 Claude 可以访问哪些工具。还涵盖了错误处理、工具注解和返回非文本内容(如图像)。

快速参考

如果您想要...执行此操作
定义工具使用 @tool(Python)或 tool()(TypeScript),包含名称、描述、模式和处理程序。请参阅创建自定义工具
将工具注册给 Claude包装在 create_sdk_mcp_server / createSdkMcpServer 中并传递给 query()mcpServers。请参阅调用自定义工具
预批准工具添加到允许的工具中。请参阅配置允许的工具
从 Claude 的上下文中移除内置工具传递 tools 数组,仅列出您想要的内置工具。请参阅配置允许的工具
让 Claude 并行调用工具在没有副作用的工具上设置 readOnlyHint: true。请参阅添加工具注解
处理错误而不中断循环返回 isError: true 而不是抛出异常。请参阅处理错误
返回图像或文件在 content 数组中使用 imageresource 块。请参阅返回图像和资源
返回机器可读的 JSON 结果在结果上设置 structuredContent。请参阅返回结构化数据
扩展到大量工具使用工具搜索按需加载工具。

创建自定义工具

工具由四个部分组成,作为参数传递给 TypeScript 中的 tool() 辅助函数或 Python 中的 @tool 装饰器:

  • 名称: Claude 用来调用工具的唯一标识符。
  • 描述: 工具的功能。Claude 读取此内容以决定何时调用它。
  • 输入模式: Claude 必须提供的参数。在 TypeScript 中,这始终是 Zod 模式,处理程序的 args 会自动从中类型化。在 Python 中,这是名称到类型的字典映射,如 {"latitude": float},SDK 会为您转换为 JSON Schema。当您需要枚举、范围、可选字段或嵌套对象时,Python 装饰器也接受完整的 JSON Schema 字典。
  • 处理程序: 当 Claude 调用工具时运行的异步函数。它接收经过验证的参数,并必须返回一个包含以下内容的对象:
    • content(必需):结果块数组,每个块的 type"text""image""resource"。有关非文本块,请参阅返回图像和资源
    • structuredContent(可选):一个 JSON 对象,将结果作为机器可读数据保存,与 content 一起返回。请参阅返回结构化数据
    • isError(可选):设置为 true 以表示工具失败,以便 Claude 可以对其做出反应。请参阅处理错误

定义工具后,使用 createSdkMcpServer(TypeScript)或 create_sdk_mcp_server(Python)将其包装在服务器中。服务器在应用程序内部以进程内方式运行,而不是作为单独的进程。

天气工具示例

此示例定义了一个 get_temperature 工具并将其包装在 MCP 服务器中。它只设置了工具;要将其传递给 query 并运行,请参阅下面的调用自定义工具

from typing import Any
import httpx
from claude_agent_sdk import tool, create_sdk_mcp_server


# Define a tool: name, description, input schema, handler
@tool(
    "get_temperature",
    "Get the current temperature at a location",
    {"latitude": float, "longitude": float},
)
async def get_temperature(args: dict[str, Any]) -> dict[str, Any]:
    async with httpx.AsyncClient() as client:
        response = await client.get(
            "https://api.open-meteo.com/v1/forecast",
            params={
                "latitude": args["latitude"],
                "longitude": args["longitude"],
                "current": "temperature_2m",
                "temperature_unit": "fahrenheit",
            },
        )
        data = response.json()

    # Return a content array - Claude sees this as the tool result
    return {
        "content": [
            {
                "type": "text",
                "text": f"Temperature: {data['current']['temperature_2m']}°F",
            }
        ]
    }


# Wrap the tool in an in-process MCP server
weather_server = create_sdk_mcp_server(
    name="weather",
    version="1.0.0",
    tools=[get_temperature],
)
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]
});

有关完整的参数详情,包括 JSON Schema 输入格式和返回值结构,请参阅 tool() TypeScript 参考或 @tool Python 参考。

Tip

要使参数可选:在 TypeScript 中,向 Zod 字段添加 .default()。在 Python 中,字典模式将每个键视为必需,因此将参数排除在模式之外,在描述字符串中提及它,并在处理程序中使用 args.get() 读取它。下面的 get_precipitation_chance 工具展示了两种模式。

调用自定义工具

通过 mcpServers 选项将您创建的 MCP 服务器传递给 querymcpServers 中的键成为每个工具完全限定名称中的 {server_name} 部分:mcp__{server_name}__{tool_name}。在 allowedTools 中列出该名称,以便工具无需权限提示即可运行。

这些代码片段复用了上面示例中的 weatherServer 来询问 Claude 特定位置的天气。

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage


async def main():
    options = ClaudeAgentOptions(
        mcp_servers={"weather": weather_server},
        allowed_tools=["mcp__weather__get_temperature"],
    )

    async for message in query(
        prompt="What's the temperature in San Francisco?",
        options=options,
    ):
        # ResultMessage is the final message after all tool calls complete
        if isinstance(message, ResultMessage) and message.subtype == "success":
            print(message.result)


asyncio.run(main())
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);
  }
}

添加更多工具

服务器可以容纳您在其 tools 数组中列出的任意数量的工具。当服务器上有多个工具时,您可以在 allowedTools 中单独列出每个工具,或使用通配符 mcp__weather__* 来覆盖服务器公开的每个工具。

下面的示例向天气工具示例中的 weatherServer 添加了第二个工具 get_precipitation_chance,并在数组中包含两个工具重新构建了服务器。

# Define a second tool for the same server
@tool(
    "get_precipitation_chance",
    "Get the hourly precipitation probability for a location. "
    "Optionally pass 'hours' (1-24) to control how many hours to return.",
    {"latitude": float, "longitude": float},
)
async def get_precipitation_chance(args: dict[str, Any]) -> dict[str, Any]:
    # 'hours' isn't in the schema - read it with .get() to make it optional
    hours = args.get("hours", 12)
    async with httpx.AsyncClient() as client:
        response = await client.get(
            "https://api.open-meteo.com/v1/forecast",
            params={
                "latitude": args["latitude"],
                "longitude": args["longitude"],
                "hourly": "precipitation_probability",
                "forecast_days": 1,
            },
        )
        data = response.json()
    chances = data["hourly"]["precipitation_probability"][:hours]

    return {
        "content": [
            {
                "type": "text",
                "text": f"Next {hours} hours: {'%, '.join(map(str, chances))}%",
            }
        ]
    }


# Rebuild the server with both tools in the array
weather_server = create_sdk_mcp_server(
    name="weather",
    version="1.0.0",
    tools=[get_temperature, 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]
});

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

添加工具注解

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

字段默认值含义
readOnlyHintfalse工具不修改其环境。控制工具是否可以与其他只读工具并行调用。
destructiveHinttrue工具可能执行破坏性更新。仅供参考。
idempotentHintfalse使用相同参数重复调用没有额外效果。仅供参考。
openWorldHinttrue工具访问进程外部的系统。仅供参考。

注解是元数据,不是强制执行。标记为 readOnlyHint: true 的工具仍然可以写入磁盘(如果处理程序这样做)。保持注解与处理程序一致。

此示例向天气工具示例中的 get_temperature 工具添加了 readOnlyHint

from claude_agent_sdk import tool, ToolAnnotations


@tool(
    "get_temperature",
    "Get the current temperature at a location",
    {"latitude": float, "longitude": float},
    annotations=ToolAnnotations(
        readOnlyHint=True
    ),  # Lets Claude batch this with other read-only calls
)
async def get_temperature(args):
    return {"content": [{"type": "text", "text": "..."}]}
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
);

请参阅 TypeScriptPython 参考中的 ToolAnnotations

控制工具访问

天气工具示例注册了一个服务器并在 allowedTools 中列出了工具。本节介绍工具名称的构造方式,以及在您有多个工具或想要限制内置工具时如何限定访问范围。

工具名称格式

当 MCP 工具暴露给 Claude 时,它们的名称遵循特定格式:

  • 模式:mcp__{server_name}__{tool_name}
  • 示例:服务器 weather 中名为 get_temperature 的工具变为 mcp__weather__get_temperature

配置允许的工具

tools 选项和允许/禁止列表影响两个层:可用性(控制工具是否出现在 Claude 的上下文中)和权限(控制 Claude 尝试调用时是否被批准)。tools 和裸名称 disallowedTools 条目更改可用性。allowedTools 和带作用域的 disallowedTools 规则仅更改权限。

选项效果
tools: ["Read", "Grep"]可用性仅列出的内置工具在 Claude 的上下文中。未列出的内置工具被移除。MCP 工具不受影响。
tools: []可用性所有内置工具被移除。Claude 只能使用您的 MCP 工具。
allowed tools权限列出的工具无需权限提示即可运行。未列出的工具仍然可用;调用通过权限流程
disallowed tools两者裸工具名称(如 "Bash")从 Claude 的上下文中移除工具,与从 tools 中省略相同。带作用域的规则(如 "Bash(rm *)")保留工具在上下文中,仅拒绝匹配的调用。

要完全移除内置工具,从 tools 中省略它或在 disallowedTools(Python:disallowed_tools)中列出其裸名称;两者都将工具排除在上下文之外,使 Claude 永远不会尝试使用它。带作用域的 disallowedTools 规则阻止匹配的调用,但保留工具可见,因此 Claude 可能会浪费一轮尝试它。有关完整的评估顺序,请参阅配置权限

处理错误

处理程序报告错误的方式决定了智能体循环是继续还是停止:

发生的情况结果
处理程序抛出未捕获的异常智能体循环停止。Claude 永远看不到错误,query 调用失败。
处理程序捕获错误并返回 isError: true(TS)/ "is_error": True(Python)智能体循环继续。Claude 将错误视为数据,可以重试、尝试不同的工具或解释失败原因。

下面的示例在处理程序内部捕获两种类型的失败,而不是让它们抛出。非 200 的 HTTP 状态从响应中捕获并作为错误结果返回。网络错误或无效 JSON 由周围的 try/except(Python)或 try/catch(TypeScript)捕获,也作为错误结果返回。在两种情况下,处理程序正常返回,智能体循环继续。

import json
import httpx
from typing import Any


@tool(
    "fetch_data",
    "Fetch data from an API",
    {"endpoint": str},  # Simple schema
)
async def fetch_data(args: dict[str, Any]) -> dict[str, Any]:
    try:
        async with httpx.AsyncClient() as client:
            response = await client.get(args["endpoint"])
            if response.status_code != 200:
                # Return the failure as a tool result so Claude can react to it.
                # is_error marks this as a failed call rather than odd-looking data.
                return {
                    "content": [
                        {
                            "type": "text",
                            "text": f"API error: {response.status_code} {response.reason_phrase}",
                        }
                    ],
                    "is_error": True,
                }

            data = response.json()
            return {"content": [{"type": "text", "text": json.dumps(data, indent=2)}]}
    except Exception as e:
        # Catching here keeps the agent loop alive. An uncaught exception
        # would end the whole query() call.
        return {
            "content": [{"type": "text", "text": f"Failed to fetch data: {str(e)}"}],
            "is_error": True,
        }
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
      };
    }
  }
);

返回图像和资源

工具结果中的 content 数组接受 textimageresource 块。您可以在同一响应中混合使用它们。

图像

图像块以内联方式携带图像字节,编码为 base64。没有 URL 字段。要返回位于 URL 的图像,请在处理程序中获取它,读取响应字节,并在返回前进行 base64 编码。结果作为视觉输入处理。

字段类型说明
type"image"
datastringBase64 编码的字节。仅原始 base64,无 data:image/...;base64, 前缀
mimeTypestring必需。例如 image/pngimage/jpegimage/webpimage/gif
import base64
import httpx


# Define a tool that fetches an image from a URL and returns it to Claude
@tool("fetch_image", "Fetch an image from a URL and return it to Claude", {"url": str})
async def fetch_image(args):
    async with httpx.AsyncClient() as client:  # Fetch the image bytes
        response = await client.get(args["url"])

    return {
        "content": [
            {
                "type": "image",
                "data": base64.b64encode(response.content).decode(
                    "ascii"
                ),  # Base64-encode the raw bytes
                "mimeType": response.headers.get(
                    "content-type", "image/png"
                ),  # Read MIME type from the response
            }
        ]
    }
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
        }
      ]
    };
  }
);

资源

资源块嵌入由 URI 标识的内容片段。URI 是供 Claude 引用的标签;实际内容在块的 textblob 字段中。当您的工具产生的内容适合按名称引用时使用此方式,例如生成的文件或来自外部系统的记录。

字段类型说明
type"resource"
resource.uristring内容的标识符。任何 URI 方案
resource.textstring内容(如果是文本)。提供此字段或 blob,不能同时提供
resource.blobstring内容的 base64 编码(如果是二进制)
resource.mimeTypestring可选

此示例展示了从工具处理程序内部返回的资源块。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
      }
    }
  ]
};
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
            },
        }
    ]
}

这些块形状来自 MCP CallToolResult 类型。有关完整定义,请参阅 MCP 规范

返回结构化数据

structuredContent 是结果上的可选 JSON 对象,与 content 数组分开。使用它返回原始值,Claude 可以将其作为精确字段读取,而不是从文本字符串或图像中解析出来。

当设置了 structuredContent 时,Claude 接收 JSON 加上 content 中的任何图像或资源块。content 中的文本块不会被转发,因为它们被假定为重复结构化数据。下面的示例将图表渲染为图像块,并在同一处理程序中将背后的数据点以 structuredContent 返回。

return {
  content: [
    {
      type: "image",
      data: chartPngBuffer.toString("base64"),
      mimeType: "image/png"
    }
  ],
  structuredContent: {
    series: "temperature_2m",
    unit: "fahrenheit",
    points: [62.1, 63.4, 65.0, 64.2]
  }
};
Note

Python 的 @tool 装饰器仅从处理程序的返回字典中转发 contentis_error。要从 Python 返回 structuredContent,请运行独立 MCP 服务器而不是进程内 SDK 服务器。

示例:单位转换器

此工具在长度、温度和重量单位之间转换值。用户可以问"将 100 公里转换为英里"或"72 华氏度是多少摄氏度",Claude 会从请求中选择正确的单位类型和单位。

它演示了两种模式:

  • 枚举模式: unit_type 被限制为固定值集。在 TypeScript 中,使用 z.enum()。在 Python 中,字典模式不支持枚举,因此需要完整的 JSON Schema 字典。
  • 不支持的输入处理: 当找不到转换对时,处理程序返回 isError: true,以便 Claude 可以告诉用户出了什么问题,而不是将失败视为正常结果。
from typing import Any
from claude_agent_sdk import tool, create_sdk_mcp_server


# z.enum() in TypeScript becomes an "enum" constraint in JSON Schema.
# The dict schema has no equivalent, so full JSON Schema is required.
@tool(
    "convert_units",
    "Convert a value from one unit to another",
    {
        "type": "object",
        "properties": {
            "unit_type": {
                "type": "string",
                "enum": ["length", "temperature", "weight"],
                "description": "Category of unit",
            },
            "from_unit": {
                "type": "string",
                "description": "Unit to convert from, e.g. kilometers, fahrenheit, pounds",
            },
            "to_unit": {"type": "string", "description": "Unit to convert to"},
            "value": {"type": "number", "description": "Value to convert"},
        },
        "required": ["unit_type", "from_unit", "to_unit", "value"],
    },
)
async def convert_units(args: dict[str, Any]) -> dict[str, Any]:
    conversions = {
        "length": {
            "kilometers_to_miles": lambda v: v * 0.621371,
            "miles_to_kilometers": lambda v: v * 1.60934,
            "meters_to_feet": lambda v: v * 3.28084,
            "feet_to_meters": lambda v: v * 0.3048,
        },
        "temperature": {
            "celsius_to_fahrenheit": lambda v: (v * 9) / 5 + 32,
            "fahrenheit_to_celsius": lambda v: (v - 32) * 5 / 9,
            "celsius_to_kelvin": lambda v: v + 273.15,
            "kelvin_to_celsius": lambda v: v - 273.15,
        },
        "weight": {
            "kilograms_to_pounds": lambda v: v * 2.20462,
            "pounds_to_kilograms": lambda v: v * 0.453592,
            "grams_to_ounces": lambda v: v * 0.035274,
            "ounces_to_grams": lambda v: v * 28.3495,
        },
    }

    key = f"{args['from_unit']}_to_{args['to_unit']}"
    fn = conversions.get(args["unit_type"], {}).get(key)

    if not fn:
        return {
            "content": [
                {
                    "type": "text",
                    "text": f"Unsupported conversion: {args['from_unit']} to {args['to_unit']}",
                }
            ],
            "is_error": True,
        }

    result = fn(args["value"])
    return {
        "content": [
            {
                "type": "text",
                "text": f"{args['value']} {args['from_unit']} = {result:.4f} {args['to_unit']}",
            }
        ]
    }


converter_server = create_sdk_mcp_server(
    name="converter",
    version="1.0.0",
    tools=[convert_units],
)
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]
});

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

import asyncio
from claude_agent_sdk import (
    query,
    ClaudeAgentOptions,
    ResultMessage,
    AssistantMessage,
    ToolUseBlock,
)


async def main():
    options = ClaudeAgentOptions(
        mcp_servers={"converter": converter_server},
        allowed_tools=["mcp__converter__convert_units"],
    )

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

    for prompt in prompts:
        async for message in query(prompt=prompt, options=options):
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, ToolUseBlock):
                        print(f"[tool call] {block.name}({block.input})")
            elif isinstance(message, ResultMessage) and message.subtype == "success":
                print(f"Q: {prompt}\nA: {message.result}\n")


asyncio.run(main())
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`);
    }
  }
}

后续步骤

自定义工具将异步函数包装在标准接口中。您可以在同一服务器中混合使用本页的模式:单个服务器可以同时容纳数据库工具、API 网关工具和图像渲染器。

接下来:

  • 如果您的服务器增长到数十个工具,请参阅工具搜索以延迟加载直到 Claude 需要它们。
  • 要连接到外部 MCP 服务器(文件系统、GitHub、Slack)而不是构建自己的,请参阅连接 MCP 服务器
  • 要控制哪些工具自动运行与需要批准,请参阅配置权限

相关文档