postgres MCP — Official Postgres Server for Claude Code | AI Code Toolkit
Official (Anthropic)Highest-ROI MCPTransport: stdio + httpRead-only supported

postgres

The official Postgres MCP server, maintained by Anthropic. Gives Claude Code direct schema awareness, query execution, and migration inspection. The single highest-ROI MCP integration for most projects.

Package
server-postgres
Maintainer
Anthropic
Transport
stdio or http
Safety
Read-only supported
Updated
Aug 2026

The @modelcontextprotocol/server-postgres MCP is the single highest-ROI integration for most projects. It gives Claude Code direct access to your Postgres schema, tables, indexes, and query execution — so instead of Claude guessing at your data model from ORM files, it reads reality. Ask "add cursor pagination to the users API" with this MCP installed and Claude checks the actual (created_at DESC, id) index that exists and writes pagination that uses it. Without the MCP, you get a plausible guess that may or may not match your schema.

This is the official Postgres MCP server maintained by Anthropic. It supports read-only mode (highly recommended default), configurable statement timeouts, and both stdio and http transports. It works against plain Postgres, RDS, Aurora, managed platforms like Neon and Supabase (though those have first-party MCPs with additional features), and any Postgres-wire-compatible database.

If you install one MCP server and one only, install this one.

The Full Config

The recommended postgres MCP setup

Two connections named differently for explicit intent. Both use environment variables so credentials never touch git.

json .claude/settings.json — recommended two-connection setup
{ "mcpServers": { "postgres": { "type": "stdio", "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-postgres", "${DATABASE_URL_READONLY}" ] }, "postgres-migrate": { "type": "stdio", "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-postgres", "${DATABASE_URL_MIGRATE}" ] } } }

And the environment file (gitignored):

shell .env.local (add to .gitignore)
# Read-only user for the default "postgres" MCP — Claude uses this for exploration DATABASE_URL_READONLY="postgres://claude_ro:xxx@localhost:5432/mydb?options=-c%20statement_timeout%3D5000" # Read-write user for the explicit "postgres-migrate" MCP — used when Claude runs migrations DATABASE_URL_MIGRATE="postgres://claude_rw:xxx@localhost:5432/mydb?options=-c%20statement_timeout%3D30000"

Two named MCPs, two named credentials, two different privilege levels. The double-naming forces explicit intent — Claude has to reach for postgres-migrate to do anything that mutates data. This is the single most important safety pattern for a database MCP.

Install

How to install

Three transport options depending on your environment. Stdio via npx is the default; Docker helps for reproducibility; HTTP is for remote hosted setups.

Stdio via npx Default

Use the settings.json above. npx downloads and runs the official server as a subprocess. Zero install; automatic version updates. This is what 90% of teams use.

Docker

For reproducibility — pin an exact server version. Change command to docker and args to ["run", "-i", "--rm", "mcp/postgres:0.6.2", "$DATABASE_URL_READONLY"]. Works well in CI or air-gapped environments.

HTTP transport

For centrally-hosted MCP servers (some teams run one Postgres MCP shared across their org). Change type to http and use "url": "https://mcp.internal.example.com/postgres/sse". Requires the server to be running remotely with auth.

Create the read-only user first One-time

CREATE USER claude_ro WITH PASSWORD 'xxx'; GRANT CONNECT ON DATABASE mydb TO claude_ro; GRANT USAGE ON SCHEMA public TO claude_ro; GRANT SELECT ON ALL TABLES IN SCHEMA public TO claude_ro; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO claude_ro; — run once, then use in DATABASE_URL_READONLY.

Usage

How to use it

The MCP exposes tools (query, list schemas) and resources (each table's schema as a URI). Claude uses these automatically when they help.

what tables and columns exist in this database?
Basic schema exploration. Claude uses the MCP's schema resource to list tables and columns without running any SQL. Fast, cheap, no query execution.
add cursor pagination to the users API endpoint
Claude reads the users table schema and existing indexes via the MCP, notices which sort columns are indexed, and writes pagination that uses the composite index efficiently. Same prompt without the MCP produces plausible but often index-unaware code.
why is this query slow?
Claude runs EXPLAIN (ANALYZE, BUFFERS) against the query via the MCP and interprets the plan. Cardinality estimates, buffer reads, index usage — all visible to Claude, no copy-paste needed. Pair with postgres-dba for the mental model.
generate a migration to add a user_preferences table linked to users
Claude reads the current schema to match FK conventions (naming, cascade behavior, index patterns) and produces a migration matching your project's style. This is where the postgres-migrate connection matters — Claude tests the migration against a real DB before writing the file.
find any tables missing primary keys
Ad-hoc metadata query using the MCP's query tool. Fast diagnostic that would normally require you to run SQL and paste results.
Variations

Alternative configs

Configurations for different security postures and use cases.

Aggressive read-only (query-only, no schema mutations)
For production-adjacent environments or shared dev DBs
Use the read-only user setup shown above. Additionally, set statement_timeout=5000 in the connection string. Claude can inspect, run SELECTs, and read plans, but cannot possibly write. Safest posture; recommended default for anything but a personal dev DB.
Development branch per session
For Neon or PlanetScale users
Use the Neon MCP or PlanetScale MCP instead of this one. Both let Claude create a per-session database branch, run migrations there, verify, and delete — without ever touching main. Best safety profile for schema work.
With row-limit hook
To prevent accidental large scans
Pair the postgres MCP with a PreToolUse hook that intercepts calls to the MCP's query tool and appends LIMIT 1000 to any SELECT without one. Belt-and-suspenders defense against runaway queries on hot tables. Especially valuable if you can't use a read-only replica.
Troubleshooting

Common issues and fixes

The five issues teams hit most often with the Postgres MCP.

MCP fails to connect on session start
Missing or wrong DATABASE_URL, network issues (VPN not connected, DB not reachable), or wrong credentials.
Test the connection string directly: psql "$DATABASE_URL_READONLY" -c "SELECT 1". If psql works, the MCP works. Common gotchas: missing URL encoding in passwords with special characters, unclosed SSH tunnel, VPN not up. Check ~/.claude/logs/ for the exact error the MCP reported.
Claude tries write operations against the read-only connection
The user has SELECT-only privileges, so the write fails at the Postgres level with a permission error.
That's the desired behavior — the read-only user can't mutate. If you want the operation to succeed, invoke it against postgres-migrate explicitly: > use the postgres-migrate connection to add this column. The named separation is intentional; making Claude choose the write connection is the safety mechanism.
MCP works but Claude ignores schema info and produces wrong queries
The MCP exposes schema as a resource, but Claude doesn't always reach for it proactively. It fetches when the prompt clearly needs it, not always.
Be explicit in your prompt: "Read the users table schema first, then write the query." Or add a rule to your CLAUDE.md: "For any query touching an unfamiliar table, first read the schema via the postgres MCP." Prompting matters.
Queries return but Claude's interpretation is wrong
Very large result sets get truncated by the MCP before Claude sees them, so it reasons from partial data.
Add explicit LIMITs in the prompt or add a PreToolUse hook that enforces LIMIT 1000. For legitimate large-result needs (audit, reporting), use psql directly via Bash and pass Claude the summarized output rather than raw rows.
Runaway query times out mid-session
No statement_timeout set at the connection level; a mistake produced an unbounded query.
Add ?options=-c%20statement_timeout%3D5000 to your read-only connection string (5-second timeout) and =30000 to your migrate connection (30 seconds for legitimate migration work). Cheap insurance against runaway queries. Do this before anything else.

🐛 Hit an error?

AI Error Hub covers Claude Code errors and stack traces — cross-referenced with everything on this site.

Visit AI Error Hub →
FAQ

Frequently asked questions

The questions developers ask most about postgres.

Because it forces explicit intent for anything that mutates data.

With one all-powerful connection, Claude has to decide moment-by-moment whether the operation is safe — and "safe" is a hard judgment call.

With two named connections, Claude has to reach for postgres-migrate to do anything mutating, which surfaces the intent in the conversation. It's the same argument as separating dev and production API keys: the discipline is worth the small config overhead.

Technically yes; you should not.

The convenience of "let Claude check prod directly" is never worth the tail risk of:

  • An unbounded query hitting a hot table.
  • An accidental full-table scan.
  • A subtle mistake with real data.

Use a staging replica, a scrubbed dev copy, or a per-session branch (Neon or PlanetScale make this trivial).

Via the connection string. Append ?options=-c%20statement_timeout%3D5000 for a 5-second timeout.

Any query running longer gets terminated. Set this on every Postgres MCP connection — cheap insurance against a mistake causing a runaway query.

Recommended values:

  • 5000 (5s) for the read-only connection.
  • 30000 (30s) for the migrate connection.

Yes, with two caveats:

  1. Use session mode or transaction mode carefully — the MCP's expectations around session state (temp tables, prepared statements) can conflict with pool modes. Session mode is safest.
  2. Keep the MCP's connection count in mind — it counts against your pool budget. If the pool is tight, consider a dedicated pool tier for MCP use.

Install the platform's first-party MCP instead of this generic one. Each adds platform-specific features:

This generic MCP is right for plain Postgres, RDS, Aurora, and self-hosted setups.

Commit .claude/settings.json to git with env-var references for credentials.

Teammates set their own DATABASE_URL_READONLY and DATABASE_URL_MIGRATE in their shell or a gitignored .env.local. Everyone gets the same MCP setup on next pull; secrets never touch the repo.

Zero manual onboarding for MCP config.

Yes. This page covers @modelcontextprotocol/server-postgres, the official Anthropic-maintained package.

There are also community packages under similar names with different feature sets — some add write helpers, some add ORM awareness.

For most teams the official one is the right choice: audited, feature-stable, updated with Postgres itself. Community wrappers are worth considering when you specifically need a feature they add and are willing to review the source.

Yes — the MCP is transparent to extensions. If your database has pgvector installed, Claude can query vector columns via the MCP just like any other columns.

Same for PostGIS geometry queries, JSONB operators, and full-text search. The MCP doesn't have special support for each extension, but nothing in the way either.

Absolutely — that's the recommended full setup:

  • Postgres MCP — the hands (reads schema, runs queries).
  • postgres-dba — the mental model (interprets EXPLAIN, thinks in indexes and MVCC).
  • migration-planner — the specialist for zero-downtime schema changes.

Together they behave like a senior DBA working with the database open in front of them.

The MCP gives Claude four things a raw shell command doesn't:

  • Structured tool inputs — SQL syntax gets validated.
  • Typed outputs — results come back as structured data.
  • Resources — schemas exposed as URIs without running SQL.
  • Guardrails at the MCP layer — the official Postgres MCP has read-only mode.

Roughly: use the MCP when you want Claude to think about the database as a system. Use raw psql via Bash for specific migration scripts or one-off runs.

Share with