SpyBara
Go Premium

Documentation 2026-06-10 23:57 UTC to 2026-06-11 23:01 UTC

1 file changed +0 −866. View all changes and history on the product overview
2026
Tue 30 23:02 Mon 29 23:02 Sat 27 01:01 Fri 26 23:00 Thu 25 23:58 Wed 24 22:02 Tue 23 22:00 Mon 22 23:59 Fri 19 22:58 Thu 18 22:00 Wed 17 17:02 Tue 16 21:57 Mon 15 23:02 Sat 13 21:59 Fri 12 22:00 Thu 11 23:01 Wed 10 23:57 Tue 9 06:34 Mon 8 06:52 Sat 6 06:24 Fri 5 06:45 Thu 4 06:52 Wed 3 06:53 Tue 2 06:51
Details

1> ## Documentation Index

2> Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt

3> Use this file to discover all available pages before exploring further.

4 1 

5# 為 Claude 提供自訂工具

6 

7> 使用 Claude Agent SDK 的同程序 MCP 伺服器定義自訂工具,讓 Claude 可以呼叫您的函數、存取您的 API,並執行特定領域的操作。

8 

9自訂工具透過讓您定義 Claude 在對話期間可以呼叫的自己的函數來擴展 Agent SDK。使用 SDK 的同程序 MCP 伺服器,您可以讓 Claude 存取資料庫、外部 API、特定領域邏輯或應用程式需要的任何其他功能。

10 

11本指南涵蓋如何使用輸入結構描述和處理程式定義工具、將它們組合到 MCP 伺服器中、將它們傳遞給 `query`,以及控制 Claude 可以存取哪些工具。它也涵蓋錯誤處理、工具註解,以及傳回非文字內容(如影像)。

12 

13<h2 id="quick-reference">

14 快速參考

15</h2>

16 

17| 如果您想要... | 執行此操作 |

18| :------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |

19| 定義工具 | 使用 [`@tool`](/zh-TW/agent-sdk/python#tool)(Python)或 [`tool()`](/zh-TW/agent-sdk/typescript#tool)(TypeScript),搭配名稱、描述、結構描述和處理程式。請參閱[建立自訂工具](#create-a-custom-tool)。 |

20| 向 Claude 註冊工具 | 在 `create_sdk_mcp_server` / `createSdkMcpServer` 中包裝,並傳遞至 `query()` 中的 `mcpServers`。請參閱[呼叫自訂工具](#call-a-custom-tool)。 |

21| 預先核准工具 | 新增至您允許的工具。請參閱[設定允許的工具](#configure-allowed-tools)。 |

22| 從 Claude 的內容中移除內建工具 | 傳遞 `tools` 陣列,僅列出您想要的內建工具。請參閱[設定允許的工具](#configure-allowed-tools)。 |

23| 讓 Claude 平行呼叫工具 | 在沒有副作用的工具上設定 `readOnlyHint: true`。請參閱[新增工具註解](#add-tool-annotations)。 |

24| 處理錯誤而不停止迴圈 | 傳回 `isError: true` 而不是擲回。請參閱[處理錯誤](#handle-errors)。 |

25| 傳回影像或檔案 | 在內容陣列中使用 `image` 或 `resource` 區塊。請參閱[傳回影像和資源](#return-images-and-resources)。 |

26| 傳回機器可讀的 JSON 結果 | 在結果上設定 `structuredContent`。請參閱[傳回結構化資料](#return-structured-data)。 |

27| 擴展到許多工具 | 使用[工具搜尋](/zh-TW/agent-sdk/tool-search)按需載入工具。 |

28 

29<h2 id="create-a-custom-tool">

30 建立自訂工具

31</h2>

32 

33工具由四個部分定義,作為 TypeScript 中 [`tool()`](/zh-TW/agent-sdk/typescript#tool) 協助程式或 Python 中 [`@tool`](/zh-TW/agent-sdk/python#tool) 裝飾器的引數傳遞:

34 

35* **名稱:** Claude 用來呼叫工具的唯一識別碼。

36* **描述:** 工具的功能。Claude 讀取此項以決定何時呼叫它。

37* **輸入結構描述:** Claude 必須提供的引數。在 TypeScript 中,這始終是 [Zod 結構描述](https://zod.dev/),處理程式的 `args` 會自動從中輸入。在 Python 中,這是將名稱對應到類型的字典,例如 `{"latitude": float}`,SDK 會為您轉換為 JSON Schema。Python 裝飾器也接受完整的 [JSON Schema](https://json-schema.org/understanding-json-schema/about) 字典,當您需要列舉、範圍、選用欄位或巢狀物件時。

38* **處理程式:** 當 Claude 呼叫工具時執行的非同步函數。它接收驗證的引數,並必須傳回具有以下內容的物件:

39 * `content`(必需):結果區塊的陣列,每個區塊的 `type` 為 `"text"`、`"image"` 或 `"resource"`。請參閱[傳回影像和資源](#return-images-and-resources)以取得非文字區塊。

40 * `structuredContent`(選用):保存結果作為機器可讀資料的 JSON 物件,與 `content` 一起傳回。請參閱[傳回結構化資料](#return-structured-data)。

41 * `isError`(選用):設定為 `true` 以表示工具失敗,讓 Claude 可以對其做出反應。請參閱[處理錯誤](#handle-errors)。

42 

43定義工具後,使用 [`createSdkMcpServer`](/zh-TW/agent-sdk/typescript#createsdkmcpserver)(TypeScript)或 [`create_sdk_mcp_server`](/zh-TW/agent-sdk/python#create_sdk_mcp_server)(Python)將其包裝在伺服器中。伺服器在應用程式內同程序執行,而不是作為單獨的程序。

44 

45<h3 id="weather-tool-example">

46 天氣工具範例

47</h3>

48 

49此範例定義 `get_temperature` 工具並將其包裝在 MCP 伺服器中。它只設定工具;若要將其傳遞至 `query` 並執行它,請參閱下面的[呼叫自訂工具](#call-a-custom-tool)。

50 

51<CodeGroup>

52 ```python Python theme={null}

53 from typing import Any

54 import httpx

55 from claude_agent_sdk import tool, create_sdk_mcp_server

56 

57 

58 # Define a tool: name, description, input schema, handler

59 @tool(

60 "get_temperature",

61 "Get the current temperature at a location",

62 {"latitude": float, "longitude": float},

63 )

64 async def get_temperature(args: dict[str, Any]) -> dict[str, Any]:

65 async with httpx.AsyncClient() as client:

66 response = await client.get(

67 "https://api.open-meteo.com/v1/forecast",

68 params={

69 "latitude": args["latitude"],

70 "longitude": args["longitude"],

71 "current": "temperature_2m",

72 "temperature_unit": "fahrenheit",

73 },

74 )

75 data = response.json()

76 

77 # Return a content array - Claude sees this as the tool result

78 return {

79 "content": [

80 {

81 "type": "text",

82 "text": f"Temperature: {data['current']['temperature_2m']}°F",

83 }

84 ]

85 }

86 

87 

88 # Wrap the tool in an in-process MCP server

89 weather_server = create_sdk_mcp_server(

90 name="weather",

91 version="1.0.0",

92 tools=[get_temperature],

93 )

94 ```

95 

96 ```typescript TypeScript theme={null}

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

98 import { z } from "zod";

99 

100 // Define a tool: name, description, input schema, handler

101 const getTemperature = tool(

102 "get_temperature",

103 "Get the current temperature at a location",

104 {

105 latitude: z.number().describe("Latitude coordinate"), // .describe() adds a field description Claude sees

106 longitude: z.number().describe("Longitude coordinate")

107 },

108 async (args) => {

109 // args is typed from the schema: { latitude: number; longitude: number }

110 const response = await fetch(

111 `https://api.open-meteo.com/v1/forecast?latitude=${args.latitude}&longitude=${args.longitude}&current=temperature_2m&temperature_unit=fahrenheit`

112 );

113 const data: any = await response.json();

114 

115 // Return a content array - Claude sees this as the tool result

116 return {

117 content: [{ type: "text", text: `Temperature: ${data.current.temperature_2m}°F` }]

118 };

119 }

120 );

121 

122 // Wrap the tool in an in-process MCP server

123 const weatherServer = createSdkMcpServer({

124 name: "weather",

125 version: "1.0.0",

126 tools: [getTemperature]

127 });

128 ```

129</CodeGroup>

130 

131請參閱 [`tool()`](/zh-TW/agent-sdk/typescript#tool) TypeScript 參考或 [`@tool`](/zh-TW/agent-sdk/python#tool) Python 參考,以取得完整的參數詳細資訊,包括 JSON Schema 輸入格式和傳回值結構。

132 

133<Tip>

134 若要使參數成為選用:在 TypeScript 中,將 `.default()` 新增至 Zod 欄位。在 Python 中,字典結構描述將每個鍵視為必需,因此請將參數留出結構描述,在描述字串中提及它,並在處理程式中使用 `args.get()` 讀取它。下面的 [`get_precipitation_chance` 工具](#add-more-tools)顯示兩種模式。

135</Tip>

136 

137<h3 id="call-a-custom-tool">

138 呼叫自訂工具

139</h3>

140 

141透過 `mcpServers` 選項將您建立的 MCP 伺服器傳遞至 `query`。`mcpServers` 中的鍵成為每個工具的完全限定名稱中的 `{server_name}` 區段:`mcp__{server_name}__{tool_name}`。在 `allowedTools` 中列出該名稱,以便工具執行而不會出現權限提示。

142 

143這些程式碼片段重複使用上面[範例](#weather-tool-example)中的 `weatherServer`,以詢問 Claude 特定位置的天氣。

144 

145<CodeGroup>

146 ```python Python theme={null}

147 import asyncio

148 from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage

149 

150 

151 async def main():

152 options = ClaudeAgentOptions(

153 mcp_servers={"weather": weather_server},

154 allowed_tools=["mcp__weather__get_temperature"],

155 )

156 

157 async for message in query(

158 prompt="What's the temperature in San Francisco?",

159 options=options,

160 ):

161 # ResultMessage is the final message after all tool calls complete

162 if isinstance(message, ResultMessage) and message.subtype == "success":

163 print(message.result)

164 

165 

166 asyncio.run(main())

167 ```

168 

169 ```typescript TypeScript theme={null}

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

171 

172 for await (const message of query({

173 prompt: "What's the temperature in San Francisco?",

174 options: {

175 mcpServers: { weather: weatherServer },

176 allowedTools: ["mcp__weather__get_temperature"]

177 }

178 })) {

179 // "result" is the final message after all tool calls complete

180 if (message.type === "result" && message.subtype === "success") {

181 console.log(message.result);

182 }

183 }

184 ```

185</CodeGroup>

186 

187<h3 id="add-more-tools">

188 新增更多工具

189</h3>

190 

191伺服器在其 `tools` 陣列中列出的工具一樣多。如果有多個工具在伺服器上,您可以在 `allowedTools` 中個別列出每個工具,或使用萬用字元 `mcp__weather__*` 來涵蓋伺服器公開的每個工具。

192 

193下面的範例將第二個工具 `get_precipitation_chance` 新增至[天氣工具範例](#weather-tool-example)中的 `weatherServer`,並使用陣列中的兩個工具重建它。

194 

195<CodeGroup>

196 ```python Python theme={null}

197 # Define a second tool for the same server

198 @tool(

199 "get_precipitation_chance",

200 "Get the hourly precipitation probability for a location. "

201 "Optionally pass 'hours' (1-24) to control how many hours to return.",

202 {"latitude": float, "longitude": float},

203 )

204 async def get_precipitation_chance(args: dict[str, Any]) -> dict[str, Any]:

205 # 'hours' isn't in the schema - read it with .get() to make it optional

206 hours = args.get("hours", 12)

207 async with httpx.AsyncClient() as client:

208 response = await client.get(

209 "https://api.open-meteo.com/v1/forecast",

210 params={

211 "latitude": args["latitude"],

212 "longitude": args["longitude"],

213 "hourly": "precipitation_probability",

214 "forecast_days": 1,

215 },

216 )

217 data = response.json()

218 chances = data["hourly"]["precipitation_probability"][:hours]

219 

220 return {

221 "content": [

222 {

223 "type": "text",

224 "text": f"Next {hours} hours: {'%, '.join(map(str, chances))}%",

225 }

226 ]

227 }

228 

229 

230 # Rebuild the server with both tools in the array

231 weather_server = create_sdk_mcp_server(

232 name="weather",

233 version="1.0.0",

234 tools=[get_temperature, get_precipitation_chance],

235 )

236 ```

237 

238 ```typescript TypeScript theme={null}

239 // Define a second tool for the same server

240 const getPrecipitationChance = tool(

241 "get_precipitation_chance",

242 "Get the hourly precipitation probability for a location",

243 {

244 latitude: z.number(),

245 longitude: z.number(),

246 hours: z

247 .number()

248 .int()

249 .min(1)

250 .max(24)

251 .default(12) // .default() makes the parameter optional

252 .describe("How many hours of forecast to return")

253 },

254 async (args) => {

255 const response = await fetch(

256 `https://api.open-meteo.com/v1/forecast?latitude=${args.latitude}&longitude=${args.longitude}&hourly=precipitation_probability&forecast_days=1`

257 );

258 const data: any = await response.json();

259 const chances = data.hourly.precipitation_probability.slice(0, args.hours);

260 

261 return {

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

263 };

264 }

265 );

266 

267 // Rebuild the server with both tools in the array

268 const weatherServer = createSdkMcpServer({

269 name: "weather",

270 version: "1.0.0",

271 tools: [getTemperature, getPrecipitationChance]

272 });

273 ```

274</CodeGroup>

275 

276此陣列中的每個工具在每個回合都會消耗內容視窗空間。如果您定義了數十個工具,請參閱[工具搜尋](/zh-TW/agent-sdk/tool-search)以改為按需載入它們。

277 

278<h3 id="add-tool-annotations">

279 新增工具註解

280</h3>

281 

282[工具註解](https://modelcontextprotocol.io/docs/concepts/tools#tool-annotations)是描述工具行為方式的選用中繼資料。在 TypeScript 中將它們作為 `tool()` 協助程式的第五個引數傳遞,或在 Python 中透過 `@tool` 裝飾器的 `annotations` 關鍵字引數傳遞。所有提示欄位都是布林值。

283 

284| 欄位 | 預設值 | 意義 |

285| :---------------- | :------ | :----------------------------- |

286| `readOnlyHint` | `false` | 工具不會修改其環境。控制工具是否可以與其他唯讀工具平行呼叫。 |

287| `destructiveHint` | `true` | 工具可能執行破壞性更新。僅供參考。 |

288| `idempotentHint` | `false` | 使用相同引數重複呼叫沒有額外效果。僅供參考。 |

289| `openWorldHint` | `true` | 工具到達程序外的系統。僅供參考。 |

290 

291註解是中繼資料,不是強制執行。標記為 `readOnlyHint: true` 的工具如果處理程式執行該操作,仍然可以寫入磁碟。保持註解準確反映處理程式。

292 

293此範例將 `readOnlyHint` 新增至[天氣工具範例](#weather-tool-example)中的 `get_temperature` 工具。

294 

295<CodeGroup>

296 ```python Python theme={null}

297 from claude_agent_sdk import tool, ToolAnnotations

298 

299 

300 @tool(

301 "get_temperature",

302 "Get the current temperature at a location",

303 {"latitude": float, "longitude": float},

304 annotations=ToolAnnotations(

305 readOnlyHint=True

306 ), # Lets Claude batch this with other read-only calls

307 )

308 async def get_temperature(args):

309 return {"content": [{"type": "text", "text": "..."}]}

310 ```

311 

312 ```typescript TypeScript theme={null}

313 tool(

314 "get_temperature",

315 "Get the current temperature at a location",

316 { latitude: z.number(), longitude: z.number() },

317 async (args) => ({ content: [{ type: "text", text: `...` }] }),

318 { annotations: { readOnlyHint: true } } // Lets Claude batch this with other read-only calls

319 );

320 ```

321</CodeGroup>

322 

323請參閱 [TypeScript](/zh-TW/agent-sdk/typescript#toolannotations) 或 [Python](/zh-TW/agent-sdk/python#toolannotations) 參考中的 `ToolAnnotations`。

324 

325<h2 id="control-tool-access">

326 控制工具存取

327</h2>

328 

329[天氣工具範例](#weather-tool-example)註冊了伺服器並在 `allowedTools` 中列出了工具。本節涵蓋工具名稱的構造方式,以及當您有多個工具或想要限制內建工具時如何限制存取。

330 

331<h3 id="tool-name-format">

332 工具名稱格式

333</h3>

334 

335當 MCP 工具公開給 Claude 時,它們的名稱遵循特定格式:

336 

337* 模式:`mcp__{server_name}__{tool_name}`

338* 範例:伺服器 `weather` 中名為 `get_temperature` 的工具變成 `mcp__weather__get_temperature`

339 

340<h3 id="configure-allowed-tools">

341 設定允許的工具

342</h3>

343 

344`tools` 選項和允許/不允許清單影響兩個層級:可用性控制工具是否出現在 Claude 的內容中,權限控制 Claude 嘗試呼叫後是否核准呼叫。`tools` 和裸名稱 `disallowedTools` 項目改變可用性。`allowedTools` 和限定範圍的 `disallowedTools` 規則只改變權限。

345 

346| 選項 | 層級 | 效果 |

347| :------------------------ | :-- | :------------------------------------------------------------------------------------------------------ |

348| `tools: ["Read", "Grep"]` | 可用性 | 只有列出的內建工具在 Claude 的內容中。未列出的內建工具會被移除。MCP 工具不受影響。 |

349| `tools: []` | 可用性 | 所有內建工具都被移除。Claude 只能使用您的 MCP 工具。 |

350| 允許的工具 | 權限 | 列出的工具執行時不會出現權限提示。未列出的工具保持可用;呼叫會通過[權限流程](/zh-TW/agent-sdk/permissions)。 |

351| 不允許的工具 | 兩者 | 裸工具名稱(例如 `"Bash"`)會將工具從 Claude 的內容中移除,與從 `tools` 中省略它相同。限定範圍的規則(例如 `"Bash(rm *)"`)會將工具保留在內容中,並僅拒絕符合的呼叫。 |

352 

353若要完全移除內建工具,請從 `tools` 中省略它或在 `disallowedTools` 中列出其裸名稱(Python:`disallowed_tools`);兩者都會將工具保留在內容之外,以便 Claude 永遠不會嘗試它。限定範圍的 `disallowedTools` 規則會阻止符合的呼叫,但會將工具保留為可見,因此 Claude 可能會浪費一個回合嘗試它。請參閱[設定權限](/zh-TW/agent-sdk/permissions)以取得完整的評估順序。

354 

355<h2 id="handle-errors">

356 處理錯誤

357</h2>

358 

359您的處理程式報告錯誤的方式決定代理迴圈是繼續還是停止:

360 

361| 發生的情況 | 結果 |

362| :---------------------------------------------------------- | :--------------------------------------- |

363| 處理程式擲出未捕獲的例外 | 代理迴圈停止。Claude 永遠看不到錯誤,`query` 呼叫失敗。 |

364| 處理程式捕獲錯誤並傳回 `isError: true`(TS)/ `"is_error": True`(Python) | 代理迴圈繼續。Claude 將錯誤視為資料並可以重試、嘗試不同的工具或解釋失敗。 |

365 

366下面的範例在處理程式內捕獲兩種失敗,而不是讓它們擲出。非 200 HTTP 狀態從回應中捕獲並作為錯誤結果傳回。網路錯誤或無效 JSON 由周圍的 `try/except`(Python)或 `try/catch`(TypeScript)捕獲,也作為錯誤結果傳回。在兩種情況下,處理程式正常傳回,代理迴圈繼續。

367 

368<CodeGroup>

369 ```python Python theme={null}

370 import json

371 import httpx

372 from typing import Any

373 

374 

375 @tool(

376 "fetch_data",

377 "Fetch data from an API",

378 {"endpoint": str}, # Simple schema

379 )

380 async def fetch_data(args: dict[str, Any]) -> dict[str, Any]:

381 try:

382 async with httpx.AsyncClient() as client:

383 response = await client.get(args["endpoint"])

384 if response.status_code != 200:

385 # Return the failure as a tool result so Claude can react to it.

386 # is_error marks this as a failed call rather than odd-looking data.

387 return {

388 "content": [

389 {

390 "type": "text",

391 "text": f"API error: {response.status_code} {response.reason_phrase}",

392 }

393 ],

394 "is_error": True,

395 }

396 

397 data = response.json()

398 return {"content": [{"type": "text", "text": json.dumps(data, indent=2)}]}

399 except Exception as e:

400 # Catching here keeps the agent loop alive. An uncaught exception

401 # would end the whole query() call.

402 return {

403 "content": [{"type": "text", "text": f"Failed to fetch data: {str(e)}"}],

404 "is_error": True,

405 }

406 ```

407 

408 ```typescript TypeScript theme={null}

409 tool(

410 "fetch_data",

411 "Fetch data from an API",

412 {

413 endpoint: z.string().url().describe("API endpoint URL")

414 },

415 async (args) => {

416 try {

417 const response = await fetch(args.endpoint);

418 

419 if (!response.ok) {

420 // Return the failure as a tool result so Claude can react to it.

421 // isError marks this as a failed call rather than odd-looking data.

422 return {

423 content: [

424 {

425 type: "text",

426 text: `API error: ${response.status} ${response.statusText}`

427 }

428 ],

429 isError: true

430 };

431 }

432 

433 const data = await response.json();

434 return {

435 content: [

436 {

437 type: "text",

438 text: JSON.stringify(data, null, 2)

439 }

440 ]

441 };

442 } catch (error) {

443 // Catching here keeps the agent loop alive. An uncaught throw

444 // would end the whole query() call.

445 return {

446 content: [

447 {

448 type: "text",

449 text: `Failed to fetch data: ${error instanceof Error ? error.message : String(error)}`

450 }

451 ],

452 isError: true

453 };

454 }

455 }

456 );

457 ```

458</CodeGroup>

459 

460<h2 id="return-images-and-resources">

461 傳回影像和資源

462</h2>

463 

464工具結果中的 `content` 陣列接受 `text`、`image` 和 `resource` 區塊。您可以在同一回應中混合它們。

465 

466<h3 id="images">

467 影像

468</h3>

469 

470影像區塊以 base64 編碼的方式內聯攜帶影像位元組。沒有 URL 欄位。若要傳回位於 URL 的影像,請在處理程式中擷取它、讀取回應位元組,並在傳回前進行 base64 編碼。結果作為視覺輸入進行處理。

471 

472| 欄位 | 類型 | 備註 |

473| :--------- | :-------- | :------------------------------------------------------ |

474| `type` | `"image"` | |

475| `data` | `string` | Base64 編碼的位元組。僅原始 base64,沒有 `data:image/...;base64,` 前綴 |

476| `mimeType` | `string` | 必需。例如 `image/png`、`image/jpeg`、`image/webp`、`image/gif` |

477 

478<CodeGroup>

479 ```python Python theme={null}

480 import base64

481 import httpx

482 

483 

484 # Define a tool that fetches an image from a URL and returns it to Claude

485 @tool("fetch_image", "Fetch an image from a URL and return it to Claude", {"url": str})

486 async def fetch_image(args):

487 async with httpx.AsyncClient() as client: # Fetch the image bytes

488 response = await client.get(args["url"])

489 

490 return {

491 "content": [

492 {

493 "type": "image",

494 "data": base64.b64encode(response.content).decode(

495 "ascii"

496 ), # Base64-encode the raw bytes

497 "mimeType": response.headers.get(

498 "content-type", "image/png"

499 ), # Read MIME type from the response

500 }

501 ]

502 }

503 ```

504 

505 ```typescript TypeScript theme={null}

506 tool(

507 "fetch_image",

508 "Fetch an image from a URL and return it to Claude",

509 {

510 url: z.string().url()

511 },

512 async (args) => {

513 const response = await fetch(args.url); // Fetch the image bytes

514 const buffer = Buffer.from(await response.arrayBuffer()); // Read into a Buffer for base64 encoding

515 const mimeType = response.headers.get("content-type") ?? "image/png";

516 

517 return {

518 content: [

519 {

520 type: "image",

521 data: buffer.toString("base64"), // Base64-encode the raw bytes

522 mimeType

523 }

524 ]

525 };

526 }

527 );

528 ```

529</CodeGroup>

530 

531<h3 id="resources">

532 資源

533</h3>

534 

535資源區塊嵌入由 URI 識別的內容片段。URI 是 Claude 參考的標籤;實際內容位於區塊的 `text` 或 `blob` 欄位中。當您的工具產生稍後按名稱尋址有意義的內容時使用此項,例如生成的檔案或來自外部系統的記錄。

536 

537| 欄位 | 類型 | 備註 |

538| :------------------ | :----------- | :----------------------------- |

539| `type` | `"resource"` | |

540| `resource.uri` | `string` | 內容的識別碼。任何 URI 配置 |

541| `resource.text` | `string` | 內容,如果是文字。提供此項或 `blob`,不要同時提供兩者 |

542| `resource.blob` | `string` | 內容 base64 編碼,如果是二進位 |

543| `resource.mimeType` | `string` | 選用 |

544 

545此範例顯示從工具處理程式內傳回的資源區塊。URI `file:///tmp/report.md` 是 Claude 稍後可以參考的標籤;SDK 不會從該路徑讀取。

546 

547<CodeGroup>

548 ```typescript TypeScript theme={null}

549 return {

550 content: [

551 {

552 type: "resource",

553 resource: {

554 uri: "file:///tmp/report.md", // Label for Claude to reference, not a path the SDK reads

555 mimeType: "text/markdown",

556 text: "# Report\n..." // The actual content, inline

557 }

558 }

559 ]

560 };

561 ```

562 

563 ```python Python theme={null}

564 return {

565 "content": [

566 {

567 "type": "resource",

568 "resource": {

569 "uri": "file:///tmp/report.md", # Label for Claude to reference, not a path the SDK reads

570 "mimeType": "text/markdown",

571 "text": "# Report\n...", # The actual content, inline

572 },

573 }

574 ]

575 }

576 ```

577</CodeGroup>

578 

579這些區塊形狀來自 MCP `CallToolResult` 類型。請參閱 [MCP 規格](https://modelcontextprotocol.io/specification/2025-06-18/server/tools#tool-result)以取得完整定義。

580 

581<h2 id="return-structured-data">

582 傳回結構化資料

583</h2>

584 

585`structuredContent` 是結果上的選用 JSON 物件,與 `content` 陣列分開。使用它傳回原始值,Claude 可以將其讀取為確切欄位,而不是從文字字串或影像中解析它們。

586 

587設定 `structuredContent` 時,Claude 接收 JSON 加上 `content` 中的任何影像或資源區塊。`content` 中的文字區塊不會轉發,因為假設它們複製結構化資料。下面的範例將圖表呈現為影像區塊,並從同一處理程式在 `structuredContent` 中傳回其背後的資料點。

588 

589```typescript TypeScript theme={null}

590return {

591 content: [

592 {

593 type: "image",

594 data: chartPngBuffer.toString("base64"),

595 mimeType: "image/png"

596 }

597 ],

598 structuredContent: {

599 series: "temperature_2m",

600 unit: "fahrenheit",

601 points: [62.1, 63.4, 65.0, 64.2]

602 }

603};

604```

605 

606<Note>

607 Python `@tool` 裝飾器僅從處理程式的傳回字典轉發 `content` 和 `is_error`。若要從 Python 傳回 `structuredContent`,請改為執行[獨立 MCP 伺服器](/zh-TW/agent-sdk/mcp)。

608</Note>

609 

610<h2 id="example-unit-converter">

611 範例:單位轉換器

612</h2>

613 

614此工具在長度、溫度和重量的單位之間轉換值。使用者可以詢問「將 100 公里轉換為英里」或「72°F 是多少攝氏度」,Claude 從請求中選擇正確的單位類型和單位。

615 

616它演示了兩種模式:

617 

618* **列舉結構描述:** `unit_type` 受限於一組固定值。在 TypeScript 中,使用 `z.enum()`。在 Python 中,字典結構描述不支援列舉,因此需要完整的 JSON Schema 字典。

619* **不支援的輸入處理:** 當找不到轉換對時,處理程式傳回 `isError: true`,以便 Claude 可以告訴使用者出了什麼問題,而不是將失敗視為正常結果。

620 

621<CodeGroup>

622 ```python Python theme={null}

623 from typing import Any

624 from claude_agent_sdk import tool, create_sdk_mcp_server

625 

626 

627 # z.enum() in TypeScript becomes an "enum" constraint in JSON Schema.

628 # The dict schema has no equivalent, so full JSON Schema is required.

629 @tool(

630 "convert_units",

631 "Convert a value from one unit to another",

632 {

633 "type": "object",

634 "properties": {

635 "unit_type": {

636 "type": "string",

637 "enum": ["length", "temperature", "weight"],

638 "description": "Category of unit",

639 },

640 "from_unit": {

641 "type": "string",

642 "description": "Unit to convert from, e.g. kilometers, fahrenheit, pounds",

643 },

644 "to_unit": {"type": "string", "description": "Unit to convert to"},

645 "value": {"type": "number", "description": "Value to convert"},

646 },

647 "required": ["unit_type", "from_unit", "to_unit", "value"],

648 },

649 )

650 async def convert_units(args: dict[str, Any]) -> dict[str, Any]:

651 conversions = {

652 "length": {

653 "kilometers_to_miles": lambda v: v * 0.621371,

654 "miles_to_kilometers": lambda v: v * 1.60934,

655 "meters_to_feet": lambda v: v * 3.28084,

656 "feet_to_meters": lambda v: v * 0.3048,

657 },

658 "temperature": {

659 "celsius_to_fahrenheit": lambda v: (v * 9) / 5 + 32,

660 "fahrenheit_to_celsius": lambda v: (v - 32) * 5 / 9,

661 "celsius_to_kelvin": lambda v: v + 273.15,

662 "kelvin_to_celsius": lambda v: v - 273.15,

663 },

664 "weight": {

665 "kilograms_to_pounds": lambda v: v * 2.20462,

666 "pounds_to_kilograms": lambda v: v * 0.453592,

667 "grams_to_ounces": lambda v: v * 0.035274,

668 "ounces_to_grams": lambda v: v * 28.3495,

669 },

670 }

671 

672 key = f"{args['from_unit']}_to_{args['to_unit']}"

673 fn = conversions.get(args["unit_type"], {}).get(key)

674 

675 if not fn:

676 return {

677 "content": [

678 {

679 "type": "text",

680 "text": f"Unsupported conversion: {args['from_unit']} to {args['to_unit']}",

681 }

682 ],

683 "is_error": True,

684 }

685 

686 result = fn(args["value"])

687 return {

688 "content": [

689 {

690 "type": "text",

691 "text": f"{args['value']} {args['from_unit']} = {result:.4f} {args['to_unit']}",

692 }

693 ]

694 }

695 

696 

697 converter_server = create_sdk_mcp_server(

698 name="converter",

699 version="1.0.0",

700 tools=[convert_units],

701 )

702 ```

703 

704 ```typescript TypeScript theme={null}

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

706 import { z } from "zod";

707 

708 const convert = tool(

709 "convert_units",

710 "Convert a value from one unit to another",

711 {

712 unit_type: z.enum(["length", "temperature", "weight"]).describe("Category of unit"),

713 from_unit: z

714 .string()

715 .describe("Unit to convert from, e.g. kilometers, fahrenheit, pounds"),

716 to_unit: z.string().describe("Unit to convert to"),

717 value: z.number().describe("Value to convert")

718 },

719 async (args) => {

720 type Conversions = Record<string, Record<string, (v: number) => number>>;

721 

722 const conversions: Conversions = {

723 length: {

724 kilometers_to_miles: (v) => v * 0.621371,

725 miles_to_kilometers: (v) => v * 1.60934,

726 meters_to_feet: (v) => v * 3.28084,

727 feet_to_meters: (v) => v * 0.3048

728 },

729 temperature: {

730 celsius_to_fahrenheit: (v) => (v * 9) / 5 + 32,

731 fahrenheit_to_celsius: (v) => ((v - 32) * 5) / 9,

732 celsius_to_kelvin: (v) => v + 273.15,

733 kelvin_to_celsius: (v) => v - 273.15

734 },

735 weight: {

736 kilograms_to_pounds: (v) => v * 2.20462,

737 pounds_to_kilograms: (v) => v * 0.453592,

738 grams_to_ounces: (v) => v * 0.035274,

739 ounces_to_grams: (v) => v * 28.3495

740 }

741 };

742 

743 const key = `${args.from_unit}_to_${args.to_unit}`;

744 const fn = conversions[args.unit_type]?.[key];

745 

746 if (!fn) {

747 return {

748 content: [

749 {

750 type: "text",

751 text: `Unsupported conversion: ${args.from_unit} to ${args.to_unit}`

752 }

753 ],

754 isError: true

755 };

756 }

757 

758 const result = fn(args.value);

759 return {

760 content: [

761 {

762 type: "text",

763 text: `${args.value} ${args.from_unit} = ${result.toFixed(4)} ${args.to_unit}`

764 }

765 ]

766 };

767 }

768 );

769 

770 const converterServer = createSdkMcpServer({

771 name: "converter",

772 version: "1.0.0",

773 tools: [convert]

774 });

775 ```

776</CodeGroup>

777 

778定義伺服器後,以與天氣範例相同的方式將其傳遞至 `query`。此範例在迴圈中傳送三個不同的提示,以顯示同一工具處理不同的單位類型。對於每個回應,它檢查 `AssistantMessage` 物件(包含 Claude 在該回合期間進行的工具呼叫)並在列印最終 `ResultMessage` 文字之前列印每個 `ToolUseBlock`。這讓您看到 Claude 何時使用工具與從自己的知識回答。

779 

780<CodeGroup>

781 ```python Python theme={null}

782 import asyncio

783 from claude_agent_sdk import (

784 query,

785 ClaudeAgentOptions,

786 ResultMessage,

787 AssistantMessage,

788 ToolUseBlock,

789 )

790 

791 

792 async def main():

793 options = ClaudeAgentOptions(

794 mcp_servers={"converter": converter_server},

795 allowed_tools=["mcp__converter__convert_units"],

796 )

797 

798 prompts = [

799 "Convert 100 kilometers to miles.",

800 "What is 72°F in Celsius?",

801 "How many pounds is 5 kilograms?",

802 ]

803 

804 for prompt in prompts:

805 async for message in query(prompt=prompt, options=options):

806 if isinstance(message, AssistantMessage):

807 for block in message.content:

808 if isinstance(block, ToolUseBlock):

809 print(f"[tool call] {block.name}({block.input})")

810 elif isinstance(message, ResultMessage) and message.subtype == "success":

811 print(f"Q: {prompt}\nA: {message.result}\n")

812 

813 

814 asyncio.run(main())

815 ```

816 

817 ```typescript TypeScript theme={null}

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

819 

820 const prompts = [

821 "Convert 100 kilometers to miles.",

822 "What is 72°F in Celsius?",

823 "How many pounds is 5 kilograms?"

824 ];

825 

826 for (const prompt of prompts) {

827 for await (const message of query({

828 prompt,

829 options: {

830 mcpServers: { converter: converterServer },

831 allowedTools: ["mcp__converter__convert_units"]

832 }

833 })) {

834 if (message.type === "assistant") {

835 for (const block of message.message.content) {

836 if (block.type === "tool_use") {

837 console.log(`[tool call] ${block.name}`, block.input);

838 }

839 }

840 } else if (message.type === "result" && message.subtype === "success") {

841 console.log(`Q: ${prompt}\nA: ${message.result}\n`);

842 }

843 }

844 }

845 ```

846</CodeGroup>

847 

848<h2 id="next-steps">

849 後續步驟

850</h2>

851 

852自訂工具在標準介面中包裝非同步函數。您可以在同一伺服器中混合本頁上的模式:單一伺服器可以並排保存資料庫工具、API 閘道工具和影像呈現器。

853 

854從這裡:

855 

856* 如果您的伺服器增長到數十個工具,請參閱[工具搜尋](/zh-TW/agent-sdk/tool-search)以延遲載入它們,直到 Claude 需要它們。

857* 若要連接到外部 MCP 伺服器(檔案系統、GitHub、Slack)而不是建立自己的,請參閱[連接 MCP 伺服器](/zh-TW/agent-sdk/mcp)。

858* 若要控制哪些工具自動執行與需要核准,請參閱[設定權限](/zh-TW/agent-sdk/permissions)。

859 

860<h2 id="related-documentation">

861 相關文件

862</h2>

863 

864* [TypeScript SDK 參考](/zh-TW/agent-sdk/typescript)

865* [Python SDK 參考](/zh-TW/agent-sdk/python)

866* [MCP 文件](https://modelcontextprotocol.io)

867* [SDK 概觀](/zh-TW/agent-sdk/overview)