Skip to main content
Glama
pleware

postgres-mcp

by pleware

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-mcp

Related 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: true

Resolution 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:

  1. masstrade-agentselect_database APR (upserts the APR profile).

  2. postgres-mcpselect_profile APR (re-points at the same database).

  3. postgres-mcpquery "SELECT ..." (read-only against APR).

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_mcp

Tools

Tool

Description

query

Run a validated read-only SQL statement

list_tables

List base tables in the public schema

describe_table

Describe the columns of a table or view

relationships

List foreign-key relationships

select_profile

Switch to a profile in ~/.wren/profiles.yml (wren mode only)

Security model

  1. Allowlist — the first command must be on allowlist_commands.

  2. Deny-list — any whole-word deny_keywords entry anywhere in the SQL rejects the statement.

  3. Row limit — a LIMIT is appended to SELECT when the query has none (SHOW/EXPLAIN are left untouched, since they reject LIMIT).

  4. Timeoutstatement_timeout is set per connection from query_timeout_ms.

  5. Query log — when log_queries is 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 tools
describe_tableB
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
table_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior3/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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_tablesA
Read-only

List all base tables in the public schema.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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.

queryA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
sqlYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

relationshipsA
Read-only

List foreign-key relationships between tables in the public schema.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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.

  1. 4 tool updatesv0.1.0
    • First observeddescribe_table
    • First observedlist_tables
    • First observedquery
    • First observedrelationships

TDQS

A3.8/5.0

Scored across 4 tools

Disambiguation5/5

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.

Naming Consistency4/5

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.

Tool Count5/5

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.

Completeness4/5

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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides 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.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides 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
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables safe, read-only querying of PostgreSQL databases with defense-in-depth protections including single-statement SELECT guard, row caps, and per-identity audit logging.
    1
    MIT