ツールは、モデルがタスク実行中に呼び出せる能力です。Qoder Agent SDK は次の2種類のツールをサポートします。
組み込みツールを使う場合、ツール自体を実装する必要はありません。options で、このセッションが見えるツール、事前承認するツール、禁止するツールを制御するだけです。
よく使う組み込みツールには
モデルに自分の業務能力を呼び出させたい場合は、カスタムツールを定義します。たとえば注文検索、内部ナレッジベース検索、承認システム呼び出し、読み取り専用データベースアクセスなどです。
カスタムツールは通常、次の3ステップで構成します。
まず完全な最小例を示し、その後で各ステップの設定項目を説明します。
このステップでは、ツール名、説明、入力パラメータ、実行ロジック、ツールメタ情報を定義します。
TypeScript の
Python のツールハンドラーは async 関数でなければならず、通常は
2つの SDK は入力 schema の書き方が異なりますが、最終的にはどちらも MCP プロトコルの JSON Schema に正規化されます。
TypeScript:Zod raw shape——つまりフィールドオブジェクトを渡します。
Python:3つの書き方をサポートします。
書き方1:シンプル dict。少数の単純なパラメーター向けです。key はパラメーター名、value は Python の型で、この書き方ではすべての key が required です。
書き方2:
書き方3:完全な JSON Schema dict。enum、数値範囲、文字列フォーマット制約、ネストされたオブジェクトが必要な場合に使います:
annotations は MCP ツールアノテーションを渡します。SDK はこれを MCP tool 定義に載せ、CLI はスケジューリング、権限、状態表示に利用できます。
よく使うフィールド:
注意:これらのフィールドは権限設定の代わりにはなりません。ツールの実行可否は引き続き
Python の
server を MCP servers 設定に入れると、CLI がその中のツールを発見し、モデルが必要とするときに SDK 経由でハンドラーをコールバックします。
カスタムツールの完全名形式は次のとおりです。
たとえば server 名が
モデルがツールを呼び出すとき、SDK は複数層の権限制御を提供します。次のことを決められます。
これらの方式は組み合わせられます。よくあるパターン:まず
同じツールが許可ルールと禁止ルールの両方に一致した場合、禁止ルールが優先されます。
権限モードは1行の設定でセッション全体のデフォルト権限動作を設定します。
通常のツールでは、ユーザー承認が必要な場合だけ SDK が
よく使う戻り値:
サブ Agent 内でカスタムツールを使う場合も完全ツール名を使います。
すでに hooks 体系を使っている場合は、
ツールハンドラーにはいくつかのエラーパスがあります。
予期可能なビジネス上の失敗にはエラーフラグ(TypeScript は
エラーフラグが適した場面:
ハンドラーが例外を投げた場合、MCP レイヤーが例外をエラー結果に変換するため、通常のツール例外で agent loop が直接クラッシュすることはありません。ただしモデルには通常例外メッセージしか見えず、明示的なエラーフラグ返却に比べてフォーマットと内容の制御性が劣ります。
推奨:ビジネス上予期可能な失敗にはエラーフラグを使い、本当に予期しない例外のみ throw してください。
Python SDK はランタイムで handler の戻り値をフォールバックチェックします。
ツールハンドラーは MCP の
構造化 JSON 文字列を返すこともできます。モデルが理解し、処理を続けやすくなります。
よく使うコンテンツブロック:
Python 版にはさらに 2 つ注意すべき結果の差異があります。
- 組み込みツール:Qoder CLI が提供します。ファイル読み取り、検索、コマンド実行、サブ Agent 呼び出しなどがあります。
- カスタムツール:SDK 利用者が定義し、インプロセス MCP server としてモデルに公開します——TypeScript は
tool()+createSdkMcpServer()、Python は@tool()デコレーター +create_sdk_mcp_server()を使います。
組み込みツール
組み込みツールを使う場合、ツール自体を実装する必要はありません。options で、このセッションが見えるツール、事前承認するツール、禁止するツールを制御するだけです。
Read、Edit、Write、Bash、Glob、Grep、WebFetch、WebSearch、Agent などがあります。ツール名は基盤の Qoder CLI が決定し、権限設定では CLI がモデルに公開するツール名を使ってください。完全なリスト、名前、入出力構造は SDK References を参照してください。
カスタムツール
モデルに自分の業務能力を呼び出させたい場合は、カスタムツールを定義します。たとえば注文検索、内部ナレッジベース検索、承認システム呼び出し、読み取り専用データベースアクセスなどです。
カスタムツールは通常、次の3ステップで構成します。
- ツールを作成:TypeScript は
tool()、Python は@tool()でasync defハンドラーをデコレートします。 - インプロセス MCP server に登録:
createSdkMcpServer()/create_sdk_mcp_server()。 - options の MCP servers 設定で接続し、権限設定で呼び出しを制御します。
カスタムツール接続手順
まず完全な最小例を示し、その後で各ステップの設定項目を説明します。
ステップ1:ツールを作成する
このステップでは、ツール名、説明、入力パラメータ、実行ロジック、ツールメタ情報を定義します。
パラメーター
TypeScript の tool() は5つ、Python の @tool() デコレーターは4つのパラメーターを取ります:
| パラメーター | 必須 | 意味 |
|---|---|---|
name | はい | 当該 MCP server 内でのツールの一意な識別子 |
description | はい | モデル向けのツール説明。いつ使うか、何をするか、何を返すか |
inputSchema / input_schema | はい | ツール入力パラメーターの定義。TypeScript は Zod raw shape、Python はシンプル dict、TypedDict、完全な JSON Schema dict をサポート |
handler(TypeScript) | はい | 解析済み引数を受け取り CallToolResult を返す非同期実行関数。Python ではデコレートされた async def がハンドラー |
extras.annotations(TypeScript)/ annotations(Python) | いいえ | readOnlyHint、destructiveHint、openWorldHint などの MCP ツールアノテーション |
args dict を1つ受け取ります。ハンドラーが2つ目の位置引数を宣言すると、SDK は ToolInvocationContext を渡します。その signal は asyncio.Event で、CLI が実行中のツール呼び出しをキャンセルするとセットされます。長時間タスクの自発的な停止に適しています:
入力パラメータの設定
2つの SDK は入力 schema の書き方が異なりますが、最終的にはどちらも MCP プロトコルの JSON Schema に正規化されます。
TypeScript:Zod raw shape——つまりフィールドオブジェクトを渡します。z.object(...) ではありません:
| ニーズ | TypeScript の書き方 |
|---|---|
| 必須文字列 | z.string().describe('...') |
| 任意パラメータ | z.string().optional().describe('...') |
| デフォルト値 | z.number().default(5) |
| 列挙値 | z.enum(['docs', 'tickets']) |
| 数値範囲 | z.number().min(1).max(10) |
typing.Annotated でフィールドに説明を追加できます:
| Python の書き方 | JSON Schema の意味 |
|---|---|
str | {"type": "string"} |
int | {"type": "integer"} |
float | {"type": "number"} |
bool | {"type": "boolean"} |
list[str] | 文字列配列 |
dict | オブジェクト |
Annotated[T, "..."] | T のスキーマに description を追加 |
TypedDict。フィールドが多い、省略可能フィールドが必要、型定義を再利用したい場合に適しています。省略可能フィールドは NotRequired を使います(Python 3.11+ は typing から直接インポート可能、3.10 は typing_extensions が必要):
ツールメタ情報の設定
annotations は MCP ツールアノテーションを渡します。SDK はこれを MCP tool 定義に載せ、CLI はスケジューリング、権限、状態表示に利用できます。
| フィールド | 型 | 意味 |
|---|---|---|
title | string | ツールの人間可読なタイトル |
readOnlyHint | boolean | ツールが読み取り専用で、状態を変更しないことを示す |
destructiveHint | boolean | ツールがデータを変更・削除する可能性を示す |
openWorldHint | boolean | ツールが外部システムやネットワークにアクセスすることを示す |
maxResultSizeChars(Python) | int | Python SDK が _meta["anthropic/maxResultSizeChars"] 経由で CLI に渡し、ツール戻り値の長さ制限を緩和 |
tools、allow/deny ルール、権限モード、権限コールバック、hooks が決めます。MCP status にエコーされる annotations のフィールド名は、MCP 本来の *Hint 名ではなく、CLI が投影した readOnly、destructive、openWorld になる場合があります。ホスト UI で表示が必要なら、自前のツール定義側でマッピングを保持してください。
ステップ2:MCP server に登録する
createSdkMcpServer() / create_sdk_mcp_server() は1つ以上のツールを同一プロセスの MCP server として登録します。server 名は完全ツール名の一部になるため、短く安定した名前を推奨します。
| フィールド | 設定例 | 説明 |
|---|---|---|
name | kb、orders など | server 名。mcp__{name}__{tool} の完全ツール名を構成します |
version | '1.0.0' など | 情報用バージョン。省略できます |
tools | [searchDocs, lookupOrder] | この server に登録するツール一覧 |
create_sdk_mcp_server() は同期バリデーションを行います:server 名 / tool 名 / tool 説明は空でない文字列であること、同一 server 内で tool 名が重複しないこと。
ステップ3:query() に接続する
server を MCP servers 設定に入れると、CLI がその中のツールを発見し、モデルが必要とするときに SDK 経由でハンドラーをコールバックします。
orders、tool 名が lookup_order なら、完全ツール名は mcp__orders__lookup_order です。この完全名はツールの許可/拒否リスト、権限コールバック、hooks matcher、サブ Agent の tools 設定で使われます。
Python の QoderSDKClient によるマルチターンセッションも同じ mcp_servers 設定を使います:
tool 権限の制御
モデルがツールを呼び出すとき、SDK は複数層の権限制御を提供します。次のことを決められます。
- このセッションに提供するツール。
- デフォルトで許可するツール。
- 明示的に禁止するツール。
- ツールに確認が必要なとき、アプリケーションが判断するかどうか。
権限制御方式の概要
| 方式(TypeScript / Python) | 役割 | 粒度 | 適した場面 |
|---|---|---|---|
tools | このセッションに見えるツール集合を制限 | セッション | モデルに見えるツールを元から絞りたい |
allowedTools / allowed_tools、disallowedTools / disallowed_tools | 特定ツールの事前承認または禁止 | ツール単位 | 許可・禁止するツールが明確な場合 |
permissionMode / permission_mode | セッション全体のデフォルト権限ポリシーを設定 | グローバル | plan モード、編集自動承認、権限スキップなどの素早い切り替え |
canUseTool / can_use_tool | ツールにユーザー確認が必要なときアプリケーションのコードを呼び出す | 呼び出し単位 | ツール入力から判断する、または AskUserQuestion を処理する |
hooks.PreToolUse | hooks ライフサイクルでツール呼び出しをインターセプト | 呼び出し | hooks 体系を使っており、監査やブロックを統一したい |
tools で可視ツールセットを絞り、allow/deny ルールで静的ルールを設定し、最後に権限コールバックで引数レベルの判断を行います。
方式1:ツールセットと allow/deny ルール
tools はセッションの可視ツールセットを制御し、allow/deny ルールは権限を制御します。カスタム MCP ツールは完全ツール名を使ってください。
方式2:権限モード
権限モードは1行の設定でセッション全体のデフォルト権限動作を設定します。
| モード | 効果 |
|---|---|
default | 標準の権限動作。機密性の高い操作はルールまたはランタイムポリシーに従って処理 |
acceptEdits | ファイル編集系の操作を自動承認。他の機密操作は引き続き権限ポリシーに従う |
bypassPermissions | 権限チェックをスキップ。明示的なスキップ確認も同時に必要 |
yolo | bypassPermissions の互換エイリアス。同じく明示的な確認が必要 |
plan | 計画モード。まずモデルに方案を出させる用途に適する |
dontAsk | 対話的確認なし。事前承認もルール許可もない操作は拒否される |
auto | ランタイムが allow / deny を自動判断 |
方式3:権限コールバック
通常のツールでは、ユーザー承認が必要な場合だけ SDK が canUseTool / can_use_tool を呼び出します。すでに許可・拒否されている、または権限モードで自動処理された通常のツールは呼び出しません。AskUserQuestion は例外です。コールバック設定後、ユーザー操作が明示的に禁止されていなければ、実際の回答を得るために引き続き呼び出されます。完全な規則と回答形式は承認とユーザー入力を参照してください。
| 戻り値 | 効果 |
|---|---|
| allow | 元の引数で実行を許可 |
| allow + 更新後の入力 | ツール引数を置き換えて実行を許可 |
deny + message | 実行を拒否。モデルは理由を見て別の方法を試せる |
deny + message + interrupt: true | 拒否し、現在の agent loop を中断 |
方式4:hooks.PreToolUse
すでに hooks 体系を使っている場合は、PreToolUse でツール呼び出しを統一的にインターセプトまたは監査できます。
PreToolUse の permissionDecision は allow、deny、ask、defer のいずれかです。より完全な権限戦略は 権限制御 を参照してください。
SDK が tool のエラー戻り値を処理する方法
ツールハンドラーにはいくつかのエラーパスがあります。
ビジネス上の失敗:明示的なエラーフラグを返す
予期可能なビジネス上の失敗にはエラーフラグ(TypeScript は isError: true、Python は is_error: True)の返却を推奨します。SDK はこの結果を MCP CallToolResult に変換して CLI に渡し、モデルは失敗内容を見てリトライや別の方法を選べます。
- パラメータは正しいが、業務上の結果がない。たとえば注文が存在しない場合。
- セキュリティポリシーが実行を拒否する。たとえば
SELECTクエリだけを許可する場合。 - 外部サービスが理解可能な業務エラーを返す場合。
予期しない例外:handler が throw する
ハンドラーが例外を投げた場合、MCP レイヤーが例外をエラー結果に変換するため、通常のツール例外で agent loop が直接クラッシュすることはありません。ただしモデルには通常例外メッセージしか見えず、明示的なエラーフラグ返却に比べてフォーマットと内容の制御性が劣ります。
不正な戻り値:SDK がエラーにラップ(Python)
Python SDK はランタイムで handler の戻り値をフォールバックチェックします。
Noneを返す:handler は"content"を含む dict を返す必要があるという内容のエラーテキストに変換されます。- 非 dict(文字列、数値、リストなど)を返す:テキスト content に変換され、
isError=Trueがマークされます。 "content"を持たない dict を返す:実際のキー一覧を含むエラーテキストに変換されます。- サポートされていない content 型を返す:そのコンテンツブロックはスキップされ、warning ログが記録されます。
Tool 戻り値
ツールハンドラーは MCP の CallToolResult を返します(Python では dict を返し、SDK が変換)。最もよく使うのはテキストコンテンツです:
| 種類 | 形状 | 説明 |
|---|---|---|
| テキスト | { type: 'text', text } | 最も一般的。自然言語または JSON 文字列に適しています |
| 画像 | { type: 'image', data, mimeType } | data は base64 |
| 音声 | { type: 'audio', data, mimeType } | data は base64(TypeScript) |
| リソースリンク | { type: 'resource_link', uri, name?, description?, mimeType? } | 参照可能なリソースを返す。Python ではテキストに降格し、name / uri / description を連結してモデルに渡す |
| 埋め込みリソース | { type: 'resource', resource } | テキストまたはバイナリのリソース内容を返す。Python では埋め込みテキストリソースを TextContent に変換 |
- handler が返す dict のトップレベル
_metaはCallToolResultに透過されません。 - handler がエラーマークを返す際は Python のフィールド名
"is_error": Trueを使用します。MCP/TypeScript 風のisErrorではありません。SDK 内部で MCP の結果にマッピングされます。
よくある落とし穴
- 権限設定でカスタムツールを書くときは、
mcp__server__toolの完全名を使ってください。 - TypeScript では
tool()の第3引数に Zod raw shape を渡します。z.object(...)を渡さないでください。 - Python のシンプル dict スキーマではすべてのフィールドが required です。オプションフィールドが必要な場合は
TypedDict + NotRequiredまたは完全な JSON Schema を使ってください。 - enum、数値範囲、ネストされたオブジェクト、文字列 pattern/format が必要な場合、Python では完全な JSON Schema dict を使ってください。
- Python のハンドラーは
async defで、"content"リストを含む dict を返す必要があります。 - ツールの説明は「いつ使うか、何をするか、何を返すか」を書いてください。
queryやhelperのような曖昧な説明だけでは不十分です。 readOnlyHintはツールメタ情報およびスケジューリングヒントであり、権限スイッチではありません。実行を許可するかどうかは権限設定で決まります。- 大きすぎる万能の業務入口を1つのツールに詰め込まないでください。1つのツールは明確な一種類のアクションを完了するのが理想です。
続きを読む
- Tools Reference:組み込みツールリスト、ツール作成 API、
CallToolResult、組み込みツールの入出力型。 - MCP 統合:インプロセス、stdio、SSE、HTTP、OAuth などの MCP サーバー接続方式。
- 権限制御:権限モード、ツール許可リスト、権限コールバック、権限ルール更新。
- サブ Agent 使用ガイド:異なる Agent に異なるツール集合を使わせる方法。