
Durinの内部:MCPリクエストが管理される仕組み
エージェントによるツール呼び出しを1件取り上げ、サインイン済みのリクエストとアクセスチェックから、審査、認証情報の扱い、記録される実行結果まで、Durinの中での流れをたどります。
決定の概要
Durinは、エージェントのツール呼び出しを、従うべき指示ではなく、評価すべきリクエストとして扱います。ゲートウェイが呼び出し元を確認し、組織のランタイムが現在のアクセス権とポリシーを改めてチェックし、独立したブローカーが本人のプロバイダー認可を付加します。変更操作は、実行を試みる前と後にそれぞれ記録されます。Durinを経由するリクエストはこの経路に任せ、直接アクセス、モデル提供元、プロバイダー側の権限については、別の管理策を維持してください。
ツール呼び出しを境界にする
たとえば、エンジニアがコーディングエージェントに、失敗しているテストのチケットを起票するよう頼んだとします。チケットの下書きを作るのは、モデルにとって簡単です。しかし実際に作成するには、実際のシステムのツールを実際のアカウントで呼び出し、ほかの人にも見える変更を残すことになります。Durinはこの呼び出しを、そのまま実行する指示ではなく、ワークスペースが判断するリクエストとして扱います。
Durinは、エージェントクライアントと、ワークスペースが接続したシステムの間に位置します。モデルや、ローカルファイルの読み取り、テストの実行、コードの編集など、エージェントが自身の環境で行う作業は、クライアント側にとどまります。Durinはモデルのホスティングも学習も行いません。Durinが管理するのは、文書の検索、チケットの読み取り、イシューの作成、メッセージの送信など、Durinのエンドポイントを経由して届くツール呼び出しです。
ユーザーはそれぞれ自分専用のエンドポイントから接続します。個人用URLではその人が利用できるすべての接続を使え、接続用URLではクライアントを1つの接続に限定できます。URLはアドレスであり、パスワードではありません。クライアントはそのアドレスに対してOAuthでDurinにサインインし、Durinは検証済みの本人情報から本来のアドレスを導き出して、一致しなければ拒否します。クライアントがプロバイダーのトークンを必要とすることはありません。
エンドポイントの先にある接続は、それぞれ承認済みのシステム1つを表します。プロバイダーがホストするMCPサーバーや、自社で運用するMCPサーバーです。組み込みのDurinサンドボックスは3つ目の種類で、Durinの内部からデモ用の文書やチケットを返し、外部のプロバイダーには一切接続しません。いずれも同じチェックの対象です。
エージェントクライアントとそのモデルはDurinの外にあり、そのエンドポイント専用に発行されたOAuthトークンを付けてツール呼び出しを送ります。ゲートウェイはトークンを検証し、組織を特定します。30秒間有効な署名付きリクエストが呼び出しを組織ランタイムに渡し、ランタイムは現在のアクセス権を再チェックし、ポリシーと審査を適用して、送信前に実行意図を記録します。認証情報ブローカーは、その呼び出しにひも付いた署名付きリクエストを受け取り、判定を再確認して、本人のプロバイダートークンを付加します。エグレスサービスは、リダイレクトや再試行なしに、公開HTTPS経由でリモートMCPサーバーへ送信します。結果はクライアントに返りますが、プロバイダーのトークンは返りません。プロバイダーへの直接アクセスがDurinを通ることはありません。
図を原寸で開く: ツール呼び出しは、ゲートウェイ、組織ランタイム、認証情報ブローカー、エグレスを通過してから、リモートMCPサーバーに届きます。アクセス範囲を広げずにツールを見つける
エージェントがツールを呼び出すには、まずツールを見つける必要があります。標準のtools/listリクエストは、そのユーザーが利用できるプロバイダーのツールをページ単位で返します。カタログが大きい場合に備えて、Durinは3つの検出用ツールを追加しています。durin_list_connectionsは目的の接続を見つけ、durin_list_toolsは許可されたツールの概要を、必要に応じてテキストで絞り込みながら一覧表示し、durin_describe_toolsは正確な名前で指定した最大5つのツールについて、レビュー済みのスキーマを返します。4つ目のdurin_call_toolは、ツール名と引数、冪等キーを指定してツールを実行します。
検出できる内容はアクセス権によって決まりますが、検出できることがアクセスできることを意味するわけではありません。現在のポリシーでブロックされるツールは一覧から除外されます。一方、審査が必要なツールや、呼び出しで指定するリソースによって判定が変わるツールは表示されます。判定が個々のリクエストによって決まるためです。利用できないものがある場合、レスポンスにはサインイン、同意、レビュー、ポリシーによる許可のどれが不足しているかが示されますが、ブロックされたツールの定義は明かされません。接続用URLを使うと、検出と呼び出しはその接続に限定され、どのフィルターでもその範囲を広げることはできません。
一覧を取得した後で、メンバーシップ、ポリシー、接続が変わっている可能性があるため、すべての呼び出しは届いた時点で改めて評価されます。Durinがクライアントに示す指示にも、そのことが明記されています。ツール名を推測で作らないこと、複数の接続が当てはまる場合はどれを使うかを尋ねること、そしてすべての呼び出しが改めてチェックされることを前提にすることです。
1件の呼び出しをステップごとに見る
クライアントがチケット用のツールを呼び出すと、次のように処理されます。各ステップは役割を絞り込んだサービスで実行され、サービス間の受け渡しにはそれぞれ、受け取る側のサービス向けの署名が付きます。
- ゲートウェイが呼び出し元を認証します。OAuthアクセストークンの署名、発行者、オーディエンスを検証したうえで、そのトークンがまだ有効か、どのクライアントに発行されたものかをIDプロバイダーに問い合わせます。この確認はキャッシュを使わず、リクエストのたびに行います。クライアントが自己申告する名前や、トークンに書き込まれたロールは、呼び出し元の特定には一切使われません。
- ゲートウェイは、その本人情報から組織を特定します。ヘッダーやリクエスト本文で指定された組織を使うことはありません。組織のランタイムが、その人が有効なメンバーであることを確認し、現在のロールを返します。
- ゲートウェイは、呼び出しを署名付きの内部リクエストとしてそのランタイムに渡します。このリクエストには組織、環境、ユーザー、ロール、クライアント、操作が明記され、30秒で期限切れになります。ランタイムは、別の組織、環境、操作向けに発行されたリクエストを拒否します。
- ランタイムは、トークンではなく自身の記録と照らし合わせて、現在のアクセス権を再チェックします。対象は、メンバーシップと取り消しの状況、接続の状態とチームの利用範囲、本人のプロバイダー認可、レビュー済みのツール、そして呼び出しの対象リソースです。引数はツールのレビュー済みスキーマに一致し、検査を通過する必要があります。これらのチェックはいずれもフェイルクローズで、確認できなければリクエストは拒否されます。
- ランタイムがワークスペースのルールを適用します。初期設定では、これらのチェックを通過したリクエストは、変更操作も含めて許可されます。管理者は、変更操作に別の管理者の審査を必須にすることも、変更操作を拒否することも、すべてのアクセスを拒否することもできます。チームポリシーやカスタムルールは、判定をより厳しくすることはできても、緩めることはできません。
- 許可された呼び出しについては、ランタイムが実行意図を記録してから、呼び出しを認証情報ブローカーに渡します。ブローカーは、プロバイダーに接続する前に、現在の記録と照らし合わせて判定を再確認します。
- ランタイムが実行結果を記録し、クライアントに結果を返します。
認証と認可は、最初から最後まで分けて扱われます。有効なトークンによってわかるのは誰が呼び出しているかであり、その人が今この呼び出しを行ってよいかどうかを決めるものではありません。それを決めるのはランタイムで、呼び出しの時点で、自ら管理する記録に基づいて判断します。
ランタイムの内部では、組織と環境ごとに1つある調整用のオブジェクト(Cloudflare Durable Object)が、これらのリクエストを1件ずつ処理します。そのため、判定、承認、ポリシー変更、取り消しの処理が互いに割り込むことはありません。呼び出しの評価中にポリシーが変わった場合、その呼び出しは競合として停止し、許可として記録されるものは何もありません。
サーバーが今提供するツールではなく、レビュー済みのツールを実行する
MCPサーバーは、説明や入力スキーマも含め、ツールをいつでも変更できます。管理者がツールをレビューすると、Durinはその定義のダイジェストを記録します。レビューでは、そのツールがデータを読み取るのか変更するのか、どのリソースを扱ってよいか、それらのリソースが引数のどこに現れるかも決めます。Durinは、ツールが読み取り専用であるというサーバー自身のヒントには頼りません。また、新たに検出されたツールは、レビューされるまで無効のままです。
後の検出で異なる定義が返された場合、Durinはレビューが必要な新しいバージョンを作成し、有効なバージョンを一時停止して、その未処理の承認を取り消します。そのユーザー自身が検出した定義がレビュー済みの定義と一致しなくなった場合、そのユーザーのリクエストは拒否されます。レビューされていないツールは拒否され、その名前が呼び出し可能なツールとしてクライアントに提示されることもありません。
有効化されたツールにはすべて、引数のバリデーターも必要です。シンプルなスキーマであれば、Durinがレビュー中にバリデーターを作成します。スキーマが複雑すぎてそれができないツールは、別途署名されたバリデーターが用意されるまで有効化できません。送信時、ブローカーは接続先でのツール名とスキーマを、クライアントのリクエストではなくレビュー済みの記録から取得します。
レビューでは、引数とリソースの対応付けも行います。管理者がツールの入力から最大4つのフィールドを指定すると、Durinはそれらの値を結合して、オーナーとリポジトリのように、ルールが参照するリソースを組み立てます。リソースがツールの許可リストにない呼び出しは拒否され、値が欠けている場合も一致とはみなされません。
承認は1件の呼び出しに厳密にひも付く
ルールで審査が必要とされている場合、呼び出しには「承認が必要」が返され、接続先には何も送信されません。リクエスト元本人を除く、別の有効な管理者が、「承認」画面で、または設定されていればSlackで、そのリクエストを開きます。審査担当者は、リクエスト元、接続、ツール、リソース、引数のダイジェスト、バージョン、有効期限を確認したうえで、「一度許可する」「常に許可する」「拒否する」のいずれかを選びます。
承認によって操作が実行されるわけではありません。リクエスト元は、元のリクエストから15分後に承認の有効期限が切れる前に、同じ冪等キーと承認参照を付けて、まったく同じ呼び出しをもう一度送信します。ランタイムは現在のアクセス権をもう一度チェックし、許可を消費して判定を記録したうえで、1回分の実行を確保します。メンバーシップが取り消された場合、ポリシーが変更された場合、引数が異なる場合は、以前の承認でその呼び出しを認可することはできません。
| リクエストの要素 | ひも付ける理由 |
|---|---|
| リクエスト元と組織 | 別の人がその許可を使うことはできません。 |
| 接続と認証情報 | 許可を別のアカウントに移すことはできません。 |
| ツールのバージョン、定義のダイジェスト、対応付け | ツールが変更されると、改めてレビューが必要になります。 |
| 引数のダイジェストとリソース | タイトルや対象が異なれば、別の操作として扱われます。 |
| スキーマとポリシーのバージョン | 新しいルールを公開すると、未処理の承認は無効になります。 |
| リクエスト元の取り消しエポック | アクセス権を失ってから再び得ても、以前の許可は復活しません。 |
| 有効期限内の1回の実行 | 許可は1回の試行で消費されます。 |
審査担当者が判断を保存するとき
定型的な変更操作を、繰り返されるたびに審査していると、内容を読まずに承認ボタンを押す癖がついてしまいます。「常に許可する」は、厳しく限定された条件のもとでこの問題に対処します。「承認履歴の活用」がオンの間(初期設定ではオン)、この選択は継続的な許可として保存され、組織が別の有効期間を設定しない限り30日間有効です。その後のリクエストは、同じリクエスト元から同じ接続、ツール、リソースに対して送られ、ひも付いたバージョンがすべて変わっておらず、引数が同一であるか、組織の一致度のしきい値(初期設定では90%)を満たしていれば、新たな審査なしで進めることができます。
一致度は、引数そのものではなく、引数からソルトを加えて作成した一方向のスケッチを使って計算され、同じ入力からは常に同じスコアが得られます。スケッチで類似していると示せないものは、新しいリクエストとして扱われます。「一度許可する」が後のリクエストに適用されることはなく、次の審査担当者に前例として表示されるだけです。
継続的な許可があっても、現在のアクセスチェックはすべて通過しなければならず、ブローカーもほかの承認と同じようにこれを再確認します。ポリシーの変更、リクエスト元や審査担当者のアクセス権の取り消し、「承認履歴の活用」のオフ、管理者による取り消しのいずれかがあると、継続的な許可は期限前に終了します。管理者は「承認」→「記憶」で、保存済みの判断を1件ずつ、それが使われたすべての記録とあわせて確認できます。
プロバイダーのトークンをエージェントに渡さない
プロバイダーとの接続では、Durinはリクエストした本人の認可を使ってプロバイダーを呼び出します。ユーザーは利用する接続ごとに、Durinを通じてプロバイダーにサインインします。そのため、チームメンバーの同意によって、ほかの誰かのアクセス範囲が広がることはありません。トークンはAES-256-GCMで暗号化して保存されます。組織、環境、接続、ユーザーは認証対象データとして各レコードに組み込まれているため、レコードを別の人のものとして開くことはできません。鍵のローテーション中は、キーリングに最大5つの鍵を保持できます。新しいレコードは最新の鍵で暗号化され、既存のレコードは登録されているどの鍵でも開けます。
これらのトークンを使うのは、認証情報ブローカーだけです。ブローカーは独立したサービスで、呼び出せるのは組織のランタイムだけです。呼び出しには、呼び出し本文そのものにひも付いた、30秒間有効な署名付きリクエストが使われます。ブローカーは、プロバイダーに接続する前に現在の記録を読み直し、ポリシーの判定をやり直します。変更操作の場合は、記録済みの実行意図、変わっていない取り消しエポック、同じ認証情報のバージョンも必要です。そのうえで、ブローカー自身がトークンを付加します。ランタイム、クライアント、モデルにトークンを返すエンドポイントはありません。
プロバイダーがホストするMCPサーバーやカスタムMCPサーバーへの呼び出しは、1つのエグレス(外部送信)サービスを経由して送信されます。このサービスは公開ホスト名へのHTTPSリクエストだけを受け付け、リダイレクトを拒否し、メソッドとヘッダーを制限し、リクエストとレスポンスのサイズに上限を設けます。各呼び出しは接続のレビュー済みエンドポイントに固定され、自動再試行なしでtools/callを1回だけ実行します。
トークンをモデルのコンテキストに入れないからといって、結果が無害になるわけではありません。許可されたツールが返す内容は、どのようなものでもクライアントとそのモデル提供元に届く可能性があります。Durinは各結果を、レビュー済みのスキーマとの照合と検査が終わるまで保留しますが、この検査が探すのは秘密鍵や有効なAPIトークンといった一般的なシークレットの形式であり、あらゆる種類の機密データではありません。プロバイダーのスコープはできるだけ狭くしてください。Durinで承認しても、プロバイダーのアカウント自体に許された操作の範囲が広がることはありません。
変更操作は最大1回だけ実行する
エージェントは再試行し、ネットワークではレスポンスが失われることがあります。チケットが二重に作成されるのは厄介ですが、メッセージや支払いが二重に送られるのはさらに深刻です。Durinは、許可された1件のリクエストにつき、試行が最大1回になるように設計されています。
- すべての呼び出しには、クライアントが選んだ冪等キーが付いています。同じキーで再送された呼び出しは、まず改めて評価されます。引数、ツール、認証情報のいずれかが変わっていれば、競合として拒否されます。変わっていなければ、以前のステータスとともに「重複」が返され、何も送信されません。
- プロバイダーに接続する前に、ランタイムは実行記録と監査エントリを1つのトランザクションで書き込みます。この書き込みに失敗すると、呼び出しは停止します。ブローカーは、この実行意図の記録がない変更操作をすべて拒否します。
- 各変更操作は、実行記録をキーとする1つの送信権によって保護されます。同じリクエストが再び届いても、その送信権をもう一度確保することはできません。
- Durinが「完了」と記録するのは、検査を通過した結果をブローカーが返した場合だけです。プロバイダーのエラー、タイムアウト、最終イベントの欠落、検査を通過しなかった結果は、いずれも「結果不明」として記録されます。
許可された変更操作には、クライアントが選んだ冪等キーが付いています。ランタイムはまず、実行記録と監査エントリを1つのトランザクションで書き込みます。この書き込みに失敗した場合は何も送信されません。次に送信権を1回だけ確保するため、同じリクエストが再び届いても、送信権を確保することはできません。ブローカーは現在の記録を読み直し、自動再試行なしでプロバイダーを1回だけ呼び出します。記録される実行結果は、結果が返されて検査を通過した場合は「完了」、エラー、タイムアウト、検査の不合格があった場合は「結果不明」です。同じキーを繰り返し使うと、内容が変わっていないリクエストには「重複」が、変わったリクエストには競合エラーが返され、どちらの場合も何も送信されません。
図を原寸で開く: 許可された変更操作は、実行意図を記録し、送信権を1回だけ確保して、「完了」または「結果不明」で終わります。結果不明の変更操作は、すでに実行されている可能性があるため、自動で再試行されることはありません。クライアントには、再試行の前に記録を確認するよう伝えられます。新しいリクエストを送る前に、担当者がプロバイダー側の状況と監査証跡を確認してください。新しい冪等キーで無理に再試行すると、すでに行われた操作が重複するおそれがあります。読み取りであれば、新しいリクエストでやり直しても通常は問題ありません。
Durinが記録するものと、対象外のもの
Durinは、ポリシーの判定と実行結果を、追記専用の監査ログに別々のエントリとして記録します。データベースのトリガーが更新や削除をすべて拒否し、エントリを書き換えるコードパスもありません。記録からは、ユーザー、クライアント、接続、ツール、リソース、判定、理由がわかり、引数はそのものではなくダイジェストとして残ります。呼び出しの経路では、リクエストや結果のペイロードは保存されません。
Durinからは、クライアント内の会話は見えません。キャプチャ用の計測機能を組み込んだクライアントは、実際に確認したメッセージを別のキャプチャ用エンドポイントから送信できます。送信されたメッセージは、そのクライアント自身の実行記録にひも付けられ、「クライアントからの報告」と表示されます。管理者が機密情報を除去したキャプチャを有効にしない限り、キャプチャで保持されるのはメタデータのみです。管理者が外部のコンテンツ評価サービスを有効にした場合、そのサービスはチェック対象の引数や結果を受け取ります。このサービスは判定をより厳しくすることはできても、緩めることはできません。
この経路の外に残るものが3つあります。まず、Durinを経由せずにプロバイダーに届くリクエストには、ネットワークやIDによる制限など、それ専用の管理策が必要です。次に、利用しているモデル提供元は、ツールの結果も含め、クライアントが送信したものをすべて受け取ります。そして、プロバイダー自身の権限が最終的な基準であることに変わりはありません。Durinは接続を通じてエージェントができることを絞り込めますが、広げることはできません。
この経路を実際に確かめるには、ワークスペースでDurinサンドボックスを申請し、読み取りを1回行ってみてください。次に、管理者に変更操作の審査を必須にしてもらい、デモ用チケットを作成して、「承認が必要」から記録された実行結果までをたどります。評価キットには、どのゲートウェイを比較する際にも使える同じテストがまとめられています。