MCPでPostgreSQLをClaude Codeに接続し、読み取り専用アカウントと権限設定を行う。ClaudeがスキーマやDBを直接操作でき、手動でスキーマをコピーする手間がなくなる。
データベースを接続すると、Claude Codeの動き方が変わる。テーブル構造をプロンプトにコピーする必要も、フィールド名を教える必要もない。Claudeが直接接続し、自分でスキーマを読み、クエリを書き、結果を分析してくれる。
この記事ではPostgreSQLを例に、設定から実際の使い方まで一通り解説する。
公式の @modelcontextprotocol/server-postgres がサポートしているのは:
読み取り専用。このServerはクエリのみを行うよう設計されており、INSERT/UPDATE/DELETEは実行しない。
npm install -g @modelcontextprotocol/server-postgres
.claude/settings.json(プロジェクト単位)を編集:
{
"mcpServers": {
"db": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-postgres",
"postgresql://readonly_user:password@localhost:5432/myapp_production"
]
}
}
}
接続文字列の形式:postgresql://USER:PASSWORD@HOST:PORT/DATABASE
パスワードを設定ファイルに書きたくない場合は環境変数を使う:
{
"mcpServers": {
"db": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "postgresql://readonly_user:password@localhost:5432/myapp_production"
}
}
}
}
.claude/settings.json をgitにコミットする場合は、平文のパスワードが含まれていないか確認すること。機密情報は .claude/settings.local.json に置き、.gitignore に追加する。
書き込み権限のあるアカウントをClaudeに渡してはいけない。PostgreSQLで読み取り専用ユーザーを作成する:
-- 読み取り専用ユーザーの作成
CREATE USER claude_readonly WITH PASSWORD 'your_password';
-- 接続権限の付与
GRANT CONNECT ON DATABASE myapp_production TO claude_readonly;
-- スキーマの使用権限を付与
GRANT USAGE ON SCHEMA public TO claude_readonly;
-- 全テーブルへのSELECT権限を付与
GRANT SELECT ON ALL TABLES IN SCHEMA public TO claude_readonly;
-- 将来作成されるテーブルにも同じ権限を適用
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO claude_readonly;
sessions や audit_logs など見せたくないテーブルがある場合は、そのテーブルへの権限を付与しないか、別スキーマに移動する。
Claude Codeを再起動してから聞いてみる:
データベースにあるテーブルを一覧表示して
Claudeが「データベースへのアクセス権がありません」と言う代わりにテーブル名の一覧を返してきたら、MCP接続は成功している。
設定が完了すると、Claudeにできることがぐっと広がる。実際のシナリオをいくつか見てみよう。
シナリオ1:データ構造の把握
usersテーブルとordersテーブルはどういう関係ですか?
外部キー制約はありますか?
Claudeは information_schema を直接クエリしてテーブル構造と制約を読み取り、わかりやすく説明してくれる。スキーマを貼り付ける必要はない。
シナリオ2:データ分析
過去30日間に登録したユーザーのうち、
注文を少なくとも1件入れた割合はどれくらい?
登録チャネル別に集計して
ClaudeがSQLを書いて実行し、結果を分析する。クエリが間違っていた場合(フィールド名が違うなど)、エラーを見て自分で修正する。
シナリオ3:問題の調査
ordersテーブルでstatus = 'pending'なのに
created_atが7日以上前のレコードはいくつある?
一番最近のものはいつ?
このような即席の調査は、以前は自分でSQLを書くかデータベースツールで手動確認する必要があった。今は必要なことを言うだけでいい。
シナリオ4:開発サポート
usersテーブルにlast_login_atカラムを追加したい。
マイグレーションSQLを書いて、
既存のインデックスで十分かどうかも確認して
Claudeは現在のテーブル構造を確認してからマイグレーションを書き、インデックスの状況も分析してアドバイスしてくれる。
デフォルトでは、権限を付与した全テーブルの完全なスキーマとデータにClaudeはアクセスできる。必要に応じて以下の制限を加えよう。
テーブル単位での制御
特定のテーブルだけに権限を付与する:
-- 全テーブルではなく特定のテーブルのみ許可
GRANT SELECT ON TABLE users, orders, products TO claude_readonly;
-- sessions, payment_tokens, audit_logsなどには権限を付与しない
ビューで機密フィールドをフィルタリング
テーブルに機密フィールド(パスワードハッシュ、APIキー、電話番号)が含まれている場合は、それらを除いたビューを作る:
CREATE VIEW users_safe AS
SELECT id, email, created_at, plan, status
FROM users;
-- password_digest, phone, payment_method_idは除外
GRANT SELECT ON users_safe TO claude_readonly;
-- 元のテーブルへの権限は付与しない
Claudeはビューしかクエリできず、元のフィールドは見えない。
行数の制限
@modelcontextprotocol/server-postgres はデフォルトでクエリ結果に行数制限(通常1000行)を設けており、テーブル全体を引っ張ってくることを防いでいる。この制限は適切なので増やす必要はない。
本番データベースがリモートサーバーにある場合、直接ポートを公開することは通常しない。SSHトンネルを使う:
# localhost:5433をリモートサーバーの5432に転送するトンネルを作成
ssh -L 5433:localhost:5432 [email protected] -N
設定ファイルではローカルポートを指定:
"postgresql://readonly_user:password@localhost:5433/myapp_production"
pgBouncer のような接続プーラーを使う方法もある。
プロジェクトで複数のデータベース(メインDB・分析DB・キャッシュDBなど)を使っている場合は、複数のMCP Serverを設定できる:
{
"mcpServers": {
"main-db": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://...メインDB..."]
},
"analytics-db": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://...分析DB..."]
}
}
}
Claudeは両方のDBに接続する。どちらを使うかはその都度伝えればいい。
データベースを接続した後、最も大きく変わるのは、データ関連の話題に事前説明が不要になることだ。テーブル構造を説明する必要も、フィールドの型を教える必要もない。必要なことを伝えれば、Claudeが自分で調べてくれる。
バグの調査で特に効果を感じる。以前の流れ:自分でDBをクエリ → 結果をコピー → Claudeに貼り付け → 分析してもらう。今の流れ:問題を説明 → Claudeが自分でクエリ → 直接結論が出る。