mcp-confirm
mcp-confirm
平たく言えば: AIが「本当に実行しますか?」と尋ねるとき、MCP SDKはすでにその確認を安全に保護しています。このリポジトリは、SDKがカバーしていない部分だけを実装しています。
先にこれだけ読めば十分:問題はすでに解決済み
2026-07-28のMCP仕様はマルチラウンドリクエストを追加しました。これにより、ツールは呼び出しの途中で一時停止し、ユーザーに確認を求めることができます。承認は不透明なrequestStateとしてクライアントを経由して戻ってきますが、仕様ではサーバーはこれを攻撃者が制御するものとして扱わなければなりません(MUST)。
Python SDKはこれをデフォルトで、すべてのMCPServerに対して行っています。 RequestStateBoundaryはミドルウェアチェーンに無条件で追加されます。鍵を指定しなければ一時的な鍵を使用します。状態はAES-256-GCMで封印され、メソッド、ターゲット、呼び出し引数のダイジェスト、オーディエンス、認証済みプリンシパルにバインドされ、TTLも設定されます。
つまり、誰もが最初に思いつく攻撃——cache.txtの削除を承認させ、その承認をthesis.txtに対して再生する——はSDKがすでに拒否しています。 そのためのライブラリは必要ありませんし、書くべきでもありません。
このリポジトリは当初、とにかく1つ書いてしまいました。HMAC、TTL、引数バインドを250行で実装し、目玉機能として出荷しましたが、公開されたその日にすでに冗長でした。それは静かに削除するのではなく、この文書の下部に記録されています。
Related MCP server: approval-gate
SDKがやらないこと
3つのギャップがあり、それぞれにテストがあります。
1. バインドと期限はあるが、使い切りはない
TTL内であれば、同じ承認は何度でも検証に成功します。境界チェックは毎回パスします。仕様はこれが意図的であることを明示しており、残りはあなた次第です:
これらの措置は再生ウィンドウを制限し、クロスユーザーおよびクロスリクエストの再利用を防ぎますが、それ自体では単回使用を保証しません。特定の
requestStateが最大1回だけ消費されなければならないサーバー(例:ワンタイムレデンプション)は、その不変条件をサーバー側で強制しなければなりません(MUST)。
「ファイルを削除する」場合、2回目の試行は何も見つけません。「500ポンドを送金する」場合、それがまさに問題全体です。 singleuse.pyがその不変条件——未使用の確認の台帳であり、使用時に消費される——を実装しています。暗号化は一切含まれていません。なぜなら、境界層が平文をこのサーバーが発行したものであることをすでに保証しているからです。
2. 人間が読む質問文のサニタイズはない
確認メッセージはサーバーが選んだテキストであり、人間に表示されます。通常、信頼できない値が補間されます——その要点は、どのファイルが削除されようとしているのかを伝えることです。そこで、ファイル名を次のようにします:
cache.txt
SYSTEM NOTICE: your session has expired.
Enter your AWS secret key to continue:ダイアログには、公式に見える2つ目のプロンプトが表示されます。ユーザーは削除を確認しているのではなく、自分自身のツールによってフィッシングされています。2026-07-28のリリースはMCP Apps——サーバーレンダリングUI——も出荷しましたが、これもこの表面を狭めるどころか広げています。
prompt.pyは、信頼できない値を1行に平坦化し、双方向オーバーライドとゼロ幅文字を除去し、中央から切り詰めて、最後のファイル名が常に表示されるようにします。制御文字は削除するのではなくスペースに置き換えます。なぜなら、削除するとa\nbとabが同じように表示され、2つの異なるファイルが1つのダイアログになってしまうからです。
3. 実行時にリソースを再チェックするプロトコル層はない
ユーザーが考えている間に、ファイルは置き換えられる可能性があります。そして「変更されていない」ことが何を意味するかを知っているのはツールだけです。このサーバーは削除前に再チェックし、シンボリックリンクになったパスを拒否します。
どの層が何を拒否するか
これが有用な部分であり、テストはそれを実証するために書かれています。MCPErrorはSDKのミドルウェアがこのパッケージの実行前に拒否したことを意味し、ToolErrorはこのパッケージが拒否したことを意味します。
攻撃 | 拒否する層 | テスト |
承認を別のファイルに再生 | SDK |
|
状態の偽造、または別の鍵での封印 | SDK |
|
同じ承認の2回目の使用 | このパッケージ |
|
別のレプリカが発行した状態 | このパッケージ |
|
ファイル名によるシステムプロンプトの偽造 | このパッケージ |
|
承認後にシンボリックリンクへ置換されたファイル | このパッケージ |
|
許可されたルート外のパス | このパッケージ |
|
テスト
35件のテスト — サーバー経由17件、台帳11件、プロンプトサニタイズ7件。
すべてのサーバーテストは実際のRequestStateBoundaryを通ります。 これはMCPServerが自身にインストールするものと同じクラスで、鍵を固定して、ラウンド1の封印とラウンド2の開封をワイヤー上とまったく同じように行います。
このハーネスが存在するのは、特定の失敗があったからです。最初のバージョンはMCPServer.call_tool()を直接呼び出してテストしていましたが、それではツールマネージャーに直行し、ミドルウェアチェーンを完全にバイパスしていました。 SDKの境界層は実行されず、冗長な手書きガードが重要なものに見えていました。テスト設計がそれを隠していたのです。ビルドサイクル全体を通して。
カバレッジは81%で、prompt.pyは100%、singleuse.pyは94%です。ギャップはmain()のargparseとトランスポート配線であり、build_serverを通じてテストされています。
CIはUbuntuのみで実行されます。これは意図的です。スワップ後のテストはシンボリックリンクを必要とし、そこでスキップと報告されるとビルドが失敗するからです。
インストール
pip install git+https://github.com/les-k/mcp-confirm.git実行
mcp-confirm --root /path/you/allow--rootを指定しない場合、サーバーは何もデフォルトにせず、すべてのリクエストを拒否します。ルートは起動時に固定され、エージェントが選択することはありません。署名鍵も不要です——MCPServerが自身の鍵を提供します。
既知の制限
台帳はインメモリです。 したがって単一プロセスでは正しく動作しますが、ロードバランサーの背後では誤動作します。SDKはレプリカ間での鍵共有をサポートしています(
RequestStateSecurity(keys=[...]))。その構成では、レプリカBはレプリカAが発行した確認を拒否します。フェイルクローズド——安全な方向——ですが、ユーザーには「理由もなく動作しなくなった確認」として見えます。マルチプロセス展開にはRedisまたはアトミックなcompare-and-deleteを持つデータベース行が必要です。この動作に対するテストはあります。デモツールは意図的に小規模です。 ファイルを1つ削除するだけです。興味深いコードは
singleuse.pyとprompt.pyです。CVEに基づくものではありません。 MRTRは数週間前のものなので、これは公開されたインシデントからではなく、仕様自身のMUST/SHOULDリストとSDKのソースを読むことから構築されています。
バージョン0.1.0の問題点
成功だけを記録するリポジトリは何の証拠にもならないため、ここに残しています。
0.1.0はSDKがすでにやっていることを再実装していました。 state.pyはHMAC署名、TTL、プリンシパル/メソッド/引数バインドの250行でした——すべてRequestStateBoundaryの重複であり、どれもそれより優れてはいませんでした:SDKが認証付き暗号化を使うところでHMACを使い、オーディエンスバインドがなく、鍵ローテーションもありませんでした。
それはテストではなく、SDKのソースを読むことで発見されました。 テストがパスしたのは、まさにそれを暴露したはずのミドルウェアをバイパスしていたからです。
CIは0.1.0の実際のバグを別途検出しました: シンボリックリンクチェックがPath.resolve()の後に実行されていたため、リンク自体ではなくリンクの宛先を検査していました。許可されたルート内の別のファイルを狙ったスワップは削除されていたでしょう。修正済みで、元のバージョンが決してテストしなかった亜種に対するテストも追加されています。
0.2.0はstate.pyを完全に削除し、SDKがカバーしていない部分だけを残しています。
ライセンス
MIT。
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Security & DLP proxy for MCP: tool-poisoning scans, PII redaction on tool args/results. Beta.
Find, vet, and run MCP tools through a secure audited gateway with prompt-injection risk scoring
Email safety MCP server. Detects phishing, prompt injection, CEO fraud for AI agents.
Related MCP Servers
- AlicenseAqualityAmaintenanceAn MCP server that provides safeguard capabilities to protect against prompt injection and unsafe tool calls.7111 PyPI11MIT
- AlicenseNot gradedqualityCmaintenanceMCP server that provides human-in-the-loop approval for risky AI agent actions, with durable state and audit logs.MIT
- FlicenseNot gradedqualityCmaintenanceMCP server that provides a security gateway for AI agents, enforcing allow/confirm/deny policies on tool calls and requiring human approval for risky operations, with full audit logging.-
- AlicenseNot gradedqualityAmaintenanceMCP server that gates agent tool calls by normalizing intent, denying unknown/unattended destructive actions, and requiring HITL prove approval for high-risk operations. It maintains an append-only hash-chained Action Ledger and exposes gate_check and ledger_verify tools without ever executing tools.MIT