A production-safe MCP server for PostgreSQL — lets Claude introspect your schema, run parameterized read queries, and (opt-in) perform writes, with safety guards against destructive operations.
Built on
psycopg[binary]3.x. Use it on a read-replica or a sanitized dev database first; never point it at unfiltered production without auditing the audit log.
Кому это подойдёт:
- У тебя PostgreSQL в production / staging и ты хочешь чтобы Claude/Cursor мог делать аналитику без переноса данных в чат
- Ты dev-консультант и тебе нужен structured Postgres access для пары клиентов
- Ты аналитик/dev на проекте — хочешь чтобы AI читал твою схему и предлагал SQL без guessing типов
Что внутри: Python-сервер на psycopg 3, авторизация через connection string (env var), безопасность (запрет DROP/TRUNCATE/ALTER по умолчанию + read-only режим default), готовый docker-compose с PostgreSQL 16 для теста, sample schema.
Заказать кастомную версию (под твою специфическую схему, дополнительные tools, RLS-aware queries, multi-tenant access): Kwork → agentforge_ru — от 4 500 ₽, сроки 2-4 дня.
| Tool | Purpose | Default behavior |
|---|---|---|
list_tables(schema) |
Lists tables in a schema (default: public) |
Always available |
get_schema(table, schema) |
Returns columns, types, constraints, indexes for a table | Always available |
query(sql, params) |
Runs a SELECT/WITH query with parameter binding | Always available |
execute_write(sql, params) |
Runs INSERT/UPDATE/DELETE with parameter binding | Off by default; enable with --allow-writes |
database_stats(schema) |
Per-table row counts (estimate from pg_class.reltuples) |
Always available |
explain_query(sql) |
Returns EXPLAIN ANALYZE for a SELECT | Always available |
Destructive operations (DROP, TRUNCATE, ALTER, GRANT, REVOKE) are blocked unless the server is started with --unsafe.
pip install git+https://github.com/agentforge-ru/mcp-postgres-serverSet DATABASE_URL in your environment or via Claude Desktop's env block:
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
For read-only access (recommended), use a dedicated Postgres role:
CREATE USER claude_reader WITH PASSWORD 'strong-password';
GRANT CONNECT ON DATABASE mydb TO claude_reader;
GRANT USAGE ON SCHEMA public TO claude_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO claude_reader;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO claude_reader;Add to claude_desktop_config.json:
{
"mcpServers": {
"postgres-readonly": {
"command": "python",
"args": ["-m", "mcp_postgres_server"],
"env": {
"DATABASE_URL": "postgresql://claude_reader:strong-password@localhost:5432/mydb"
}
}
}
}For read-write access (use a separate user with INSERT/UPDATE/DELETE grants):
{
"mcpServers": {
"postgres-readwrite": {
"command": "python",
"args": ["-m", "mcp_postgres_server", "--allow-writes"],
"env": {
"DATABASE_URL": "postgresql://claude_writer:strong-password@localhost:5432/mydb"
}
}
}
}Restart Claude Desktop. Tools appear in the model's context.
You: What's in the public schema?
Claude: [calls list_tables(schema="public")]
You have 12 tables: users, accounts, transactions, ...
You: Show me the schema of the transactions table.
Claude: [calls get_schema(table="transactions")]
- id BIGSERIAL PRIMARY KEY
- account_id BIGINT REFERENCES accounts(id) ON DELETE CASCADE
- amount NUMERIC(12,2) NOT NULL CHECK (amount > 0)
- created_at TIMESTAMPTZ DEFAULT now()
- INDEX idx_transactions_account_id ON (account_id)
- INDEX idx_transactions_created_at ON (created_at)
You: Top 10 accounts by total transaction volume last month?
Claude: [calls query with appropriate SQL]
Blocked unless --unsafe:
DROP TABLE,DROP DATABASE,DROP SCHEMA,DROP INDEX,DROP VIEW,DROP TRIGGER,DROP FUNCTIONTRUNCATE TABLEALTER TABLE ... DROPGRANT/REVOKECREATE EXTENSION(privilege escalation risk)
Recommended layering:
- Use a read-only Postgres role for the connection (defense at the database layer)
- Run with default flags (the destructive guard layer)
- Audit
stderroutput between sessions (the audit log layer)
Three layers; any one alone is not sufficient.
[ Claude Desktop / Cursor / Claude Code ]
↓ MCP protocol (stdio)
[ mcp-postgres-server ]
↓ psycopg 3 (binary build)
[ PostgreSQL 12+ ]
Single connection per session. The server reuses one psycopg connection across all tool calls in the session. When the MCP client closes, the connection closes.
- Single-connection model. Long-running queries block other tool calls within the session. For production analytics where you need concurrency, fork and add pooling.
- No transaction support exposed. Each
execute_writeis auto-committed. For multi-statement transactions, wrap them as a single SQL string (BEGIN; ...; COMMIT;). - No COPY / bulk-load tools. If you need to ingest CSVs, do it from your application code.
- No notify/listen. Postgres LISTEN/NOTIFY would need a different transport.
- Free-tier Postgres compatible but I haven't tested it against managed services (RDS, Supabase, Neon) — should work, but YMMV.
MIT — see LICENSE.
Built by agentforge_ru — custom Claude Code subagents, MCP servers, and Telegram bots with AI logic.
Need a custom MCP server for your specific stack (MySQL? ClickHouse? MongoDB? Your internal API?) — open an issue or reach via Kwork.