Skip to main content
Glama
adamabdo-xynora

mcp-capability-guard

mcp-capability-guard

多くのMCPサーバーは、モデルに共有ベアラートークンという装填済みの銃を渡します。1つの認証情報で、すべてのツール、すべての呼び出しが可能です。このサーバーは、モデルに弾丸ごとの許可を求めさせます。

これは、架空のインメモリCRM(Larkspur Supply Co.、7件の架空の連絡先)上で動作する、小規模で完全なMCPサーバーであり、ケイパビリティトークンによる書き込み認可を実演します。これは、私が実際の12,000件以上の連絡先帳に対して運用している本番CRMエージェントから抽出したパターンです。ここにあるデータは架空ですが、施行される部分は実際に製品化されるものです。

設計:5つのレイヤー

  1. 階層化されたツール面。 読み取り(list_contacts、get_contact)は自由です。書き込みは単一のツールとして存在せず、add_note ツールも delete_contact ツールもありません。すべての変更は、正確に2つの呼び出し、propose_write と execute_write を経由します。

  2. ケイパビリティトークン(中心要素)。 propose_write は、1つの正確な変更に紐づく、単回使用・TTL付きのワラントを発行します。トークンは変更を埋め込んでおり、変更を指し示すわけではないため、ルックアップテーブルを汚染する余地も、IDを再ターゲットする余地もありません。execute_write はトークンと変更を一緒に提示し、ガードはフィールドごとの等価性を検証します。異なる変更でワラントを提示すると、単に失敗するだけでなく、トークンは焼却され、攻撃者の正当な書き込みも道連れにします。

  3. 破壊的階層に対する人間の確認。 change_stage、remove_tag、delete_contact はさらに、オペレーターの明示的な「はい」をMCPフォームの引き出しを通じて要求します。プロンプトは、操作、連絡先、ペイロードを1文で示します。この要求はガードの前に実行されるため、拒否してもワラントは消費されません。また、引き出しチャネルを持たないクライアントは、破壊的書き込みを黙って実行するのではなく、拒否されます。両方向でフェイルクローズです。

  4. 上位レイヤーが上書きできない下限。 Closed-Lost-DNC ステージ(連絡禁止、法的保留)の連絡先は、トークンやMCPを一切知らないストア自体の内部で、すべての書き込みを拒否します。完全に承認されたフロー(有効なワラント、一致する変更、確認済みの人間)でも、そこで行き止まりになります。これこそが、3つの標識が付いた単一のゲートではなく、多層防御である理由です。

  5. ワラントを漏らさない追記専用監査ログ。 すべての提案、確認、実行、拒否が記録されます。トークンIDは8文字のフィンガープリントとしてのみログに入ります。これはコンパイル時の保証です。フィンガープリントフィールドは、切り詰め関数だけが生成できるブランド化されたTypeScript型を保持します。自由テキストも値によってスクラブされます。ガード自身の拒否メッセージが拒否したトークンを名指しするからです。(これは私のwebhook-guardと同じ、値による編集の規律です。あちらはHTTP認証情報用、こちらは生のワラント用です。)read_audit はデフォルトで拒否です。サーバーが exposeAudit: true でビルドされない限り、ツールは登録されません。

Related MCP server: tenant-scoped-crm

実行例

npm install
npm run demo

デモは、実際のサーバーをスクリプト化されたクライアントにインメモリMCPトランスポートで接続し、8つのステップをナレーションします。2つの書き込みが成功し(1つは元に戻せるもの、1つは破壊的で確認済みのもの)、その後5つの攻撃(リプレイ、すり替え、確認拒否、ターゲット変更、凍結レコードへの完全承認済み書き込み)がそれぞれ型付きの拒否に遭遇し、ストアはバイト単位で同一のままです。最後に監査トレイルを読み取り、完全なトークンIDがどこにも現れていないことを確認します。デモはすべての期待値をインラインで検証し、ミスがあれば非ゼロで終了するため、スモークテストを兼ねており、プッシュのたびにCIで実行されます。

npm test              # 158 offline tests
npm run typecheck     # strict TypeScript, no emit

すべてオフラインです。APIキーも、ネットワークも、環境変数も、設定するものもありません。だからこそCIは、シークレットなしで、プッシュのたびにデモを含む全スイートを実行します。

証拠はテストスイートにある

上記の主張を正直に保つために、2つのスイートが存在します。

  • test/structural.test.ts はソースをテキストとして読み、アーキテクチャを固定します。src/tools.ts がMCP SDKをインポートする唯一のモジュールであり、ストアはその上の何も知らず、ガードと監査モジュールはヘッダーが主張するものだけをインポートし、トークンの鋳造はガードに限定され、文字列 tokenId は src/audit.ts に現れません。リファクタリングが静かにSDKコードをストアに移動させた場合、このスイートは動作の前に失敗します。

  • test/adversarial.test.ts は、敵対的なモデルを完全に配線されたサーバーに対して実行します。提案スキップ、リプレイ、焼却検証付きのすり替え、ワラントの別の連絡先への再ポイント、凍結レコードへの完全承認攻撃、注入されたクロックによる期限切れワラント、確認回避、攻撃者が選んだトークンIDによる監査整合性チェック。すべての攻撃は正確な型付き拒否に遭遇しなければならず、そのすべての後でストアは変更されていなければなりません。

残りの約140のテストは、ストア、ガード、監査、ツール面をユニットごとにカバーし、確認がワラント消費の前に実行されるという順序の不変条件も含みます。

バージョンと範囲

@modelcontextprotocol/sdk 1.30.0 上に構築されており、これはMCPリビジョン2025-11-25を対象としています。2026-07-28リビジョンは、サーバーが発行したハンドルを通常のツール引数として渡すことを、クロスコール状態の標準メカニズム(SEP-2567)にします。このリポジトリのケイパビリティトークンはまさにそのパターンを、認可プリミティブとして使用したものであり、設計はステートレスプロトコルにそのまま引き継がれます。

実行時依存関係は2つです。SDK自体と、SDK自身のピア依存関係であるスキーマ言語 zod です。ツール入力スキーマはSDKの設計上zodスキーマであるため、追加の依存関係というよりは、SDKのもう半分です。他には何もツリーに入りません。ストア、ガード、監査モジュールは純粋なTypeScriptで、node:crypto と互いの型以外のインポートはゼロです。これにより、158のテストがオフラインで0.5秒未満で実行できます。

これは何ではないか。 このリポジトリは、OAuthやMCP認可仕様のリソースサーバー役割を実装していません。それらは別の問題を解決します。トランスポート境界でクライアントが誰であるかを証明することです。ケイパビリティトークンは、認証されたセッションが何をできるか、一度に1つの書き込みを管理します。この2つは競合するのではなく補完し合います。これらを混同すると、すべてを認可する1つのベアラートークンでサーバーが終わることになります。トランスポートのアイデンティティは意図的に範囲外であり、認可パターンが読み取り可能なままになるようにしています。

制限事項、明確に述べる

  • CRMは架空でインメモリです。永続化、並行性、マルチユーザーセッションは、このデモが持たない現実の問題です。

  • トークンはサーバーメモリに存在し、再起動すると忘れられます。本番では、同じパターンが永続ストアに対して同じ単回使用セマンティクスで実行されます。

  • 引き出し確認は、クライアントのレンダリング次第です。サーバーの文の代わりに素の「許可しますか?」をユーザーに表示するクライアントは、保証を弱めます。これは、このサーバーが行うように完全な文をリクエストに入れるべきだという議論であり、確認をスキップすべきだという議論ではありません。

  • ストアのメモのタイムスタンプは壁時計を使用するため、デモ出力の1行は実行ごとに異なります。ガードと監査ログは注入されたクロックを使用し、決定的です。

適応方法

このパターンは、書き込みに結果が伴うあらゆるMCPサーバーに移行できます。ストアを自分のシステムに置き換え、提案/実行の分割を維持し、独自の階層を決定し、下限ルールをツールレイヤーではなくデータレイヤーに置きます。ガードと監査モジュールはMCPから何もインポートせず、全体をそのまま持ち上げることができます。

MITライセンス。

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    Security-enforcing MCP proxy that sits between an AI agent and any number of downstream MCP servers, intercepting every tool call through a capability-token policy gateway that can allow, deny, or escalate to human approval before the call reaches any real tool. It also exposes built-in operator tools for approval workflows, audit trail queries, token management, voice/HUD output, and hierarchical
    21
    14
    Apache 2.0
  • A
    license
    Not graded
    quality
    D
    maintenance
    A reference MCP server demonstrating safe agent access to multi-tenant CRM data with tenant isolation enforced in the data layer, role-based permissions, and human confirmation on writes.
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    A secure MCP server for CRM operations (contacts and deals) with Auth0 OIDC authentication, role-based access control (sales-rep read-only vs sales-manager full access), and on-behalf-of token exchange.
    -
  • A
    license
    B
    quality
    A
    maintenance
    A secure MCP server enabling tool calls (kb_search, read_doc, publish_report) through a zero-trust CapabilityBroker with OWASP LLM Top-10 guardrails and human-in-the-loop approval.
    3
    Apache 2.0