CountLineage

Postgres MCP: connect Claude to PostgreSQL without handing it the keys

AI for data and analytics · Facts checked 22 October 2026

PostgreSQL has no official MCP server. Anthropic's original reference server was archived in May 2025 and has a published SQL-injection flaw that bypasses its read-only mode, so avoid it. The main community option is Postgres MCP Pro, which runs locally with Claude Desktop. Use its restricted mode, a SELECT-only role and a read replica.

There is no official Postgres MCP server, and the old reference one is unsafe

Search "postgres mcp" and the first package many people find is @modelcontextprotocol/server-postgres, Anthropic's reference server from the official MCP servers repository. Don't use it.

It was archived in May 2025. Three months later, Datadog Security Labs published a SQL-injection flaw in it (21 August 2025): the server wrapped each query in a read-only transaction, but the driver accepted several statements at once, so input like COMMIT; DROP SCHEMA public CASCADE; ended the read-only transaction and ran the write as normal. A fix was merged to the repository but, per Datadog, never released to npm, where the last version, 0.6.2, was still being downloaded about 21,000 times a week when they wrote it up.

The PostgreSQL project itself doesn't publish an MCP server. So the realistic choices are:

Option What it is Status
Postgres MCP Pro (crystaldba/postgres-mcp) Open-source server with SQL, schema browsing, query plans and health checks. MIT licence, about 3,400 GitHub stars (October 2026) Community; the most-used option we found
A managed provider's own server Some hosted-Postgres companies ship one (Supabase's has a read_only mode, per General Analysis's write-up) Check your provider's docs
Zed's fork of the reference server @zeddotdev/postgres-context-server, patched for the injection in April 2025 Narrow; fine for an editor, not our pick for analysis

For most teams on self-managed or cloud Postgres, Postgres MCP Pro is the one to evaluate. The rest of this page assumes it, and assumes you'll still lock the database down as if the server had no safety features at all.

Connect it to Claude Desktop in four steps

Postgres MCP Pro runs on your machine (stdio by default), which means Claude Desktop, not claude.ai. Anthropic's custom connector help article is explicit that local servers configured in claude_desktop_config.json aren't available in claude.ai or Cowork, and that remote connectors must be reachable from Anthropic's IP ranges over the public internet. Exposing a database tool to the internet to make the web app work is the wrong trade.

  1. Create a read-only role (next section) and, ideally, point it at a read replica rather than the primary.
  2. Install the server. Docker (docker pull crystaldba/postgres-mcp), pipx (pipx install postgres-mcp) or uv all work, per the project README.
  3. Add it to Claude Desktop's config. On macOS the file is ~/Library/Application Support/Claude/claude_desktop_config.json; Settings in Claude Desktop can open it. Use restricted mode:
{
  "mcpServers": {
    "postgres": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "-e", "DATABASE_URI",
               "crystaldba/postgres-mcp", "--access-mode=restricted"],
      "env": {
        "DATABASE_URI": "postgresql://claude_ro:PASSWORD@replica.internal:5432/analytics"
      }
    }
  }
}
  1. Restart Claude Desktop and test with list_schemas, then a question whose answer you know.

The README's own example uses --access-mode=unrestricted. Change it. Unrestricted gives "full read/write access to data and schema" and the project positions it for development only.

The tools you get: list_schemas, list_objects, get_object_details, execute_sql, explain_query, get_top_queries, plus index-tuning and database-health checks. In restricted mode, execute_sql runs each statement in a read-only transaction with a time limit.

The setupPostgres to Claude, with a check before it shipsClaude Desktop runs the MCP server locally against a read replica, as a SELECT-only role. Count audits the answer before it goes anywhere.
  1. Warehouse
    • Postgres · read replica, reporting schema
    read as a SELECT-only role
  2. query from Claude Desktop
  3. audit before it ships
  4. share
  5. Where it goes
    • Dashboard
    • Board pack
    • Slack thread

SQL you can read, answers you can check

A read-only role keeps Postgres safe from Claude. Count keeps your reader safe from a wrong answer: every claim traced to the query behind it, with the assumptions flagged.

Restricted mode is the second lock; the role is the first

Postgres MCP Pro's restricted mode is careful. It parses SQL before running it and rejects any statement containing COMMIT or ROLLBACK, which closes exactly the hole Datadog found in the reference server. The project is also candid: it says further measures may be added to make restricted mode safe for production, and that enabling unsafe procedural languages could weaken it.

So don't rely on it alone. Give Claude a Postgres role that couldn't do damage even if every guard in the MCP server failed (illustrative; adjust names):

CREATE ROLE claude_ro LOGIN PASSWORD '…';
GRANT CONNECT ON DATABASE analytics TO claude_ro;
GRANT USAGE ON SCHEMA reporting TO claude_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA reporting TO claude_ro;
ALTER DEFAULT PRIVILEGES IN SCHEMA reporting GRANT SELECT ON TABLES TO claude_ro;
ALTER ROLE claude_ro SET default_transaction_read_only = on;
ALTER ROLE claude_ro SET statement_timeout = '30s';

Three notes on that block. The GRANT SELECT lines are what hold: a role with no INSERT, UPDATE, DELETE or ownership can't write whatever SQL it sends. default_transaction_read_only is only a default (PostgreSQL docs), and a session can change it, which is the same class of escape the reference server fell to; it's a seatbelt, not the brakes. And statement_timeout stops one runaway query hogging the replica.

Grant only the schemas Claude needs. A reporting schema of clean views is better than public, for safety and, as the next sections show, for accuracy.

One more weakness the Postgres MCP Pro README points out: the connection string sits in plain text in the client's config file. Use the read-only role's credentials there, never an admin's.

Prompts that make Claude read the schema before it writes SQL

Postgres schemas built for an application are rarely built for analysis. Status codes, soft deletes and one-to-many tables trip models up. These prompts make the model look first (examples illustrative).

Map the schema:

Using the postgres tools, list the schemas, then the tables in reporting. For
orders, subscriptions and customers, give the grain, the primary and foreign keys,
any soft-delete or status columns, and the timestamp columns with their time zone.
No analysis yet.

Ask with the traps named:

How many customers churned in September 2026? Exclude soft-deleted rows and test
accounts, and tell me how you identified each. Say if you're counting
customers or subscriptions. Show the SQL and the row count.

Check the plan before running something heavy:

Before running the query, call explain_query on it and tell me whether it does a
sequential scan on any large table. If it does, suggest a cheaper query that gives
the same answer.

Make it reconcile:

Calculate September revenue from orders and from invoices. If the totals differ by
more than 1%, list which orders have no invoice and which invoices have no order.

The explain_query prompt is specific to Postgres MCP Pro, and it's a good habit on a shared replica.

Postgres is where MCP's worst database incidents happened

Two of the best-documented MCP security failures involve Postgres directly.

  • 21 August 2025: the reference server. Datadog's write-up of the read-only bypass above. Their mitigations: a Postgres user with restricted privileges (which they say should be in place regardless), avoiding the deprecated server wherever writes must be prevented, and discarding connections after each call.
  • 8 July 2025: Supabase MCP, which runs on Postgres. A support ticket containing hidden instructions led a coding agent, connected with the service_role key that bypasses row-level security, to read an integration_tokens table and post its contents back into the ticket (General Analysis). Read-only wouldn't have stopped this: it was a read. What would have: a role that couldn't see that table.

And two that apply to any server:

  • 1 April 2025: tool poisoning. Hidden instructions in a tool's description (Invariant Labs). Community servers update often, so pin the version you've reviewed rather than pulling latest every launch.
  • 26 May 2025: GitHub MCP. An agent with "Always Allow" on copied private data into a public pull request (Invariant Labs).

Our rule for Postgres: the Claude session that can read the database shouldn't also be reading untrusted text and able to post it somewhere. Keep secrets, tokens and personal data out of the schemas the role can see.

Application tables answer the question you didn't ask

An application database stores what the app needs, not what finance means. A subscriptions table may hold one row per plan change; a customer with three upgrades looks like three customers if Claude counts rows. A status = 'cancelled' may be a churn, a downgrade or a test. A timestamp may be UTC while your month boundaries are in London.

None of this produces an error. It produces a plausible number. On ChartMogul's worked example, logo churn and revenue churn differ by 17 points (33% against 50%) on the same three customers; your schema can add another choice on top.

Benchmarks put numbers on it. The best agent in the original Spider 2.0 paper solved 21.3% of real enterprise text-to-SQL tasks against 91.2% on the older academic Spider 1.0 (Lei et al., November 2024). Agents have improved since, but the gap that remains is mostly schema and meaning, not syntax. Our text-to-SQL guide has the current numbers.

The fix is a layer of meaning between the app tables and the model: a reporting schema of views with one documented definition each, or a semantic layer such as dbt's (see dbt MCP and semantic layers for AI). Grant Claude that, not the raw tables.

Two minutes with the SQL before the number leaves

Claude Desktop shows every call to the Postgres tools. Open them.

  1. Read the FROM and joins. Is each join one-to-one, or could it multiply rows? Count distinct IDs, not rows.
  2. Look for the filters you'd expect (soft deletes, test accounts, status) and any you wouldn't.
  3. Check time. Which timestamp column, which time zone, inclusive or exclusive end date.
  4. Run the query yourself in psql or your SQL client against the same replica.
  5. Ask Claude: "Which numbers came straight from a query result, and which did you calculate or assume afterwards?"

For an answer that's going further than your screen, Count adds a structured audit. Connect Count's MCP server to Claude and ask it to check the answer: it replies with a link to a canvas where each claim is labelled (Citation, Assumption, Model knowledge or Hallucination) and has a reasoning chain showing the queries and calculations underneath. An unstated "we counted subscriptions, not customers" surfaces as an Assumption. The canvas connects to Postgres as well, so the fix and the re-run happen in the same place.

Questions people ask

Is there an official Postgres MCP server?

No. The PostgreSQL project doesn't publish one, and Anthropic's reference server (@modelcontextprotocol/server-postgres) is archived. Postgres MCP Pro from Crystal DBA is the most-used community option we found; some managed Postgres providers ship their own.

Is the reference Postgres MCP server safe to use?

No. Datadog showed in August 2025 that input such as COMMIT; DROP SCHEMA public CASCADE; escapes its read-only transaction. The fix was merged but, per Datadog, not released to npm. Use a maintained server and a SELECT-only role.

Can I connect Postgres to claude.ai, not just Claude Desktop?

Only through a remote MCP server reachable from Anthropic's IP ranges over the public internet. For a database, we'd stay with a local server in Claude Desktop unless you have a properly authenticated remote deployment.

How do I make a Postgres MCP server read-only?

Use the server's read-only mode (Postgres MCP Pro: --access-mode=restricted) and, more importantly, connect as a role with only SELECT grants on the schemas Claude needs. Point it at a read replica and set a statement_timeout.

Sources

  1. Crystal DBA: Postgres MCP Pro on GitHub (checked 22 October 2026)
  2. Datadog Security Labs: SQL injection in the PostgreSQL MCP server (21 August 2025)
  3. PostgreSQL documentation: client connection defaults
  4. Anthropic Help Centre: Getting started with custom connectors using remote MCP (checked 22 October 2026)
  5. General Analysis: Supabase MCP can leak your entire SQL database (8 July 2025)
  6. Invariant Labs: MCP security notification, tool poisoning attacks (1 April 2025)
  7. Invariant Labs: GitHub MCP exploited (26 May 2025)
  8. Lei et al.: Spider 2.0 (arXiv, v1 12 November 2024, v2 17 March 2025)
  9. ChartMogul: Customer churn rate

Early access

Count Lineage isn't ready to download yet.

Count Lineage is coming to Claude Desktop in the next few weeks. Leave your work email and we'll send you the download the day it's ready.

Where should Lineage go after Claude? Optional

One email when it's ready. No newsletter.