Skip to main content
Glama
Nick-Msk
by Nick-Msk

pg-explain-mcp

Tag Python License MCP

An MCP (Model Context Protocol) server for analyzing PostgreSQL query execution plans. Built as a bridge between LLM-based coding assistants (Continue.dev, Claude Desktop, Cursor) and a PostgreSQL database.

The server runs EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) on SELECT queries and returns a structured report highlighting performance bottlenecks — so an LLM can explain why a query is slow and what to do about it, instead of just describing the SQL.

Features

  • ping — health check.

  • list_tables — returns all user tables with their columns.

  • explain — runs EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) on a SELECT/WITH query and returns a structured report highlighting:

    • Sequential scans on large tables (likely missing indexes)

    • Large mismatches between planner estimates and actual row counts

    • Disk spills in sorts and hash joins (work_mem issues)

    • Excessive Nested Loop iterations

  • list_indexes — returns existing indexes for a table (or all tables). All database access is read-only — the connection runs inside SET TRANSACTION READ ONLY, so even a buggy query cannot modify data.

Related MCP server: Postgres Scout MCP

Architecture

LLM (Continue.dev) ──MCP──> pg-explain-mcp ──psycopg3──> PostgreSQL
                                  │
                                  ├── db.py        (connection, EXPLAIN)
                                  ├── analyzer.py  (plan analysis)
                                  └── server.py    (MCP tools)
  • db.py — connection layer. Opens a read-only transaction, provides get_schema() and explain_query().

  • analyzer.py — recursive traversal of the JSON plan tree. Detects bottlenecks and produces a structured report with issues and summary.

  • server.py — MCP entry point. Exposes 4 tools via FastMCP.

Requirements

  • Python 3.10+

  • PostgreSQL 12+ (tested on 16, 17, 18)

  • An MCP-compatible client (Continue.dev, Claude Desktop, Cursor, etc.)

Installation

git clone https://github.com/Nick-Msk/pg-explain-mcp.git
cd pg-explain-mcp

python3.12 -m venv .venv
source .venv/bin/activate      # Windows: .venv\Scripts\activate

pip install --upgrade pip
pip install -e .

pip install -e . installs the package in editable mode and registers the pg-explain-mcp console script.

Verify installation

python -c "from pg_explain_mcp import server; print('OK')"
# → OK

Configuration

The server reads connection parameters from environment variables:

Variable

Default

Description

PG_HOST

localhost

PostgreSQL host

PG_PORT

5432

PostgreSQL port

PG_USER

postgres

Database user

PG_PASSWORD

Database password

PG_DATABASE

postgres

Database name

Usage with Continue.dev

Create .continue/mcpServers/pg-explain.yaml in your workspace:

name: PostgreSQL Explain MCP
version: 0.0.1
schema: v1
mcpServers:
  - name: pg-explain
    command: /path/to/pg-explain-mcp/.venv/bin/python
    args:
      - "-m"
      - "pg_explain_mcp.server"
    env:
      PG_HOST: localhost
      PG_PORT: "5432"
      PG_USER: your_user
      PG_PASSWORD: your_password
      PG_DATABASE: your_database

Then in VS Code:

  1. Cmd+Shift+PContinue: Reload Config.

  2. Open a new chat in Agent Mode (not Chat, not Edit).

  3. Ask:

    Use the pg-explain tool to analyze: SELECT * FROM onek1 WHERE hundred BETWEEN 5 AND 55;

The agent will call the explain tool and return a structured report with execution time, detected issues, and recommendations.

Debugging

If the tool doesn't appear, check that:

  • The path in command: points to the actual Python inside .venv.

  • The package is installed: pip show pg-explain-mcp (should show Editable project location: .../pg-explain-mcp).

  • You are in Agent Mode, not Chat or Edit.

You can also test the server standalone via the official MCP Inspector:

mcp dev src/pg_explain_mcp/server.py

⚠️ Warning. explain runs EXPLAIN (ANALYZE, ...), which actually executes the query. Avoid running it against production databases during peak hours. Use a replica or staging environment whenever possible.

Example

Prompt:

Use the pg-explain tool to analyze: SELECT * FROM onek1 WHERE hundred BETWEEN 5 AND 55;

Response (abridged):

✓ Continue used the pg-explain explain tool

Execution Time: 0.904 ms
Planning Time:  1.228 ms
Total Time:     2.132 ms
Issues Found:   None

Analysis:
The query is running very fast, likely because the onek1 table is
relatively small (estimated at 1,000 rows), allowing a Sequential Scan
almost instantly.

Note: There is no index on the `hundred` column. For a small table this
is fine, but if the table grows to millions of rows, this query would
become slower...

Demo

See usage_examples/ for full write-ups.

The IndexScanCheck examples include a reproducible SQL scenario: usage_examples/pg_index_scan_adapters/pg_samples.sql.

Development

# Run the server manually (waits for JSON-RPC on stdio)
python -m pg_explain_mcp.server

# Or use the console script
pg-explain-mcp

Note: running the server manually in a terminal is not a valid test — MCP servers speak JSON-RPC over stdio and expect a client. Use mcp dev or an MCP-compatible assistant for interactive testing.

Changelog

See CHANGELOG.md for a list of changes.

Project structure

pg-explain-mcp/
├── src/
│   └── pg_explain_mcp/
│       ├── __init__.py
│       ├── server.py       # MCP entry point
│       ├── db.py           # connection + EXPLAIN
│       └── analyzer.py     # plan analysis
├── pyproject.toml
├── README.md
└── LICENSE

Continue.dev Integration

Ready-to-use configuration files are available in examples/:

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

License

MIT — see LICENSE for details.

Disclaimer

This project is a diagnostic tool provided "as is". Recommendations from the analyzer — or from an LLM assistant using it — are suggestions, not guarantees. Always validate against your own database before applying changes to a production system.

See DISCLAIMER.md for the full text.

Available Tools

3 tools
explainA

Run EXPLAIN ANALYZE on a SELECT query and return a structured report.

Args: sql: A SQL query. Only SELECT and WITH statements are allowed.

ParametersJSON Schema
NameRequiredDescriptionDefault
sqlYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full responsibility for behavioral disclosure. It usefully notes that only SELECT and WITH statements are allowed, but it does not mention that EXPLAIN ANALYZE actually executes the query and may be resource-intensive, nor does it address error behavior. This is adequate but leaves notable behavioral traits implicit.

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?

The description is compact and well-structured: a single front-loaded sentence states the action and output, followed by a minimal Args block. Every line earns its place with no filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the core call requirements: the operation, the output, and the parameter constraint. The output schema supplies return structure. However, for a tool with no annotations, it should also mention that EXPLAIN ANALYZE executes the query, which affects cost and safety expectations, and provide clearer usage context.

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%, but the description compensates by defining sql as 'A SQL query' and adding the important SELECT/WITH restriction. For a single self-explanatory parameter, this is sufficient, though it omits minor details like whether semicolons or parameterized queries are accepted.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb-resource pair ('Run EXPLAIN ANALYZE on a SELECT query') and states the deliverable ('structured report'). This makes the tool's purpose immediately clear and distinguishes it from sibling tools ping and list_tables without ambiguity.

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 context is implied: an agent would use this when it needs an EXPLAIN ANALYZE report for a SELECT/WITH query. However, the description does not explicitly state when to prefer this tool over alternatives or provide any exclusionary guidance beyond the allowed statement types.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_tablesA

Return a list of all user tables and their columns.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses that the tool returns a list (read-only behavior) and scopes results to 'user tables' and 'their columns', which is meaningful behavioral context. However, it does not mention potential side effects, permissions, performance characteristics, or ordering, leaving some gaps for a simple read operation.

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. Every word contributes to the purpose, and it is appropriately sized for the tool's simplicity.

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?

Given the tool has no parameters and an output schema exists, the description is fully sufficient. It tells the agent exactly what the tool returns, and no additional usage or behavioral information is required for correct invocation.

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 has zero parameters, so the schema is empty and coverage is trivially 100%. Per the rubric, 0 parameters earns a baseline of 4; the description adds nothing about parameters because there are none, and none are needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Return') and resource ('list of all user tables and their columns'), clearly distinguishing it from siblings 'ping' and 'explain'. It states exactly the operation and scope without ambiguity.

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 provides no guidance on when to use this tool versus alternatives, no prerequisites, and no exclusions. It only states what the tool does, leaving the agent to infer usage context from the tool name and sibling names.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pingA

Health check — returns 'pong' if the server is running.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It discloses the success behavior (returns 'pong') and implicitly signals a non-mutating operation, but it does not state what happens on failure — whether the call errors, times out, or returns a non-pong payload when the server is down.

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 that wastes no words: the purpose ('Health check') appears first, and the expected response is stated immediately. Every word 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?

For a zero-parameter tool with an output schema present, the description covers the essential purpose and response behavior. It could add failure semantics, but the output schema handles return-value details and the tool's simplicity means nothing critical is missing.

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 has zero parameters, so the description correctly omits parameter details and the empty schema is fully covered. With no parameters to document, the baseline of 4 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a clear, specific purpose: a liveness health check that returns 'pong' when the server is running. This unambiguously distinguishes it from siblings list_tables and explain — there is no overlap in function, and an agent can tell immediately what this tool does.

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?

The usage context is implied but not explicit: an agent would infer this is the tool to call when verifying server liveness, and the sibling tools are clearly unrelated. However, there is no explicit statement of when to use it vs. alternatives, no prerequisites, and no named 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. 3 tool updatesv0.1.0
    • First observedexplain
    • First observedlist_tables
    • First observedping

TDQS

A4.2/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a unique role: ping is a health check, list_tables surfaces schema metadata, and explain performs query analysis. There is no overlap or ambiguity in selecting among them.

Naming Consistency4/5

Names are short, lowercase verb forms and are easy to predict. list_tables follows the verb_noun pattern, while ping and explain are bare verbs, so the pattern is not perfectly uniform.

Tool Count5/5

Three tools is minimal but appropriate for the narrow purpose of examining table schemas and running EXPLAIN ANALYZE. Each tool serves a distinct, necessary function without redundancy.

Completeness5/5

Within its stated scope of listing tables and explaining SELECT/WITH queries, the workflow is complete: discover tables, write a query, and get a structured plan. The restriction to read-only queries is intentional and avoids unsafe mutations.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    A
    quality
    D
    maintenance
    Enables AI assistants to interact with PostgreSQL databases using natural language queries, providing secure read-only access to database schemas and SQL translation capabilities.
    6
    7 npm
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to safely explore, analyze, and maintain PostgreSQL databases with read-only mode by default, SQL injection prevention, query performance analysis, and optional write operations.
    31 npm
    Apache 2.0
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to safely interact with PostgreSQL databases, perform queries, inspect schemas, and analyze query performance.
    2
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Securely connect AI assistants to PostgreSQL databases with read-only access, schema discovery, querying, and performance analysis tools.
    5 npm
    MIT