postgres-mcp
This MCP server gives Claude read-only access to a PostgreSQL database through three tools: running SQL queries, inspecting execution plans, and examining table schemas.
execute_query — Run a single read-only SQL statement (
SELECT/WITH/VALUES/TABLE) and get the rows back as JSON; writes, DDL, and multiple statements are rejected.explain_query — Fetch the
EXPLAINplan for one read-only query, or passanalyze=trueto runEXPLAIN ANALYZE, which actually executes the query inside a read-only, time-limited transaction.get_table_schema — List a table's columns and indexes, defaulting to the
publicschema.Not exposed here: the README describes six tools, but this schema only exposes three —
list_tables,get_slow_queries, and the LangGraph-poweredanalyze_queryoptimization pipeline are absent, so no AI query-optimization or benchmark workflow is available from this schema.
Provides tools for executing SQL queries, obtaining query execution plans, and inspecting table schemas in a PostgreSQL database.
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 schema of the users 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.
sql-surgeon-mcp
An MCP server that connects Claude Desktop to a PostgreSQL database, exposing both direct query tools and an AI-powered query optimization pipeline built on SQL-Surgeon.
What it does
This project wraps two layers of capability into a single MCP server:
Layer 1 — Direct database tools: Claude can execute SQL, inspect execution plans, and query table schemas against a live PostgreSQL database.
Layer 2 — AI query optimization pipeline: Claude can invoke a multi-step LangGraph agent (SQL-Surgeon) that analyzes a slow query, identifies performance bottlenecks, generates optimization advice, self-reviews the advice for quality, and optionally benchmarks the result in a sandbox schema.
The MCP interface means Claude decides which tool to use based on the user's question — no manual tool selection needed.
Related MCP server: @yawlabs/postgres-mcp
Architecture
Claude Desktop
│
│ MCP protocol
▼
server.py ← tool registration + MCP entry point
│
tools.py ← tool logic
│
┌───┴──────────────────────────────────┐
│ │
db.py sql_surgeon.agent.graph
(Layer 1: direct tools) (Layer 2: LangGraph pipeline, from the
│ sql-surgeon package — see below)
├── execute_query │
├── explain_query preprocess_sql → rewrite_sql → run_explain
├── list_tables │
├── get_table_schema identify_issues → generate_advice
└── get_slow_queries │ ▲
review_advice ───────┘ retry loop (max 2x)
│
generate_benchmark_schema (optional)The pipeline is not copied into this repo. It comes from the SQL-Surgeon project as the sql-surgeon package (backend/ of that repo), pinned to a release tag in pyproject.toml. Fixes made in SQL-Surgeon reach this server by bumping that tag.
MCP Tools
Tool | Parameters | Description |
|
| Run one read-only query (SELECT / WITH / VALUES / TABLE) and return JSON rows. Writes, DDL and multiple statements are rejected |
|
| Get the execution plan of one read-only query; |
|
| List all tables in a schema |
|
| List columns, types, nullability, defaults, and indexes |
|
| Return the slowest queries by mean execution time from |
|
| Run full SQL-Surgeon optimization pipeline; returns issues (with the plan nodes each is about), the execution plan with estimated vs actual rows, where row estimates first go wrong, advice, warnings (SQL anti-patterns, tables without a primary key), index recommendations with reasons, optimized SQL, and optional benchmark |
SQL-Surgeon Pipeline
analyze_query invokes the SQL-Surgeon LangGraph graph (7 nodes):
preprocess_sql — rewrites comma-style joins (
FROM a, b WHERE a.id = b.id) into explicitJOIN ... ONrewrite_sql — flags SQL anti-patterns (e.g.
SELECT *) and drops redundantDISTINCTrun_explain — executes
EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON)in a read-only, time-limited transaction; fetches column definitions and existing indexes for every table in the query; flags tables without a primary keyidentify_issues — sends the execution plan + DDL to Gemini 2.5 Pro; returns a JSON array of identified bottlenecks (missing indexes, sequential scans, row count misestimation, etc.)
generate_advice — generates specific optimization recommendations and a complete optimized SQL script (index DDL + rewritten query)
review_advice — a second LLM call acting as a senior DBA reviewer; returns
passorretrywith feedback; a retry goes back togenerate_advice, up to 2 timesgenerate_benchmark_schema (optional) — copies the query's tables into a temporary schema, applies the suggested DDL (only
CREATE INDEX/CREATE EXTENSION/ANALYZEon the copies), and re-runs EXPLAIN to compare plans. Runs in one transaction that is always rolled back
Project Layout
src/sql_surgeon_mcp/
server.py # MCP entry point, tool registrations
tools.py # Tool logic; calls db.py and the sql_surgeon pipeline
db.py # Connection helper (reads DATABASE_URL)
tests/
test_tools.py # Unit tests with mocked DB connections
examples/
claude_desktop_config.jsonSetup
Prerequisites
Python 3.10+
uv —
brew install uvA running PostgreSQL instance
A Google API key (Gemini 2.5 Pro) for
analyze_query
Install
git clone https://github.com/RachelHuangZW/sql-surgeon-mcp
cd sql-surgeon-mcp
uv syncConfigure environment
Create .env in the project root:
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
GOOGLE_API_KEY=your-google-api-key
# Required for safe use: a SELECT-only role for SQL that comes from Claude (see Security below)
SURGEON_READONLY_DATABASE_URL=postgresql://sql_surgeon_readonly:password@localhost:5432/dbnameRegister with Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"sql-surgeon-mcp": {
"command": "uv",
"args": [
"run",
"--directory", "/path/to/sql-surgeon-mcp",
"--env-file", "/path/to/sql-surgeon-mcp/.env",
"python", "-m", "sql_surgeon_mcp.server"
]
}
}
}Fully quit and reopen Claude Desktop after saving.
Verify
Open Claude Desktop and ask:
"What MCP tools do you have available?"
Claude should list all six tools.
Development
uv sync --group dev
uv run pytestTests use mocked database connections and do not require a live PostgreSQL instance.
Updating the SQL-Surgeon engine
The pipeline (sql_surgeon) is a dependency, pinned to a tag of the SQL-Surgeon repo:
In SQL-Surgeon: commit the change, then
git tag vX.Y.Z && git push origin main --tagsHere: change
tag = "..."under[tool.uv.sources]inpyproject.tomlto the new taguv lock --upgrade-package sql-surgeon && uv sync, thenuv run pytest
To try an unreleased SQL-Surgeon change locally, temporarily point the source at your checkout instead of the tag:
sql-surgeon = { path = "../SQL-Surgeon/backend", editable = true } — and switch back before committing.
Tech Stack
MCP framework: FastMCP
Agent framework: LangGraph
LLM: Gemini 2.5 Pro via
langchain-google-genaiDatabase: PostgreSQL via
psycopg2Package manager: uv
How this was built
This project was built with Claude Code as a pair-programming partner. I designed the architecture (two-layer tool exposure, separation of db.py vs db_client.py), made all technical decisions (MCP framework choice, LangGraph integration approach, security boundaries), and iterated on implementation with AI assistance. Every design decision documented in this README reflects my own thinking about MCP server design and enterprise database tool exposure.
Security
SQL written by Claude never changes your data. execute_query, explain_query and analyze_query all go through the SQL-Surgeon DB client:
One statement only. Input such as
SELECT 1; COMMIT; DELETE ...is rejected before it reaches the database.Queries only. The statement must start with
SELECT,WITH,VALUESorTABLE.READ ONLY transaction, never committed. This also blocks data-modifying CTEs and
SELECT ... FOR UPDATE.statement_timeout/lock_timeout. Defaults are 5s / 2s. SetSURGEON_STATEMENT_TIMEOUT_MS/SURGEON_LOCK_TIMEOUT_MSto change them.Least-privilege role. When
SURGEON_READONLY_DATABASE_URLis set, these queries run as that SELECT-only role instead ofDATABASE_URL. Create the role withscripts/setup_security_role.sqlfrom SQL-Surgeon. When it is not set, they fall back toDATABASE_URLand a warning is logged.
Two things still use DATABASE_URL directly:
The sandbox benchmark, because it needs to create a schema. Only allowlisted index DDL runs there, and the transaction is always rolled back.
The server's own fixed catalog queries (
list_tables,get_table_schema,get_slow_queries).
Always set SURGEON_READONLY_DATABASE_URL. Checks 1–3 limit what kind of statement runs, not which functions it calls. A plain SELECT can still call server-side functions such as pg_read_file() or pg_ls_dir(), in the select list or in the FROM clause (SELECT * FROM pg_read_file('/etc/passwd')). They read files on the database host whenever the role is a superuser or a member of pg_read_server_files. The read-only role is neither, so it is the only layer that blocks them. Without it, Claude's SQL runs as DATABASE_URL, which is often the postgres superuser.
Available Tools
3 toolsexecute_queryB
Execute a SQL query against the connected PostgreSQL database and return results as JSON.
Inputs: sql (required). Returns: result
explain_queryA
Return the EXPLAIN execution plan for a SQL query. Set analyze=True to run EXPLAIN ANALYZE (this actually executes the query).
Inputs: sql (required), analyze. Returns: result
get_table_schemaB
Get columns and indexes for a PostgreSQL table.
Inputs: table_name (required), schema. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 3 tools
Each tool serves a distinct purpose: executing queries, explaining plans, and retrieving table schema. No overlap exists.
All tools follow a consistent verb_noun snake_case pattern (execute_query, explain_query, get_table_schema) with clear, descriptive names.
Three tools is slightly low for a database server, but the scope is focused on query execution and schema inspection, which is reasonable. Could benefit from additional tools like listing tables.
Core query execution and schema retrieval are covered, but missing tools to list tables or databases, manage transactions, or modify data directly. Agents would need to rely on raw SQL for many operations.
Maintenance
Related MCP Connectors
Hosted PostgreSQL MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
Query Postgres, MySQL, SQL Server, Oracle, BigQuery, ClickHouse and Redshift from your AI client.
Query PostgreSQL databases in plain English — LLM-generated, safety-validated SQL.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables natural language querying of PostgreSQL databases through the Model Context Protocol. It translates user questions into validated SQL, executes read-only queries safely, and returns results to MCP-compatible clients like Claude Desktop.-
- AlicenseAqualityBmaintenanceQuery and manage PostgreSQL databases from Claude Code, Cursor, and any MCP client, with read-only by default and built-in schema introspection, EXPLAIN, and performance diagnostics.231,124 npm10MIT
- FlicenseNot gradedqualityCmaintenanceExposes PostgreSQL database operations as tools for AI assistants, allowing SQL queries and schema inspection.-
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to execute SQL queries and inspect PostgreSQL database schemas via MCP tools.-