mcpField
A
approval-gate-mcp

approval-gate-mcp

ローカル
github.com/itcustomsolutionセキュリティ03 日前に更新

approval-gate-mcp について

approval-gate-mcp は、送信、削除、公開、支払い、デプロイなど、AI エージェントによる重要な操作に人間の承認を求める MCP サーバーです。承認はデフォルト拒否で、期限付き・単回使用とし、指定された操作に結び付けます。操作自体は実行せず、監査ログを記録します。

主な機能

  1. 01人間への承認申請と応答待ち
  2. 02CLI での一覧、承認、拒否、取り消し
  3. 03操作に紐付く期限付きの単回承認
  4. 04デフォルト拒否と監査ログ
  5. 05信頼された実行境界で承認を消費

活用シーン

  1. 01メール送信前に人間の確認を求める
  2. 02データの削除や公開に承認手順を設ける
  3. 03支払いやデプロイ前に操作内容とペイロードを確認
  4. 04未消費の承認を確認して取り消す

MCP 対応

MCP サーバーとして、承認の申請、確認、待機、拒否、消費のツールを提供します。エージェント自身が承認できないよう、MCP 経由の承認はデフォルトで拒否され、人間はターミナル CLI から判断します。サーバーは操作を実行せず、意図と判断を記録します。

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

mcp.json · 共通設定
{
"mcpServers": {
"itcustomsolution-approval-gate": {
"command": "npx",
"args": [
"-y",
"@itcustomsolution/approval-gate-mcp"
]
}
}
}
起動コマンドnpx -y @itcustomsolution/approval-gate-mcp

ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。

パッケージ
npm@itcustomsolution/approval-gate-mcp0.3.0

ツール

6

掲載時のツール一覧 · 2 週間前に更新

パラメーター型必須説明
actionstringはい実行する操作の正確な説明。例:'send email to [email protected] with subject X'。
reasonstringはい今この操作が必要な理由
ttl_secondsintegerいいえリクエストが期限切れになるまで保留される時間(デフォルト 1 時間)
requested_bystringいいえリクエスト元のエージェントまたはワークフローの識別子

詳細

approval-gate-mcp

AI エージェントが送信、削除、公開、支払い、デプロイを行う前に停止し、人間に確認を求める MCP サーバーです。

npm

license: MIT

なぜ必要か

エージェントは処理の実行が得意です。難しいのは、影響の大きい処理 (メールの送信、データの削除、公開、金銭の支出)が、人間の承認を得た場合にのみ 実行されるようにすることです。このサーバーはそのためのゲートです。長年にわたり 本番環境で運用してきたシステムから切り出しました。自動化のインシデントを経験し、 その教訓を痛感して以来、「人間のゲートなしに、自動で破壊的な操作を実行することは 決してない」というルールを徹底しています。これは、そのルールを汎用的に再利用できる 形にしたものです。

30秒で始める

claude mcp add approval-gate -- npx -y @itcustomsolution/approval-gate-mcp

Claude Desktop(claude_desktop_config.json):

{
  "mcpServers": {
    "approval-gate": {
      "command": "npx",
      "args": ["-y", "@itcustomsolution/approval-gate-mcp"]
    }
  }
}

ターミナルで npx -p @itcustomsolution/approval-gate-mcp approval-gate list を実行すると、承認または拒否できます。

使用例

  1. エージェントが顧客にメールを送ろうとしています。action: "send email to [email protected], subject: Invoice 1042" を指定して request_approval を呼び出すと、id a1b2c3d4e5f6 が返されます。
  2. wait_for_approval を呼び出します。メールは送信されません。
  3. 自分のターミナルで approval-gate list を実行し、続けて approval-gate approve a1b2c3d4e5f6 looks right を実行します。
  4. エージェントは approved を確認し、同じ id と完全に同じ操作テキストを指定して consume_approval を呼び出します(1回限り)。その後にのみメールを送信します。拒否した場合、無視した場合、または有効期限が切れた場合は、承認されません。
  5. ~/.approval-gate/audit.jsonl にリクエストと決定が記録されます。

設計原則

  • フェイルクローズ。 操作を許可するのは、consume が成功した場合のみです。 consume_approval が ok: true を返した場合(承認された操作と完全に一致し、1回限り)、または 信頼されたコードで executeApproved を呼び出した場合です。保留中、承認済みだが未消費、拒否、 期限切れ、タイムアウト、エラーのいずれも許可を意味しません。すべて 不許可 です。
  • ゲートは何も実行しません。 ゲートは意図と決定を記録します。エージェントはまず承認を求め、 承認された場合にのみ処理を実行します。決定と実行を分離することで、ゲートを シンプルで監査しやすく保てます。
  • 決定はエージェントの外部で行われます。 人間はエージェントのコンテキスト内ではなく、 自分のターミナルで CLI を使って承認または拒否します。MCP ツールから承認することはできません。 CLI は対話型ターミナルと、確認内容の再入力を求めます。これは操作を少し面倒にするためのものであり、 認証ではありません。OS ユーザーとして実行されているもの(シェル、PTY、ファイルアクセスなど)は、 依然としてこの仕組みを回避できます。脅威モデルを参照してください。
  • 操作を許可するのは consume のみです。 status: "approved" は情報を示すだけです。ステータスの応答には authorizesExecution: false と effectiveStatus(approved_unconsumed、 approved_expired、consumed、revoked など)が含まれます。副作用を実行する信頼されたコードは、 承認自体を消費する executeApproved を呼び出してください (信頼された実行境界を参照)。MCP 経由、ファイル経由、 エージェント経由で届いた consume の結果は、どれほど適切な形式であっても承認の証明にはなりません。
  • すべて監査されます。 すべてのリクエスト、決定、有効期限切れ、消費は、 ~/.approval-gate/audit.jsonl に追記されます(改ざん防止ログではなく、追記のみを行う慣例です)。
  • リクエストには有効期限があります。 デフォルトの TTL は 1 時間です。有効期限が切れた承認は、承認として扱われません。
  • 承認は1回限りで、操作にひも付けられます。 consume_approval が成功するのは1回だけで、 承認された操作テキストと完全に一致し(リクエストに含まれている場合は、同じ操作名と同じ正規化済み JSON ペイロードも一致し)、 さらに、永続化の完了後に読み取った時刻がリクエストの有効期限以前である場合に限られます。

インストール

Node.js 22 以降が必要です(Node 18 と 20 はサポート終了済みです。MCP SDK の @hono/node-server 依存関係には Node 20 以降が必要です)。

npm から:

npm install -g @itcustomsolution/approval-gate-mcp   # installs `approval-gate` and `approval-gate-mcp`

ソースから:

npm install
npm run build
npm link        # makes `approval-gate` and `approval-gate-mcp` available on PATH

MCP クライアントに接続する

Claude Code:

claude mcp add approval-gate -- node /path/to/approval-gate-mcp/dist/index.js

または、任意の MCP クライアントの設定:

{
  "mcpServers": {
    "approval-gate": {
      "command": "node",
      "args": ["/path/to/approval-gate-mcp/dist/index.js"]
    }
  }
}

ツール

ツール目的
request_approval実行予定のアクション(action、reason、任意の ttl_seconds、任意の operation および紐付ける JSON payload)を登録します。ID(および payloadDigest)を返します。
check_approvalリクエストのステータス(pending / approved / denied / expired)を確認します。
wait_for_approval決定が下されるまで timeout_seconds の間待機します。タイムアウトした場合、ステータスは保留中のままであり、承認されていません。
list_pending人間の対応を待つリクエストを、古いものから順に1ページずつ一覧表示します(limit は1~100、デフォルトは50です。nextCursor を cursor として渡します)。
consume_approval実行の直前に呼び出します。承認済みで、有効期限内であり、action(およびリクエストに指定されていた場合は operation / payload)が完全一致する場合に限り、一度だけ成功します。それ以外の場合は、処理を続行しないでください。JSON の戻り値は、譲渡可能な認証情報ではありません。
decide_approval保留中のリクエストを拒否するか、未消費の承認を取り消します。MCP 経由での承認はデフォルトで拒否されるため、エージェントは自分のリクエストを承認できません。承認は CLI から行います。運用担当者は APPROVAL_GATE_ALLOW_MCP_APPROVE=1 を指定して許可できます(推奨されません)。

人間側の操作

approval-gate list                # pending requests
approval-gate show a1b2c3d4e5f6
approval-gate approve a1b2c3d4e5f6 looks right, ship it
approval-gate deny a1b2c3d4e5f6 wrong recipient
approval-gate revoke a1b2c3d4e5f6 changed my mind   # approved but not yet consumed
approval-gate list approved --limit 20 --after a1b2c3d4e5f6   # page through history
approval-gate archive --older-than-days 30          # retention: move finished requests aside

リクエストに operation が紐付いている場合、show と approve の確認には、その操作と正規化されたペイロード全体(エスケープ済み)が表示されます。これは、実行側が実行を許可される内容と完全に一致します。

推奨されるエージェントポリシー

エージェントのシステムプロンプトまたはポリシーファイルに、次のような内容を記述してください。

外部への送信や破壊的な操作(送信、公開、削除、購入、デプロイ)の前に、 request_approval を呼び出してから wait_for_approval を呼び出してください。結果が approved であれば、同じ ID と完全に同じアクションテキストを指定して consume_approval を呼び出し、ok: true が返された場合に限り処理を進めてください。 自分のリクエストに対して decide_approval を呼び出してはいけません。

信頼された実行境界

副作用を発生させるのがエージェントではなく独自のコードである場合は、その境界でゲートに承認を消費させ、承認されたペイロードをそのまま実行してください。

import { executeApproved } from "@itcustomsolution/approval-gate-mcp/dist/store.js";

// id comes from the agent; the action, operation and payload are what your code is about to run.
await executeApproved(id, { action, operation: "smtp.send", payload: { to, subject, body } }, async (ctx) => {
  ctx.assertActive();          // re-check expiry immediately before the side effect
  await smtp.send(ctx.payload); // ctx.payload is a frozen copy of what the human approved
});

executeApproved はレシートを受け取りません。単一使用の承認を自ら消費し(アクションテキストに、リクエストに含まれている場合は操作とペイロードも紐付けます)、execution_started の監査ログ行を書き込み(fsync)、有効期限を再確認してから、関数を呼び出します。開始記録を書き込めない場合、または書き込み中に承認の有効期限が切れた場合は、何も実行されません。副作用の前に await がある場合は、その後にもう一度 ctx.assertActive() を呼び出してください。

assertConsumed(result, id, action, binding?) は、自身で consumeApproval を呼び出すコード用に引き続き提供されます。同じ ID /アクション/紐付けに対して、有効期限前に、同じプロセス内で consumeApproval が発行した許可オブジェクトを一度だけ受け入れます。コピー、JSON の往復変換(MCP の応答、ファイル、エージェントのメッセージ)、または手作業で作成したオブジェクトは、常に拒否されます。0.3.0 では、形式が整った任意のオブジェクトが受け入れられていました。変更履歴を参照してください。

クラッシュおよびリプレイ時のセマンティクス。 消費は最大1回です。.used が確保されると、確保後に何が起きても(永続化中の期限切れや監査ログの失敗による拒否を含めて)、承認は消費済みになります。execution_started の後、execution_finished の前にクラッシュした場合、結果は不明です。外部システムを確認し、必要であれば新たなリクエストを作成して承認してください。自動で再試行されることはなく、このゲートのファイルとコールバックが操作する外部システムとの間にアトミック性の保証はありません。詳細:docs/authorization-states.md。

制限

制限値
action、reason、decision reasonそれぞれ8192 UTF-8 バイト
requested_by256 バイト(自己申告であり、認証されません)
operationA-Z a-z 0-9 . _ : / - の文字を1~128文字
payloadJSON のみ。正規化後(RFC 8785)32 KiB、深さ32、値10000個まで。"__proto__" キーは不可
TTLMCP:整数で10秒~7日。ライブラリ:7日までの任意の有限数(ゼロまたは負の値の場合、すでに期限切れのリクエストになります)
判断待ちのリクエストAPPROVAL_GATE_MAX_PENDING、デフォルトは100、1~10000。同時に作成する場合、それぞれの作成数分だけ上限を超えることがあります。無効な値の場合はフェイルクローズします。
リストのページ1~100(デフォルトは50)
状態ディレクトリrequests/ 内のエントリが100,000件に達すると新しいリクエストは拒否されます。200,000件を超えると一覧表示は拒否されます。読み取り、判断、使用、および archive はどの件数でも動作します。

キューがいっぱいの場合、担当者がリクエストを判断するか期限切れになるまで、request_approval は approval queue full で失敗します。完了したリクエストは approval-gate archive を実行するまでディスク上に残ります。このコマンドは、作成から8日以上経過し、期限切れになった完了済みリクエストのみを移動するため、アーカイブされたリクエストが使用されることはありません。MCP クライアントは、人間の操作なしに自身のリクエストを作成して拒否できるため、requests/ を作成上限まで埋めることができます。その場合、新しいリクエストがブロックされます(キュー上限と同様の可用性に関する制限であり、人間による判断はブロックされません)。一覧表示の各ページではすべてのリクエストファイルを読み取るため、アーカイブするまで履歴が増えるにつれて一覧表示が遅くなります。

状態

すべてのデータは ~/.approval-gate/ に保存されます(APPROVAL_GATE_DIR で変更可能)。 requests/*.json は現在の状態、requests/*.final / *.used は一度限りの判断および使用のマーカー、audit.jsonl は履歴、archive/ はアーカイブ済みリクエストを保存します。ディレクトリは 0700、ファイルは 0600 の権限で作成されます。

プライバシー: アクションテキスト、理由、requested_by、およびバインドされたペイロードは、これらのファイルにプレーンテキストで保存されます。また、アクションテキストと理由は audit.jsonl にもコピーされます。認証情報やシークレットを含めないでください。

脅威モデル

このゲートで防げること:

  • MCP 経由でこのサーバーにしか到達できないエージェントが、自分のリクエストを承認すること(MCP からは承認できません)。
  • 非対話型シェルから CLI を操作するエージェントが、承認すること(approve には TTY と確認の入力が必要です)。
  • 1 つの承認を 2 回目のアクションや別のアクションに使い回すこと(consume_approval は 1 回限りで、アクションに紐付けられています)。
  • リクエストの有効期限が切れた後に承認を使うこと、承認・拒否・有効期限切れの間で競合が起きること、ID を推測すること (128 ビットの乱数を使用)、対応する決定記録のない不正な状態ファイルや手動編集された状態ファイルを使うこと、承認対象を偽装しようとするリクエストテキスト内のターミナルエスケープシーケンス、双方向制御文字、不可視文字(CLI では \u エスケープとして表示されます)。他の文字体系の通常の紛らわしい文字(ホスト名内のキリル文字の「а」など)は、そのまま表示されます。リクエストテキストをよく読み、流し読みしないでください。

このゲートで防げないこと:

  • 信頼上の制約であり、修正済みのバグではありません。シェル、PTY、またはお使いの OS ユーザーとしてのファイルアクセス権を持つエージェント。 擬似端末を操作したり、~/.approval-gate/ を編集したり、ゲートを迂回してアクションを実行したりできます。このゲートは協調プロトコルと監査証跡であり、サンドボックスではありません。強制力を持たせるには、エージェントを別の OS ユーザー(またはコンテナ)として実行し、ゲートのディレクトリを読み書きできないようにして、ゲートの CLI はご自身で使用してください。
  • 実際のペイロード。 consume_approval が照合するのはアクションのテキストです。その後エージェントが実行するメール、SQL、デプロイが、読んだ内容と一致することを証明することはできません。この紐付けは協調に基づきます。強制力のある設計(提案のみ)については、docs/design-trusted-executor.md を参照してください。
  • 無人での重大な操作を伴う使用。 OS レベルで分離しない限り(上記を参照)、不可逆な操作を行う無人エージェントに対する唯一の制御として、このゲートを扱わないでください。そのような処理経路はフェイルクローズに保ち、自動実行を行わないでください。
  • ゲートを一度も呼び出さないエージェント。確認を求めることの強制は、エージェントのポリシーとツール次第です。
  • 書き込みアクセス権を持つユーザーによる audit.jsonl の改ざん。

executeApproved とペイロードの紐付けはローカルの安全対策です。信頼できるコードがこれらを使う場合、実行されるペイロードが承認されたものと一致するようにします。人間を認証するものではなく、同じユーザーとして動作するエージェントによるゲートの迂回を防ぐものでもありません。別途信頼できる権限主体/実行者を用意するには、さらに次の要件が必要です。

  1. エージェントが制御できない別の OS ユーザー、コンテナ、またはサービスアカウントとして実行され、副作用を起こすための唯一の認証情報を保持する実行者。
  2. エージェントのユーザーが読み書きできないゲート状態ディレクトリ。
  3. エージェントが持っていない認証情報(ハードウェアキーによる署名や、別のユーザー向けの OS プロンプトなど)を使って行う人間の承認。TTY は使用しません。
  4. ペイロードを再送せず、承認済み ID を参照して実行者に実行を依頼すること。
  5. 改ざんを検知できる(ハッシュチェーン方式またはホスト外に保存する)監査ログ。

このパッケージでこれらが実現されるわけではありません。所有者の判断と新しい認証情報が必要です。docs/design-trusted-executor.md を参照してください。

APPROVAL_GATE_ALLOW_MCP_APPROVE=1 を設定すると、MCP 経由での承認が再び有効になり、主要な保護が失われます。MCP クライアントを操作するのが人間だけである場合に限り使用してください。

状態遷移、承認の取り消し、クラッシュ時の動作については、docs/authorization-states.md で規定しています。approval-gate revoke <id>(または承認済みリクエストに対する deny)を実行すると、まだ消費されていない承認を取り消せます。

なぜこれほど小さいのか?

仕組みよりもパターンが重要だからです。本番システムでは、この同じ形式(リクエスト、帯域外での人間による判断、フェイルクローズのデフォルト、監査証跡)をメール、公開、デプロイの前段に配置しており、自動化によるインシデントの種類を大幅に減らせました。まずは小さく始め、リスクの高いものにゲートを設け、次に何をゲートするかはインシデントの事後分析をもとに判断してください。

貢献

Issue やプルリクエストを歓迎します。変更は小さく、フェイルクローズにしてください。「いいえ」を「はい」に変える可能性のある変更には、テストが必要です。PR を作成する前に npm test を実行してください。 リリース履歴については、CHANGELOG.md を参照してください。

ライセンス

MIT。詳しくは LICENSE をご覧ください。


Olufela "Lu" Fagbure が制作 · itcustomsolution.com · MIT ライセンス

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。