MCP Write Gate について
MCP Write Gateは、AIエージェントと実際のMCPサーバーの間に置くローカル制御レイヤーです。メールやCRMなどに接続するGTM・運用チーム向けに、読み取りを通し、リストや読み取り専用設定、承認ルールで書き込みを制御し、APIキーと呼び出しログを管理します。
主な機能
- 01対象リストに基づく書き込み判定
- 02読み取り専用モードの強制
- 03対象外への承認要求
- 04連絡頻度の上限設定
- 05APIキーの保護と呼び出し記録
活用シーン
- 01CRMレコードへの変更を制限
- 02顧客や対象外へのメール送信を阻止
- 03リクエストを送らずにルールをテスト
MCP 対応
MCPクライアントはバックエンドのMCPサーバーではなく、このサーバーに接続します。許可された読み取り・書き込みツール呼び出しを転送し、設定ルールに反する要求を拒否します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
mcp-write-gate
mcp-write-gate は、AI エージェントと、メール、CRM、Smartlead、Slack など、MCP 経由でエージェントが使用するツールの間に位置します。エージェントは自由に読み取れますが、書き込みはすべて送信前にチェックされ、顧客、進行中の商談、またはリストに載っているその他の相手を対象とするものは、ツールに届く前に拒否されます。
私は、Claude Code のようなエージェントを実際のシステムに接続し、エージェントが言いくるめて回避できないルールを設けたい GTM チームやオペレーションチーム向けに、これを作りました。最も一般的な設定は読み取り専用モードです。Smartlead、HubSpot、Salesforce を全権限の API キーで接続すると、エージェントはすべてを参照できますが、何も変更できません。
+---------------+ +------------------+ +-------------------+
| AI agent | tool call | mcp-write-gate | allowed calls | Real MCP server |
| (Claude Code, | ------------> | | ---------------> | (HubSpot, Gmail, |
| Cursor, ...) | <------------ | | <--------------- | Smartlead, ...) |
+---------------+ the result, +--------+---------+ results +-------------------+
or why it |
was refused v
+-----------------------------+
| read -> forward |
| write, safe -> forward |
| write, listed -> refuse |
| write, unsure -> hold |
| read-only -> refuse |
| every call -> log |
+-----------------------------+
仕組み
エージェントは実際のサーバーではなく mcp-write-gate に接続し、同じ名前と入力のツールを参照します。エージェントがツールを呼び出すと、ゲートが処理を判断します。読み取りはそのまま通過します。書き込みはリストと照合され、顧客、進行中の商談、または連絡禁止としてマークされた相手に関係する場合は拒否され、その理由がエージェントに伝えられます。ツールには何も届きません。どのリストにも載っていない相手への書き込みは、デフォルトで通過するか、希望に応じて人の承認を待ちます。また、たとえば同じ相手への連絡を週に1通までに制限することもできます。読み取り専用サーバーでは、キーで許可されている内容にかかわらず、すべての書き込みが拒否されます。
エージェントが実際の API キーを保持することはありません。キーはゲート専用のフォルダーに保存され、ゲートはサーバーから返される情報からキーを除去します。許可された呼び出しも拒否された呼び出しもすべてログに記録され、後から誰かが編集したかどうかも確認できます。
クイックスタート
Python 3.10 以降が必要です。
pip install mcp-write-gate
mcp-write-gate init
mcp-write-gate add mail -- npx -y your-mail-mcp-server
init は、プロジェクトとは別のユーザーフォルダーにゲート用フォルダーを作成します。このフォルダーには、ルールとサーバーを記録した gate.json、lists/off-limits.csv にある初期リスト、実際のサーバーの API キーを保存する keys.env、およびログが含まれます。
add は実際のサーバーを一度起動してツールを読み込み、どれが読み取り用でどれが書き込み用かを推測します。推測結果を、エージェントの MCP 設定用ブロックとともに表示します。推測内容を確認してから、実際のサーバーの設定があった場所にそのブロックを貼り付けてください。Claude Code では、コマンドを1つ実行するだけです。
claude mcp add mail -- mcp-write-gate serve mail --config "<gate folder>/gate.json"
リモートサーバーは URL で追加します。キーは keys.env に保存し、${NAME} で参照します。OAuth を使用するサーバーでは、人が一度サインインする必要があります。その後は、ゲートが自動的にトークンを更新します。
mcp-write-gate add crm --url https://mcp.example.com/mcp --header 'Authorization: Bearer ${CRM_TOKEN}'
mcp-write-gate add crm --url https://mcp.example.com/mcp --oauth
mcp-write-gate login crm
ルールを適用する前に、何も送信せずにテストできます。
mcp-write-gate check mail send_email --args '{"to": ["[email protected]"]}'
読み取り専用モード
mcp-write-gate add smartlead --preset read-only --url 'https://mcp.smartlead.ai/sse?user_api_key=${SMARTLEAD_KEY}'
mcp-write-gate reads smartlead
mcp-write-gate confirm smartlead get_campaigns get_campaign_stats
読み取り専用モードでは、すべての書き込みが拒否され、リスト、モード、承認によってこれが変更されることはありません。読み取りが通過するのは、サーバーがツールを読み取り専用としてマークし、かつツール名が読み取り操作を示している場合、または人が mcp-write-gate confirm で確認した場合に限られます。mcp-write-gate reads では、すべての読み取りと、それを確認した人物を一覧表示します。
ゲートはサーバーの判定をすべて鵜呑みにするわけではありません。サーバーが読み取り専用とラベル付けした delete_campaign というツールも、書き込みとして扱われます。確認後にサーバーがツールを変更した場合、そのツールは再確認されるまで拒否されます。HTTP DELETE、書き込みを行う SQL 文、GraphQL のミューテーションなど、引数を使って何かを変更しようとする読み取りも拒否されます。
そのため、以下の4つの条件を満たせば、全権限のキーをゲートの背後に安全に配置できます。
- エージェントがそのツールにアクセスする経路は、ゲートだけであること。
- エージェントがゲートのフォルダーを読み取ったり、ゲートのユーザーとしてコードを実行したりできないこと。そうでなければ、キーを見つけて API を直接呼び出せる可能性があります。docs/security.md では、これを防ぐ3つの方法を説明しています。最も強力なのは、別のコンテナーを使用する方法です。
- 確認する前に、各読み取りをチェックしていること。
call_apiやrun_queryなどの汎用ツールには特に注意が必要です。ベンダー API が GET リクエストで削除を行う場合、読み取りに見えるからです。 - キーのスコープが、ベンダーが提供する最小限の範囲に設定されていること。ゲートは二重目のロックなので、最初のロックも維持してください。
リスト
リストは lists/ フォルダーにある通常の CSV、TXT、JSON ファイルなので、CRM からエクスポートしたり、手動で管理したりできます。すべてのファイルが読み込まれ、変更は次回の呼び出しから反映されます。
target,status,note
example.com,customer,paying account
[email protected],open_deal,in a live deal
[email protected],allow,partner contact inside a customer
#sales-internal,blocked,chat channel the agent must not post in
*/contracts/*,blocked,signed contracts stay untouched
ドメインを指定すると、そのすべてのサブドメインも対象になります。また、メールアドレスの行は、同じメールボックスを +tag 付き、または Gmail のドット付きで表記したものも対象になります。複数の行が一致した場合は、より具体的な行が優先されるため、[email protected],allow を顧客のドメイン内に設定できます。ゲートが認識しないステータスは拒否として扱われるため、入力ミスでゲートが開くことはありません。情報がファイルではなく CRM にある場合は、docs/configuration.md で説明されているように、どのリストにもない対象についてゲートから検索コマンドを実行できます。
実際のサーバーでのテスト
| サーバー | テスト内容 |
|---|---|
| Smartlead | 170 個すべてのツールを読み取りと書き込みに分類しました。リードへの返信、キャンペーンの開始、メールの転送は拒否され、送信されないことを確認しました。確認済みの読み取りはそのまま通過し、API キーがエージェントに渡ることもありませんでした。 |
| HubSpot | 読み取りは HubSpot に通過しました。レコードの作成とエンゲージメントの記録は拒否され、送信されませんでした。 |
| Gmail | 23 個すべてのツールを分類しました。下書き、ラベル、迷惑メール、ゴミ箱は書き込みとして扱われます。 |
| Salesforce | 74 個すべてのツールを分類しました。デプロイ、権限の変更、Apex テストは書き込み、クエリは読み取りです。 |
| Notion | 24 個すべてのツールを分類しました。ページの作成、編集、移動、削除は書き込み、取得は読み取りです。 |
| MCP filesystem および everything servers | 対象としてのファイルパス、リソース、プロンプト、補完、長時間実行される呼び出しをテストしました。 |
エージェントとして Claude Code でも実行しました。ゲートがない場合、Claude は依頼されたメールを送信しました。ゲートを読み取り専用モードにすると、メールは送信されず、ログに拒否が記録されました。
保護できないこと
ゲートが確認するのは、呼び出しが誰に対して、何に対して行われるかであり、メッセージの内容ではありません。そのため、別の相手へのメール本文に顧客の名前が含まれていても検出されません。暗号化されたペイロード、独自のバイナリ形式、または contact 123 のような単独のレコード ID に隠された対象は確認できません。ID については検索コマンドを追加でき、それ以外については、そのツールをリストにない相手には拒否するよう設定できます。同じ OS ユーザーとしてコードを実行するエージェントは止められません。そのため、Dockerfile ではゲートを独自のコンテナーで実行します。また、制御できるのはエージェントがサーバーに送信する内容だけなので、信頼できるサーバーのみをゲートの背後に配置してください。
詳細情報
docs/configuration.md では、gate.json のすべての設定項目(対象、プリセット、レート制限、検索コマンド、保留中の呼び出しと承認ページ、HTTP 経由での提供、すべてのコマンド一覧)について説明しています。docs/security.md では、ゲートにエージェントがアクセスできないようにする方法、シークレットの保存場所、ログで改ざんを確認する方法、攻撃テストの対象について説明しています。
テストの実行
pip install -e ".[dev]"
pytest
テストではゲートの背後で実際の MCP サーバーを起動し、公式の MCP クライアントを使って、stdio と HTTP の両方で通信します。
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。