
PostgreSQL Performance (read-only)
io.github.gouranshulv0.1.0更新于 Oct 10, 2026
Read-only PostgreSQL performance diagnostics: slow queries, EXPLAIN, index advice, locks, functions
概览
只读的 PostgreSQL 性能诊断:慢查询、EXPLAIN 计划、索引建议、表健康、锁与函数。
- 功能
- 通过一个受限的只读接口,让助手从 pg_stat_statements、EXPLAIN 和 PostgreSQL 系统目录中获取真实数据。工具包括 top_slow_queries、explain_query、suggest_indexes、unused_indexes、table_health、blocking_sessions、slow_functions 和 explain_function,另有 schema 资源和引导式 diagnose_slow_database 提示。它只建议索引,从不创建索引,也不会取消或终止会话。
- 适用场景
- 当数据库变慢,希望助手查看真实执行计划、表大小、现有索引和查询负载而不是凭空猜测时使用。适合在副本或预发布数据库上诊断慢查询、索引候选、表膨胀和锁争用。
- 运行要求
- 运行已发布镜像需要 Docker,从源码构建需要 Java 25。需要一个 PostgreSQL 数据库,在 shared_preload_libraries 中启用 pg_stat_statements,并有一个具备 pg_read_all_stats 和 pg_monitor 的只读角色。需设置 PGPERF_DB_URL、PGPERF_DB_USER、PGPERF_DB_PASSWORD 和 MCP_API_KEY;客户端以 Authorization bearer 头发送该密钥。函数相关工具还需启用 track_functions 和 auto_explain。
安装
在 SourceWeft 中
- 打开 控制台中的 PostgreSQL Performance (read-only),将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
pg-perf-mcp
[CI] [License: MIT] [Java 25] [Spring Boot 4.1]
An MCP server that lets AI assistants diagnose PostgreSQL performance problems safely: slow queries, EXPLAIN plans, index suggestions, table health and lock contention. It is read-only by design.
A real Claude Code session against the demo shop, sped up. First it finds which database functions are slow and why. Then it explains a slow catalog query and estimates the fix with a hypothetical index. Asked to create the index, it says it can't: every tool is read-only.
Why
When a page is slow, developers paste a query into a chat and ask "why is this slow?". The assistant then guesses, because it cannot see the plan, the table sizes, the existing indexes or which queries actually dominate the load.
pg-perf-mcp gives the assistant real numbers from pg_stat_statements, EXPLAIN and the
catalogs, through a narrow, audited, read-only interface. It cannot change data, cannot run DDL,
and never creates the indexes it recommends.
Demo
A condensed, illustrative session against the demo shop (docker compose up, then
./demo/workload.sh). Exact numbers vary from run to run:
Architecture
Tools
Resources: pg://schema/overview (tables, row estimates, sizes, indexes) and
pg://schema/{table} (columns, indexes with scan counts, foreign keys flagged when unindexed).
Prompt: diagnose_slow_database, a guided workflow: slow queries, then explain, suggest
indexes, table health, functions, then a prioritized summary.
Why a separate tool for database functions
EXPLAIN shows a function call as one opaque expression, and charges its time to whichever plan
node evaluates it. On the demo catalog page (20 products, each calling shop.product_rating),
explain_query blames the index scan on products (184 ms self time) and finds nothing else
serious. explain_function on the same query, against the full demo data:
How it works (ADR 0006): the query runs once
with auto_explain enabled for that transaction only, so the plan of each nested statement comes
back as a notice; per-function time comes from pg_stat_xact_user_functions and per-statement
calls from pg_stat_statements, both as before/after differences.
Security model
Five independent layers stand between the assistant and a write (details in ADR 0001):
- SQL guard: exactly one plain
SELECT. It is checked by a PostgreSQL-faithful lexer and JSqlParser, and both must agree. Blocks DML/DDL, multiple statements, data-modifying CTEs,SELECT INTO,FOR UPDATE/SHARE,COPY,DO, and dangerous functions (pg_sleep*,*_file,lo_*,dblink*,set_config,pg_terminate_backend,query_to_xml, ...). It fails closed. - Read-only role:
mcp_readonlyhasSELECTpluspg_read_all_stats/pg_monitor, withdefault_transaction_read_only = onandstatement_timeout = 5sset on the role. - Read-only connections: Hikari
readOnly=trueand a read-only session default. - One rolled-back read-only transaction per call:
statement_timeout/lock_timeoutset locally,standard_conforming_stringsforced on, always rolled back. - Row cap: every result is capped (default 200 rows).
Around those layers: a bearer API key (constant-time comparison; only /actuator/health is
open), a JSON audit line per call (SQL stored as a SHA-256 hash plus an 80-character preview),
error messages with no stack traces or connection details, and metrics mcp.tool.duration and
mcp.guard.rejections.
Quickstart
Requirements: Docker. There are two ways to start:
- Use it on your database: pull the published image. No clone or build.
- Try the demo shop: clone the repo and get a seeded database with realistic problems to diagnose.
Either way, finish with connecting your AI client.
Use it on your database
1. Pull the image (public on GHCR, built for amd64 and arm64):
2. Prepare the database (once). Create a read-only role like mcp_readonly (see
docker/init.sql) and make sure pg_stat_statements is in
shared_preload_libraries. Prefer a replica or staging database: analyze=true and
explain_function execute the query. For the function tools, also
enable function tracking.
3. Run it. Put the settings in a file so secrets stay out of your shell history:
host.docker.internal reaches a database on your machine (Docker Desktop; on Linux add
--add-host=host.docker.internal:host-gateway). The MCP endpoint is now
http://localhost:8080/mcp.
4. Connect your AI client: see below.
Try the demo shop
To build and test from source you also need Java 25.
Generate some slow-query statistics (optional, but makes top_slow_queries interesting):
Connect from Claude Code
In PowerShell, set the key first, or the header goes out empty and the server answers 401:
Then ask: "Use pg-perf to find out why the shop database is slow", or run the
diagnose_slow_database prompt.
Connect from Claude Desktop
Claude Desktop launches stdio servers, so use the mcp-remote bridge
(claude_desktop_config.json):
Connect from Cursor
~/.cursor/mcp.json (or .cursor/mcp.json in a project):
Connect from VS Code (Copilot agent mode)
.vscode/mcp.json. VS Code prompts for the key once and stores it securely:
Enable the function tools (optional)
slow_functions and explain_function need two extra settings on your own database. The demo
shop already has them, and every other tool works without them:
Without these, explain_function still reports what it can and says in notes what is missing.
Configuration
Properties can also be set as environment variables (PGPERF_QUERY_STATEMENT_TIMEOUT=3s, ...).
Metrics are at /actuator/prometheus (requires the API key).
Build and test
This runs unit tests, Testcontainers integration tests against PostgreSQL 18 (same image, init
scripts and read-only role as compose; needs Docker), an end-to-end test with the MCP Java SDK
client over HTTP, and a JaCoCo gate (80% lines on the guard and analysis packages).
Design decisions
- 0001: Read-only by design, enforced in depth
- 0002: Streamable HTTP transport
- 0003: Summarized plans instead of raw EXPLAIN
- 0004: Suggest indexes, never execute them
- 0005: Platform versions and API differences
- 0006: Looking inside database functions
Roadmap
- OAuth 2.1 resource server per the MCP authorization spec (per-user identity instead of a shared key)
- Multiple named database targets, with read replicas preferred
- Workload-level index advice (weigh candidates across all top queries, not one at a time)
auto_explainlog /pg_stat_kcacheingestion for plans of queries that already ran in production- Optional raw-plan output and per-tool rate limits
- MCP elicitation to confirm
analyze=trueon expensive queries
License
MIT © 2026 Anshul Gour
来源:README.md,提交 2b97e2b
工具
0版本历史
1- v0.1.0最新Oct 10, 2026


