Contextflo Blog

Connect Claude to Postgres: MCP Setup Guide

How to connect Claude to Postgres with a maintained MCP server: create a read-only user, point Claude at your PostgreSQL database, and run SQL from chat. Plus what a team needs beyond the connector.

May 17, 20268 min readVivek Sah

Connecting Claude to Postgres takes about ten minutes. Keeping it reliable once a second person starts asking questions is the actual work.

MCP gets you a working connection. What it does not get you is consistent answers, access control, credentials that are not on every laptop, or any idea what queries are running. The connection is not the bottleneck. The context around it is.

Claude connected to a Postgres database through a context layer

What a team actually needs

Before the setup, the checklist. When more than one person queries Postgres through an LLM, you need:

  1. A read-only connection your team never touches directly
  2. Shared business definitions so revenue means the same thing for everyone
  3. Table and column context so nothing has to guess what amt_net means
  4. Per-user or per-group access control so sales cannot reach payroll
  5. Query logs so you know what was asked and whether the answer was right
  6. A way to update context as the schema changes without editing prompts by hand

MCP gives you the first one. The other five are where teams get stuck, and none of them announce themselves on day one.

Step 1: create a read-only user, on a replica

Two things before any MCP config.

CREATE ROLE claude_ro LOGIN PASSWORD '<generated>';
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;

The ALTER DEFAULT PRIVILEGES line is what stops new tables from being invisible next month. As in Redshift, defaults are scoped to the role that creates the objects, so if migrations run as a different user, set it for that user.

Point it at a read replica, not your primary. An exploratory aggregation over a few million rows is a perfectly reasonable question and a perfectly capable way to degrade your app. RDS, Supabase, Neon and most hosted providers give you a replica; use it.

This is the single highest-value line in this post and it is the one most often skipped, because everything works fine right up until the query that does not.

Step 2: run a maintained MCP server

// claude_desktop_config.json
{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": [
        "-y",
        "@bytebase/dbhub",
        "--dsn",
        "postgresql://claude_ro:pass@replica-host:5432/mydb"
      ]
    }
  }
}

Do not use @modelcontextprotocol/server-postgres. It is the one most tutorials still show. Anthropic archived it in May 2025, and the published version (0.6.2) has a confirmed SQL-injection vulnerability that bypasses the READ ONLY transaction guard and allows arbitrary writes. It still gets roughly 21,000 npm downloads a week, unpatched.

Sources: Datadog Security Labs and the archived repo.

If you copied that snippet from somewhere else, this is worth acting on today. We compare the maintained alternatives in best Postgres MCP servers.

Once connected, Claude can list tables, inspect schemas and run SQL. Ask "how many users signed up this week?" and it writes the query, runs it, and answers. Fast, free, and genuinely good for one person exploring a schema they already know.

Tip: add context with a Claude Project. Create a project, add notes about your schema — table descriptions, metric definitions, business rules — and query from inside it. Accuracy improves noticeably.

The catch is that the context lives in your Claude account and is shared with nobody, which becomes the problem in the next section.

Where it breaks for a team

Two things go wrong, and they go wrong quietly.

The answers stop agreeing

Production Postgres schemas are messy. They grow over years, with abbreviated column names, legacy tables and implicit business logic. Claude sees this:

usr_acct (id, sts, crt_at, upd_at, tier_id, ref_src, acq_ch)
ord       (id, usr_id, amt_gross, amt_net, disc_cd, sts, crt_at)
sub       (id, usr_id, plan_id, mrr_cents, churn_at, cancel_rsn)

Without context it guesses. Is sts a code or a string? Does amt_net include tax? Which values of sts mean completed?

Your head of growth asks what revenue was last week, and Claude computes it from ord.amt_net. Your finance lead asks the same question and gets a different number, because their Claude Project has different notes. That is not self-serve analytics. That is self-serve inconsistency, and it is worse than no answer because both numbers look confident.

The context becomes somebody's second job

The Claude Project workaround is real and it works. It also means context is now maintained by hand. A column gets renamed, a table gets added, a metric definition changes, and someone has to remember to update the notes — in every teammate's separate project.

Context drifting out of sync across several separate Claude Projects

And the operational overhead

  • Everyone manages their own config. Each person edits a JSON file containing database credentials. Your head of ops is not doing that.
  • Everyone gets identical access. One connection string, one view of the database. Restricting who sees what means a separate Postgres user per person, with the grants and rotation that implies.
  • Credentials sit on laptops in plaintext config files. Revoking one person's access means changing the password for everyone.
  • Changing provider breaks everybody. Move from Supabase to Neon, or RDS to Railway, and every person updates their config.
  • No audit trail. No record of what ran, who asked, or whether the answer was right.

The team-ready shape: a context layer

You do not need another connector. You need context that stays correct as the schema, the team and the definitions move.

Contextflo connects to Postgres with read-only credentials, reads the schema plus any source code and docs you point it at, and generates what each table and column means, how they relate, and how key metrics are calculated. Your team still asks questions in Claude. What changes is what Claude knows, and who is allowed to ask what.

Claude discovering tables and definitions through Contextflo
Claude running a query through Contextflo, with per-user access control applied

Works with any hosted Postgres: AWS RDS, Supabase, Neon, PlanetScale, Google Cloud SQL, Azure Postgres, Railway, Render, or self-hosted.

The generated context is a draft, and worth saying so plainly: it gets structure right and business meaning wrong often enough that someone who knows the data should read it once. What changes is that reviewing takes an afternoon and writing from scratch takes weeks.

Which one

Direct MCPContextflo
SetupJSON config, per personConnect once, invite the team
Schema contextRaw table and column namesGenerated, then reviewed
Metric consistencyWhatever each person's notes sayDefined once, shared
Access controlSame DB user for everyonePer-table, per-user
CredentialsOn every laptopCentralised, never exposed
Changing providerUpdate every configUpdate one connection
Audit trailNoneEvery question and query

If you want Claude to query Postgres once, use MCP — pick a maintained server and point it at a replica. If your team is going to rely on the answers, you need something holding the context in the middle.

Connect your Postgres database and have your team querying in Claude in about fifteen minutes. Get started for free.