# psql MCP Server
An MCP server that wraps the PostgreSQL psql CLI, giving AI clients the full backslash-command surface of psql — schema inspection, queries, EXPLAIN plans, COPY, roles, extensions — behind a small, risk-classified tool set. Every operation shells out to the real psql binary; this is a process wrapper, not a driver. Read-only by default: writes, local file I/O, and shell escapes are all disabled unless explicitly enabled.
## How It Works
Every tool call shells out to the real psql binary rather than reimplementing a driver. Plain SQL sent to run_query runs with default_transaction_read_only=on, so PostgreSQL itself — not a regex — rejects any write attempt. On psql 18+, SQL is prefixed with a per-call \restrict key that disables every backslash command until a matching \unrestrict, so a \! smuggled inside a string or comment can't execute without guessing the key. Capabilities (writes, file I/O, shell) default to off and can be scoped per named connection, so a single config can keep dev writable and prod permanently read-only.
MCP Client (Claude) ──stdio──▶ psql MCP Server (Node.js)
└── Risk classifier (safe/writes/fileIo/shell/session)
└── spawn: psql ──▶ PostgreSQL
└── \restrict guard (psql 18+)
└── read-only session (run_query)## Screenshots
❯ list_objects kind=table SCHEMA NAME KIND ────────────────────────────── public users table public orders table public order_items table ❯ describe_object name=orders ✓ 4 columns · 1 primary key · 2 indexes · 1 FK → users
❯ run_query sql="DELETE FROM orders WHERE id = 42" ✗ Rejected: session is read-only (default_transaction_read_only=on) ❯ run_statement sql="DELETE FROM orders WHERE id = 42" connection=dev ✗ Rejected: allowWrites is false for connection 'dev' (enable PSQL_MCP_ALLOW_WRITES to permit — off by default)
## Features
- +Every backslash command classified by risk (safe / writes / fileIo / shell / session)
- +Read-only by default — writes, file I/O, and shell escapes opt-in per connection
- +\restrict-based injection protection on psql 18+ (scans for embedded commands on older versions)
- +Full schema inspection: tables, views, functions, roles, extensions, definitions
- +psql_meta escape hatch reaches every documented psql backslash command
- +Named multi-connection registry — keep prod hard-read-only while allowing writes on dev
## vs. The Field
| Feature | psql MCP Server | Direct pg driver | DBeaver / pgAdmin |
|---|---|---|---|
| MCP protocol native | ✓ | ✗ | ✗ |
| Read-only by default | ✓ | ✗ | ✗ |
| SQL-injection-safe backslash guard | ✓ (\restrict) | n/a | n/a |
| No GUI required | ✓ | ✗ | ✗ |
| Per-connection write scoping | ✓ | partial | ✗ |
## Installation
Install psql client tools
macOS: brew install libpq (set PSQL_MCP_PSQL_PATH if not on PATH). psql 18+ recommended for \restrict support.
Install
No cloning or build step needed.
npx -y @web4w3/psql-mcp-server
Add to your MCP client config
Simplest setup — a single database, read-only.
{
"mcpServers": {
"psql": {
"command": "npx",
"args": ["-y", "@web4w3/psql-mcp-server"],
"env": {
"DATABASE_URL": "postgres://user:password@host:5432/dbname"
}
}
}
}⚠ For multiple named connections with per-connection write scoping, use PSQL_MCP_CONNECTIONS instead of DATABASE_URL.