pgtriage
Officialpgtriage is an MCP server that performs read-only PostgreSQL performance auditing and returns actionable findings for AI clients like Claude Code.
Full database audit: Run
full_auditto get a comprehensive, severity-sorted report covering table health, slow queries, index health, and configuration issues.Table health checks: Inspect dead tuples, autovacuum status, sequential scan ratios, and TOAST bloat for specific tables.
Slow query analysis: Pull top queries from
pg_stat_statements, run safeEXPLAIN ANALYZE, and detect patterns like sequential scans, type casts on indexed columns, stale statistics, and N+1 queries.Index health review: Find unused indexes, duplicate indexes, and missing-index opportunities based on scan patterns.
Configuration review: Flag suboptimal PostgreSQL settings (
shared_buffers,work_mem,max_connections, autovacuum) and check connection pressure.Safety guarantees: All operations are read-only, with session-level read-only enforcement, query validation, and transaction rollback for any
EXPLAIN ANALYZE.
Allows auditing PostgreSQL database performance, providing tools for analyzing table health, slow queries, index usage, and configuration.
pgtriage
MCP server for PostgreSQL performance auditing. Connect it to Claude Code (or any MCP client) and say "audit my database" to get actionable performance findings with exact fixes.
Not related to the pgAudit logging extension. pgtriage does performance triage, not compliance logging.
Why I built this
Built after diagnosing implicit type casts and missing indexes on multi-million-row tables in production fintech systems. The fixes were simple (one CREATE INDEX CONCURRENTLY statement each), but finding them required reading query plans most engineers never look at. pgtriage automates that diagnostic process and lets any AI client explain the results.
Related MCP server: postgres-mcp-server
How it works
Any MCP Client (Claude Code / Cursor / Windsurf / VS Code)
| MCP (stdio)
v
pgtriage (data collection + pattern detection)
| psycopg3 (read-only)
v
PostgreSQL databasepgtriage connects to your PostgreSQL database and exposes performance auditing tools via the Model Context Protocol. It collects metrics from PostgreSQL system views, runs deterministic pattern detection, and returns structured findings. The MCP client provides the AI layer, interpreting results and explaining fixes in plain English.
No API keys required. No AI costs. No vendor lock-in. The intelligence comes from your MCP client.
Example output
{
"severity": "high",
"category": "connection_pressure",
"detail": "Connection utilization at 104% (104/100). Approaching max_connections limit.",
"suggested_fix": "Consider using a connection pooler (PgBouncer) or increasing max_connections if RAM allows.",
"evidence": {
"total_connections": 104,
"max_connections": 100,
"utilization_pct": 104.0
}
}{
"severity": "medium",
"category": "duplicate_index",
"table": "account",
"detail": "Duplicate indexes on 'account': 'account_title_reverse_index' (16 kB) and 'account_group_reverse_index' (16 kB). Same column definition. One can be dropped.",
"suggested_fix": "DROP INDEX CONCURRENTLY account_group_reverse_index;"
}From a real audit: 118 tables scanned, 88 findings, prioritized by severity.
What it finds
Sequential scans on large tables with missing index suggestions
Type casts on indexed columns that suppress index usage, verified against PostgreSQL catalog metadata and the observed query plan
Dead tuple buildup and autovacuum health issues
Unused and duplicate indexes wasting disk and slowing writes
N+1 query patterns from pg_stat_statements analysis
Stale table statistics causing bad query plans
TOAST table bloat from large JSONB/TEXT columns
Configuration issues (shared_buffers, work_mem, autovacuum tuning)
Connection pressure approaching max_connections
Long-running queries holding locks
Quick start
Install
pip install pgtriageConfigure Claude Code
Add to your MCP settings (.claude/settings.json or project settings):
{
"mcpServers": {
"pgtriage": {
"command": "python",
"args": ["-m", "pgtriage"],
"env": {
"PGTRIAGE_CONNECTION_STRING": "postgres://user:pass@localhost:5432/dbname"
}
}
}
}Recommended: Use a dedicated read-only database role:
CREATE ROLE pgtriage_reader LOGIN PASSWORD 'secure_password';
GRANT pg_read_all_stats TO pgtriage_reader;
GRANT USAGE ON SCHEMA public TO pgtriage_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO pgtriage_reader;Use
> audit my database
> check table health for the users table
> are there any unused indexes?
> review my PostgreSQL configuration
> find slow queries
> audit only the accounts schemaTools
full_audit
Run a comprehensive performance audit covering table health, slow queries, index health, and configuration. Pass the optional schema_name argument to scope table, plan, and index findings to one user schema; omit it to audit every non-system schema. Configuration findings remain database-wide. Returns all findings sorted by severity.
check_table_health
Analyze dead tuples, autovacuum stats, sequential scan ratios, and TOAST bloat. Optionally filter to a specific user schema and/or table.
analyze_slow_queries
Pull the slowest queries from pg_stat_statements, inspect their execution plans, and detect patterns like indexed-column type casts, sequential scans, stale statistics, and N+1 queries. An optional schema_name filter uses verbose execution-plan metadata rather than parsing SQL text. Literal queries use bounded EXPLAIN ANALYZE; normalized queries containing placeholders use a non-executing generic plan.
check_index_health
Find unused indexes (zero scans), duplicate indexes (same column definition), and tables that likely need indexes based on scan patterns. Optionally scope the analysis to one user schema.
check_config
Review PostgreSQL settings (shared_buffers, work_mem, autovacuum_vacuum_scale_factor, random_page_cost, etc.) and flag suboptimal values. Checks connection utilization and long-running queries.
Agent runtime integration
pgtriage publishes MCP safety annotations for every tool. All tools are marked
read-only and non-destructive; tools that can run bounded EXPLAIN ANALYZE are
deliberately not marked idempotent. Agent runtimes must still allowlist,
authorize, and validate every call because MCP annotations are descriptive
hints, not permissions. See
Agent Runtime Integration for the complete
contract, schema-scoped audit behavior, and retry guidance.
Resources
Resource | Description |
| Connection status, PostgreSQL version, loaded extensions |
| All tables with sizes and approximate row counts |
Requirements
Python 3.11+
PostgreSQL 12+
pg_stat_statementsextension (recommended for slow query analysis, not required for other tools)Database user with read access to
pg_stat_*views
Safety
pgtriage is designed for read-only production use and does not issue write SQL. Three independent layers protect database state:
Session-level read-only:
SET default_transaction_read_only = trueon every connection. PostgreSQL rejects any write attempt at the server level.Query validation: EXPLAIN ANALYZE only runs on SELECT statements. INSERT, UPDATE, DELETE, DROP, SELECT INTO, SELECT FOR UPDATE, and stacked queries are all rejected before execution.
Transaction rollback: Every EXPLAIN ANALYZE runs inside an explicit BEGIN/ROLLBACK block with a 10-second
statement_timeout. Transactional database changes are rolled back and long-running queries are canceled. Rollback cannot undo external side effects triggered by database extensions or functions, so the dedicated read-only role and session-level read-only enforcement remain essential.
Additionally:
Connection strings are never exposed in tool outputs
Suggested fixes are advisory and are never executed by pgtriage; findings default to
safe_to_apply: falseAll database access is single-connection, no pooling
Development
git clone https://github.com/pgtriage/pgtriage.git
cd pgtriage
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytestLicense
MIT
Available Tools
5 toolsanalyze_slow_queriesA
Find and analyze slow queries from pg_stat_statements. Runs EXPLAIN ANALYZE on top slow SELECT queries and detects performance patterns like sequential scans and missing indexes.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| min_calls | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full disclosure burden. It explicitly reveals that the tool runs EXPLAIN ANALYZE on top slow SELECT queries, which is an important behavioral trait with potential performance implications, and it describes the detection patterns. It stops short of noting any side effects or limitations, but the core behavior is clearly disclosed.
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?
Two sentences, no filler. The first sentence states the purpose, and the second adds the method and detection details. Each clause 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?
The description covers the main functionality and output patterns, but it leaves parameter semantics unexplained and does not mention potential performance impact of running EXPLAIN ANALYZE. Without an output schema, this tool would benefit from a bit more context, yet the overall complexity is low, making this adequate with clear gaps.
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 schema provides no descriptions and coverage is 0%, so the description must compensate. While 'limit' is somewhat intuitive from 'top slow SELECT queries', 'min_calls' is not explained, and no parameter details are provided. The description adds minimal value for understanding parameter meaning beyond the raw names.
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 clearly states a specific verb ('Find and analyze') and a specific resource ('slow queries from pg_stat_statements'), and further details the method ('Runs EXPLAIN ANALYZE') and detection patterns. This distinguishes it from sibling tools like check_table_health and check_config.
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 clear context for when to use the tool: analyzing slow queries and performance patterns. However, it does not explicitly state when not to use it or name alternatives, though the behavior described is distinct from the sibling health-check tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_configA
Review PostgreSQL configuration settings and flag suboptimal values for shared_buffers, work_mem, max_connections, and autovacuum parameters.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the responsibility for behavioral disclosure. Reviewing and flagging suboptimal values strongly implies a read-only, non-destructive analysis, but the description does not explicitly state whether it modifies anything, what permissions are needed, or what form the 'flags' take. This is adequate but lacks explicit safety confirmation.
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 a single, focused sentence that immediately conveys the tool's purpose and scope. It is front-loaded with the action ('Review') and resource ('PostgreSQL configuration settings'), and every phrase adds value without unnecessary detail. No redundancy or fluff.
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 tool is simple, has no parameters, and no output schema, so the description covers the essential information about what it does and what it checks. It could benefit from a note about being read-only or returning a report, but the core purpose is sufficiently complete for an agent to select it appropriately.
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, and the schema is trivially covered at 100%. There is nothing to explain beyond what the schema already indicates, so the baseline of 4 for zero-parameter tools is appropriate. The description adds context by listing the specific parameters checked (shared_buffers, work_mem, max_connections, autovacuum), which is useful.
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 clearly states the tool reviews PostgreSQL configuration settings and flags suboptimal values for specific parameters. It uses a specific verb ('flag') and resource, and it is distinct from sibling tools focused on table health, slow queries, index health, and full audit.
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 implies the tool is for checking PostgreSQL configuration, but it does not explicitly state when to use this tool versus alternatives like full_audit or check_table_health. There are no direct comparisons or exclusions, leaving usage somewhat inferred rather than explicitly guided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_index_healthB
Find unused indexes, duplicate indexes, and missing index opportunities based on sequential scan patterns.
| Name | Required | Description | Default |
|---|---|---|---|
| schema_name | No | public |
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 reveals the detection method ('based on sequential scan patterns') but does not state whether the tool is read-only, whether it returns recommendations, or if any side effects or permissions are needed. The name implies a check, but that is not explicitly stated.
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 a single, direct sentence that states the primary function and adds a relevant methodological detail. It is front-loaded, contains no filler, and every part of the sentence contributes to understanding the tool.
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 tool is relatively simple with one parameter, but the description omits what kind of output to expect (e.g., a list of recommendations, a health score, or a report). Since there is no output schema, the description should at least hint at the return value. It also does not mention prerequisites or permissions, leaving some gaps for an agent that needs to invoke it.
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 schema has one parameter (schema_name) with 0% description coverage. The tool description does not explain this parameter or its purpose. While the name 'schema_name' is fairly self-explanatory, the description should compensate for the lack of schema-level detail, especially if the default value might not be obvious. It does not.
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 clearly states the tool's purpose: finding unused, duplicate, and missing indexes. It uses a specific verb 'Find' and names the exact resource ('unused indexes, duplicate indexes, and missing index opportunities'). It also distinguishes this tool from siblings like check_table_health, which would target table-level issues, and analyze_slow_queries, which targets query-level performance.
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 implies the tool is for analyzing index health when sequential scan patterns are a concern, but it does not explicitly state when to use this tool versus alternatives or provide any exclusions. No sibling tools are mentioned, so the agent must infer the use case from the name and description alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_table_healthA
Check table health: dead tuples, bloat, vacuum stats, scan ratios. Optionally filter to a specific table by name.
| Name | Required | Description | Default |
|---|---|---|---|
| table_name | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full responsibility for behavioral disclosure. It lists the metrics checked but does not state whether the operation is read-only, whether it has performance implications, or how it handles invalid table names. This leaves significant transparency gaps.
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 two concise sentences: the first states the core purpose and metrics, the second adds the optional filter. Every word is informative and there is no redundancy.
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 minimal schema, no output schema, and no annotations, the description covers the tool's purpose and the main parameter adequately. However, it omits return value structure, permission requirements, and any operational cautions, leaving it incomplete for a tool with no output schema.
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 schema has one parameter (table_name) with no description, but the description explicitly explains that it is an optional filter. This compensates for the 0% schema description coverage, though it does not specify exact matching semantics or behavior when omitted.
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 clearly states the tool checks table health, enumerating specific metrics (dead tuples, bloat, vacuum stats, scan ratios) and mentions an optional filter. This distinguishes it from sibling tools like check_index_health or check_config.
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 implies usage for assessing table health but does not explicitly state when to use it over alternatives, nor does it mention any exclusions or prerequisites. The optional filter suggests targeted use, but general guidance on when to choose this tool is absent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
full_auditB
Run a comprehensive performance audit: table health, slow queries, index health, and configuration review. Returns a unified report with all findings sorted by severity.
| Name | Required | Description | Default |
|---|---|---|---|
| slow_query_limit | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden of behavioral disclosure. It adds value by stating the tool returns a unified report sorted by severity, giving insight into output format. However, it does not mention whether the audit is read-only, any permission requirements, or potential performance impacts, leaving notable gaps.
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 two sentences, front-loading the purpose and then describing the output. Every word contributes, with no fluff or repetition. It efficiently conveys scope and result format.
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 combines four audit areas and lacks an output schema, the description provides basic context but omits details about how the parameter affects the audit, any prerequisites, or expected behavior nuances. It is adequate for understanding the high-level purpose but not fully complete for a complex audit tool.
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 schema has one parameter, slow_query_limit, with 0% description coverage. The description does not mention this parameter at all, failing to explain how it influences the audit (e.g., number of slow queries included). The parameter name is somewhat self-explanatory, but the description should compensate for the low schema coverage and does not.
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 explicitly states the tool runs a comprehensive performance audit covering table health, slow queries, index health, and configuration review, and returns a unified report sorted by severity. This clearly distinguishes it from the sibling tools that handle individual audit areas, as it combines all of them into one operation.
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 implies use for comprehensive audits but provides no explicit guidance on when to choose this tool over the individual sibling tools. It does not state exclusions or mention that individual checks can be run separately, so the agent is left without clear decision-making context.
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.
5 tool updates
v0.1.2- First observed
analyze_slow_queries - First observed
check_config - First observed
check_index_health - First observed
check_table_health - First observed
full_audit
TDQS
Scored across 5 tools
Each tool targets a distinct performance domain: table health, slow queries, index health, and configuration. The full_audit tool is clearly positioned as a comprehensive wrapper, not a duplicate, so there is no ambiguity.
Most tools follow a verb_noun pattern (check_table_health, check_index_health, check_config, analyze_slow_queries), but 'full_audit' breaks the pattern by being a noun phrase instead of a verb-led name. This is a minor inconsistency in an otherwise predictable scheme.
Five tools is well-scoped for a PostgreSQL performance triage server. Each tool covers a major diagnostic area, and the full_audit tool provides an integrated option without bloating the surface.
The toolset covers all key aspects of a performance triage workflow: table health, slow queries, index efficiency, and configuration review. The full_audit tool ties everything together, leaving no obvious operational gaps for the stated purpose.
Maintenance
Related MCP Connectors
Hosted MCP server for PostgreSQL diagnostics: slow queries, missing indexes, connection pressure.
Paid remote MCP for governed database query review, SQL simulation, approvals, and audits.
Read-only MCP access to a documented IT fleet: state, changes, posture. 15 tools.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceRead-only PostgreSQL analytics MCP server — query plans, slow queries, index usage, table bloat, vacuum status. No DDL/DML/writes. Curated by Archimedes Market with a verified Trust Report.MIT
- AlicenseAqualityCmaintenanceProvides PostgreSQL database management and analysis via MCP, enabling schema exploration, query execution, performance monitoring, and database health checks.3622 npmMIT
- AlicenseAqualityAmaintenanceGoverned PostgreSQL DBA operations — slow-query, bloat, and blocking-lock RCA, index management, vacuum/analyze, and replication lag, with unbypassable audit logging (MCP + CLI), budget/runaway guards, dry-run, and undo/rollback.35MIT
- AlicenseNot gradedqualityCmaintenanceProvides a read-only PostgreSQL MCP server with schema introspection. Enforces least-privilege database roles to prevent any writes, even from malicious SQL.MIT