Command Palette

Search for a command to run...

UnylyUnyly
Browse all

PostgreSQL Secure

FreeNot checked

Security-hardened read-only PostgreSQL MCP server with AST-based SQL guard using pglast, per-transaction safety envelope, and JSON-Lines audit logging.

GitHubEmbed

About

Security-hardened read-only PostgreSQL MCP server with AST-based SQL guard using pglast, per-transaction safety envelope, and JSON-Lines audit logging.

README

A Model Context Protocol server for PostgreSQL. Gives an agent (Claude Code, Cursor, etc.) a vetted set of read-only tools for schema introspection, query execution with row caps and timeouts, structured EXPLAIN analysis, pg_stat_statements summaries, and pgvector similarity search. Writable and admin tools exist behind opt-in flags.

Status: alpha (0.0.1). Tested on PostgreSQL 13–17.

Why bother with another one

Anthropic's reference Postgres MCP shipped a bypassable read-only mode in mid-2025 — Datadog disclosed that COMMIT; DROP SCHEMA public CASCADE; escaped its BEGIN TRANSACTION READ ONLY envelope (the underlying driver accepted multi-statement strings). The server was archived. The safety story here is the layered model in docs/safety.md: a least-privilege role grant at the database, an AST guard (via libpg_query) in the server, a per-transaction envelope, and an audit log. The role grant is the load-bearing one; everything else is defense in depth.

tests/adversarial/test_readonly_payloads.py runs 30 bypass attempts against the AST guard, including the original Datadog payload. PRs adding new payloads are welcome.

Install

pipx install mcp-postgres        # or: pip install mcp-postgres

Python 3.11+. Postgres 13+. The wheel includes pglast (libpg_query bindings) and psycopg[binary].

Run

mcp-postgres connect "postgresql://mcp_postgres_ro:****@host/mydb" \
    --readonly --row-limit 1000 \
    --statement-timeout 10s \
    --audit-log /var/log/mcp-pg/audit.log

Then register it with your MCP client. For Claude Code:

claude mcp add postgres -- \
  mcp-postgres connect "$DSN" --readonly --row-limit 1000

docs/quickstart.md walks through the bundled docker fixture.

Tools

Group Tools Available
Schema list_schemas, list_tables, describe_table, list_views, describe_view, list_indexes, list_extensions, list_functions, refresh_schema_cache always
Query run_query, validate_query, run_query_streaming, fetch_more, explain_query always
Stats & health table_stats, growing_tables, missing_indexes, slow_queries, lock_waits, active_sessions, io_stats (PG 16+) always
pgvector list_vector_columns, similarity_search, cosine_distance_top when pgvector is installed
Admin kill_session, run_vacuum, run_analyze with --allow-admin

The schema-introspection tools cover FKs, partial / expression / GIN / BRIN indexes, JSONB columns, views, materialised views, partitioning, RLS policies, triggers, stats. describe_table returns all of that in one call.

explain_query parses the JSON plan from PostgreSQL and walks it for common patterns: large seq scans on filtered tables, row-count mis-estimates, sorts that spill to disk, hash joins with multiple batches, nested loops with large outer sides, partition pruning failures, unindexed join keys, lateral subquery loops, temp-file spills. Suggestions include CREATE INDEX CONCURRENTLY candidates (equality-first then range) and work_mem bumps.

For pgvector: similarity_search runs EXPLAIN before the real query and emits a vector_scan_no_index warning when the plan won't use an hnsw/ivfflat index on a table with more than 100k rows.

Deployment

Five patterns documented with role grants in docs/deployment.md and grants/: local dev, CI, prod read-only (the common case), prod read-write on a sandbox schema, and multi-DB.

The default posture is:

  • Read-only at the Postgres role level.
  • AST guard rejects multi-statement input, data-modifying CTEs, SELECT FOR UPDATE, SELECT INTO, forbidden SET targets, COPY ... TO PROGRAM, and any non-SELECT top-level statement.
  • SET LOCAL transaction_read_only = on, statement_timeout, idle_in_transaction_session_timeout, lock_timeout per transaction.
  • Audit log to JSON-Lines file, syslog, or stderr.

Tests

# Spin up the fixture:
cd tests/ && docker compose up -d

# Run everything:
MCP_PG_TEST_DSN=postgresql://postgres:postgres@localhost:55432/hranalytics \
  pytest tests/

# Or just the units (no DB needed):
MCP_PG_NO_DB=1 pytest tests/unit/ tests/adversarial/

CI runs the full suite against PostgreSQL 13, 14, 15, 16, 17 with pgvector enabled.

License

Apache 2.0. See LICENSE.

from github.com/bettyguo/mcp-postgres

Installing PostgreSQL Secure

This server has no published package — it is built from source. Open the repository and follow its README.

▸ github.com/bettyguo/mcp-postgres

FAQ

Is PostgreSQL Secure MCP free?

Yes, PostgreSQL Secure MCP is free — one-click install via Unyly at no cost.

Does PostgreSQL Secure need an API key?

No, PostgreSQL Secure runs without API keys or environment variables.

Is PostgreSQL Secure hosted or self-hosted?

Self-hosted: the server runs locally on your machine via the install command above.

How do I install PostgreSQL Secure in Claude Desktop, Claude Code or Cursor?

Open PostgreSQL Secure on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.

Related MCPs

Compare PostgreSQL Secure with

Not sure what to pick?

Find your stack in 60 seconds

Author?

Embed badge for your README

Browse similar

All data MCPs