postgres-mcp
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-mcpshow 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: mcp-read-only-sql
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| table_name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so safety is covered structurally. The description adds the useful scope constraint that only the public schema is inspected, but says nothing about behavior on a missing table, permissions, or output detail beyond the annotation baseline.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose sentence is front-loaded, followed by tidy Args and Returns blocks with no filler. It is slightly over-structured for a single-parameter tool, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so the return shape does not need explaining, and the description still gives a one-line summary of it. For a simple introspective tool with full annotation coverage, the definition is complete apart from missing usage routing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the parameter meaning, and it does explain table_name as the name of the table or view. The public-schema scope also implies the name is unqualified. It stops short of stating an expected format or whether views in other schemas are rejected.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Describe') and resource ('columns of a table or view') with the added scope constraint of the public schema. It is clearly distinguishable from list_tables and query by intent, but it never names or contrasts with those siblings explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use or when-not-to-use guidance, no mention of prerequisites, and no routing to alternatives such as list_tables for discovering table names first. Usage is only implied by the pair of Args/Returns blocks.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_tablesARead-only
List all base tables in the public schema.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so safety is covered. The description adds genuine behavioral scope beyond the annotations: only base tables are returned (views/materialized views excluded) and only the public schema is scanned, which meaningfully constrains the result set.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with zero filler. Scope qualifiers come immediately after the verb, so the agent gets the key constraint before anything else.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and readOnly annotations cover the safety profile. For a zero-parameter discovery tool, the description supplies everything an agent needs to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; the baseline for a parameterless tool is 4. No param-related confusion is possible here.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (list), resource (tables), and scope qualifiers (base tables, public schema), which lets an agent distinguish it from describe_table and relationships. It does not explicitly name the siblings it is not, so it falls just short of the top mark.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description contains no when-to-use, when-not-to-use, or alternative-selection guidance. The intended use (discovery before query/describe_table) is only inferable from the tool name and scope, not stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the description had a lower bar, yet it adds substantive behavior: pre-execution validation against a security policy, allowlist/denylist keyword handling, and automatic LIMIT appending. Those are non-obvious operational traits that materially affect how an agent should write SQL.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and the security/validation behavior in a tight three-sentence block. The Args/Returns sections are mild boilerplate, and the Returns prose is partly redundant given an output schema exists, but nothing is bloated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-param read-only query tool with an output schema, the description covers the action, the security/validation behavior, and the error-shape at a high level. The remaining gap is routing guidance against sibling schema-inspection tools, which would make it fully self-sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% for the single parameter, so the schema itself gives no semantics. The description only restates 'sql: SQL statement to execute (read-only)', adding just the read-only constraint; it does not clarify dialect, expected syntax, or LIMIT interaction beyond the general policy note. Minimum viable.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Run a read-only SQL query against the database') and the read-only scope, which clearly separates it from the DDL-ish siblings. It never explicitly contrasts itself with list_tables/describe_table/relationships, so sibling differentiation is left implicit rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the 'read-only SQL query' framing, but there is no explicit when-to-use/when-not guidance and no mention of when an agent should reach for describe_table or list_tables instead. Adequate but with a clear gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
relationshipsARead-only
List foreign-key relationships between tables in the public schema.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds the public-schema scope, but says nothing about pagination, ordering, or whether unconstrained FK columns are included. With an output schema present, return-format detail isn't required.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, front-loaded sentence with no filler. Every clause (verb, resource, scope) earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no parameters, annotations covering safety, and an output schema defining the return shape, the remaining burden is minimal and the description covers scope. Only the absence of any usage routing against the three siblings keeps it from a 5.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; baseline for a no-param tool is 4. The description correctly implies no filtering is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb (List) and resource (foreign-key relationships between tables) with scoping to the public schema. An agent can distinguish this from list_tables and describe_table, though it doesn't explicitly name those siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No statement of when to use this versus query, list_tables, or describe_table. The listing nature implies a discovery use case, but the description offers no explicit context or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.0- First observed
describe_table - First observed
list_tables - First observed
query - First observed
relationships
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.
Query 40 databases from Claude, ChatGPT, or Cursor — on any device. Read-only, encrypted, audited.
Generate, fix, explain and run read-only SQL on PostgreSQL, MySQL and SQL Server
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides read-only access to PostgreSQL databases with schema inspection, query execution in multiple formats (JSON, CSV, Markdown), and query history tracking with built-in security features.-
- AlicenseNot gradedqualityCmaintenanceProvides secure read-only SQL access to PostgreSQL and ClickHouse databases with built-in safety features like read-only enforcement, timeouts, and managed result files.MIT
- AlicenseNot gradedqualityDmaintenanceRead-only access to PostgreSQL databases, enabling schema inspection and safe SQL queries.15 npmMIT
- AlicenseNot gradedqualityCmaintenanceEnables 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