Inspect Postgres schemas, run safe SELECTs, EXPLAIN queries, find slow queries + table bloat — from Claude Desktop, Cursor, Cline, or any MCP-compatible client.
Read-only by default. Writes require explicit PG_ALLOW_WRITES=true. Read queries run inside a transaction that always ROLLBACKs. Belt and suspenders.
- 8 production-ready MCP tools
- Single-file TypeScript source (
src/index.ts) you can fork, audit, or extend - Install snippets for Claude Desktop, Cursor, and Cline
- MIT licensed - use commercially, no attribution required
| Tool | Purpose |
|---|---|
list_schemas |
All non-system schemas with owner |
list_tables |
Tables in a schema with estimated row count + size on disk |
describe_table |
Columns + types + indexes + foreign keys for one table |
query |
Read-only SELECT/WITH/EXPLAIN/SHOW. Rejects writes. Auto-LIMIT. Transaction always ROLLBACKs |
explain |
EXPLAIN (ANALYZE, BUFFERS) for a query — see the actual plan + I/O |
slow_queries |
Top N by mean time from pg_stat_statements |
table_bloat |
Dead tuple ratio per table — decide when to VACUUM |
unsafe_write |
INSERT/UPDATE/DELETE/DDL — only enabled if PG_ALLOW_WRITES=true |
The default mode is what you want for letting Claude poke around a production DB:
- Statement timeout (default 30s) — catches runaway queries
- Auto-LIMIT on
query(default 100, max 10000) — caps row counts - Write detection — string-checks for INSERT/UPDATE/DELETE/ALTER/etc; rejects
- Transactional rollback — even if write detection misses something, ROLLBACK reverses it
- Connection pool of 5 — won't exhaust your server's connection slots
To enable writes (for migrations, data fixes), set PG_ALLOW_WRITES=true. The unsafe_write tool then accepts arbitrary SQL and commits. Use sparingly.
npm install
npm run buildStandard postgres URL: postgres://user:password@host:5432/dbname. Use a role with the minimum privileges needed:
- Read-only mode: a role with
SELECTon the schemas you want to expose - Write-enabled mode: a role with
INSERT/UPDATE/DELETEas needed
For slow_queries, the extension must be installed:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- and ensure shared_preload_libraries = 'pg_stat_statements' in postgresql.conf~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"postgres": {
"command": "node",
"args": ["/absolute/path/to/postgres-mcp-server/build/index.js"],
"env": {
"DATABASE_URL": "postgres://readonly:pass@host:5432/db",
"PG_STATEMENT_TIMEOUT_MS": "10000"
}
}
}
}~/.cursor/mcp.json or .cursor/mcp.json:
{
"mcpServers": {
"postgres": {
"command": "node",
"args": ["/absolute/path/to/postgres-mcp-server/build/index.js"],
"env": {
"DATABASE_URL": "postgres://readonly:pass@host:5432/db"
}
}
}
}Same JSON shape - paste into Cline's MCP Servers settings.
"What tables in the public schema are biggest?" Calls
list_tablesfor schema=public.
"Describe the users table and tell me the foreign keys pointing at it." Calls
describe_table+ aqueryfollow-up.
"Why is this query slow? SELECT * FROM orders WHERE created_at > '2026-01-01' AND user_id = 5" Calls
explain. Returns plan with timing + buffer hits.
"Show me my 10 slowest queries from the last week." Calls
slow_queries.
"Which tables need vacuuming?" Calls
table_bloat. Returns dead-tuple ratios.
"Run: UPDATE users SET tier='pro' WHERE id=42" (with PG_ALLOW_WRITES=true) Calls
unsafe_write. Returns rowCount=1.
The official @modelcontextprotocol/server-postgres is fine for basic SELECT exposure. This server adds the production-DBA tools: explain with ANALYZE+BUFFERS, slow_queries via pg_stat_statements, table_bloat, and the optional unsafe_write with explicit opt-in. Use whichever fits.
MIT. Modify, redistribute, embed in your own product, no attribution required.