Skip to main content

pgops-mcp

A production-grade MCP server that gives AI agents safe, audited, expert-level control over a real PostgreSQL database and the Docker stack around it — no shell commands, no Python scripts, just tools.

Why

Existing Postgres MCP servers are thin query wrappers: introspect + SELECT. None handle migrations with lock-impact analysis, none diagnose performance from EXPLAIN + pg_stat_statements, none understand the containerized environment the database lives in. Agents operating databases today are flying blind and unsafe.

pgops-mcp is the operations brain: schema intelligence → guarded queries → migration engine → performance diagnosis → environment awareness, with a safety architecture that makes every action classifiable, confirmable, and auditable.

Tool surface

Group Tools
Schema schema.inspect
Queries query.read, query.write (guarded), query.explain (parsed plan + verdict)
Performance index.advise, db.health
Migrations migration.plan (dry-run + lock analysis), migration.describe (plain English), migration.apply, migration.rollback, migration.history
Environment env.topology, env.correlate, container.logs, container.stats
Gated container.restart, container.exec

* Not registered at all unless the server runs with --approval-mode, and even then each call needs a confirmation token. container.exec additionally enforces a read-only diagnostic command allowlist — it does not offer a shell. The Docker socket is root-equivalent on the host, so the default is read-only access.

Safety model (the core differentiator)

  • Separate read-only / read-write connection roles; tools bind to the right role
  • Statement classification before execution — unbounded DELETE/UPDATE blocked
  • Destructive actions require explicit confirmation tokens
  • Every executed statement lands in an append-only audit log with timing and verdict
  • Runaway-query cancellation with timeout tiers

MCP surface

Primitive What's here
Tools 17 — schema, query, explain, advise, migrate, environment
Resources pgops://schema, schema/summary, schema/{table}, health, migrations, audit/recent, config
Prompts diagnose-slow-query, plan-safe-migration, incident-triage, review-index-health, explain-safety-model
Elicitation Dangerous actions ask the user directly, not via the agent; confirmation tokens are the fallback
Sampling migration.describe turns English into a plan using your model — this server ships no API key
Completions Table-name autocomplete for pgops://schema/{table}
Progress / logging Best-effort notifications during long operations

Remote access & agent tokens

stdio needs no auth — the server is a subprocess your client spawns, with no open port. HTTP does, so it refuses to start without a key:

pgops-mcp keygen                                    # RS256 keypair
pgops-mcp issue-token --subject my-agent            # read-only by default
pgops-mcp issue-token --subject deploy-bot --scope pgops:read --scope pgops:write
pgops-mcp scopes                                    # which scope each tool needs

pgops-mcp --transport http --public-key ~/.pgops/keys/pgops_public.pem

The server holds only the public key, so it can verify tokens but never mint them. Scopes (pgops:read / pgops:write / pgops:admin) map to the same danger tiers as the guardrails, and a tool with no scope entry requires admin — deny by default. Binds loopback unless you say otherwise.

Install

pgops-mcp is an MCP server, not a Python library — nothing in it is meant to be imported, and pgops.* carries no API-stability promise. You install it the way you install any MCP server: point your client at it.

Claude Desktop / Cursor / VS Code:

{
  "mcpServers": {
    "pgops": {
      "command": "uvx",
      "args": ["pgops-mcp"],
      "env": { "PGOPS_DSN": "postgresql://user:pass@localhost:5432/mydb" }
    }
  }
}

uvx fetches and runs it in a throwaway environment — nothing to install first, and nothing added to your own project's dependencies.

Or run the container, if you would rather not put a Python toolchain on the machine that talks to your database:

{
  "mcpServers": {
    "pgops": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "PGOPS_DSN",
        "-v", "pgops-audit:/var/lib/pgops",
        "ghcr.io/arzharch/pgops-mcp:latest"
      ],
      "env": { "PGOPS_DSN": "postgresql://user:pass@host.docker.internal:5432/mydb" }
    }
  }
}

Two things the container changes: mount a volume at /var/lib/pgops or the audit log dies with the container, and localhost inside a container is the container itself — use host.docker.internal or a compose service name.

Check the connection before wiring a client to it:

uvx pgops-mcp --selfcheck --dsn "postgresql://user:pass@localhost:5432/mydb"

Both paths install the same server and are listed together in the MCP Registry entry — they fail for different people. uvx needs nothing preinstalled but assumes the host may run Python; the container assumes only Docker.

See SETUP.md for configuration, HTTP transport, agent tokens and troubleshooting, and CONTRIBUTING.md to run it from a source checkout.

Docs

For users:

  • docs/API.md — full tool catalog: parameters, returns, error codes, scopes
  • docs/BENCHMARKS.md — what the benchmarks measure and what they are compared against
  • docs/GETTING_STARTED.md — first 15 minutes, guided tour
  • SETUP.md — full setup guide: config, clients, HTTP auth, observability, troubleshooting
  • .env.example — every environment variable, documented

Internal (design & process):

Status

Phases 0–6f complete (436 tests, every guardrail, verdict and lock-impact rule proven against real Postgres via testcontainers — no mocks — plus end-to-end suites driving the server as a real MCP subprocess over stdio and as an authenticated HTTP server, verified through the MCP Inspector).

Phase State Tools
0 · Bootstrap seeded dev stack (1.2M-row orders), CI, lint/type gates
1 · Connection core + read path schema.inspect, query.read, db.health
2 · Write path + safety query.write, guardrails, confirmation tokens, audit log
3 · Performance brain query.explain (plan verdicts), index.advise
4 · Migration engine migration.plan (lock analysis + dry run), apply, rollback, history
5 · Docker layer env.topology, env.correlate, container.logs/stats/restart/exec
6a · MCP completeness resources, prompts, elicitation, sampling, completions, progress
6b · Remote + auth HTTP transport, JWT, per-tool scope enforcement, keygen CLI
6c · Observability OTel spans/metrics, liveness/readiness endpoints (all optional)
6d · Adversarial testing red-team suite, property-based tests, live evals in CI
6e · Forensics pgops-mcp replay — the audit log as an executable record
6f · Distribution PyPI package, container image, server.json for the MCP Registry

Sample of what migration.plan returns for a type change on the 1.2M-row orders:

ALTER TABLE "orders" ALTER COLUMN "total_cents" TYPE bigint
  op=table_rewrite  risk=high  estimate=4800ms  confidence=medium
  why:   rewrites every row and rebuilds every index, holding AccessExclusiveLock
  SAFER: add a new column of the target type, backfill in batches, sync with a
         trigger, swap the names, then drop the old column

Quickstart the dev database (host port 5435, to avoid colliding with a local Postgres on 5432):

docker compose up -d
export PGOPS_DSN="postgresql://pgops:pgops_dev@localhost:5435/pgops_demo"
uv run pgops-mcp --selfcheck

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pgops_mcp-0.1.1.tar.gz (100.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pgops_mcp-0.1.1-py3-none-any.whl (120.6 kB view details)

Uploaded Python 3

File details

Details for the file pgops_mcp-0.1.1.tar.gz.

File metadata

  • Download URL: pgops_mcp-0.1.1.tar.gz
  • Upload date:
  • Size: 100.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pgops_mcp-0.1.1.tar.gz
Algorithm Hash digest
SHA256 6c0d179c101b4d7dceb9d7b6ca85777d0a46daca4552ca117ab6d503b3116478
MD5 8144845d415114b0a603ce55bc5cd106
BLAKE2b-256 3cd133e38c7f1c32f372632a4c99afd41b6b5d05b57ed04fcf90f11c2daa3388

See more details on using hashes here.

Provenance

The following attestation bundles were made for pgops_mcp-0.1.1.tar.gz:

Publisher: publish.yml on arzharch/pgops-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pgops_mcp-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: pgops_mcp-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 120.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pgops_mcp-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d4f6050e62763436b9217ff50de16be2319e4315b7828e39cabe6661e4a840be
MD5 80e574471f6a7ddfaefe7c777c71b4e5
BLAKE2b-256 9f7e701f1076ee9dc8a62bf7f2b096c50a1d02fb1da0d853a2a51cb6c6ad1d26

See more details on using hashes here.

Provenance

The following attestation bundles were made for pgops_mcp-0.1.1-py3-none-any.whl:

Publisher: publish.yml on arzharch/pgops-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.1.2

2 files

This release

0.1.1 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page