セルフホスト型サンドボックスでのカスタムツール
セルフホスト型サンドボックスのワーカーからカスタムツールを提供し、トンネルを実行せずにネットワーク内のMCPサーバーをカスタムツールとしてラップします。
カスタムツールは、独自のコードが実行するツールです。エージェントは agent.custom_tool_use イベントを発行し、対応する user.custom_tool_result を待ちます。ワーカーがそのコードになることができます。ワーカーはサンドボックス内で実行されるため、ツールはサンドボックスに設定した内部サービス、認証情報、ネットワークの「egress」(エグレス)にアクセスでき、それ以外にはアクセスしません。
環境キーによってカスタムツールの結果の送信が認可されるため、Claude APIキーをワーカーホストに置く必要はありません。
カスタムツールを提供する
エージェントでツールを宣言する
エージェントの
toolsにcustomエントリを追加し、そのnameをワーカーが登録するツールと一致させます。宣言の完全な形式については、カスタムツールを参照してください。{ "type": "custom", "name": "get_order_status", "description": "Look up an order in the internal fulfillment system by order ID.", "input_schema": { "type": "object", "properties": { "order_id": { "type": "string", "description": "The order ID" } }, "required": ["order_id"] } }ワーカーに実装を登録する
組み込みツールセットと並べて、ワーカーの
toolsファクトリ(EnvironmentWorkerを参照)を通じてツールを渡します。import asyncio import os from anthropic import AsyncAnthropic, beta_async_tool from anthropic.lib.environments import EnvironmentWorker from anthropic.lib.tools.agent_toolset import beta_agent_toolset_20260401 @beta_async_tool async def get_order_status(order_id: str) -> str: """Look up an order in the internal fulfillment system by order ID.""" # ワーカーホスト上で実行されます:サンドボックスから到達できるものは何でも呼び出せます。 return f"Order {order_id}: shipped" async def main() -> None: environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"] environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"] async with AsyncAnthropic(auth_token=environment_key) as client: await EnvironmentWorker( client, environment_id=environment_id, environment_key=environment_key, workdir="/workspace", tools=lambda env: [*beta_agent_toolset_20260401(env), get_order_status], ).run() asyncio.run(main())
ワーカーは、自身に登録されたツールにのみ応答します。ツールがエージェントで宣言されているものの、それを提供するワーカーやクライアントが存在しない場合、セッションは requires_action の停止理由で一時停止します。何かが結果を送信するまで、セッションは一時停止したままになります。イベントフローについては、カスタムツール呼び出しの処理を参照してください。
MCPサーバーをカスタムツールとしてラップする
MCPコネクタは、Anthropic側からMCPサーバーに接続します。そのため、サーバーは、直接またはMCPトンネルを介して、Anthropicが到達できるHTTPエンドポイントを公開する必要があります。
自社のネットワークからしか到達できないサーバーを使用するには、代わりにワーカーをMCPクライアントにし、サーバーのツールをカスタムツールとして宣言します。MCPサーバーには、ネットワーク外部からのインバウンド接続は必要ありません。Anthropicが受け取るのは、エージェントで宣言したツール定義、各呼び出しの入力、そしてワーカーが送り返す結果です。
実行時、モデルはラップされたツールを他のカスタムツールと同様に呼び出します。
- エージェントが
agent.custom_tool_useイベントを発行します。 - サンドボックス内のワーカーが、開いているMCPセッションを介して、ネットワーク上のサーバーに呼び出しを転送します。
- ワーカーがサーバーの応答を
user.custom_tool_resultとして送信します。
MCP SDKをインストールする
SDKのクライアントサイドのMCPヘルパーは、サーバーのツールをワーカーが受け付ける実行可能なツールに変換します。Anthropic SDKと併せてMCP SDKをインストールしてください:pip install "anthropic[mcp]" "mcp>=1.24"。
例では認証なしで接続しています。認証情報を送信するには、MCPトランスポートに渡す http_client を設定してください。
ツールを宣言して提供する
エージェントでサーバーのツールを宣言する
MCPサーバーのツールを一覧表示し、それぞれを
customツールとして宣言します。MCPのname、description、inputSchemaは、カスタムツールのフィールドに1対1で対応します。サーバーがツール一覧をページ分割している場合は、すべてのページを宣言してください。ワーカーも同じページを一覧表示する必要があります。import asyncio from typing import Any, cast from anthropic import AsyncAnthropic from anthropic.types.beta import BetaManagedAgentsCustomToolParams from mcp import ClientSession, types # mcp >= 1.24 が必要です(streamablehttp_client が streamable_http_client に改名されました)。 from mcp.client.streamable_http import streamable_http_client MCP_SERVER_URL = "http://mcp.internal.example.com:8000/mcp" def to_custom_tool(tool: types.Tool) -> BetaManagedAgentsCustomToolParams: # MCPのフィールドはカスタムツール宣言に1対1で対応します。cast は # スキーマ辞書をそのままSDKの型付きパラメータに渡します。 return { "type": "custom", "name": tool.name, "description": tool.description or tool.name, "input_schema": cast(Any, tool.inputSchema), } async def main() -> None: # これはワーカーホストではなく、エージェントを作成する場所で実行してください。 # Claude APIキー(ANTHROPIC_API_KEY)で認証します。 async with ( streamable_http_client(MCP_SERVER_URL) as (read, write, _), ClientSession(read, write) as mcp_session, AsyncAnthropic() as client, ): await mcp_session.initialize() listed = await mcp_session.list_tools() agent = await client.beta.agents.create( name="Internal tools agent", model="claude-opus-5-5", tools=[ {"type": "agent_toolset_20260401"}, *[to_custom_tool(tool) for tool in listed.tools], ], ) print(agent.id) asyncio.run(main())ワーカーからツールを提供する
起動時に同じMCPサーバーに接続し、
async_mcp_toolでそのツールを変換して、beta_agent_toolset_20260401と並べて登録します。ワーカーが稼働している間は、1つのMCPセッションを開いたままにしてください。import asyncio import os from datetime import timedelta from anthropic import AsyncAnthropic from anthropic.lib.environments import EnvironmentWorker from anthropic.lib.tools.agent_toolset import beta_agent_toolset_20260401 from anthropic.lib.tools.mcp import async_mcp_tool from mcp import ClientSession # mcp >= 1.24 が必要です(streamablehttp_client が streamable_http_client に改名されました)。 from mcp.client.streamable_http import streamable_http_client MCP_SERVER_URL = "http://mcp.internal.example.com:8000/mcp" async def main() -> None: environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"] environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"] # 起動時に一度だけ MCP サーバーに接続し、ワーカーの存続期間中は # セッションを開いたままにします。タイムアウトにより、ハングしたツール呼び出しは # 停止したままになるのではなくエラー結果として返されます。 async with ( streamable_http_client(MCP_SERVER_URL) as (read, write, _), ClientSession(read, write, read_timeout_seconds=timedelta(seconds=60)) as mcp_session, AsyncAnthropic(auth_token=environment_key) as client, ): await mcp_session.initialize() listed = await mcp_session.list_tools() mcp_tools = [async_mcp_tool(tool, mcp_session) for tool in listed.tools] await EnvironmentWorker( client, environment_id=environment_id, environment_key=environment_key, workdir="/workspace", tools=lambda env: [*beta_agent_toolset_20260401(env), *mcp_tools], ).run() asyncio.run(main())
制限と動作
ツールは宣言されるものであり、実行時に検出されるものではない
ワーカーは起動時に一度だけMCPサーバーのツールを一覧表示し、実行中のセッションにツールを追加することはできません。サーバーのツールが変更された場合は、次の手順を実行します。
- エージェントで、またはエージェント設定の更新を通じてアイドル状態のセッションで、ツールを再度宣言します。
- ワーカーを再起動します。
宣言はManaged Agents APIに適合している必要がある
MCPヘルパーはサーバーの名前と説明を保持し、ほとんどのスキーマは変更されずにそのまま渡されます。宣言が次のいずれかのルールに違反する場合は、名前の変更、切り詰め、またはインライン化を行ってください。
| フィールド | ルール |
|---|---|
name | エージェントごとに一意。英字、数字、アンダースコア、ハイフンで1〜128文字。bash や read などの組み込みエージェントツールと一致させることや、予約済みの mcp__ プレフィックスを使用することはできません。 |
description | 必須で、空にはできません。 |
input_schema | additionalProperties や title など、MCPサーバーが一般的に出力するJSON Schemaキーワードを受け付けます。$ref などの参照キーワードはどこにあっても拒否され、トップレベルの oneOf、anyOf、allOf も拒否されます。プロパティ名には英字、数字、アンダースコア、ドット、ハイフンを使用し、1〜64文字です。 |
エージェントの tools 配列 | 最大128エントリ。ラップされた各ツールが1エントリとなり、組み込みツールセットがさらに1エントリとなります。 |
次の2つのケースでは追加の作業が必要です。
- 2つのサーバーが同じツール名を公開している場合: プレフィックス付きの名前でラッパーを自分で定義し、そのラッパーからサーバーの元のツール名を呼び出すようにします。
- pydanticなどのジェネレーターがスキーマを
$defsに分解している場合: ツールを宣言する前に、それらのスキーマをインライン化します。
ツールの失敗はエラーのツール結果として表面化する
MCPサーバーがツールエラーを報告すると、ワーカーはモデルが対応できるエラーのツール結果を送信します。オーディオブロックやリソースリンクなど、ツール結果に相当するものがないMCPコンテンツも、エラーとして表面化します。
Pythonワーカーの例で read_timeout_seconds を使用しているように、MCPクライアントにタイムアウトを設定すると、より迅速かつ明確に失敗させることができます。タイムアウトがない場合に何が起こるかについては、ラップされたMCPツール呼び出しがハングするを参照してください。
自社で運用しているか信頼できるサーバーのみをラップする
ラップされたツールの名前、説明、結果は、他のツールと同様にモデルのコンテキストに入ります。これらは信頼できない入力であり、ワーカーホスト上の bash を含め、エージェントが他のツールで行う動作に影響を与える可能性があります。エージェントに使用させるつもりのツールのみを宣言してください。
権限ポリシーは適用されない
権限ポリシーは、組み込みツールセットとMCPツールセットを管理します。ワーカーはモデルが行うラップされたツール呼び出しをすべて実行するため、承認ステップが必要な場合は独自のツールコードに組み込んでください。
Was this page helpful?