postgres-mcp
You can interact with a PostgreSQL database through a read-only MCP server that enforces SQL security policies.
query: Run read-only SQL queries (allowlisted commands, denied keywords, automatic LIMIT, statement timeout).
list_tables: List base tables in the
publicschema.describe_table: Get column metadata for a table or view.
relationships: List foreign-key relationships between tables.
select_profile: Switch to a database profile when integrated with masstrade-agent / wren profiles.
Read-only guarantees: Connection is opened with
default_transaction_read_only=on, so writes are blocked even if validation is bypassed.Startable without a connection: If no profile is selected, the server still starts and returns actionable errors instead of crashing.
Provides read-only access to PostgreSQL databases, enabling validated SQL queries, listing tables, describing table schemas, and inspecting foreign-key relationships.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@postgres-mcp show me the columns of the orders table"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
postgres-mcp
A read-only PostgreSQL MCP server with a
SQL security policy. It exposes a small set of read-only tools and validates
every query against an allowlist of commands, a deny-list of keywords, an
automatic row limit, and a per-statement timeout.
Read-only is enforced twice: by the SQL validator and by the connection itself,
which is opened with default_transaction_read_only=on and a
statement_timeout. A statement that slips past the validator still cannot
write and cannot run forever.
Install
pip install -e ".[dev]" # editable, with test deps
# or from a published index:
pip install postgres-mcpRelated MCP server: pgmcp
Configure
Copy config.example.yaml to config.yaml (gitignored) and fill it in. Any
value may reference an environment variable as ${VAR} — keep secrets in the
environment, never in a committed file.
postgres:
host: "localhost"
port: 5432
dbname: "postgres"
user: "${POSTGRES_MCP_USER}"
password: "${POSTGRES_MCP_PASSWORD}"
security:
query_timeout_ms: 30000
max_rows_limit: 1000
allowlist_commands: ["SELECT", "EXPLAIN", "SHOW", "WITH", "ANALYZE"]
deny_keywords: ["DROP", "DELETE", "INSERT", "UPDATE", "ALTER",
"CREATE", "TRUNCATE", "GRANT", "REVOKE"]
log_queries: trueResolution order: $POSTGRES_MCP_CONFIG (explicit path), then ./config.yaml,
then ./config.example.yaml in the working directory.
Cooperation with masstrade-agent
postgres-mcp can share its connection source with masstrade-agent: point it at
the same ~/.wren/profiles.yml that masstrade-agent maintains, and both
servers read the readonly credentials from MASSTRADE_RO_USER /
MASSTRADE_RO_PASSWORD (process environment or ~/.wren/.env).
wren:
profiles: true # read ~/.wren/profiles.yml
profile: null # null = follow `active`; or a tenant SID (e.g. "APR")With wren.profiles: true the postgres: block is ignored, and the
select_profile tool is registered. The typical flow is:
masstrade-agent→select_database APR(upserts theAPRprofile).postgres-mcp→select_profile APR(re-points at the same database).postgres-mcp→query "SELECT ..."(read-only againstAPR).
When no config file is found at all and ~/.wren/profiles.yml exists,
wren-profiles mode is enabled automatically.
No profile chosen yet is not a startup failure
A client may launch this server before select_database has picked a tenant.
Exiting there is expensive: the client sees a closed connection and respawns
the process on every reconnect attempt — a spawn loop that shows up as
"failed initial connection … parking" in the client's log.
So a configuration that cannot yet produce a connection is a startable state, not an error. The server starts either way, and every tool call that needs a connection answers with the actionable message instead of a dead process:
{ "error": "No profile selected yet. Available: APR, EAC, EAL, EEE, ESK. …" }The profiles file is re-read on each resolution, so select_database APR on
masstrade-agent, a hand-edited active:, or select_profile APR all take
effect without restarting this server. Profile names are matched
case-insensitively, and the password never appears in any tool output.
The strict, fail-fast behaviour is still one keyword away — load_config()
without allow_unresolved=True raises as before, which is what the tests and
any caller that knows a connection must exist should use.
Run
postgres-mcp # stdio, via the installed entry point
# or
python -m postgres_mcpTools
Tool | Description |
| Run a validated read-only SQL statement |
| List base tables in the |
| Describe the columns of a table or view |
| List foreign-key relationships |
| Switch to a profile in |
Security model
Allowlist — the first command must be on
allowlist_commands.Deny-list — any whole-word
deny_keywordsentry anywhere in the SQL rejects the statement.Row limit — a
LIMITis appended toSELECTwhen the query has none (SHOW/EXPLAINare left untouched, since they rejectLIMIT).Timeout —
statement_timeoutis set per connection fromquery_timeout_ms.Query log — when
log_queriesis true, each query is logged (truncated) to stderr.
The validator is deliberately lightweight (string + regex, no SQL parser), so a denied keyword inside a string literal or quoted identifier can cause a false rejection — safe by design, but noted. The connection-level guards remain the authoritative boundary.
MCP client wiring
Point any MCP client at the stdio server. With Cursor or Hermes the entry is a
server whose command is postgres-mcp (or python -m postgres_mcp); the
user/password come from the environment of the process that launches it.
License
MIT — see LICENSE.
Available Tools
4 toolsdescribe_tableBRead-only
Describe the columns of a table or view in the public schema.
Args: table_name: Name of the table or view.
Returns: Column metadata as a JSON array of objects.
Inputs: table_name (required). Returns: result
list_tablesARead-only
List all base tables in the public schema.
Inputs: no named parameters. Returns: result
queryARead-only
Run a read-only SQL query against the database.
The query is validated against the security policy before execution: only allowlisted commands are accepted, denied keywords are rejected, and a LIMIT is appended automatically when the query has none.
Args: sql: SQL statement to execute (read-only).
Returns: Rows as a JSON array of objects, or an object with an "error" key.
Inputs: sql (required). Returns: result
relationshipsARead-only
List foreign-key relationships between tables in the public schema.
Inputs: no named parameters. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 4 tools
Each tool has a clearly distinct purpose: query runs ad-hoc read-only SQL, list_tables enumerates tables, describe_table returns column metadata, and relationships exposes foreign keys. There is no overlap in their intended use, so an agent can easily select the right tool.
Three tools follow a verb_noun pattern (list_tables, describe_table) or a clear verb (query), while relationships is a noun. This is a minor deviation, but all names use snake_case and remain readable and predictable overall.
Four tools is well-scoped for a read-only Postgres introspection server. Each tool serves a distinct, necessary function (querying, listing, describing, and mapping relationships) without redundancy or bloat.
The toolset covers the core read-only workflows: running queries, listing base tables, describing columns, and discovering foreign keys. However, it lacks tools for listing views or schemas (list_tables only covers public base tables), which are minor gaps for full schema exploration.
Maintenance
Related MCP Connectors
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
Query PostgreSQL databases in plain English — LLM-generated, safety-validated SQL.
Governed SQL access to your databases: redaction, query review and an audit log.
Query 40 databases from Claude, ChatGPT, or Cursor — on any device. Read-only, encrypted, audited.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceProvides secure read-only SQL access to PostgreSQL and ClickHouse databases with built-in safety features like read-only enforcement, timeouts, and managed result files.241 PyPIMIT
- AlicenseNot gradedqualityDmaintenanceEnables safe, read-only querying of PostgreSQL databases with defense-in-depth protections including single-statement SELECT guard, row caps, and per-identity audit logging.1MIT
- AlicenseAqualityDmaintenanceRead-only Postgres access with a policy gate that blocks writes and restricts visible tables and columns.68 npmMIT
- AlicenseAqualityCmaintenanceEnables read-only PostgreSQL interaction through safe query execution, query planning, table and column inspection, and privilege checks, with multi-layer defenses against write operations and transaction-control exploits.5MIT