pg-explain-mcp
This server acts as a read-only MCP bridge that lets LLM assistants inspect PostgreSQL schemas and analyze query execution plans for performance bottlenecks.
ping — health check to confirm the server is running.
list_tables — list all user tables and their columns.
list_indexes — list existing indexes for a table or all tables.
explain — run
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)onSELECT/WITHqueries and return a structured report highlighting sequential scans, planner/actual row mismatches, disk spills, and excessive nested loop iterations.
Provides tools for analyzing PostgreSQL query execution plans by running EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) on SELECT/WITH queries, returning structured reports on performance bottlenecks such as sequential scans, planner estimate mismatches, disk spills, and excessive nested loop iterations. Also lists user tables and their columns, with read-only database access.
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., "@pg-explain-mcpanalyze this query: SELECT * FROM orders WHERE status = 'pending'"
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.
pg-explain-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— runsEXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)on aSELECT/WITHquery 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_memissues)Excessive
Nested Loopiterations
list_indexes— returns existing indexes for a table (or all tables). All database access is read-only — the connection runs insideSET 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, providesget_schema()andexplain_query().analyzer.py— recursive traversal of the JSON plan tree. Detects bottlenecks and produces a structured report withissuesandsummary.server.py— MCP entry point. Exposes 4 tools viaFastMCP.
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')"
# → OKConfiguration
The server reads connection parameters from environment variables:
Variable | Default | Description |
|
| PostgreSQL host |
|
| PostgreSQL port |
|
| Database user |
| — | Database password |
|
| 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_databaseThen in VS Code:
Cmd+Shift+P→Continue: Reload Config.Open a new chat in Agent Mode (not Chat, not Edit).
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 showEditable 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.
explainrunsEXPLAIN (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-mcpNote: 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
└── LICENSEContinue.dev Integration
Ready-to-use configuration files are available in examples/:
examples/mcpServers/pg-explain.yaml— MCP server configexamples/postgres-agent.md— agent prompt
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 toolsexplainA
Run EXPLAIN ANALYZE on a SELECT query and return a structured report.
Args: sql: A SQL query. Only SELECT and WITH statements are allowed.
| 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?
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.
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.
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.
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.
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.
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.
| 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?
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.
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.
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.
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.
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.
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.
| 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?
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.
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.
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.
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.
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.
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.
3 tool updates
v0.1.0- First observed
explain - First observed
list_tables - First observed
ping
TDQS
Scored across 3 tools
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.
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.
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.
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
Related MCP Connectors
Query PostgreSQL databases in plain English — LLM-generated, safety-validated SQL.
Generate, fix, explain and run read-only SQL on PostgreSQL, MySQL and SQL Server
Deterministic safety, correctness & cost gate that vets Postgres SQL before your AI agent runs it.
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
Related MCP Servers
- FlicenseAqualityDmaintenanceEnables AI assistants to interact with PostgreSQL databases using natural language queries, providing secure read-only access to database schemas and SQL translation capabilities.67 npm-
- AlicenseNot gradedqualityDmaintenanceEnables 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 npmApache 2.0
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to safely interact with PostgreSQL databases, perform queries, inspect schemas, and analyze query performance.2-
- AlicenseNot gradedqualityCmaintenanceSecurely connect AI assistants to PostgreSQL databases with read-only access, schema discovery, querying, and performance analysis tools.5 npmMIT