Tool Gateway / MCP Broker|ツールゲートウェイ・MCP仲介¶
一言で(TL;DR)¶
エージェントから外部ツール・MCP サーバへのすべての呼び出しを単一のゲートウェイ層に集約し、認可・レート制限・入力サニタイズ・監査ログ・動的ツールスコーピングを一元管理します。ツールの追加・削除がエージェント本体のコード変更なしに行える「チョークポイント」を作るパターンです。
解決する問題¶
エージェントが複数の外部ツールや MCP サーバを直接呼び出す構成では、以下の問題が分散して発生します。
ツール/MCP で副作用を持つ(F8)特性により、各ツールが独立にデータ変更・送信・決済などを実行し、呼び出し順序や二重実行の制御が各所に散らばります。プロンプトインジェクション(F14)により、悪意ある入力がツール引数に混入してもツール側で弾けず、権限昇格や意図しない操作につながります。監査対象(F16)の観点では、呼び出しログが各ツールに分散していると「いつ・誰の権限で・なぜこのツールが呼ばれたか」を後から追跡するコストが跳ね上がります。
単一ゲートウェイを挟むことで、認可・入力検証・レート制限・ログ取得をツールごとに個別実装する必要がなくなり、セキュリティポリシーの一貫性と監査の網羅性を確保できます。
選定条件(When to use / When NOT)¶
- 使う条件
- エージェントが呼び出し可能なツールが複数あり、少なくとも一つは副作用を持ちます(書き込み・送信・課金など)。
[input_trust]が低い:ユーザ入力や外部データがツール引数に含まれうるため、サニタイズの一元化が必要です。[accountability]が中〜高:後から「どのツールが、どの引数で、誰の権限で呼ばれたか」を説明する義務があります。- MCP サーバを複数接続しており、それぞれの認可・バージョン管理を統一したい場合です。
- 使わない条件(=代替に倒す)
- ツールが1つだけ、かつ読み取り専用の場合です。ゲートウェイのオーバーヘッドが見合わないため、直接呼び出しで十分です。
- すべてのツールが社内かつ信頼済みで、
[input_trust]が高く[accountability]も低い実験環境の場合です。ゲートウェイは後回しにし、まずプロトタイプを優先します。
駆動変数とチューニング(程度)¶
| 目盛り | 効かなすぎ ⇔ 効きすぎ | 決め方 [駆動変数] |
目安(出発点) |
|---|---|---|---|
| 同時露出ツール数 | 仕事ができない ⇔ LLM が選択ミス・幻ツール呼び出し | 文脈に応じて動的スコーピングで必要分だけ露出 [input_trust] |
同時露出は概ね 10〜20 以下。超過時はルーティング層で分割 |
| 認可粒度 | 粗すぎて権限昇格を許す ⇔ 細かすぎて運用負荷・遅延増 | [accountability] が高いほど細粒度(ツール×操作×リソース単位) |
副作用ツールは操作単位で認可。読取ツールはカテゴリ単位でよい |
| レート制限 | 暴走ループでコスト爆発 ⇔ 正当な連続呼び出しをブロック | [input_trust] が低いほど厳格に。コスト感度も加味 |
書込系は概ね 5〜20 req/min/session。読取系は緩めに 60〜120 |
| 入力サニタイズ深度 | インジェクションを素通し ⇔ 正当な入力を過剰拒否 | [input_trust] が低いほど深く。スキーマ検証+値域チェック+パターン除外 |
全ツールでスキーマ検証は必須。外部入力が混ざるツールのみパターン除外を追加 |
| 監査ログ粒度 | 障害・不正時に再現できない ⇔ ストレージコスト爆発 | [accountability] が高いほど全量に近づける |
書込系は全量。読取系は標本(1〜10%)または成功は要約のみ |
相反における立ち位置(相反)¶
- F-15 読取専用 vs 書込可能 → ハイブリッド。ゲートウェイは読取と書込の両方を通しますが、ポリシーの厳しさを非対称にします。読取は C2 Read-Free / Write-Gated の原則に従い比較的自由に、書込はゲートで認可・承認・dry-run を挟みます。この非対称制御を一元的に実現するのがゲートウェイの役割であり、
[input_trust]が低いほど読取側にもサニタイズを強化します。
構造¶
flowchart TD
Agent[エージェント] --> GW[Tool Gateway]
GW --> Scope[動的スコーピング]
Scope --> AuthZ[認可チェック]
AuthZ -->|拒否| Deny[拒否応答]
AuthZ -->|許可| Sanitize[入力サニタイズ]
Sanitize --> RateLimit[レート制限]
RateLimit -->|超過| Throttle[429 応答]
RateLimit -->|通過| Dispatch[ツールディスパッチ]
Dispatch --> MCP_A[MCP Server A]
Dispatch --> MCP_B[MCP Server B]
Dispatch --> Tool_C[REST Tool C]
Dispatch --> Log[監査ログ]
MCP_A --> Res[応答集約]
MCP_B --> Res
Tool_C --> Res
Res --> Agent
ゲートウェイが単一の通過点(チョークポイント)となり、エージェントは個々の MCP サーバやツール API の存在を意識しません。ツールの追加・削除はゲートウェイの設定変更だけで完結します。
実装メモ¶
ゲートウェイのポリシー定義(概念例):
tools:
- name: "db_query"
type: read
auth: category # カテゴリ単位認可
rate_limit: 120/min
sanitize: schema_only
log: sample_10pct
- name: "send_email"
type: write
auth: per_operation # 操作単位認可
rate_limit: 5/min
sanitize: schema + pattern_block
log: full
requires_approval: true # HITL承認
- name: "payment_execute"
type: write
auth: per_resource # リソース単位認可
rate_limit: 3/min
sanitize: schema + pattern_block + value_range
log: full
requires_approval: true
idempotency_key: required
動的スコーピングの最小実装(擬似コード):
def resolve_tools(context: TaskContext) -> list[ToolSpec]:
"""タスク種別・ユーザ権限・会話フェーズに応じて露出ツールを絞る"""
all_tools = registry.get_all()
scoped = [t for t in all_tools if t.matches(context.task_type)]
permitted = [t for t in scoped if authz.check(context.user, t)]
if len(permitted) > MAX_EXPOSED:
# ルーティング層で分割し、メタツール経由で段階的に露出
return group_into_routers(permitted)
return permitted
落とし穴:
- ゲートウェイ自体が単一障害点になります。ヘルスチェックと縮退モード(読取のみ許可など)を設計しておきましょう。
- MCP サーバ間でスキーマが不統一になりがちです。ゲートウェイ層でツール名・引数名の正規化を行い、エージェント側に一貫したインターフェースを提供します。
- 認可とサニタイズをプロンプトで行ってはいけません。「このツールは使わないで」とプロンプトに書いてもインジェクションで迂回されます。認可はコードで強制します(B1 決定論的な殻の原則)。
- レート制限はセッション単位とグローバル単位の二層で設けます。セッション単位だけでは大量セッション攻撃を防げません。
隔離実行と権限リース¶
ゲートウェイを通過するツール呼び出しのうち、特にリスクが高い 2 つのカテゴリ — 任意コード実行と長時間セッションでの権限管理 — には追加の防御層が必要です。
サンドボックスによる隔離実行¶
LLM が生成したコード(Python/Shell/SQL 等)を実行する場合、プロンプトインジェクション(F14) によって悪意あるコードが注入される可能性があります。ゲートウェイは「コード実行が必要か」を判別し、必要な場合は隔離環境(サンドボックス)へルーティングします。
サンドボックスの設計指針は以下のとおりです。
- 隔離強度の選択 —
[input_trust]が低いほど強い隔離を選択します。プロセス隔離 → gVisor → コンテナ → VM の順に強度が上がりますが、起動コストも増大します。外部入力を含む場合はコンテナ以上を推奨します。 - ネットワーク制限 — デフォルトで全外部通信を遮断(deny)し、必要な API エンドポイントのみ許可リストで穴を開けます。DNS リバインディング対策として IP レベルの制御も併用します。
- リソース上限 — CPU(1〜2 コア)、メモリ(256MB〜1GB)、実行時間(30〜120 秒)を設定し、無限ループやメモリ枯渇を防ぎます。A7 期限・予算カスケード と整合させます。
- ファイルシステム — 作業ディレクトリのみ書込可能とし、入力データは読取専用でマウントします。Docker ソケットや
/etc/shadowなどのマウントは禁止です。 - 寿命管理 —
[input_trust]が低いほど短命にします。基本は 1 リクエスト = 1 サンドボックスで、実行後に破棄します。レイテンシが問題になる場合はプリウォームプールで起動コストを緩和します。
サンドボックスからの出力は構造化データ(JSON 等)として抽出し、ログサイズも制限します。出力経由のインジェクション(出力にペイロードを仕込み後続の LLM 呼び出しで実行させる攻撃)にも注意が必要です。
短命権限リース(Capability Lease)¶
エージェントセッションが長時間化すると、初期に付与されたツール権限がそのまま残り続け、インジェクションの標的になります。ゲートウェイはツール実行権限を恒久トークンではなく、短命・スコープ限定のリースとして発行します。
リースの構成要素は以下のとおりです。
- TTL(有効期間) —
[input_trust]が低いほど短く設定します。書込系は 30〜120 秒、読取系は 60〜300 秒が出発点です。 - スコープ — ステップが必要とするツール+リソース単位に絞ります。1 リースに含めるツールは概ね 1〜3 個です。
- 呼び出し回数上限(max_invocations) — 書込系は 1〜3 回、読取系は 5〜20 回が目安です。暴走ループによる被害を回数で封じ込めます。
- 自動失効 — ステップ完了時または TTL 到達時にリースは自動失効します。明示的な revoke は「あればベター」の位置づけで、TTL が最終防衛線です。
リース更新(renewal)時にはポリシーエンジン(E2)を再度呼び出し、セッション中にポリシーが変更された場合にも追従します。更新は最大 2〜3 回に制限します。
サンドボックス内で外部 API アクセスが必要な場合も、リースで権限を限定します。サンドボックスの寿命とリースの TTL を合わせることで、サンドボックス破棄と同時に権限も自動失効します。
効かせる力学(forces)¶
- F8(ツール/MCP 副作用):副作用を持つツール呼び出しがすべてゲートウェイを通過するため、認可漏れ・二重実行・未記録の操作が構造的に排除されます。冪等キーの強制(C4)もゲートウェイ層で一元適用できます。
- F14(プロンプトインジェクション):入力サニタイズと認可をコードで強制し、インジェクションによる権限昇格を防ぎます。動的スコーピングにより、そもそも危険なツールが LLM の選択肢に入らない状態を作れます。サンドボックスにより、インジェクション経由の悪意あるコードもホスト環境から隔離されます。短命リースにより、万が一の漏洩時も被害の時間的・範囲的限定が保証されます。
- F16(監査対象):全呼び出しがゲートウェイを通るため、「いつ・誰の権限で・どの引数で」を単一ログストアに記録できます。トレースID を付与して G2 トレース と接続すればエンドツーエンドの監査証跡になります。
関連・代替¶
- B1 決定論的な殻:殻がゲートウェイ経由でツール呼び出しを制御します。ゲートウェイは殻の一部として機能します。
- C2 Read-Free / Write-Gated:ゲートウェイ内部のポリシーとして読取自由・書込ゲートを実現します。本パターンの具体的なポリシー戦略です。
- C6 Confused Deputy 防御:ゲートウェイがリクエスト元の権限を伝搬し、ツールがエージェントの権限ではなくユーザの権限で動作するようにします。
- E2 Policy-as-Code:ゲートウェイの認可ルールを OPA/Cedar 等のポリシーエンジンに外部化し、デプロイなしでルール変更を可能にします。
[accountability]が高い場合に併用を推奨します。 - G2 構造化トレース:ゲートウェイが発行するトレースIDと接続し、ツール呼び出しをエンドツーエンドで追跡可能にします。
コーディングエージェント向け指示(machine-actionable)¶
このパターンを人間に提案するなら、同時に以下を提案/確認します:
- [ ]
[input_trust]の水準を確認し、動的スコーピングの同時露出ツール数と入力サニタイズ深度を理由を添えて提示したか - [ ]
[accountability]の水準を確認し、認可粒度と監査ログ粒度を導出したか - [ ] 書込ツールがあるなら C2 Read-Free / Write-Gated のポリシー分離を併せて提案したか
- [ ] 長時間セッションがあるなら本パターンの短命権限リース機能で短命権限の発行を検討したか
- [ ] ユーザ権限の伝搬が必要なら C6 Confused Deputy 防御 を併置したか
- [ ]
[accountability]が高いなら E2 Policy-as-Code でポリシー外部化を提案したか - [ ] G2 構造化トレース との接続を設計し、トレースID の付与方針を示したか
- [ ] 目盛り(上表)の値を
[駆動変数]から導き、理由を添えて提示したか - [ ] ゲートウェイの可用性設計(縮退モード・ヘルスチェック)を検討したか