データベースMCPサーバーの読み取り専用設定を5製品で比較する
5製品のMCPサーバーが読み取り専用をどう実装しているかを比較します。サーバー側で強制する製品と、DB側の権限に依存する製品に分かれます。
PostgreSQL・MySQL・MongoDB・Redis・Elasticsearchの公式MCPサーバーは、いずれも「読み取り専用」を掲げています。ただし実装の中身は5製品で一致しません。MCPサーバー自身がSQLやツール登録を書き換えて書き込みを止める製品と、MCPサーバーには制御の仕組みが無くデータベース側のユーザー権限だけが頼りの製品に分かれます。この違いを知らずに接続すると、「読み取り専用のつもりが、実は書き込みを止める層が1つも無かった」という事故につながります。
読み取り専用は「サーバーが強制」か「DB権限に依存」かで分かれる
5製品を並べると、読み取り専用の担保方法は大きく2系統です。PostgreSQL・MySQL・MongoDBの3製品は、MCPサーバー自身がSQLの種類やツールの操作タイプを見て書き込みをブロックします。データベース側のユーザーが仮に書き込み権限を持っていても、サーバーが間に立って止めます。一方RedisとElasticsearchの2製品は、MCPサーバー自体に読み取り専用の設定項目がありません。防御線は接続に使うデータベースユーザーやAPIキーの権限だけです。同じ「読み取り専用」という言葉でも、防御が二重になっている製品と一重しかない製品があります。
5製品を横並びで見る
比較の軸は3つです。読み取り専用をどこで実現しているか(サーバー内部かデータベース側か)、設定に使う具体的なフラグや環境変数の名前、そしてDB側の権限設定を別途用意する必要があるかです。この3つを押さえておけば、READMEの「read-only」という単語だけを見て安心する事故を避けられます。
| データベース(MCPサーバー) | 読み取り専用の実現方式 | 主要なフラグ・環境変数 | DB側の権限設定も必要か |
|---|---|---|---|
| PostgreSQL(postgres-mcp) | 読み取り専用の実現方式サーバーが読み取り専用トランザクションを強制し、実行時間も制限 | 主要なフラグ・環境変数--access-mode=restricted | DB側の権限設定も必要か不要(サーバー側で完結。読み取り専用DBユーザーは補完的な二重防御) |
| MySQL(mcp-server-mysql) | 読み取り専用の実現方式既定で読み取り専用。書き込みはツールの動作自体がopt-in | 主要なフラグ・環境変数ALLOW_INSERT_OPERATION / ALLOW_UPDATE_OPERATION / ALLOW_DELETE_OPERATION(未設定はfalse) | DB側の権限設定も必要か不要(サーバー側フラグで完結) |
| MongoDB(mongodb-mcp-server) | 読み取り専用の実現方式ツール登録時に操作タイプ(create/update/delete)をフィルタして除外 | 主要なフラグ・環境変数--readOnly / MDB_MCP_READ_ONLY | DB側の権限設定も必要か不要(Atlas API連携時はProject Read Onlyロールを別途推奨) |
| Redis(mcp-redis) | 読み取り専用の実現方式サーバー自体に読み取り専用の設定項目が無い | 主要なフラグ・環境変数なし | DB側の権限設定も必要か必須(RedisのACLで+@read -@writeのユーザーを作る) |
| Elasticsearch(mcp-server-elasticsearch) | 読み取り専用の実現方式書き込み系のツールがそもそも実装に無い | 主要なフラグ・環境変数なし(ツール構成そのものが読み取りのみ) | DB側の権限設定も必要か必須(APIキーの権限スコープが唯一の防御線) |
PostgreSQLとMySQLはサーバー自身が書き込みを止める
postgres-mcp(crystaldba配布のPostgres MCP Pro)は、接続そのものが読み書き可能なコネクションでも、--access-mode=restrictedを指定するとMCPサーバーが読み取り専用トランザクションを強制します。PostgreSQL自体には接続やセッションを丸ごと読み取り専用にする仕組みが無いため、公式実装はトランザクション単位でこれを実現しています。加えて実行時間の制限も同時にかかり、長時間クエリで本番のリソースを食い潰す事故も防ぎます。
claude mcp add postgres-ro \
--env DATABASE_URI="postgresql://user:pass@host:5432/db" \
-- uvx postgres-mcp --access-mode=restricted本番環境向けには--transport=sseによるSSE配信にも対応しており、複数のMCPクライアントが1つのリモートサーバーを共有する構成も組めます。この場合も--access-mode=restrictedは同じフラグとして機能し、共有先を増やしても読み取り専用の担保は揺らぎません。
この読み取り専用モードには、単純なSQLキーワードのフィルタでは防ぎきれない抜け道への対策も入っています。読み取り専用トランザクションの最中にROLLBACKを発行してから新しいトランザクションを開始すれば、理屈の上ではモードを回避できてしまいます。Postgres MCP Proはこの回避パターンを想定してトランザクションの状態を監視しており、単純な文字列マッチだけの実装より一段深い防御になっています。ただしデータベース側で危険なストアドプロシージャ言語を有効にしていると、この防御も迂回されうるとREADME自身が注記しています。
mcp-server-mysqlはもっと単純です。接続直後の既定状態がすでに読み取り専用で、ALLOW_INSERT_OPERATION・ALLOW_UPDATE_OPERATION・ALLOW_DELETE_OPERATIONという3つの環境変数を明示的にtrueにしない限り、書き込み系の操作そのものがツールとして機能しません。opt-inの設計なので、接続設定を書いた本人がうっかり書き込みを許可してしまうリスクは低くなります。さらに結果セットに含まれる機微情報を自動でマスクするPII redaction機能も備えており、読み取り専用に加えて「読み取った内容をどこまでモデルに渡すか」という別軸の防御も用意されています。
MongoDBは操作タイプ単位でツール登録をフィルタする
公式のmongodb-mcp-serverは、--readOnly(または環境変数MDB_MCP_READ_ONLY=true)を渡すと、「read」「connect」「metadata」に分類されたツールだけを登録し、「create」「update」「delete」に分類されたツールをそもそも登録しません。ドキュメントを書き込む関数自体がサーバー内に生成されないため、Claude側から見ても書き込み手段が存在しない状態になります。ログにも、どのツールが読み取り専用モードによって登録を止められたかが出力されます。
なお、MongoDB Atlasのクラスタ管理API(サービスアカウントのapiClientId/apiClientSecret)を併用する場合は、これとは別の権限軸があります。クラスタやデータベースを閲覧するだけならProject Read Onlyロールで足り、Organization Ownerのような強い権限を割り当てる必要はないと公式ドキュメントが明記しています。データの読み取り専用化(readOnlyフラグ)とAtlas管理APIの権限(ロール)は別レイヤーなので、両方を絞って初めて多重防御になります。
RedisとElasticsearchはMCPサーバーが読み取り専用フラグを持たない
mcp-redisには、読み取り専用を切り替えるオプション自体がありません。公式READMEが唯一示す方法は、Redis本体のACL機能でユーザーを作ることです。
redis-cli ACL SETUSER readonlyuser on '>mypassword' '~*' '+@read' '-@write'
claude mcp add redis-ro \
--env REDIS_HOST="127.0.0.1" \
--env REDIS_USERNAME="readonlyuser" \
--env REDIS_PWD="mypassword" \
-- uvx --from redis-mcp-server@latest redis-mcp-server~*は全キーへのパターンマッチ、+@readは読み取り系コマンド群の許可、-@writeは書き込み系コマンド群の拒否を意味します。MCPサーバー側に何の設定も無い以上、このACLユーザーを作り忘れると、接続情報を知っているエージェントは書き込みも実行できてしまいます。
Elasticsearch向けの公式mcp-server-elasticsearchはさらに徹底しています。提供されるツールはlist_indices・get_mappings・search・esql・get_shardsの5つだけで、インデックスへの書き込みや削除を行うツールが実装自体に存在しません。読み取り専用フラグが無いのではなく、書き込む手段そのものが無い設計です。その代わり公式READMEは「必要最小限の権限に絞ったAPIキー(読み取り専用アクセス)を使うこと」をベストプラクティスとして挙げており、防御線はクラスタ側のAPIキー権限に一本化されています。なおこのリポジトリはREADME内で非推奨化が明記されており、後継はElastic Agent Builderが提供するMCPエンドポイント(Elasticsearch 9.2.0以降およびServerless環境で利用可能)です。既存構成からの移行を計画するときはこの後継先を確認してください。
二重防御が必要かは運用環境で変わる
読み取り専用の防御が一重で足りるか、DB側の権限も含めて二重にすべきかは、接続先が個人の検証環境か本番環境かで判断が変わります。
| 運用環境 | 推奨構成 | 理由 |
|---|---|---|
| 個人の検証・ローカルDB | 推奨構成サーバー側フラグのみで可 | 理由影響範囲が自分のマシンに閉じる |
| 本番DBへの直接接続(Postgres/MySQL/MongoDB) | 推奨構成サーバー側フラグ + DB側の読み取り専用ユーザーを両方設定 | 理由フラグの設定漏れが即データ変更事故に直結するため |
| RedisやElasticsearchで本番に接続 | 推奨構成DB側の権限設定が唯一の防御。省略は不可 | 理由サーバー側に代替の防御手段が無い |
PostgreSQL・MySQL・MongoDBであっても、本番データベースに接続するときはサーバー側のフラグだけに頼らず、接続に使うDBユーザー自体の権限もSELECT権限のみに絞ることを推奨します。Claude Code側のpermissionsルールでMCPツールの呼び出し自体を制限する設計は、Claude CodeでMCPからデータベースに接続する方法で扱っている多重防御の一部です。
どの製品を使うときも確認すべきこと
PostgreSQL・MySQL・MongoDBの3製品でも、フラグ設定を忘れれば読み書き両方が可能な既定状態のまま接続してしまいます。postgres-mcpはDocker/uvx/pipxいずれの起動例でも--access-mode=unrestrictedが公式サンプルの既定値なので、コピペしたコマンドをそのまま使うと書き込み可能な状態で動きます。
RedisとElasticsearchは、DB側の権限を絞らない限り読み取り専用になりません。MCPサーバーのREADMEだけを読んで「読み取り専用モードがある」と誤解しないよう注意します。この2製品では、読み取り専用ユーザーやAPIキーを用意する作業自体が必須の手順です。
MongoDBには権限軸が2つあります。データ操作のreadOnlyフラグと、Atlas管理APIのロール設定は別物です。クラスタ管理まで任せるなら両方を確認します。
マネージドサービス側にも、見落としやすい追加の防御レイヤーがあります。MongoDB AtlasのIPアクセスリストや、クラウド事業者のネットワークピアリングのように、読み取り専用化とは別軸のアクセス制御を提供しているサービスもあります。これらは読み取り専用フラグの代わりにはなりませんが、積み増しできる防御として構成に組み込む価値があります。
まとめ
読み取り専用の実装方式は、PostgreSQL・MySQL・MongoDBがサーバー側で強制する型、RedisとElasticsearchがデータベース側の権限に依存する型に分かれます。前者はフラグの設定漏れ、後者は権限設定そのものの作り忘れが主な事故パターンです。どちらの型であっても、接続情報をコピーして終わりにせず、実際に書き込み系のツールが呼べない状態になっているかを一度は手元で確認しておくと安心です。PostgreSQLの索引提案やヘルスチェックまで含めた具体的な使い方はPostgreSQL MCPサーバーの使い方にまとめています。複数のDBに横断で接続する設計や、Claude Code側のpermissionsルールによる多重防御はClaude CodeでMCPからデータベースに接続する方法を参照してください。分析用途のClickHouse・DuckDB・BigQueryはClickHouse・DuckDB・BigQueryのMCP接続を比較するで扱っています。