MCPで本番環境に接続する権限設計 — 読み取り専用ロールと承認フロー
本番のデータベースやクラウド、IaCにMCPで接続する前提の権限設計を扱います。バックエンド側で読み取り専用ロールをどう作るか、書き込みをどこで人の承認に止めるかを横断でまとめます。
本番のデータベースやAWSアカウント、Kubernetesクラスタ、HCP TerraformにMCPで接続するとき、決めるべきことは2つです。接続する側に何をさせないか(読み取り専用ロールの設計)と、残った操作のうちどこで人の承認を挟むか(承認フローの設計)です。MCPサーバーごとの許可ルールの構文はMCPセキュリティガイドにまとめています。本記事はその手前、バックエンド側でどう読み取り専用を作るか、複数のプロダクトに共通する承認フローの設計原則を扱います。
本番接続の権限設計はallow/denyルールとは別の層
Claude Codeの許可ルールとMCPサーバーの向こう側の権限は、別々の層で効きます。
どちらの層が何を止めるか
Claude Code側の許可ルール
allow / ask / denyが決めるのは、Claude Codeがどのツール呼び出しを実行するかです。評価順はdeny、ask、allowで、最初に一致したものが結果になります。接続先のDBやAPIが何を許すかは、このルールの外です。
バックエンドの認証情報
DBユーザー・IAMポリシー・ServiceAccountが、実際に実行できる操作を決めます。allow ruleで書き込みツールを許可していても、接続先が読み取り専用なら書き込みは失敗します。逆に権限が強すぎれば、Claude Code側をどれだけ絞っても防ぎきれません。
本番接続の安全性は、まずバックエンド側の権限をどう絞るかで決まります。
読み取り専用ロールをどう作るか
バックエンドごとに「読み取り専用」の実装方法が違います。
| バックエンド | 読み取り専用の作り方 | 参考 |
|---|---|---|
| リレーショナルDB | 読み取り専用の作り方接続文字列に渡すDBユーザー自体をSELECT権限のみで作成する | 参考MCPでデータベースに接続する |
| Kubernetes | 読み取り専用の作り方専用ServiceAccountを読み取り専用RBAC Roleに紐付け、TOML設定のread_only = true(旧--read-onlyフラグ)と併用する | 参考Kubernetes MCPサーバーの権限設計 |
| AWS(CloudFormation診断) | 読み取り専用の作り方IAMポリシーをDescribe*系アクションとcloudtrail:LookupEventsのみに絞る | 参考CloudFormation/CDKをMCPで自動検証する |
| HCP Terraform | 読み取り専用の作り方registryツールセットのみ有効にし、TFE_TOKEN自体を渡さない | 参考Terraform MCPサーバーの使い方 |
共通しているのは、MCPサーバーの設定でなく、接続先の認証情報そのものを読み取り専用にする点です。DBならユーザー、KubernetesならServiceAccountとRole、AWSならIAMポリシー、Terraformならトークンを渡すか渡さないか。MCPサーバー側のフラグは補助に過ぎず、最後の砦は接続情報の権限範囲です。ヘッダーで書き込みツールを隠す開発者ポータルの例はClaudeとPortの連携手順にあります。
MCPサーバー側のフラグだけに頼らない理由
MCPサーバーが持つ「読み取り専用モード」のようなフラグは、実装によって有無も効き方も違います。RabbitMQ向けのMCPサーバーには、書き込みツールを--allow-mutative-toolsを付けたときだけ有効にする実装もあります。一方、Pulumiの@pulumi/mcp-serverはREADMEに書き込みを無効化するフラグの記載がなく、デプロイを実行するpulumi-cli-upが接続した時点で登録されます。
フラグの有無はREADMEで個別に調べるほかありません。まず接続情報自体を読み取り専用にする設計なら、どのMCPサーバーを使う場合でも通用します。隔離環境を操作するMCPの例はSprites MCPにあります。
承認を人に届ける仕組みと、その抜け道
読み取り専用ロールで防げるのは接続先の書き込みだけです。読み取り専用でも実行してよいか判断が要る操作(大量データの一括取得、外部への通知送信、コスト影響のあるクエリ等)には、Claude Codeの承認の仕組みで人を挟めます。
承認を強制する2つの経路
ツール単位のrequiresUserInteraction
MCPサーバー開発者が
tools/list応答の_meta["anthropic/requiresUserInteraction"]をtrueにすると、そのツールは呼び出しごとに確認が出ます。acceptEdits・auto・bypassPermissionsでも省略されず、allow ruleも「次回から確認しない」も効きません。同意そのものが目的のツール(アクセス権の付与等)に向きます。組織のコネクタ制御
claude.aiコネクタのツールに組織が
askを設定すると、どの権限モードでも毎回「Your organization requires approval for this tool」の確認が出ます。blockedならツールはClaudeの一覧にそもそも渡されません。個人のallow ruleでは上書きできません。
どちらも万能ではありません。たとえばデスクトップアプリのローカル・SSHセッションでは、blockedはアプリが先に除外しますが、askはClaude Codeに届かず、通常の許可ルールが適用されます。requiresUserInteractionを付けられるのもサーバーの作り手だけです。他社製サーバーのツールを毎回確認にしたいときは、利用側がpermissions.askにmcp__サーバー名__ツール名のルールを書きます。
dontAskモードや無人実行では、確認が必要な呼び出しは承認でなく拒否に倒れます。claude -pで--permission-prompt-toolを使う場合、requiresUserInteraction付きツールへのallowは拒否に変換され、MCP tool requires user interaction; not supported via --permission-prompt-toolと返ります。Agent SDKのcanUseToolコールバックは呼び出しを受け取り、アプリが利用者に見せる前提で承認できます。定期ジョブのように答える人がいないときは--permission-prompts noneで確認を拒否に統一でき、未応答のelicitationはキャンセルされます。
elicitationは承認でなく入力の要求
elicitation(構造化入力の要求)は、MCPサーバーがタスクの途中で追加情報を求める仕組みです。フォーム形式かURL形式のダイアログが自動で出ます。認証情報の入力や、ブラウザで完結するサインインの案内には使えますが、操作の可否を判断させる関門ではありません。
何を承認必須にすべきか
承認を全操作に付けると、確認疲れで承認そのものが形骸化します。承認を挟む対象は取り消せない操作と影響範囲が広い操作に絞ります。デプロイ・削除・大量データの外部送信は候補になりますが、単純な一覧取得や単一レコードの参照までゲートする必要はありません。
絞り込みの手がかりは、IaC系MCPサーバーの実装差にあります。AWSのCloudFormation診断用サーバーには、そもそもインフラを変更するツールがありません。Terraform MCPサーバーは、ワークスペースを操作するterraformツールセットが既定で無効で、有効化とTFE_TOKENが要ります。Pulumiはpulumi-cli-preview・pulumi-cli-up・pulumi-cli-refreshがすべて既定で登録され、upを呼ぶこと自体を止める仕組みがサーバー側にありません。Pulumiのように変更系ツールが並ぶサーバーでは、upの手前に人の確認を置く設計が効きます。詳しい比較はIaC MCPサーバー比較にあります。
MCP仕様も同じ前提に立っています。仕様書のセキュリティ原則は「ホストはツールを呼び出す前に明示的なユーザーの同意を得なければならない」とし、ツールの動作説明(アノテーション等)は信頼できるサーバーから得たものでない限り信用しない、とも定めています。ツールのページではさらに、ツール呼び出しを拒否できる人間を常に介在させることが推奨されています。承認フローの設計は、Claude Code固有の機能というより、MCPというプロトコルそのものの前提です。
読み取り専用にしても消えないリスク
読み取り専用ロールは書き込みを防ぎますが、読み取った内容が接続先のAIモデル提供元に送られること自体は止めません。DBの読み取り専用ユーザーであっても、SELECTできる列に個人情報や機密情報が含まれていれば、その内容はクエリの応答としてモデル側に渡ります。読み取り専用ロールを作るときは、書き込み権限だけでなく参照できる列・テーブルの範囲も同時に絞り込みます。組織のデータ取り扱い方針に照らして問題がないかは、接続前に決めておく事項です。
elicitationのURL形式にも長さの制約があります。Claude CodeはURLをコマンドライン引数としてシステムのURLハンドラに渡し、長さに上限を設けています。エスケープが必要な文字(%や&等)は1文字がエスケープ後4文字分として数えられます。そうした文字を含まないURLでおよそ8,000文字、3文字に1回%が入る込み入ったURLでおよそ4,000文字が上限です。上限を超えると、承認側は拒否しか選べません。OAuth連携のようにURLが長くなりがちなフローを持つサーバーを選ぶときは、この制約も設計に含めます。
実際に試す
読み取り専用のDBユーザーで接続する例です。接続文字列自体にSELECT権限のみのユーザーを渡します。
claude mcp add --transport stdio db -- npx -y @bytebase/dbhub \
--dsn "postgresql://readonly:pass@prod.db.com:5432/analytics"/mcpでdbがconnectedと表示されれば、接続は成立しています。書き込みクエリは接続先のDB権限で拒否されます。
トークンを環境変数で受け取るサーバーなら、claude mcp addの-e KEY=value(--env)で渡します。v2.1.287のclaude mcp add --helpでは、設定の保存先を決める-s, --scopeの既定はlocalで、userとprojectも選べます。チームの.mcp.jsonに載るprojectスコープへ本番の認証情報を直書きしないよう、スコープを意識して登録します。
接続を追加するときの確認手順
複数のバックエンドを同時に扱うプロジェクトでは、接続を追加するたびに次の順で確かめます。順序を飛ばして③の承認だけで守ろうとすると、MCPサーバーの実装差に安全性が左右されます。
本番接続の追加前チェック
- 1
接続情報を読み取り専用で発行できるか
DBユーザー・トークン・ServiceAccountのどれも、バックエンド側で書き込み権限なしに作れるかを見ます。参照できる列・テーブルの範囲もここで絞ります。
- 2
サーバー側のフラグが無くても二重に防げるか
MCPサーバーに書き込みを止めるフラグがあっても、無効にした状態でバックエンドの権限が書き込みを拒否することを確かめます。
- 3
取り消せない操作だけを承認の対象にできているか
requiresUserInteraction、permissions.ask、組織のask、プレビュー確認のいずれかで、削除・デプロイのような操作の手前に人が入っているかを見ます。
3つとも「はい」と答えられない接続は、本番に向ける前に権限設計を見直す対象です。
まとめ
本番へのMCP接続の設計は、認証情報を読み取り専用で発行し、サーバー側のフラグには頼らず、承認は取り消せない操作にだけ残す、という順序です。Kubernetesクラスタへの具体的な実装手順はKubernetes MCPサーバーの権限設計、MCPサーバーごとの許可ルールの書き方はMCPセキュリティガイドを参照してください。