MongoDB MCPを本番で使うときの読み取り専用設定
MongoDB MCPサーバーを本番クラスタに繋ぐ前提で、--readOnlyフラグ・IPアクセスリスト・DBユーザー権限を重ねる手順をまとめます。
MongoDB MCPサーバーの接続手順で動作確認を終えたら、本番クラスタに繋ぐ前に権限を絞り込みます。MDB_MCP_READ_ONLYの既定値はfalseで、何も指定しなければinsert-manyやdrop-collectionのような書き込み・削除ツールもそのまま登録されます。--readOnlyフラグ・接続元IPの制限・DBユーザー権限の3層を重ねておくと、どれか1つの設定ミスだけでは本番データに書き込みが届きません。
前提条件
接続手順の記事で解説した接続文字列、またはAtlas APIサービスアカウントでの接続を前提にします。Atlasを使っている場合は、IPアクセスリストの操作にAtlas APIの認証情報が必要です。
書き込み系ツールをそもそも登録させない
MongoDB MCPサーバーのツールには、操作の種類(operation type)が付いています。readOnlyを有効にすると、種類が「read」「connect」「metadata」以外のツールは起動時に登録されません。insert-many・update-many・delete-many・drop-collection・drop-databaseなどはClaudeから見て存在しないツールになります。サーバーのログには、登録を見送ったツールの一覧が出ます。
使い分けは、止めたい範囲で決まります。
readOnlyとdisabledToolsの違い
--readOnly
書き込み系の種類を一括で外します。止め忘れが起きにくく、本番接続の既定にしやすい方法です。
--disabledTools
ツール名・操作の種類(create update delete read metadata connect)・カテゴリ(atlas mongodb)で指定します。データベース操作だけを使うならatlasカテゴリごと外せます。
環境変数ではMDB_MCP_DISABLED_TOOLS="create,update,delete,atlas"のようにカンマ区切り、コマンドライン引数では--disabledTools create update delete atlasのように空白区切りで書きます。
チームで共有する.mcp.jsonに入れる
Claude Codeに登録するときは、接続文字列そのものを設定に書かず、環境変数の参照にします。claude mcp add-jsonの--scopeの既定はlocalで、チームで共有する.mcp.jsonに書き出すのはprojectを指定したときです。実行すると次のようになります。
claude mcp add-json mongodb \
'{"command":"npx","args":["-y","mongodb-mcp-server@latest","--readOnly"],"env":{"MDB_MCP_CONNECTION_STRING":"${MDB_MCP_CONNECTION_STRING}"}}' \
-s projectAdded stdio MCP server mongodb to project config生成された.mcp.jsonです。
{
"mcpServers": {
"mongodb": {
"command": "npx",
"args": ["-y", "mongodb-mcp-server@latest", "--readOnly"],
"env": {
"MDB_MCP_CONNECTION_STRING": "${MDB_MCP_CONNECTION_STRING}"
}
}
}
}JSON全体をシングルクォートで囲んでいるので、${...}はシェルに展開されず、文字列のままファイルに入ります。Claude Codeは.mcp.jsonのenvでも${VAR}を展開するため、接続文字列は各自のシェルの環境変数に置き、リポジトリにはパスワードを残さずに済みます。変数が未設定でデフォルトも無いときは、claude mcp listに警告が出て、${VAR}の文字列がそのまま使われます。
プロジェクトスコープのサーバーは、対話セッションで承認するまで使われません。優先順位は、コマンドライン引数、環境変数、設定ファイルの順に高いので、--readOnlyとMDB_MCP_READ_ONLY=falseのように食い違う指定を同居させないようにします。
aggregateはreadOnlyでも登録される
aggregateとaggregate-dbは、操作の種類が「read」のツールです。readOnlyを有効にしても外れません。パイプラインに$outや$mergeが含まれる場合、この2つのツールはconfirmationRequiredToolsの設定にかかわらず、実行前に確認を求めます。READMEによると$outは対象コレクションの内容を丸ごと置き換えるステージで、確認メッセージには対象のコレクション名と処理内容が入ります。
ただしこの確認はelicitationという仕組みに依存します。elicitationに対応していないクライアントでは、確認プロンプト自体が出ず、ツールはそのまま実行されます。readOnlyに確認プロンプトを足しても、パイプライン内の書き込みを最後に止めるのはDBユーザーの権限です。次の節の専用ユーザーが土台になります。
IPアクセスリストで接続元を絞る
Atlasでは、接続元のIPをアクセスリストで制限できます。MCPサーバーを動かすマシンのIPがアクセスリストに登録済みか、Atlasの管理コンソールで先に確認します。
Atlas APIサービスアカウントで接続している場合は、atlas-inspect-access-listで現在の登録状況をClaudeに見せ、atlas-create-access-listで追加できます。atlas-create-access-listは既定のconfirmationRequiredToolsに含まれるので、elicitationに対応したクライアントでは実行前に確認が入ります。CIやヘッドレス実行のように確認プロンプトを挟めない場面では、事前にAtlas管理コンソールから手動で登録しておくほうが確実です。
IPの許可先は2種類あります。READMEのサービスアカウント作成手順では、Client IDとClient Secretを発行したあとで、自分のIPを「API access list」に追加します。これはAtlas APIを呼べる接続元の制限です。クラスタへの接続を許可するatlas-create-access-listの対象は、このAPI access listとは別に設定します。
DBユーザーの権限を絞る
--readOnlyはMCPサーバー内部でのツールの公開範囲を絞るだけで、接続文字列に含まれるDBユーザーの権限そのものは変えません。管理者権限のユーザーを接続文字列にそのまま渡していれば、MCPサーバーの設定に穴があったとき、DB側では書き込みが通る状態が残ります。
Atlasでは、データベースユーザーを作成するときに、読み取りだけを許すビルトインロールを割り当てます。セルフホストのMongoDBでも、読み取り権限だけを持つ専用ユーザーを作り、MCPサーバー専用の接続文字列に使います。管理者アカウントの使い回しは避けます。
Atlas APIを使うなら、サービスアカウントのロールも絞る
Atlas API経由でクラスタ一覧やパフォーマンスアドバイザーを使う場合は、サービスアカウントに付けるロールも用途に応じて最小限にします。READMEが示す、用途別に最も安全なロールは次のとおりです。
| やりたいこと | 割り当てるロール(スコープ) |
|---|---|
| 組織・プロジェクトの一覧を見る | 割り当てるロール(スコープ)Org MemberまたはOrg Read Only(組織) |
| 新しいプロジェクトを作る | 割り当てるロール(スコープ)Org Project Creator(組織) |
| プロジェクト内のクラスタ・DBを見る | 割り当てるロール(スコープ)Project Read Only(プロジェクト) |
| クラスタを作成・管理する | 割り当てるロール(スコープ)Project Cluster Manager(プロジェクト) |
| アクセスリストを管理する | 割り当てるロール(スコープ)Project IP Access List Admin(プロジェクト) |
| データベースユーザーを管理する | 割り当てるロール(スコープ)Project Database Access Admin(プロジェクト) |
| Stream Processingリソースを管理する | 割り当てるロール(スコープ)Project Stream Processing Owner(プロジェクト) |
READMEはプロジェクト単位のロールを優先し、必要なプロジェクトにだけ割り当てることを勧めています。Organization Ownerは、組織内の全プロジェクトと設定を管理する必要がある場合を除き、避けるよう警告しています。
1回のクエリで返す量に上限をかける
--readOnlyは書き込み系ツールを止めるだけで、読み取り系ツールが返す量は別の設定で制限します。本番のコレクションを相手にするときに効く既定値は、次のとおりです。
取得量まわりの既定値
maxDocumentsPerQuery
100件
findまたはaggregateが返せる件数の上限
maxBytesPerQuery
16MB
結果サイズの上限(16777216バイト)
maxTimeMS
未設定
設定すると読み取り操作に実行時間の上限がかかる
queryCountMaxTimeMsCap
10秒
findの件数カウント段階の上限(10000ms)
findツールでは、maxDocumentsPerQueryとツール自身のlimitパラメーターのうち小さいほうが実効上限になります。maxBytesPerQueryはresponseBytesLimitパラメーターの上限として働きます。aggregateのカウント段階には別の上限aggregationCountMaxTimeMsCap(既定60000ミリ秒)があります。本番のプライマリに重いaggregateを向けたくないなら、設定ファイルで次のように絞ります。
{
"maxDocumentsPerQuery": 50,
"maxBytesPerQuery": 5242880,
"maxTimeMS": 10000
}サーバーサイドJSと全件スキャンを塞ぐ
disableServerSideJsは既定がtrueで、$where・$function・$accumulatorといったサーバーサイドJavaScriptの演算子を、クエリのフィルターとaggregationパイプラインの両方で禁止します。readOnlyとは独立に最初から効いているので、意図して無効にしない限り追加の設定は要りません。
インデックスを使わない全件スキャンを止めたいときは、indexCheckを有効にします。環境変数ならMDB_MCP_INDEX_CHECK=true、引数なら--indexCheckです。コレクションスキャンを伴うクエリは拒否され、エラーメッセージが返ります。
ディスクに残るものを管理する
本番データを扱うと、MCPサーバーを動かすマシンのディスクにもデータの痕跡が残ります。置き場所は3か所です。
- エクスポート:
exportツールが出力したデータはexportsPathに一時ファイルとして置かれます。既定はmacOS・Linuxで~/.mongodb/mongodb-mcp/exports、Windowsで%LOCALAPPDATA%\mongodb\mongodb-mcp\exportsです。5分で期限切れになり、2分間隔のクリーンアップで削除されます - ログ: 既定のロガーは
disk,mcpで、ログがディスクに書かれます。macOS・Linuxの既定先は~/.mongodb/mongodb-mcp/.app-logsで、logPathで変えられます。ディスクに残したくない場合は、--loggers mcp stderrのようにロガーを選びます - 設定ファイル:
MDB_MCP_CONFIGで読み込むJSONには、接続文字列やAPIシークレットが入りえます
READMEは、exportsPathとlogPathについて、実行ユーザーが読み書きできる状態にしたうえで、権限を適切に絞るよう求めています。設定ファイルについても、所有者を実行ユーザーだけに限る例が載っています。
chmod 600 /path/to/config.json
chown your-username /path/to/config.json同じサーバーに複数のユーザーがいる環境では、この権限が緩いと、DBユーザーのパスワードやAtlasのAPIシークレットが他のユーザーから読めます。READMEは、機密性の高い項目を--config引数や設定ファイルの本文より、環境変数で渡すことを勧めています。コマンドライン引数はプロセス一覧に見えるためです。
最後に、Atlas API経由でクラスタに接続すると、MCPサーバーが一時的なデータベースユーザーを作ります。atlasTemporaryDatabaseUserLifetimeMsがその生存時間で、既定は4時間(14400000ミリ秒)です。時間が過ぎると自動で削除されます。外部へのテレメトリ送信を止めたい場合は、MDB_MCP_TELEMETRY=disabledまたはDO_NOT_TRACK=1を設定します。
5つの層の抜け穴を見比べる
ここまでの設定は、どれも「書き込みを止める」ように見えて、効く階層が違います。1つが漏れても他の層で被害を抑えられる構成にしておきます。
層ごとの止め方と抜け穴
--readOnly
MCPサーバーが登録するツール自体を絞ります。抜け穴は、フラグの設定漏れと優先順位の取り違えです。
DBユーザー権限
データベース側での書き込み実行を止めます。抜け穴は、管理者アカウントの使い回しです。
IPアクセスリスト
未許可のネットワークからの接続を止めます。抜け穴は、開発時に開けた
0.0.0.0/0の放置です。confirmationRequiredTools
削除系ツールの無確認実行を止めます。抜け穴は、elicitationに未対応のクライアントです。
取得量の上限と indexCheck
過大な取得と全件スキャンを止めます。抜け穴は、上限を既定値のまま放置することです。
さらに細かくツール単位で許可・要確認を分けたいときは、Claude Code側のpermissions設定も重ねられます。書き方はClaude Code MCP設定ガイドにあります。
よくあるつまずき
readOnlyを有効にしたのにAtlasクラスタの作成が失敗する: 想定どおりの挙動です。クラスタの作成・更新にあたるツールは書き込み系の操作と考えられ、readOnlyの接続では登録されません- 接続元IPが変わって突然繋がらなくなる: 動的IPの回線からMCPサーバーを動かしている場合に起きます。固定IPの環境に寄せるか、アクセスリストに現在のIPを登録し直します
confirmationRequiredToolsが効かない: elicitationに対応していないMCPクライアントでは、確認プロンプトが出ず、対象ツールはそのまま実行されます。クライアントの対応状況を先に見ておきます.mcp.jsonに書いたサーバーが動かない: プロジェクトスコープのサーバーは、対話セッションで承認するまで使われません。承認の選択をやり直すときはclaude mcp reset-project-choicesを使います- 開発用の広いDBユーザー権限を本番接続に使い回している: 検証時に作った管理者権限の接続文字列を、本番用の設定にコピーしたまま残しているケースです。環境ごとに接続文字列とDBユーザーを分けます
よくある質問
confirmationRequiredToolsのツール名は自分で追加・変更できますか
できます。既定のリスト(atlas-create-access-list,atlas-create-db-user,drop-database,drop-collection,delete-many,drop-index,atlas-streams-manage,atlas-streams-teardown)は初期値で、カンマ区切りの文字列を上書きすれば、確認を挟みたい任意のツールを足せます。aggregateを加えると、すべての呼び出しが実行前の確認の対象になり、$outや$mergeだけの個別確認は重ねて出ません。
Dockerで動かす場合も同じ読み取り専用設定が使えますか
使えます。READMEのDocker例では、docker run --rm -i -e MDB_MCP_CONNECTION_STRING -e MDB_MCP_READ_ONLY="true" mongodb/mongodb-mcp-server:latestのように、環境変数で同じ設定を渡します。接続文字列は事前にシェルへexportしておき、値を書かずに-eで引き継ぎます。
まとめ
本番に繋ぐ土台は、読み取り専用のDBユーザーです。--readOnlyは公開するツールを絞るだけで、aggregateのような読み取り系ツールは残るので、書き込みの最後の歯止めはDB側の権限が担います。Atlasのクラスタ作成やスケーリングを任せたい場合は、読み取り専用とは別の接続を用意する前提で設計します。