メインコンテンツへスキップ
カスタムツールは Agent SDK を拡張し、Claude が会話中に呼び出せる独自の関数を定義できるようにします。SDK のインプロセス MCP サーバーを使用すると、Claude にデータベース、外部 API、ドメイン固有のロジック、またはアプリケーションが必要とするその他の機能へのアクセスを提供できます。 このガイドでは、入力スキーマとハンドラーを使用してツールを定義し、それらを MCP サーバーにバンドルし、query に渡し、Claude がアクセスできるツールを制御する方法について説明します。また、エラーハンドリング、ツール注釈、および画像などの非テキストコンテンツを返す方法についても説明します。

クイックリファレンス

カスタムツールを作成する

ツールは 4 つの部分で定義され、TypeScript の tool() ヘルパーまたは Python の @tool デコレーターに引数として渡されます。
  • 名前: Claude がツールを呼び出すために使用する一意の識別子。
  • 説明: ツールが何をするかを説明します。Claude はこれを読んで、ツールをいつ呼び出すかを決定します。
  • 入力スキーマ: Claude が提供する必要がある引数。TypeScript では常に Zod スキーマであり、ハンドラーの args は自動的に型付けされます。Python では {"latitude": float} のような名前から型へのマッピングであり、SDK が JSON Schema に変換します。Python デコレーターは、列挙型、範囲、オプションフィールド、またはネストされたオブジェクトが必要な場合、完全な JSON Schema 辞書も受け入れます。
  • ハンドラー: Claude がツールを呼び出すときに実行される非同期関数。検証された引数を受け取り、以下を含むオブジェクトを返す必要があります。
    • content(必須):結果ブロックの配列。各ブロックは "text""image""audio""resource"、または "resource_link"type を持ちます。非テキストブロックについては、画像とリソースを返すを参照してください。
    • structuredContent(オプション):結果をマシン可読データとして保持する JSON オブジェクト。content と共に返されます。構造化データを返すを参照してください。
    • isError(オプション):ツール障害を通知するために true に設定し、Claude が対応できるようにします。エラーを処理するを参照してください。
ツールを定義した後、createSdkMcpServer(TypeScript)または create_sdk_mcp_server(Python)でサーバーにラップします。サーバーはアプリケーション内でインプロセスで実行され、別のプロセスとしては実行されません。

天気ツールの例

この例は get_temperature ツールを定義し、MCP サーバーにラップします。ツールのセットアップのみを行います。query に渡して実行するには、以下の カスタムツールを呼び出すを参照してください。
完全なパラメーター詳細については、tool() TypeScript リファレンスまたは @tool Python リファレンスを参照してください。JSON Schema 入力形式と戻り値の構造を含みます。
パラメーターをオプションにするには:TypeScript では、Zod フィールドに .default() を追加します。Python では、辞書スキーマはすべてのキーを必須として扱うため、パラメーターをスキーマから除外し、説明文字列で言及し、ハンドラーで args.get() で読み取ります。以下の get_precipitation_chance ツールは両方のパターンを示しています。

カスタムツールを呼び出す

作成した MCP サーバーを mcpServers オプション経由で query に渡します。mcpServers のキーは各ツールの完全修飾名の {server_name} セグメントになります:mcp__{server_name}__{tool_name}。その名前を allowedTools にリストして、ツールが許可プロンプトなしで実行されるようにします。 これらのスニペットは、上記の例weatherServer を再利用して、特定の場所の天気について Claude に尋ねます。

さらにツールを追加する

サーバーは tools 配列にリストされた数だけのツールを保持します。複数のツールがサーバーにある場合、allowedTools で各ツールを個別にリストするか、ワイルドカード mcp__weather__* を使用してサーバーが公開するすべてのツールをカバーできます。 以下の例は、天気ツールの例weatherServer に 2 番目のツール get_precipitation_chance を追加し、両方のツールを配列で再構築します。
この配列内のすべてのツールは、毎ターン、コンテキストウィンドウスペースを消費します。数十のツールを定義している場合は、ツール検索を参照して、代わりにオンデマンドで読み込みます。

ツール注釈を追加する

ツール注釈は、ツールの動作を説明するオプションのメタデータです。TypeScript の tool() ヘルパーの 5 番目の引数として、または Python の @tool デコレーターの annotations キーワード引数として渡します。すべてのヒントフィールドはブール値です。 注釈はメタデータであり、強制ではありません。readOnlyHint: true でマークされたツールは、ハンドラーがそれを行う場合、ディスクに書き込むことができます。注釈をハンドラーに正確に保ちます。 この例は、天気ツールの例get_temperature ツールに readOnlyHint を追加します。
TypeScript または Python リファレンスで ToolAnnotations を参照してください。

ツールアクセスを制御する

天気ツールの例はサーバーを登録し、allowedTools にツールをリストしました。このセクションでは、ツール名がどのように構成されるか、および複数のツールがある場合や組み込みを制限したい場合にアクセスをスコープする方法について説明します。

ツール名形式

MCP ツールが Claude に公開されるとき、それらの名前は特定の形式に従います。
  • パターン:mcp__{server_name}__{tool_name}
  • 例:weather サーバーの get_temperature という名前のツールは mcp__weather__get_temperature になります

許可されたツールを設定する

tools オプションと許可/禁止リストは 2 つのレイヤーに影響します。可用性はツールが Claude のコンテキストに表示されるかどうかを制御し、許可は Claude がそれを試みた後に呼び出しが承認されるかどうかを制御します。tools と裸の名前の disallowedTools エントリは可用性を変更します。allowedTools とスコープされた disallowedTools ルールは許可のみを変更します。 組み込みを完全に削除するには、tools から省略するか、disallowedTools(Python:disallowed_tools)に裸の名前をリストします。どちらもツールをコンテキストから外すため、Claude はそれを試みることはありません。スコープされた disallowedTools ルールは一致する呼び出しをブロックしますが、ツールを表示したままにするため、Claude はそれを試みるターンを無駄にする可能性があります。完全な評価順序については、許可を設定するを参照してください。

エラーを処理する

ハンドラーエラーはエージェントループを停止しません。SDK のインプロセス MCP サーバーはキャッチされない例外をキャッチし、エラー結果として返すため、エラーをどのように報告するかによって Claude が読む内容が決まります。クエリが失敗するかどうかではなく: どちらの場合も Claude は再試行したり、別のツールを試したり、失敗を説明したりできます。生の例外メッセージが Claude が対応するのに十分でない場合は、自分でエラーをキャッチしてください。 以下の例は、ハンドラー内で 2 種類の障害をキャッチし、Claude が読むエラーメッセージを作成します。200 以外の HTTP ステータスは応答からキャッチされ、エラー結果として返されます。ネットワークエラーまたは無効な JSON は、周囲の try/except(Python)または try/catch(TypeScript)でキャッチされ、エラー結果としても返されます。どちらの場合も Claude は、生の例外文字列ではなく、失敗を説明するメッセージを受け取ります。

画像とリソースを返す

ツール結果の content 配列は textimageaudioresource、および resource_link ブロックを受け入れます。同じ応答でそれらを混ぜることができます。TypeScript では、オーディオブロックはディスクに保存され、Claude は保存されたファイルパスを含むテキストブロックを受け取ります。Python では、SDK はツール結果からオーディオブロックを削除し、警告をログに記録します。リソースリンクブロックはリンクの名前、URI、および説明を含むテキストブロックに変換されます。

画像

画像ブロックは画像バイトをインラインで、base64 としてエンコードされた状態で運びます。URL フィールドはありません。URL に存在する画像を返すには、ハンドラーで取得し、応答バイトを読み取り、返す前に base64 エンコードします。結果は視覚入力として処理されます。

リソース

リソースブロックは URI で識別されるコンテンツを埋め込みます。URI は Claude が参照するためのラベルです。実際のコンテンツはブロックの text または blob フィールドに含まれます。これは、生成されたファイルや外部システムのレコードなど、後で名前で対処することが理にかなっているツールが生成するものを使用します。 この例は、ツールハンドラー内から返されるリソースブロックを示しています。URI file:///tmp/report.md は Claude が後で参照できるラベルです。SDK はそのパスから読み取りません。
これらのブロック形状は MCP CallToolResult 型から来ています。完全な定義については、MCP 仕様を参照してください。

構造化データを返す

structuredContent は結果のオプションの JSON オブジェクトで、content 配列とは別です。テキスト文字列または画像から解析する代わりに、Claude が正確なフィールドとして読み取ることができる生の値を返すために使用します。 structuredContent が設定されると、Claude は JSON と content からの任意の画像またはリソースブロックを受け取ります。content のテキストブロックは転送されません。構造化データを複製すると想定されるためです。以下の例は、チャートを画像ブロックとしてレンダリングし、同じハンドラーから structuredContent でそれの背後にあるデータポイントを返します。
TypeScript
Python @tool デコレーターはハンドラーの戻り辞書から contentis_error のみを転送します。Python から structuredContent を返すには、インプロセス SDK サーバーの代わりに スタンドアロン MCP サーバーを実行します。

例:単位変換ツール

このツールは長さ、温度、重量の単位間で値を変換します。ユーザーは「100 キロメートルをマイルに変換」または「72°F は摂氏何度か」と尋ねることができ、Claude はリクエストから正しい単位タイプと単位を選択します。 2 つのパターンを示しています。
  • 列挙型スキーマ: unit_type は固定値のセットに制限されます。TypeScript では z.enum() を使用します。Python では、辞書スキーマは列挙型をサポートしないため、完全な JSON Schema 辞書が必要です。
  • サポートされていない入力処理: 変換ペアが見つからない場合、ハンドラーは isError: true を返すため、Claude はユーザーに何が間違っていたかを伝えることができ、失敗を通常の結果として扱いません。
サーバーが定義されたら、天気の例と同じ方法で query に渡します。この例は、同じツールが異なる単位タイプを処理することを示すために、ループで 3 つの異なるプロンプトを送信します。各応答について、AssistantMessage オブジェクト(Claude がそのターン中に行ったツール呼び出しを含む)を検査し、最終的な ResultMessage テキストを出力する前に各 ToolUseBlock を出力します。これにより、Claude がツールを使用しているのか、独自の知識から答えているのかを確認できます。

次のステップ

カスタムツールは非同期関数を標準インターフェースにラップします。このページのパターンを同じサーバーで混ぜることができます。単一のサーバーは、データベースツール、API ゲートウェイツール、および画像レンダラーを並べて保持できます。 ここから:
  • サーバーが数十のツールに成長する場合は、ツール検索を参照して、Claude がそれらを必要とするまで読み込みを遅延させます。
  • 独自のツールを構築する代わりに、外部 MCP サーバー(ファイルシステム、GitHub、Slack)に接続するには、MCP サーバーを接続するを参照してください。
  • どのツールが自動的に実行されるか、承認が必要かを制御するには、許可を設定するを参照してください。