MCPg - Production-grade PostgreSQL MCP Server
Supports translating natural language questions into SQL queries using OpenAI's API.
Provides tools for safe inspection, querying, operation, and tuning of PostgreSQL databases, including catalog introspection, query intelligence, natural-language SQL, structural diffs, hybrid search, graph queries, data movement, and live ops.
Exposes a /metrics endpoint with Prometheus metrics for observability, including tool call counts and durations.
Integrates with TimescaleDB for hypertable management and time-series data operations.
MCPg
A production-grade Model Context Protocol server for PostgreSQL. Lets AI agents safely inspect, query, operate, and tune a Postgres database — over 100 tools spanning catalog introspection, query intelligence, natural-language SQL, structural diffs, hybrid search, graph queries, data movement, live ops, and more.
📍 Listed On
Aspect | MCPg |
Safety | Read-only default + AST validation |
Transport | stdio + HTTP/SSE |
Install |
|
Postgres Versions | 14–18 |
Key Differentiator | Production observability + multi-tenancy |
Why MCPg
Safe by default. Read-only access mode. Every user-supplied SQL statement parses through a validated AST allowlist before execution. Identifier interpolation flows through a strict
[A-Za-z_][A-Za-z0-9_]*regex — a design constraint that means user input never reaches the database through string concatenation. Capabilities like DDL, shell, andLISTEN/NOTIFYare off until you opt in.One server, broad surface. Application data access (queries, search, cursors, NL→SQL) and DBA-grade operations (health checks, index tuning, EXPLAIN analysis, locks, vacuum, dumps, replicas, migrations) in a single MCP server. Agents don't have to switch tools to switch tasks.
PostgreSQL-native everything. No ORM, no abstraction tax — uses
psycopg3directly, speaks everypg_*system view, integrates with TimescaleDB, pgvector, PostGIS, Apache AGE, andpg_stat_statementswhere they're available, and degrades gracefully when they aren't.Production-shaped, not demo-shaped. Connection pooling, per-request
SET ROLEmulti-tenancy, read-replica routing with degraded-host detection, server-side cursors with dedicated connections, rate-limiting, audit trail with regex redaction, PG TLS enforcement on startup, OIDC JWT bearer auth, per-session statement / lock timeouts.Observability built in. Prometheus
/metricsendpoint on the HTTP transport surfacesmcpg_tool_calls_total{tool,status}+mcpg_tool_duration_seconds. Every tool call records a structured audit event with credential-redacted arguments.Test-driven, multi-version. 800+ unit tests plus an integration suite that runs against a real PostgreSQL container in CI — matrix covers PG 14, 15, 16, 17, 18 on every push.
Featured In
mcp.so
mcpservers.org
Official MCP Registry (coming soon)
Related MCP server: PostgreSQL MCP Server
Install
From PyPI (recommended)
pip install mcpg
# or, in an isolated venv exposed globally:
uv tool install mcpgVerify:
mcpg --versionDocker
docker build -t mcpg https://github.com/devopam/MCPg.git
docker run --rm -p 8000:8000 \
-e MCPG_DATABASE_URL=postgresql://user:pass@host:5432/db \
-e MCPG_ACCESS_MODE=read-only \
mcpgMulti-stage image: runtime stage drops the build toolchain, runs as
uid=10001 / gid=10001 with nologin shell, application files
root-owned and read-only to the runtime user.
From source (developers)
git clone https://github.com/devopam/MCPg && cd MCPg
uv syncuv sync creates a venv with all runtime + dev dependencies and exposes
the mcpg console script.
More detail in the Installation Guide.
Quick start
Wire MCPg into Claude Desktop (stdio transport)
Drop this into your claude_desktop_config.json (macOS:
~/Library/Application Support/Claude/claude_desktop_config.json;
Windows: %APPDATA%\Claude\claude_desktop_config.json):
{
"mcpServers": {
"mcpg": {
"command": "uvx",
"args": ["mcpg"],
"env": {
"MCPG_DATABASE_URL": "postgresql://user:pass@localhost:5432/mydb"
}
}
}
}Restart Claude Desktop. The MCPg toolset is now available to the model. You can ask Claude things like:
"What schemas exist in this database? For each one, summarise the three biggest tables."
"Why is this query slow?
SELECT * FROM orders WHERE customer_id = 42 ORDER BY created_at DESC"
Run as an HTTP server (for IDE integrations, web apps, etc.)
MCPG_DATABASE_URL=postgresql://user:pass@localhost:5432/mydb \
MCPG_TRANSPORT=streamable-http \
MCPG_HTTP_PORT=8000 \
mcpgThen point any MCP-aware client at http://localhost:8000. Set
MCPG_HTTP_AUTH_TOKEN=... for a static bearer, or
MCPG_AUTH_MODE=oidc for full JWT validation against an OIDC issuer.
Configuration
MCPg is configured entirely through environment variables — no
config file, no flags. The only required one is MCPG_DATABASE_URL;
everything else has a safe default.
Common scenarios
Scenario | Set |
Local exploration, read-only |
|
Read-write app data access |
|
DBA toolkit (DDL, vacuum, etc.) |
|
HTTP transport with bearer auth |
|
Multi-tenant SaaS |
|
Read-replica fan-out |
|
NL→SQL — single provider | Set |
NL→SQL — multiple providers, caller picks | Set all vendor keys you want active. Each call to |
Full reference
Core
Variable | Default | Description |
| required | Primary PostgreSQL DSN. Supports URI ( |
|
|
|
|
|
|
|
|
|
|
| Bind address for HTTP transports. Set to |
|
| Listen port for HTTP transports (1–65535). |
Capability gates (opt-in for higher-blast-radius tools)
Variable | Default | Description |
|
| Expose DDL tools ( |
|
| Expose subprocess-backed tools ( |
|
| Expose |
Authentication (HTTP transports only)
Variable | Default | Description |
|
|
|
| — | Required bearer token when |
| — | OIDC issuer URL (required when |
| — | Expected |
| discovered | Override JWKS endpoint (auto-discovered from issuer's |
| — | JWT claim whose value becomes the per-request PG role ( |
HTTP hardening (HTTP transports only)
Variable | Default | Description |
|
| (1 MiB) Request bodies above this get a |
| — | Comma-separated CORS allowlist. Unset = no CORS middleware (no cross-origin headers emitted). |
|
|
|
|
| Per-request wall-clock cap ( |
Multi-tenancy (SET ROLE)
Variable | Default | Description |
| — | Static PG role applied to every query. Identifier-validated. |
| — | Comma-separated allowlist. When set, the |
Read replicas
Variable | Default | Description |
| — | Comma-separated replica DSNs. |
Pool / timeouts / TLS
Variable | Default | Description |
|
| Minimum pool connections. |
|
| Maximum pool connections. Must be ≥ |
|
| Per-session |
|
| Per-session |
|
| Bypass the startup TLS check that refuses remote DSNs without |
|
| On SIGTERM, wait up to this long for in-flight tool calls to finish before closing the pool and cursors. |
Subprocess tools (MCPG_ALLOW_SHELL=true only)
Variable | Default | Description |
|
| Max wall-clock for |
|
| (64 MiB) Cap on captured stdout per subprocess call. |
| — | Comma-separated absolute dirs the resolved |
| — | Per-child |
| — | Per-child |
LISTEN/NOTIFY (MCPG_ALLOW_LISTEN=true only)
Variable | Default | Description |
|
| Per-channel buffer; oldest notifications dropped on overflow. |
Audit
Variable | Default | Description |
|
| When true, every |
| — | Comma-separated regex fragments added to the secret-name pattern (defaults already cover |
|
| When true, each persisted event is signed with an HMAC chained over the previous event; the |
| — | Secret key for the audit HMAC chain. Required when |
Secrets backend
By default every secret is read straight from the environment. Set
MCPG_SECRETS_BACKEND=file to instead load API keys / bearer token /
HMAC key from a mounted file — a name in the file wins; anything absent
falls back to the env var, so partial files work.
Variable | Default | Description |
|
|
|
| — | Required when |
Rate limiting
Variable | Default | Description |
|
| Enable token-bucket per-tool rate limiting. |
|
| Global cap per window across all tools. |
|
| Window length for the global quota. |
|
| Cap for heavy tools ( |
|
| Window length for the heavy-tool quota. |
Caching & Feature flags
Variable | Default | Description |
|
| Enable or disable the adaptive cache layer. |
|
| Default cache Time-To-Live in seconds. |
|
| Maximum LRU capacity bound for the memory cache. |
| — | Optional Redis backend connection string for external, multi-node caching. |
|
| Toggle computationally heavy diagnostic, diagram, and advisor tools. |
Natural-language SQL
MCPg auto-discovers every configured provider from the environment at
startup. Set as many of ANTHROPIC_API_KEY / OPENAI_API_KEY /
GEMINI_API_KEY (or GOOGLE_API_KEY) as you have — each becomes
callable. When MCPG_NL2SQL_PROVIDER is unset, MCPg picks the default
in preference order anthropic → openai → gemini. The
translate_nl_to_sql tool accepts an optional provider="…" argument
so a caller can route between providers per call; get_server_info
reports which are available.
Variable | Default | Description |
| — | Vendor-conventional key for Anthropic / Claude. |
| — | Vendor-conventional key for OpenAI. |
| — | Vendor-conventional key for Google / Gemini. |
| auto-picked |
|
| — | Explicit key for the configured |
| provider default | Override the default model (e.g. |
| — | OpenAI-compatible endpoint override (Ollama, vLLM, OpenRouter). Applies only when the default provider is |
|
| Cap on generated tokens (hard limit: 16384). |
Usage examples
The MCP tools are invoked by the agent (Claude, Cursor, Continue, …) in response to your natural-language instructions. A handful of illustrative round-trips:
Inspect the schema
You: What tables live in the
publicschema, and which ones are the biggest by row count?
Agent (using
list_tables+summarize_table× N): Six tables:customers(1.2M rows),orders(4.7M),line_items(18.3M),products(340),addresses(1.4M),audit_log(45.8M — the largest, accumulates without retention).
Diagnose a slow query
You: Why does
SELECT * FROM orders o JOIN line_items l ON o.id = l.order_id WHERE o.created_at > now() - interval '7 days'take 8 seconds?
Agent (using
why_is_this_slow+recommend_indexes):EXPLAIN ANALYZEshows a sequential scan overorders(4.7M rows) filtered bycreated_at. There's no index onorders.created_at. Recommended:CREATE INDEX CONCURRENTLY orders_created_at_idx ON orders (created_at DESC);Expected improvement: ~95% reduction (index scan touches ~33K rows instead of full table). Runvalidate_migrationon it before applying to confirm there's no locking surprise.
Translate plain English to SQL
You: Find customers who placed an order this month but never in the previous three months — show me their email and current lifetime spend.
Agent (using
translate_nl_to_sql):SELECT c.email, SUM(l.price * l.quantity) AS lifetime_spend FROM customers c JOIN orders o ON o.customer_id = c.id JOIN line_items l ON l.order_id = o.id WHERE EXISTS ( SELECT 1 FROM orders o2 WHERE o2.customer_id = c.id AND o2.created_at >= date_trunc('month', now())) AND NOT EXISTS ( SELECT 1 FROM orders o3 WHERE o3.customer_id = c.id AND o3.created_at >= date_trunc('month', now()) - interval '3 months' AND o3.created_at < date_trunc('month', now())) GROUP BY c.email;
Picture the schema
You: Draw me an ER diagram of the
publicschema.
Agent (using
generate_schema_diagram): Returns a Mermaid diagram you can paste straight into GitHub / Notion / Obsidian.
Audit the database
You: How healthy is this database right now?
Agent (using
audit_database): Returns a graded report: Memory & I/O score 92 (GOOD), Transaction & Connection 78 (WARNING: rollback rate 0.4%, look at app logs), Concurrency & Locks 60 (CRITICAL: 14 backends waiting), Cleanliness & Bloat 88 (GOOD), Slow queries 70 (WARNING: top query template runs 5000×, mean 90 ms — seeoptimize_query).
Run a guarded write
You: Soft-delete every order older than 5 years.
Agent (using
run_writewithMCPG_AUDIT_PERSIST=true): Validates the statement through the safe-SQL kernel, runs it inside a transaction, returns affected row count, persists the call (sql + arguments — with secrets regex-redacted — + status) tomcpg_audit.eventsfor after-the-fact review.
For dozens more recipes — multi-tenant routing, RLS testing, NL→SQL,
hybrid vector + FTS search, Apache AGE Cypher, TimescaleDB, ORM schema
exports, server-side cursors — see docs/cookbook.md.
What's in the box
Compact category list. For the full, current tool reference see
docs/tools.md; for a guided walkthrough see
docs/tour.md.
Catalog introspection — schemas, tables, columns, indexes, constraints, views, functions, triggers, sequences, partitions, policies, roles, grants, enums, domains, composite types, FDWs, publications, subscriptions, extensions, generated columns.
Query intelligence —
run_select,run_select_parallel,explain_query,analyze_query_plan,why_is_this_slow,recommend_indexes,analyze_workload,check_database_health,detect_n_plus_one,audit_database.Search —
fuzzy_search(trigram),full_text_search,vector_search,hybrid_search(pgvector + FTS via RRF),geo_search(PostGIS k-NN).Natural language → SQL —
translate_nl_to_sql(Anthropic, OpenAI, or Gemini; output passes through the same safe-SQL kernel as hand-written queries).Visualisation —
generate_schema_diagram(ER),generate_fk_cascade_graph(blast-radius ofON DELETE CASCADE),generate_graph_diagram(Apache AGE property graphs).Structural diff & migrations —
compare_schemas,validate_migration, stagedprepare_migration/complete_migration/cancel_migrationworkflow.Apache AGE graph + Cypher —
list_graphs,describe_graph,run_cypher,create_graph,drop_graph,generate_graph_diagram.Composite + advisor tools —
summarize_table,find_unused_objects,find_sensitive_columns(PII heuristic),lint_naming_conventions,test_rls_for_role,list_locks,find_blocking_chains,read_pg_stat_io(PG16+),generate_test_data.Live ops & maintenance —
list_active_queries,verify_connection_encryption(TLS status of the live link),run_maintenance(VACUUM/ANALYZE),prune_audit_events(audit retention),cancel_query,terminate_backend,run_write,run_ddl,enable_extension.Data movement —
export_query/export_table(CSV/JSON),dump_database/restore_database,import_csv/import_json(COPY FROM STDIN),copy_table_between_databases.Server-side cursors —
open_cursor,fetch_cursor,close_cursor,list_cursorsfor pageable reads over millions of rows.TimescaleDB —
list_hypertables,list_chunks,create_hypertable,add_compression_policy,add_retention_policy.ORM schema exporters — Prisma, Drizzle, SQLAlchemy, sqlc, Diesel, jOOQ, Ent, Ecto.
Event streams —
subscribe_channel,poll_notifications,unsubscribe_channel,list_notification_subscriptionsbridging PostgreSQLLISTEN/NOTIFYinto the MCP poll model.Observability — Prometheus
/metricsendpoint +get_metrics_expositiontool for stdio; structured audit trail with regex-based credential redaction.
Documentation
docs/installation.md— install + configuredocs/tour.md— guided tool tourdocs/cookbook.md— practical agent recipesdocs/tools.md— complete tool referencedocs/architecture.md— how the pieces fit togetherdocs/scaling.md— pool sizing, replicas, performancedocs/security-hardening.md— security feature roadmapdocs/release-process.md— how releases ship to PyPIdocs/adr/— architecture decision recordsBrowse at https://devopam.github.io/MCPg/
Security
Vulnerability reporting: see
SECURITY.md. 90-day coordinated-disclosure window; reports todevopam@gmail.com.Defence-in-depth: capability gates, SafeSQL kernel, identifier allowlist, audit redaction, PG TLS enforcement at startup, rate-limiting, OIDC JWT validation, per-session timeouts.
See
docs/security-hardening.mdfor the living roadmap of shipped (✅) and queued (⬜) hardening items.
Release notes & changelog
See CHANGELOG.md for the full version history,
docs/release-process.md for how releases
are cut, and the GitHub Releases
page for downloadable artifacts.
Contributing
Pull requests welcome — see CONTRIBUTING.md for
the dev-loop setup, test conventions, and the per-PR review
checklist.
License
MIT — see LICENSE. The vendored SQL-safety kernel at
src/mcpg/_vendor/sql/ is also MIT-licensed; see NOTICE
for provenance.
Wrapped extensions — licenses you should know about
MCPg's source is MIT, but the PostgreSQL extensions it wraps each carry their own license. The wrappers themselves are at arm's length (SQL-level calls, no static or dynamic linking into MCPg's Python process), so MCPg-the-project is not a derivative work of any of them. Operators deploying a service built on MCPg + a given extension take on whatever obligations that extension's license imposes — same as installing the extension directly. The matrix below names the license per wrapped extension so you can make an informed choice.
Extension | License | Notes for operators |
pgvector | PostgreSQL License (BSD-style) | Permissive; no special obligations. |
pg_partman | PostgreSQL License | Permissive. |
pg_cron | PostgreSQL License | Permissive. |
pg_turboquant | MIT | Permissive. |
pg_buffercache / pg_walinspect / pgstattuple | PostgreSQL contrib | Permissive. |
TimescaleDB | Apache 2.0 (community) + Timescale License (TSL, source-available) for some features | Mixed — see Timescale's docs for which features are TSL-gated. |
Apache AGE | Apache 2.0 | Permissive. |
pg_search (ParadeDB) | AGPL-3.0 | Operators running a network service that lets users interact with |
This matrix is a starting point — for the binding answer on your specific deployment, consult the extension's upstream LICENSE file and (if it matters legally) your own counsel.
Disclaimer. Best efforts have been made to bring MCPg to production grade, but it remains an actively developed project and may contain issues. See the License terms for indemnity details.
This server cannot be installed
Maintenance
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/devopam/MCPg'
If you have feedback or need assistance with the MCP directory API, please join our Discord server