postgres-mcp-server

A secure MCP server for PostgreSQL.

Connect Claude, Cursor, or any MCP client to your database with read-only access, column filtering, and query limits. Open source, self-hostable, one small TypeScript server.

$npx @querybear/postgres-mcp-server View on GitHub

Works with Claude Desktop, Cursor, Windsurf, Zed, and any MCP-compatible client.

Tools

Four tools for reading a database.

query{ sql, schema? }

Run a read-only SELECT. Returns rows, column names, and a row count. Anything that isn't a SELECT is rejected before it reaches the database.

list_tables{ schema? }

List every table in a schema (default: public) so the assistant can learn the shape of your database.

describe_table{ table, schema? }

Return column names, data types, nullability, and defaults for a table.

list_schemas( )

List all non-system schemas — useful for multi-tenant or large databases.

Security

Read-only by default. No unsafe opt-in.

Every query runs through a security pipeline before it touches your database. The controls below are always on.

SELECT-only enforcement

INSERT, UPDATE, DELETE, DROP, TRUNCATE, and all DDL are rejected before execution.

Injection guards

Statement stacking (;), line and block comments, and EXEC-style calls are blocked at the parser level.

Column filtering

Sensitive columns — passwords, tokens, secrets — are stripped from every result. Configurable via BLOCKED_COLUMNS.

Row limits

Results are capped at MAX_ROWS with a truncation flag, so an assistant can't dump an entire table by accident.

Query timeouts

A statement_timeout from QUERY_TIMEOUT_MS kills runaway queries and protects the database under load.

Quick start

Add it to your MCP client.

Point it at a connection string and you're done. For Claude Desktop, add this to claude_desktop_config.json:

claude_desktop_config.json
{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["@querybear/postgres-mcp-server"],
      "env": {
        "DATABASE_URL": "postgresql://user:pass@host:5432/db"
      }
    }
  }
}

Optional environment variables:

env
DATABASE_URL      postgresql://…   # required
MAX_ROWS          500              # default 1000
QUERY_TIMEOUT_MS  15000            # default 30000
BLOCKED_COLUMNS   password,token   # comma-separated

Full configuration and adapters for other clients are in the README.

For teams

Works perfectly for one. Outgrows it fast.

The OSS server is one connection, one user, one set of rules. When any of these come up, you need something more:

A teammate wants in

There's no per-user configuration. Everyone shares the same connection and the same rules — or you spin up separate servers per person.

Compliance asks for a log

Every query passes through, but nothing is recorded. No user attribution, no history, nothing to show a security audit.

Access needs to vary by role

Marketing, engineering, and execs all need different table access. There's no per-user allow-list or column-level policy.

QueryBear handles all of this.

The managed version of this server — same security model, plus per-user RBAC, column-level access control, table allow-lists, audit logs, and SSO. Nothing to host, nothing to manage.

Try QueryBear