Claude Media
データベースMCPサーバーの読み取り専用設定を5製品で比較する

データベースMCPサーバーの読み取り専用設定を5製品で比較する

5製品のMCPサーバーが読み取り専用をどう実装しているかを比較します。サーバー側で止める製品と、DB側の権限に頼る製品に分かれます。

PostgreSQL・MySQL・MongoDB・Redis・Elasticsearchの5つのMCPサーバーは、READMEで読み取り専用の使い方を示しています。ただし実装は一致しません。MCPサーバー自身がSQLやツール登録を絞って書き込みを止める製品と、サーバーに制御が無くDB側のユーザー権限だけが頼りの製品に分かれます。「読み取り専用のつもりが、書き込みを止める層が1つも無かった」という状況は後者で起こります。対象のうちRedis・MongoDB・Elasticsearchは各社のリポジトリで、PostgreSQL(crystaldba)とMySQL(benborla)は第三者の製品です。

読み取り専用はサーバーが止めるか、DB権限だけか

くらべる

読み取り専用の担保は2系統

PostgreSQL・MySQL・MongoDB

サーバーが止める

DBユーザーが書き込み権限を持っていても、MCPサーバーが先に書き込みを断ります。止め方は製品ごとに違います。

Redis・Elasticsearch

DB権限だけ

サーバーに切り替えスイッチがありません。接続に使うACLユーザーやAPIキーの権限が、唯一の防御線です。

比較の軸は3つです。読み取り専用をどこで実現しているか、設定に使うフラグや環境変数の名前、DB側の権限設定を別途用意する必要があるかです。RavenDBのようにクライアント証明書の権限で上限を決める製品は、RavenDB MCPの診断手順で扱っています。

データベース(MCPサーバー)読み取り専用の実現方式主要なフラグ・環境変数DB側の権限設定も必要か
PostgreSQL(postgres-mcp)読み取り専用の実現方式読み取り専用トランザクションを強制し、実行時間も制限主要なフラグ・環境変数--access-mode=restrictedDB側の権限設定も必要かサーバー側で完結。本番では読み取り専用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_ONLYDB側の権限設定も必要か不要(Atlas API連携時はProject Read Onlyロールを別途検討)
Redis(mcp-redis)読み取り専用の実現方式サーバー自体に読み取り専用の設定項目が無い主要なフラグ・環境変数なしDB側の権限設定も必要か必須(RedisのACLで+@read -@writeのユーザーを作る)
Elasticsearch(mcp-server-elasticsearch)読み取り専用の実現方式書き込み系のツールがそもそも実装に無い。リポジトリは非推奨主要なフラグ・環境変数なし(ツール構成そのものが読み取りのみ)DB側の権限設定も必要か必須(APIキーの権限スコープが唯一の防御線)

PostgreSQLはSQLを検査し、読み取り専用トランザクションで包む

postgres-mcp(Postgres MCP Pro)の--access-modeには2つの値があります。unrestrictedは読み書きの全権で、開発環境向けです。restrictedは読み取り専用トランザクションに限り、リソース制限も課します。READMEによると、リソース制限は現状では実行時間だけです。

READMEによると、PostgreSQLには接続やセッションを丸ごと読み取り専用にする手段が無いため、読み書き可能な接続の上に自前で読み取り専用を載せています。トランザクションが読み取り専用でも、ROLLBACK; DROP TABLE users;のように途中で抜け出されると意味がありません。そこでcommitやrollbackを含むSQLは、実行前に拒否されます。READMEは、PL/pgSQLやPL/PythonではCOMMITとROLLBACKを許さないので、この拒否と矛盾しないと説明しています。ただしDB側で危険なストアドプロシージャ言語を有効にしていると、この防御は迂回されうるとREADMEが注記しています。

同じREADMEの中で、restrictedモードの位置付けは揺れています。設定の節では本番環境向けとされる一方、設計方針の節には「本番DBでも安全に使えるよう、将来さらに対策を足すかもしれない」という趣旨の一文があります。本番で使うなら、SELECT権限だけのDBユーザーと組み合わせる前提で読むのが無難です。

claude mcp add postgres-ro \
  --env DATABASE_URI="postgresql://user:pass@host:5432/db" \
  -- uvx postgres-mcp --access-mode=restricted

v2.1.289で実行すると、--より後ろの--access-mode=restrictedはClaude Codeのオプションではなく、MCPサーバーの起動引数として保存されます。ローカルスコープ(-sを省いたときの既定)では、設定ファイルの.claude.jsonに次の形で入ります。

"mcpServers": {
  "postgres-ro": {
    "type": "stdio",
    "command": "uvx",
    "args": ["postgres-mcp", "--access-mode=restricted"],
    "env": { "DATABASE_URI": "postgresql://user:pass@host:5432/db" }
  }
}

接続文字列のパスワードは平文のままenvに入ります。-s projectを付けるとプロジェクト直下の.mcp.jsonに同じ形式で書かれ、リポジトリで共有するファイルに認証情報が載ります。読み取り専用ユーザーのパスワードでも、共有ファイルに置いてよいかは別の問題です。

postgres-mcpが公開するツールは9つで、list_schemas・list_objects・get_object_details・execute_sql・explain_queryなどがあります。restrictedの読み取り専用の制限は、このうちexecute_sqlの説明に書かれています。

READMEにはほかに、--transport=sseで複数のMCPクライアントが1つのリモートサーバーを共有する構成も載っています。ただしREADMEのSSE例は、すべて--access-mode=unrestrictedです。

MySQLは書き込みの解禁スイッチを段階的に持つ

mcp-server-mysqlは、接続直後の既定状態がすでに読み取り専用です。書き込みを許可するには、操作の種類ごとの環境変数を明示的にtrueにします。

MySQL

書き込みを解禁する3つのスイッチ

  • 操作の種類ごと

    ALLOW_INSERT_OPERATION・ALLOW_UPDATE_OPERATION・ALLOW_DELETE_OPERATIONが別々にあり、いずれも既定はfalseです。

  • DDLは別枠

    CREATE・DROP・ALTERはALLOW_DDL_OPERATIONで別に解禁します。INSERT系を許可してもテーブル定義は変えられません。

  • スキーマごと

    SCHEMA_INSERT_PERMISSIONS=development:true,production:falseのように、データベース単位で許可を分けられます。

複数データベースを横断するマルチDBモードにも書き込みの既定オフ(MULTI_DB_WRITE_MODE=false)があります。設定リファレンスには、読み取り専用トランザクションの強制を切るMYSQL_DISABLE_READ_ONLY_TRANSACTIONSも載っており、既定はfalseです。つまりMySQLでも、フラグとトランザクションの二重になっています。

結果セットの機微情報を自動でマスクするPII redaction機能もあります。読み取り専用に加えて、読んだ内容をどこまでモデルに渡すかという別軸の防御です。

MongoDBは操作タイプ単位でツール登録を外す

mongodb-mcp-serverに--readOnly(環境変数ならMDB_MCP_READ_ONLY=true)を渡すと、「read」「connect」「metadata」のツールだけが登録されます。「create」「update」「delete」のツールは登録されず、書き込みの手段がモデルから見えません。サーバーログには、登録を止められたツールが出力されます。

既定値はfalseですが、READMEの設定例は、既定の安全策として--readOnlyを付けています。コピーしたまま使えば読み取り専用になり、外した時点で書き込み可能になります。

readOnlyのほかに、--disabledToolsでツール名・操作タイプ・カテゴリを指定して個別に無効化できます。たとえば--disabledTools create update delete atlasのように書けます。drop-database・drop-collection・delete-manyなどは、既定で実行前の確認を求める対象です。aggregate系は、パイプラインに$outや$mergeが含まれると常に確認を求めます。

実行前の確認はクライアントがelicitation(サーバーからの問い合わせ)に対応している場合に働き、対応していないクライアントでは確認なしで実行されます。確認の有無も、読み取り専用の防御として数えるときの前提になります。

Atlasのクラスタ管理API(サービスアカウントのapiClientId/apiClientSecret)を併用する場合は、別の権限軸が加わります。プロジェクトのクラスタやデータベースを閲覧するだけならProject Read Onlyロールで足ります。Organization Ownerの付与は「めったに必要なく、リスクになりうる」とREADMEに書かれています。

RedisとElasticsearchはサーバーに読み取り専用の設定が無い

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は書き込み系コマンド群の拒否です。このACLユーザーを作り忘れると、defaultユーザーなど書き込み可能な資格情報でつないだ時点で、書き込みを止める層はありません。

Elasticsearchのmcp-server-elasticsearchが提供するツールは5つです。list_indices・get_mappings・search・esql・get_shardsで、書き込みや削除のツールは実装にありません。それでもREADMEは、必要最小限の権限に絞ったAPIキー(特定インデックスへの読み取りのみ)をベストプラクティスに挙げています。

このリポジトリはREADME冒頭で非推奨とされ、重大なセキュリティ修正のみを受け付ける状態です。後継はElastic Agent BuilderのMCPエンドポイントで、Elasticsearch 9.2.0以降とServerlessプロジェクトで使えます。

二重防御が必要かは接続先で変わる

接続先構成例理由
個人の検証・ローカルDB構成例サーバー側フラグのみ理由影響範囲が自分のマシンに閉じる
本番DBへの直接接続(PostgreSQL・MySQL・MongoDB)構成例サーバー側フラグ + DB側の読み取り専用ユーザー理由フラグの設定漏れが、そのままデータ変更になる
本番のRedis・Elasticsearch構成例DB側の権限設定のみ。省略できない理由サーバー側に代わりの防御が無い

Claude Code側のpermissionsルールでMCPツールの呼び出しを絞る設計は、多重防御の一部です。Claude CodeでMCPからデータベースに接続する方法で扱っています。

本番に繋ぐ前の手順

手順

書き込みが止まることを先に試す

  1. 1

    DB側に読み取り専用の資格情報を用意する

    RedisならACLユーザー、ElasticsearchならAPIキー、PostgreSQLなどならSELECT権限だけのロールです。

  2. 2

    フラグを付けたコマンドで登録する

    PostgreSQLの--access-modeは、コピーした例の値がunrestrictedのままになっていないかを見ます。例のコマンドは書き込み可能な状態で動くからです。

  3. 3

    開発用DBで書き込みを頼んでみる

    「テストデータを1件追加して」のような依頼が拒否されるのを、本番の前に開発用DBで見ます。

マネージドサービスのIPアクセスリストやネットワークピアリングは、読み取り専用化の代わりにはなりませんが、積み増せる別軸の防御です。

まとめ

フラグの有無ではなく、接続に使う資格情報に書き込み権限が残っていないかで本番接続を判断すると、5製品を同じ物差しで扱えます。PostgreSQLの索引提案やヘルスチェックまで含めた使い方はPostgreSQL MCPサーバーの使い方にあります。複数のDBに横断で接続する設計は前述の接続ガイドにあります。分析用途のClickHouse・DuckDB・BigQueryのMCP接続を比較する記事も参照できます。スキーマをコードで管理する場合は、Claude CodeでDrizzle ORMを使うでpushとgenerate+migrateの違いを扱っています。

この記事を共有:XはてブLinkedIn