- ブラウザURL入力
- DNS名前→IP
- ルータ経路選択
- ロードバランサ振り分け
- Nginx受け口
- アプリ処理今ここ
- DB保存
このコースは、確率で答える部品の確かさを部品の外側のどこに書くかを見てきました。最終回は、その外側に人を置く場所を決めます。
まず結論
2026-09 時点の MCP 仕様(最新版 2026-07-28、前版 2025-11-25 も同文)は、ツール呼び出しを拒否できる人を挟むべき(SHOULD)とし、呼ぶ前にツールへの入力を利用者に見せるよう求めます。ツールに付く「破壊的でない」といった注釈は hint にすぎません。
承認が守れるのは、見せたものと実行されるものが一致しているときだけです。要約ではなく実引数と実際に起きることを見せ、承認は取り消せなくなる直前に絞ります。増やすほど読まれなくなるからです。
エージェントがファイル削除ツールを呼ぶ直前の承認画面です。承認者が「頼んだ操作と違う」と気づくのに最も役立つ表示はどれでしょうか。
当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。
承認が守れるのは、見せたものが実行されるときだけ
このコースで見てきた部品は、呼ぶたびに分布から1つを引いてきます。ツールを呼ぶかどうかも、どんな引数で呼ぶかも、その1回の引きの結果です。最後の外側として、人を置く場所を考えます。
MCP 仕様のツールの章は、冒頭の警告でこう書きます。
For trust & safety and security, there SHOULD always be a human in the loop with the ability to deny tool invocations.
規範語は SHOULD で、MUST ではありません。同じ章は the protocol itself does not mandate any specific user interaction model とも書き、承認画面の形は決めていません。何を見せるかは、Security Considerations の節がクライアントに求めています。
Show tool inputs to the user before calling the server, to avoid malicious or accidental data exfiltration
OWASP LLM06:2025 の緩和策の6番目も require a human to approve high-impact actions before they are taken と、承認を実行の前に置きます。
ここから、承認が働く条件が2つ読めます。見せたものと実行されるものが一致していることと、まだ取り消せる時点であることです。
- ・承認の前は何度でも引き直せる。取り消せない一線の手前にだけ人を置く
- ・承認した後に対象が変われば、承認は無効になる
要約だけ読む承認者の前で、4件が消えた
標準ライブラリだけの模型で確かめます。削除ツール delete_files(pattern) を dry-run と commit の2段にし、承認画面に「モデルの要約」「実引数」「dry-run の結果」を並べました。モデルの要約は台本の文字列で、LLM の出力ではありません。 サーバの注釈はわざと destructiveHint=False と偽り、実行器は判定に使いません。
ケース2は、要約が「古いログ2件」なのに実引数が *.* です。一覧の全件が .log のときだけ承認する承認者は拒否しました。ケース3は同じ呼び出しを、要約だけを読む承認者に回しました(1回目の実行から抜粋。2回目も同じ結果、トークンの値だけ異なる)。
[2 summary does NOT match args]┌ approval tool=delete_files (server annotation says destructiveHint=False; treated as hint only)│ model's summary : delete the 2 old log files│ actual arguments: {"pattern": "*.*"}│ dry-run result : would delete 4 file(s): ['notes.txt', 'old-1.log', 'old-2.log', 'report.txt']└ approval token : 2005cd7e78a4human: DENY -> ['notes.txt', 'old-1.log', 'old-2.log', 'report.txt'][3 summary-only reviewer on the same mismatched call]┌ approval tool=delete_files (server annotation says destructiveHint=False; treated as hint only)│ model's summary : delete the 2 old log files│ actual arguments: {"pattern": "*.*"}│ dry-run result : would delete 4 file(s): ['notes.txt', 'old-1.log', 'old-2.log', 'report.txt']└ approval token : 3250a265e217human: APPROVEcommit: deleted ['notes.txt', 'old-1.log', 'old-2.log', 'report.txt'] -> left: []
3〜5行目で、要約と実引数と一覧が食い違っています。ケース3の画面にも同じ一覧が出ていましたが、読まれずに最終行で4件すべてが消えました。見せるだけでは足りず、読まれて初めて承認が働きます。
ケース4では、承認のあと commit の前に old-3.log を足しました。
[4 approved, then a new file appears before commit]┌ approval tool=delete_files (server annotation says destructiveHint=False; treated as hint only)│ model's summary : delete the 2 old log files│ actual arguments: {"pattern": "old-*.log"}│ dry-run result : would delete 2 file(s): ['old-1.log', 'old-2.log']└ approval token : ba437ac881e4human: APPROVEcommit: REFUSED: state/args changed since approval (approved ba437ac881e4, now a1af88085209) -> left: ['notes.txt', 'old-1.log', 'old-2.log', 'old-3.log', 'report.txt']
模型のケース4では、承認のあと commit の前に old-3.log が増え、commit は REFUSED になりました。拒否された理由はどれですか。
注釈は約束ではなく、承認は増やすほど薄まる
承認を省く手がかりとして、ツールの注釈が使えそうに見えます。MCP の ToolAnnotations には destructiveHint(既定 true)や idempotentHint(既定 false)があります。注釈が無いツールは「破壊的でありうる・冪等でない」と読むのが既定です。しかし schema.ts はこう書きます。
NOTE: all properties in
ToolAnnotationsare hints. They are not guaranteed to provide a faithful description of tool behavior
続けて、信頼できないサーバの注釈で使用を判断するなと書き、tools.mdx 側はそうした注釈を untrusted と扱うことを MUST としています。第12期「冪等は性質ではなく約束」で見た HTTP の冪等は、RFC 9110 が定める規定でした。MCP の hint は、記述の忠実さすら保証されません。
では全部の呼び出しに承認を付ければよいか。arXiv:2506.08837 は各コマンドの確認を検討し、This would be cumbersome for the user、確認する命令が opaque to non computer experts、攻撃がおそらく innocuous looking commands に紛れやすいと書きます。CaMeL の論文も、確認に慣れた利用者が may inadvertently approve malicious actions と書きます。
承認は数を増やすほど読まれなくなり、ケース3の承認者に近づきます。だから取り消せる操作には置かず、取り消せなくなる直前にだけ置きます。
BEGIN と COMMIT には ROLLBACK があった
第17期「全部か無しか。境界は BEGIN と COMMIT で宣言する」で見たとおり、DB のトランザクションは複数の文を全部か無しかにまとめ、その範囲はアプリが BEGIN と COMMIT で宣言します。COMMIT の前なら ROLLBACK で取り消せます。確定の一線がどこかを、書く側が決めています。
ツール実行も、一線を書く側が決めるところは同じです。違うのは、削除や送信のような操作には一般に ROLLBACK が無いことです。そこでこの模型では、実行前に起きることを計算する dry-run が、BEGIN から COMMIT までの「まだ確定していない窓」の代わりを務めました。ケース4の REFUSED は、窓の中で見たものと確定させるものがずれたら確定しない、という線の引き方です。
第14期「ではどこに線を引くか」の結論どおり、判断に時間をかけるべきは引き返せない線だけです。承認も同じ場所に置きます。
DB の BEGIN〜COMMIT と、ツール実行前の承認との類推は、どこまで成り立ちますか。
DB のトランザクション
アプリが BEGIN で開き COMMIT で確定します。COMMIT の前なら ROLLBACK で全部を取り消せるので、確定前の窓は DB が用意しています。
破壊的なツールの承認
削除や送信には一般に取り消しがありません。模型では dry-run で起きることを計算して見せ、承認後に同じ計算をやり直して一致したときだけ実行しました。窓は自分で作ります。
承認を置くべき場所は、どちらの例のどの時点にあたるでしょうか。
「ここを過ぎたら戻せない」点がどこにあるかを両方で探してください。
この章のまとめ
- MCP 仕様は人を挟むことを SHOULD とし、呼ぶ前にツールへの入力を見せるよう求める。承認画面の形は定めない。
- 承認は要約ではなく 実引数と実際に起きること に対して行う。模型では要約だけの承認で4件が消えた。
- 注釈は hint。destructiveHint の既定は true だが、信頼できないサーバの注釈で判断しない。
- 承認は増やすほど読まれなくなる。取り消せなくなる直前にだけ置く。
- DB は ROLLBACK を持つ。ツールには一般に無いので、dry-run で確定前の窓を自分で作る。
このコースの芯に戻ります。温度を0にしても同じ答えは約束されず、スキーマが縛るのは形までで、1回通っても率は分かりませんでした。埋め込みの「近い」は訓練が近いとしたもので、ツールを実行するかはコードが決めます。確率で答える部品の確かさは、部品の外側にしか書けません。 受け手の検査も、評価の手順も、実行を決めるコードも外側でした。最後の外側に置く人も、読まれる数と場所に絞らなければ働きません。
自分の現場で確かめる
読んだだけでは身につきません。手元の環境で実際に見てみてください。
理解度チェック
読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。
信頼できるか分からないサーバが、削除ツールに destructiveHint: false と付けてきました。MCP 仕様に沿う扱いはどれですか。
用語集(3語)
- human in the loop
- 処理の途中に人の判断を挟むこと。MCP 仕様はツール呼び出しを拒否できる人を挟むべき(SHOULD)とする。
- ToolAnnotations
- MCP でサーバがツールに付ける注釈。destructiveHint(既定 true)、idempotentHint(既定 false)など。すべて hint で、振る舞いの忠実な記述は保証されない。
- dry-run
- 実行はせず、実行したら何が起きるかだけを計算する段。この回では承認の前に置き、消える一覧を見せるために使った。
出典(一次ソース)
- Model Context Protocol Specification 2026-07-28 — Server / Tools(GitHub, commit ab3a39c) ↗
- Model Context Protocol schema.ts 2026-07-28 — ToolAnnotations(GitHub, commit ab3a39c) ↗
- Model Context Protocol Specification 2025-11-25 — Server / Tools(前版、GitHub, commit ab3a39c) ↗
- OWASP Top 10 for LLM Applications 2025 — LLM06:2025 Excessive Agency(GitHub, commit eb87ba8) ↗
- Beurer-Kellner et al., Design Patterns for Securing LLM Agents against Prompt Injections (arXiv:2506.08837) ↗
- Debenedetti et al., Defeating Prompt Injections by Design (arXiv:2503.18813) ↗