Install
$ agentstack add mcp-devopam-mcpg ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
MCPg
A production-grade Model Context Protocol server for PostgreSQL. Lets AI agents safely inspect, query, operate, and tune a Postgres database — 252 tools spanning catalog introspection, query intelligence, natural-language SQL, structural diffs, hybrid search, graph queries, data movement, live ops, and more.
[](https://pypi.org/project/mcpg/) [](https://pypi.org/project/mcpg/) [](https://github.com/devopam/MCPg/blob/main/LICENSE) [](https://github.com/devopam/MCPg/actions/workflows/ci.yml) [](https://github.com/devopam/MCPg) [](https://smithery.ai/servers/devopam/mcpg) [](https://glama.ai/mcp/servers/devopam/MCPg)
> Try it live: point an MCP client — or the MCP Inspector — at the hosted, read-only demo endpoint https://devopam-mcpg-demo.hf.space/mcp. It serves read tools against throwaway demo data; for real use, run MCPg next to your own database (see [Quick start](#quick-start)).
📍 Listed On
| Aspect | MCPg | |---------------------|-----------------------------------| | Safety | Read-only default + AST validation | | Transport | stdio + HTTP/SSE | | Install | pip install mcpg | | Postgres Versions | 14–19 | | 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, and LISTEN/NOTIFY are off until you opt in. Every tool publishes MCP ToolAnnotations (readOnlyHint, openWorldHint) derived from those same gates, so clients can auto-approve reads and gate writes without guessing.
- 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
psycopg3 directly, speaks every pg_* system view, integrates with TimescaleDB, pgvector, PostGIS, Apache AGE, and pg_stat_statements where they're available, and degrades gracefully when they aren't.
- Production-shaped, not demo-shaped. Connection pooling, per-request
SET ROLE multi-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 surfaces mcpg_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. 2,500+ 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, plus PG 19 (beta) as an experimental (non-blocking) entry tracked under issue #120.
Install
From PyPI (recommended)
pip install mcpg
# or, in an isolated venv exposed globally:
uv tool install mcpg
Verify:
mcpg --version
Docker
Pull the pre-built image from the GitHub Container Registry (published on every tagged release — :latest tracks the newest, or pin a version like :0.6.5):
docker pull ghcr.io/devopam/mcpg:latest
docker run --rm -p 8000:8000 \
-e MCPG_DATABASE_URL=postgresql://user:pass@host:5432/db \
-e MCPG_ACCESS_MODE=read-only \
ghcr.io/devopam/mcpg:latest
Or build it yourself from source:
docker build -t mcpg https://github.com/devopam/MCPg.git
Multi-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 sync
uv sync creates a venv with all runtime + dev dependencies and exposes the mcpg console script.
More detail in the Installation Guide.
Quick start
One-click installs: [](https://cursor.com/install-mcp?name=mcpg&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyJtY3BnIl0sImVudiI6eyJNQ1BHX0RBVEFCQVNFX1VSTCI6InBvc3RncmVzcWw6Ly91c2VyOnBhc3NAbG9jYWxob3N0OjU0MzIvbXlkYiJ9fQ%3D%3D) [](https://vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522mcpg%2522%252C%2522command%2522%253A%2522uvx%2522%252C%2522args%2522%253A%255B%2522mcpg%2522%255D%252C%2522env%2522%253A%257B%2522MCPGDATABASEURL%2522%253A%2522%2524%257Binput%253Adatabaseurl%257D%2522%257D%252C%2522inputs%2522%253A%255B%257B%2522type%2522%253A%2522promptString%2522%252C%2522id%2522%253A%2522databaseurl%2522%252C%2522description%2522%253A%2522PostgreSQL%2520connection%2520URL%2520%2528postgresql%253A%252F%252Fuser%253Apass%2540host%253A5432%252Fdb%2529%2522%252C%2522password%2522%253Atrue%257D%255D%257D) [](https://github.com/devopam/MCPg/releases/latest) — setup for Windsurf, JetBrains, Zed, Cline, Antigravity, Qwen Code, Perplexity, ChatGPT, Copilot Studio, Continue, and HTTP clients in the [integrations guide](docs/integrations.md).
One-click install in Claude Desktop (.mcpb)
Download mcpg-.mcpb from the latest release and double-click it (or drag it into Claude Desktop's Settings → Extensions). You'll be prompted for your PostgreSQL connection URL — stored in the OS keychain — and an access mode (defaults to read-only). That's the whole install: the bundle is ~2 kB and the host resolves the pinned mcpg release from PyPI for your platform.
Or wire it up manually (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"
No interesting data yet? Seed the demo dataset
MCPG_DATABASE_URL=postgresql://... mcpg --demo
One command seeds a small, curated e-commerce dataset (3,000 orders, 900 product reviews, deliberately planted flaws) into an mcpg_demo schema — engineered so the index advisor, query-plan analysis, full-text search, PII audit, and graph projection all have something real to find on your first try. See the [guided tour](docs/demo.md) for a captured walkthrough, and remove it any time with mcpg --demo-drop.
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 \
mcpg
Then 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 CLI's --version / --demo / --demo-drop are one-shot commands, not configuration). The only required one is MCPG_DATABASE_URL; everything else has a safe default.
Common scenarios
| Scenario | Set | |---|---| | Local exploration, read-only | MCPG_DATABASE_URL | | Read-write app data access | MCPG_ACCESS_MODE=restricted | | DBA toolkit (DDL, vacuum, etc.) | MCPG_ACCESS_MODE=unrestricted + MCPG_ALLOW_DDL=true | | HTTP transport with bearer auth | MCPG_TRANSPORT=streamable-http + MCPG_HTTP_AUTH_TOKEN=… | | Multi-tenant SaaS | MCPG_DEFAULT_ROLE=tenant_a + MCPG_ALLOWED_ROLES=tenant_a,tenant_b,… | | Read-replica fan-out | MCPG_REPLICA_URLS=postgresql://…?sslmode=require,postgresql://…?sslmode=require | | NL→SQL — single provider | Set any one vendor key (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, XAI_API_KEY, GROQ_API_KEY, HF_TOKEN, … — 22 built-in providers). MCPg auto-picks the default. | | NL→SQL — multiple providers, caller picks | Set all vendor keys you want active. Each call to translate_nl_to_sql can pass provider="…" (any configured built-in or custom). |
Full reference
Core
| Variable | Default | Description | |---|---|---| | MCPG_DATABASE_URL | required | Primary PostgreSQL DSN. Supports URI (postgresql://…) and keyword (host=… user=…) forms. Remote hosts require sslmode=require (or stronger). | | MCPG_ACCESS_MODE | read-only | read-only \| restricted (allows write tools) \| unrestricted (also unlocks DBA tools when paired with the gate vars). | | MCPG_TRANSPORT | stdio | stdio (default, for Claude Desktop) \| streamable-http \| sse. | | MCPG_LOG_LEVEL | INFO | DEBUG \| INFO \| WARNING \| ERROR \| CRITICAL. | | MCPG_HTTP_HOST | 127.0.0.1 | Bind address for HTTP transports. Set to 0.0.0.0 inside containers. | | MCPG_HTTP_PORT | 8000 | Listen port for HTTP transports (1–65535). |
Capability gates (opt-in for higher-blast-radius tools)
| Variable | Default | Description | |---|---|---| | MCPG_ALLOW_DDL | false | Expose DDL tools (run_ddl, create_graph, drop_graph, hypertable tools, migration tools). Requires MCPG_ACCESS_MODE=unrestricted. | | MCPG_ALLOW_SHELL | false | Expose subprocess-backed tools (dump_database, restore_database, run_pg_binary). Required PG client binaries must be on PATH. | | MCPG_ALLOW_LISTEN | false | Expose LISTEN/NOTIFY tools (subscribe_channel, poll_notifications, unsubscribe_channel, list_notification_subscriptions). |
Authentication (HTTP transports only)
| Variable | Default | Description | |---|---|---| | MCPG_AUTH_MODE | static | static (compare bearer to MCPG_HTTP_AUTH_TOKEN) \| oidc (full JWT validation). | | MCPG_HTTP_AUTH_TOKEN | — | Required bearer token when MCPG_AUTH_MODE=static. Constant-time compare. | | MCPG_OIDC_ISSUER | — | OIDC issuer URL (required when MCPG_AUTH_MODE=oidc). | | MCPG_OIDC_AUDIENCE | — | Expected aud claim (required when MCPG_AUTH_MODE=oidc). | | MCPG_OIDC_JWKS_URL | discovered | Override JWKS endpoint (auto-discovered from issuer's .well-known otherwise). | | MCPG_OIDC_ROLE_CLAIM | — | JWT claim whose value becomes the per-request PG role (SET LOCAL ROLE). Composes with the tenancy driver. |
HTTP hardening (HTTP transports only)
| Variable | Default | Description | |---|---|---| | MCPG_HTTP_MAX_BODY_BYTES | 1048576 | (1 MiB) Request bodies above this get a 413. Counts streamed bytes, so a missing/lying Content-Length can't bypass it. | | MCPG_HTTP_ALLOWED_ORIGINS | — | Comma-separated CORS allowlist. Unset = no CORS middleware (no cross-origin headers emitted). | | MCPG_HTTP_HSTS_MAX_AGE | 31536000 | Strict-Transport-Security max-age. 0 disables the HSTS header. Security headers (CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy) are always added unless the app already set them. | | MCPG_HTTP_REQUEST_TIMEOUT_SECONDS | 0 | Per-request wall-clock cap (504 on expiry). 0 = disabled. Leave off if you rely on long-lived SSE / streamable-http streams — a hard cap also severs those. |
Multi-tenancy (SET ROLE)
| Variable | Default | Description | |---|---|---| | MCPG_DEFAULT_ROLE | — | Static PG role applied to every query. Identifier-validated. | | MCPG_ALLOWED_ROLES | — | Comma-separated allowlist. When set, the X-MCPG-Role header / OIDC role claim must be in this list. |
Read replicas
| Variable | Default | Description | |---|---|---| | MCPG_REPLICA_URLS | — | Comma-separated replica DSNs. force_readonly queries round-robin across healthy replicas; primary fallback on failure; 30 s degraded-replica retry window. |
Multiple databases (read-only secondaries)
| Variable | Default | Description | |---|---|---| | MCPG_SECONDARY_DATABASE_URLS | — | Comma- or newline-separated name=dsn entries naming additional read-only databases this one server can serve (e.g. analytics=postgresql://…?sslmode=require,reporting=postgresql://…?sslmode=require). Read-capable tools accept an optional database argument selecting a secondary by name; omit it for the primary. Secondaries are read-only — PostgreSQL-enforced (every query runs in a READ ONLY transaction), so writes / DDL / shell / migrate always target the primary. Names must be simple identifiers ([a-z0-9_]+), unique, and not primary (the reserved id of MCPG_DATABASE_URL). Same TLS rules as the primary DSN. Call list_databases to discover the configured ids and their reachability. |
Pool / timeouts / TLS
| Variable | Default | Description | |---|---|---| | MCPG_POOL_MIN_SIZE | 1 | Minimum pool connections. | | MCPG_POOL_MAX_SIZE | 5 | Maximum pool connections. Must be ≥ MCPG_POOL_MIN_SIZE. | | MCPG_STATEMENT_TIMEOUT_MS | 30000 | Per-session statement_timeout set on connection checkout. Runaway queries self-terminate. | | MCPG_LOCK_TIMEOUT_MS | 5000 | Per-session lock_timeout. Hanging lock waits self-terminate. | | MCPG_ALLOW_INSECURE_TLS | false | Bypass the startup TLS check that refuses remote DSNs without sslmode=require (or stronger). Loopback hosts are always exempt. | | MCPG_SHUTDOWN_DRAIN_SECONDS | 30 | 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 | |---|---|---| | MCPG_SHELL_TIMEOUT_SEC | 60 | Max wall-clock for pg_dump / pg_restore / psql invocations. | | MCPG_SHELL_MAX_OUTPUT_BYTES | 67108864 | (64 MiB) Cap on captured stdout per subprocess call. | | MCPG_SUBPROCESS_BIN_ALLOWLIST | — | Comma-separated absolute dirs the resolved pg_dump / pg_restore / psql must live under. Empty = trust PATH. Defeats a PATH-shim of these binaries. | | MCPG_SUBPROCESS_CPU_SECONDS | — | Per-child RLIMIT_CPU (seconds). POSIX only; unset = inherit. | | MCPG_SUBPROCESS_MEMORY_MB | — | Per-child RLIMIT_AS (MiB). POSIX only; unset = inherit. |
LISTEN/NOTIFY (MCPG_ALLOW_LISTEN=true only)
| Variable | Default | Description | |---|---|---| | MCPG_LISTEN_QUEUE_MAX | 1000 | Per-channel buffer; oldest notifications dropped on overflow. |
Audit
| Variable | Default | Description | |---|---|---| | MCPG_AUDIT_PERSIST | false | When true, every run_write / run_ddl call persists to a mcpg_audit.events table (auto-created idempotently). | | MCPG_AUDIT_REDACT_KEYS | — | Comma-separated regex fragments added to the se
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: devopam
- Source: devopam/MCPg
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.