MCPg - Production-grade PostgreSQL MCP Server
MCPg is a production-grade PostgreSQL MCP server with 252+ tools that lets AI agents safely inspect, query, operate, and tune PostgreSQL databases. Key capabilities include:
Catalog Introspection
Explore schemas, tables, views, columns, indexes, constraints, foreign keys, sequences, enums, triggers, functions, RLS policies, partitions, FDW components, and logical replication
Query Execution
Run validated read-only SELECTs (
run_select,run_select_tuned,run_select_parallel)Server-side cursors for paginating large result sets
Natural language → SQL translation via Anthropic, OpenAI, Gemini, and others
Performance & Query Intelligence
Diagnose slow queries (
why_is_this_slow,optimize_query)Recommend missing indexes, detect N+1 patterns
Analyze lock contention and blocking chains with Mermaid diagrams
Search
Fuzzy/trigram, full-text, vector similarity (pgvector), hybrid (pgvector + FTS via RRF), and geo/spatial (PostGIS)
Schema Diff, Migrations & Documentation
Compare schemas structurally, validate and manage staged migrations
Read migration history from Alembic, Flyway, Django, Prisma, Diesel, Goose, and more
Generate Mermaid ER diagrams, FK cascade graphs, and Markdown schema docs
ORM Schema Exporters
Generate schemas for Prisma, Drizzle, SQLAlchemy, Diesel, jOOQ, Ent, Ecto, and sqlc
Vector & Embedding Intelligence
Tune HNSW/IVFFlat indexes, measure recall@k, recommend
ef_search/probesCluster embeddings, detect outliers, monitor drift, cross-table similarity, and RAG retrieval with FK expansion
Analyze reranker lift, NDCG, and score distribution
DBA & Live Ops
Monitor/cancel active queries, run VACUUM/ANALYZE, read
pg_stat_io(PG16+), buffer cache, WAL statsCheck WAL archive status and PITR readiness
Audit sequences nearing overflow and audit
postgresql.conffor dangerous settingsGet pgtune-style configuration recommendations
Data Movement
Export to CSV/JSON, import via COPY FROM STDIN, copy tables between databases
Security & Compliance
Find sensitive/PII columns, test RLS policies per role, lint naming conventions
HMAC-chained audit log verification
Apache AGE Graph
List, create, and query property graphs; run Cypher queries; generate openCypher projections from relational schema
TimescaleDB
List hypertables/chunks, create hypertables, add compression and retention policies
LISTEN/NOTIFY
Subscribe to, poll, and unsubscribe from PostgreSQL notification channels
Observability
Prometheus metrics, structured audit trail with credential redaction, session cost analysis
Test Data Generation
Generate synthetic INSERT statements and realistic test rows respecting constraints and FK relationships
Supports translating natural language questions into SQL queries using OpenAI's API.
Provides tools for safe inspection, querying, operation, and tuning of PostgreSQL databases, including catalog introspection, query intelligence, natural-language SQL, structural diffs, hybrid search, graph queries, data movement, and live ops.
Exposes a /metrics endpoint with Prometheus metrics for observability, including tool call counts and durations.
Integrates with TimescaleDB for hypertable management and time-series data operations.
MCPg
A production-grade Model Context Protocol server for PostgreSQL. It lets AI agents safely inspect, query, operate, and tune a Postgres database — 279 tools spanning catalog introspection, query intelligence, natural-language SQL, structural diffs, hybrid search, graph queries, data movement, live ops, and more.
Try it live: point an MCP client — or the MCP Inspector — at the hosted, read-only demo endpoint
https://devopam-mcpg-demo.hf.space/mcp. It serves read tools against throwaway demo data; for real use, run MCPg next to your own database (see Quick start).
📍 Listed On
Aspect | MCPg |
Safety | Read-only default + AST validation |
Transport | stdio + HTTP/SSE |
Install |
|
Postgres Versions | 14–19 |
Key Differentiator | Production observability + multi-tenancy |
Why MCPg
Safe by default. Read-only access mode. Every user-supplied SQL statement parses through a validated AST allowlist before execution. Names that reach PostgreSQL as SQL identifiers are encoded with delimited-identifier quoting (see Identifier policy), not rejected merely for containing hyphens or other legal characters. Capabilities like DDL, shell, and
LISTEN/NOTIFYare off until you opt in. Every tool publishes MCPToolAnnotations(readOnlyHint,openWorldHint) derived from those same gates, so clients can auto-approve reads and gate writes without guessing.One server, broad surface. Application data access (queries, search, cursors, NL→SQL) and DBA-grade operations (health checks, index tuning, EXPLAIN analysis, locks, vacuum, dumps, replicas, migrations) in a single MCP server. Agents don't have to switch tools to switch tasks.
PostgreSQL-native everything. No ORM, no abstraction tax — uses
psycopg3directly, speaks everypg_*system view, integrates with TimescaleDB, pgvector, PostGIS, Apache AGE, andpg_stat_statementswhere they're available, and degrades gracefully when they aren't.Production-shaped, not demo-shaped. Connection pooling, per-request
SET ROLEmulti-tenancy, read-replica routing with degraded-host detection, server-side cursors with dedicated connections, rate-limiting, audit trail with regex redaction, PG TLS enforcement on startup, OIDC JWT bearer auth, per-session statement / lock timeouts.Observability built in. Prometheus
/metricsendpoint on the HTTP transport surfacesmcpg_tool_calls_total{tool,status}+mcpg_tool_duration_seconds. Every tool call records a structured audit event with credential-redacted arguments.Test-driven, multi-version. 2,500+ unit tests plus an integration suite that runs against a real PostgreSQL container in CI — matrix covers PG 14, 15, 16, 17, 18 on every push, plus PG 19 (beta) as an experimental (non-blocking) entry tracked under issue #120.
Related MCP server: PostgreSQL MCP Server
Install
From PyPI (recommended)
pip install mcpg
# or, in an isolated venv exposed globally:
uv tool install mcpgVerify:
mcpg --versionDocker
Pull the pre-built image from the GitHub Container Registry (published
on every tagged release — :latest tracks the newest, or pin a version
like :0.6.5):
docker pull ghcr.io/devopam/mcpg:latest
docker run --rm --name mcpg -p 8000:8000 \
-e MCPG_DATABASE_URL=postgresql://user:pass@host:5432/db \
-e MCPG_ACCESS_MODE=read-only \
ghcr.io/devopam/mcpg:latestOn Windows PowerShell replace the trailing \ with a backtick `
(or put the command on one line); the installation
guide has ready-to-copy
Linux/macOS, PowerShell, and Command Prompt blocks.
Or build it yourself from source:
docker build -t mcpg https://github.com/devopam/MCPg.gitMulti-stage image: runtime stage drops the build toolchain, runs as
uid=10001 / gid=10001 with nologin shell, application files
root-owned and read-only to the runtime user.
From source (developers)
git clone https://github.com/devopam/MCPg && cd MCPg
uv syncuv sync creates a venv with all runtime + dev dependencies and exposes
the mcpg console script.
More detail in the Installation Guide.
Quick start
One-click installs:
— setup for Windsurf, JetBrains, Zed, Cline, Antigravity, Qwen Code, Perplexity,
ChatGPT, Copilot Studio, Continue, and HTTP
clients in the integrations guide.
One-click install in Claude Desktop (.mcpb)
Download mcpg-<version>.mcpb from the
latest release and
double-click it (or drag it into Claude Desktop's Settings →
Extensions). You'll be prompted for your PostgreSQL connection URL —
stored in the OS keychain — and an access mode (defaults to
read-only). That's the whole install: the bundle is ~2 kB and the
host resolves the pinned mcpg release from PyPI for your platform.
Or wire it up manually (stdio transport)
Drop this into your claude_desktop_config.json (macOS:
~/Library/Application Support/Claude/claude_desktop_config.json;
Windows: %APPDATA%\Claude\claude_desktop_config.json):
{
"mcpServers": {
"mcpg": {
"command": "uvx",
"args": ["mcpg"],
"env": {
"MCPG_DATABASE_URL": "postgresql://user:pass@localhost:5432/mydb"
}
}
}
}Restart Claude Desktop. The MCPg toolset is now available to the model. You can ask Claude things like:
"What schemas exist in this database? For each one, summarise the three biggest tables."
"Why is this query slow?
SELECT * FROM orders WHERE customer_id = 42 ORDER BY created_at DESC"
No interesting data yet? Seed the demo dataset
MCPG_DATABASE_URL=postgresql://... mcpg --demoOne command seeds a small, curated e-commerce dataset (3,000 orders,
900 product reviews, deliberately planted flaws) into an mcpg_demo
schema — engineered so the index advisor, query-plan analysis,
full-text search, PII audit, and graph projection all have something
real to find on your first try. See the
guided tour for a captured walkthrough, and remove it
any time with mcpg --demo-drop.
Run as an HTTP server (for IDE integrations, web apps, etc.)
MCPG_DATABASE_URL=postgresql://user:pass@localhost:5432/mydb \
MCPG_TRANSPORT=streamable-http \
MCPG_HTTP_PORT=8000 \
mcpgThen point any MCP-aware client at http://localhost:8000/mcp (or
/sse for the SSE transport). The HTTP transport refuses to start
unless it's authenticated — set MCPG_HTTP_AUTH_TOKEN=... for a static
bearer, or MCPG_AUTH_MODE=oidc for full JWT validation against an
OIDC issuer. To deliberately run without auth (not recommended), set
MCPG_HTTP_ALLOW_UNAUTHENTICATED=true.
Configuration
MCPg is configured entirely through environment variables — no
config file, no flags (the CLI's --version / --demo / --demo-drop
are one-shot commands, not configuration). The only required one is
MCPG_DATABASE_URL; everything else has a safe default.
Common scenarios
Scenario | Set |
Local exploration, read-only |
|
Read-write app data access |
|
DBA toolkit (DDL, vacuum, etc.) |
|
HTTP transport with bearer auth |
|
Multi-tenant SaaS |
|
Read-replica fan-out |
|
NL→SQL — single provider | Set any one vendor key ( |
NL→SQL — multiple providers, caller picks | Set all vendor keys you want active. Each call to |
Full reference
Core
Variable | Default | Description |
| required | Primary PostgreSQL DSN. Supports URI ( |
|
|
|
|
|
|
|
|
|
|
| Bind address for HTTP transports. Set to |
|
| Listen port for HTTP transports (1–65535). |
Capability gates (opt-in for higher-blast-radius tools)
Variable | Default | Description |
|
| Expose DDL tools ( |
|
| Expose subprocess-backed tools ( |
|
| With unrestricted mode + |
|
| Expose |
|
| Expose |
Authentication (HTTP transports only)
Variable | Default | Description |
|
|
|
| — | Required bearer token when |
|
| Explicit opt-out of the HTTP transport's fail-closed auth check. Loudly logged on every startup when set; not recommended. |
| — | OIDC issuer URL (required when |
| — | Expected |
| discovered | Override JWKS endpoint (auto-discovered from issuer's |
| — | JWT claim whose value becomes the per-request PG role ( |
HTTP hardening (HTTP transports only)
Variable | Default | Description |
|
| (1 MiB) Request bodies above this get a |
| — | Comma-separated CORS allowlist. Unset = no CORS middleware (no cross-origin headers emitted). |
|
|
|
|
| Per-request wall-clock cap ( |
| — | Comma-separated list of allowed |
Multi-tenancy (SET ROLE)
Variable | Default | Description |
| — | Static PG role applied to every query. Identifier-validated. |
| — | Comma-separated allowlist. When set, the |
Read replicas
Variable | Default | Description |
| — | Comma-separated replica DSNs. |
Multiple databases (read-only secondaries)
Variable | Default | Description |
| — | Comma- or newline-separated |
Pool / timeouts / TLS
Variable | Default | Description |
|
| Minimum pool connections. |
|
| Maximum pool connections. Must be ≥ |
|
| Per-session |
|
| Per-session |
|
| Expose |
|
| Default per-call budget for |
|
| Hard ceiling for |
|
| Size of the isolated analytical pool — max simultaneous |
|
| Bypass the startup TLS check that refuses remote DSNs without |
|
| On SIGTERM, wait up to this long for in-flight tool calls to finish before closing the pool and cursors. |
Subprocess tools (MCPG_ALLOW_SHELL=true only)
Variable | Default | Description |
|
| Max wall-clock for |
|
| (64 MiB) Cap on captured stdout per subprocess call. |
| — | Comma-separated absolute dirs the resolved |
| — | Per-child |
| — | Per-child |
LISTEN/NOTIFY (MCPG_ALLOW_LISTEN=true only)
Variable | Default | Description |
|
| Per-channel buffer; oldest notifications dropped on overflow. |
Audit
Variable | Default | Description |
|
| When true, every |
| — | Comma-separated regex fragments added to the secret-name pattern (defaults already cover |
|
| When true, each persisted event is signed with an HMAC chained over the previous event; the |
| — | Secret key for the audit HMAC chain. Required when |
Secrets backend
By default every secret is read straight from the environment. Set
MCPG_SECRETS_BACKEND=file to instead load API keys / bearer token /
HMAC key from a mounted file — a name in the file wins; anything absent
falls back to the env var, so partial files work.
Variable | Default | Description |
|
|
|
| — | Required when |
Rate limiting
Variable | Default | Description |
|
| Token-bucket per-tool rate limiting. Set to |
|
| Global cap per window across all tools. |
|
| Window length for the global quota. |
|
| Cap for heavy tools ( |
|
| Window length for the heavy-tool quota. |
Caching & Feature flags
Variable | Default | Description |
|
| Enable or disable the adaptive cache layer. |
|
| Default cache Time-To-Live in seconds. |
|
| Maximum LRU capacity bound for the memory cache. |
| — | Optional Redis backend connection string for external, multi-node caching. |
|
| Toggle computationally heavy diagnostic, diagram, and advisor tools. |
|
| When true, every write/DDL/shell/listen/migrate-tier tool call (any tool whose |
Natural-language SQL
MCPg auto-discovers every configured provider from the environment at
startup — set as many vendor keys as you have and each becomes callable.
Nineteen providers ship built in. Three are first-party (Anthropic,
OpenAI, Gemini); the other sixteen speak the OpenAI-compatible API with
vendor-preset endpoints: DeepSeek, Qwen, OpenRouter, Perplexity, xAI
(Grok), Groq, Mistral, Together, Fireworks, DeepInfra, Cerebras, Nebius,
Hugging Face, GitHub Models, SambaNova, and Moonshot (Kimi). Every
built-in is plug-and-play — set the vendor's conventional API-key env
var and it's auto-discovered — and any other OpenAI-compatible
vendor or local model server (Ollama, vLLM, LM Studio) is still
pluggable through configuration alone via MCPG_NL2SQL_CUSTOM_PROVIDERS.
The whole built-in list is one declarative registry in nl2sql.py, so
adding a vendor or refreshing a retired default model is a one-line data
change.
When MCPG_NL2SQL_PROVIDER is unset, MCPg auto-picks the default in
registry order — anthropic → openai → gemini stay first so existing
deployments are unaffected. translate_nl_to_sql accepts an optional
provider="…" argument to route per call; get_server_info reports
which are configured.
Variable | Default | Description |
| — | Setting a vendor's conventional key enables that provider. Standard slugs: |
(keys that deviate) | — | A few vendors don't follow |
| auto-picked | Any built-in slug (listed above) or a custom name. Pins the default provider used when the tool is called without |
| — | Explicit key for the configured |
| provider default | Override the default model (e.g. |
| — | Endpoint override for the default provider (private gateways / regional endpoints). |
| — | Bring your own provider — no code change. Comma/newline-separated |
|
| Cap on generated tokens (hard limit: 16384). |
Usage examples
The MCP tools are invoked by the agent (Claude, Cursor, Continue, …) in response to your natural-language instructions. A handful of illustrative round-trips:
Inspect the schema
You: What tables live in the
publicschema, and which ones are the biggest by row count?
Agent (using
list_tables+summarize_table× N): Six tables:customers(1.2M rows),orders(4.7M),line_items(18.3M),products(340),addresses(1.4M),audit_log(45.8M — the largest, accumulates without retention).
Diagnose a slow query
You: Why does
SELECT * FROM orders o JOIN line_items l ON o.id = l.order_id WHERE o.created_at > now() - interval '7 days'take 8 seconds?
Agent (using
why_is_this_slow+recommend_indexes):EXPLAIN ANALYZEshows a sequential scan overorders(4.7M rows) filtered bycreated_at. There's no index onorders.created_at. Recommended:CREATE INDEX CONCURRENTLY orders_created_at_idx ON orders (created_at DESC);Expected improvement: ~95% reduction (index scan touches ~33K rows instead of full table). Runvalidate_migrationon it before applying to confirm there's no locking surprise.
Translate plain English to SQL
You: Find customers who placed an order this month but never in the previous three months — show me their email and current lifetime spend.
Agent (using
translate_nl_to_sql):SELECT c.email, SUM(l.price * l.quantity) AS lifetime_spend FROM customers c JOIN orders o ON o.customer_id = c.id JOIN line_items l ON l.order_id = o.id WHERE EXISTS ( SELECT 1 FROM orders o2 WHERE o2.customer_id = c.id AND o2.created_at >= date_trunc('month', now())) AND NOT EXISTS ( SELECT 1 FROM orders o3 WHERE o3.customer_id = c.id AND o3.created_at >= date_trunc('month', now()) - interval '3 months' AND o3.created_at < date_trunc('month', now())) GROUP BY c.email;
Picture the schema
You: Draw me an ER diagram of the
publicschema.
Agent (using
generate_schema_diagram): Returns a Mermaid diagram you can paste straight into GitHub / Notion / Obsidian.
Audit the database
You: How healthy is this database right now?
Agent (using
audit_database): Returns a graded report: Memory & I/O score 92 (GOOD), Transaction & Connection 78 (WARNING: rollback rate 0.4%, look at app logs), Concurrency & Locks 60 (CRITICAL: 14 backends waiting), Cleanliness & Bloat 88 (GOOD), Slow queries 70 (WARNING: top query template runs 5000×, mean 90 ms — seeoptimize_query).
Run a guarded write
You: Soft-delete every order older than 5 years.
Agent (using
run_writewithMCPG_AUDIT_PERSIST=true): Validates the statement through the safe-SQL kernel, runs it inside a transaction, returns affected row count, persists the call (sql + arguments — with secrets regex-redacted — + status) tomcpg_audit.eventsfor after-the-fact review.
For dozens more recipes — multi-tenant routing, RLS testing, NL→SQL,
hybrid vector + FTS search, Apache AGE Cypher, TimescaleDB, ORM schema
exports, server-side cursors — see docs/cookbook.md.
What's in the box
Compact category list. For the full, current tool reference see
docs/tools.md; for a guided walkthrough see
docs/tour.md.
Catalog introspection — schemas, tables, columns, indexes, constraints, views, functions, triggers, sequences, partitions, policies, roles, grants, enums, domains, composite types, FDWs, publications, subscriptions, extensions, generated columns.
Query intelligence —
run_select,run_select_parallel,explain_query,analyze_query_plan,why_is_this_slow,recommend_indexes,analyze_workload,check_database_health,detect_n_plus_one,audit_database.Search —
fuzzy_search(trigram),full_text_search,vector_search,hybrid_search(pgvector + FTS via RRF),geo_search(PostGIS k-NN).Natural language → SQL —
translate_nl_to_sql(22 built-in providers — Anthropic, OpenAI, Gemini, xAI, Groq, Mistral, Hugging Face, … — plus any custom OpenAI-compatible endpoint; output passes through the same safe-SQL kernel as hand-written queries).Visualisation —
generate_schema_diagram(ER),generate_fk_cascade_graph(blast-radius ofON DELETE CASCADE),generate_graph_diagram(Apache AGE property graphs).Structural diff & migrations —
compare_schemas,validate_migration, stagedprepare_migration/complete_migration/cancel_migrationworkflow.Apache AGE graph + Cypher —
list_graphs,describe_graph,run_cypher,create_graph,drop_graph,generate_graph_diagram.Composite + advisor tools —
summarize_table,find_unused_objects,find_sensitive_columns(PII heuristic),lint_naming_conventions,test_rls_for_role,list_locks,find_blocking_chains,read_pg_stat_io(PG16+),generate_test_data.Live ops & maintenance —
list_active_queries,verify_connection_encryption(TLS status of the live link),run_maintenance(VACUUM/ANALYZE),prune_audit_events(audit retention),cancel_query,terminate_backend,run_write,run_ddl,enable_extension.Data movement —
export_query/export_table(CSV/JSON),dump_database/restore_database,import_csv/import_json(COPY FROM STDIN),copy_table_between_databases.Server-side cursors —
open_cursor,fetch_cursor,close_cursor,list_cursorsfor pageable reads over millions of rows.TimescaleDB — hypertable / chunk / job / continuous-aggregate introspection and stats, policy and dimension management, and gated chunk / job administration (
drop_chunks,compress_chunk,refresh_continuous_aggregate,run_job, …). See docs/timescaledb.md.ORM schema exporters — Prisma, Drizzle, SQLAlchemy, sqlc, Diesel, jOOQ, Ent, Ecto.
Event streams —
subscribe_channel,poll_notifications,unsubscribe_channel,list_notification_subscriptionsbridging PostgreSQLLISTEN/NOTIFYinto the MCP poll model.Observability — Prometheus
/metricsendpoint +get_metrics_expositiontool for stdio; structured audit trail with regex-based credential redaction.
Documentation
docs/installation.md— install + configuredocs/tour.md— guided tool tourdocs/cookbook.md— practical agent recipesdocs/tools.md— complete tool referencedocs/architecture.md— how the pieces fit togetherdocs/scaling.md— pool sizing, replicas, performancedocs/security-hardening.md— security feature roadmapdocs/release-process.md— how releases ship to PyPIdocs/adr/— architecture decision recordsBrowse at https://devopam.github.io/MCPg/
Security
Vulnerability reporting: see
SECURITY.md. 90-day coordinated-disclosure window; reports todevopam@gmail.com.Defence-in-depth: capability gates, SafeSQL kernel, identifier allowlist, audit redaction, PG TLS enforcement at startup, rate-limiting, OIDC JWT validation, per-session timeouts.
See
docs/security-hardening.mdfor the living roadmap of shipped (✅) and queued (⬜) hardening items.
Privacy Policy
MCPg is self-hosted: your database contents never leave your
infrastructure, and there is no telemetry or phone-home of any kind.
The one documented exception is the opt-in translate_nl_to_sql tool,
which sends your question plus schema context (names, not row data) to
the LLM provider you configure. Full policy — data collection,
usage, storage, third-party sharing, retention, and contact — is in
PRIVACY.md.
Release notes & changelog
See CHANGELOG.md for the full version history,
docs/release-process.md for how releases
are cut, and the GitHub Releases
page for downloadable artifacts.
Contributing
Pull requests welcome — see CONTRIBUTING.md for
the dev-loop setup, test conventions, and the per-PR review
checklist. Participation is governed by the
Code of Conduct
(Contributor Covenant 2.1).
License
MIT — see LICENSE. The SQL-safety kernel
(src/mcpg/sql/) is first-party, re-authored from the MIT-licensed
crystaldba/postgres-mcp; see NOTICE for the lineage.
Wrapped extensions — licenses you should know about
MCPg's source is MIT, but the PostgreSQL extensions it wraps each carry their own license. The wrappers themselves are at arm's length (SQL-level calls, no static or dynamic linking into MCPg's Python process), so MCPg-the-project is not a derivative work of any of them. Operators deploying a service built on MCPg + a given extension take on whatever obligations that extension's license imposes — same as installing the extension directly. The matrix below names the license per wrapped extension so you can make an informed choice.
Extension | License | Notes for operators |
pgvector | PostgreSQL License (BSD-style) | Permissive; no special obligations. |
pg_partman | PostgreSQL License | Permissive. |
pg_cron | PostgreSQL License | Permissive. |
pg_turboquant | MIT | Permissive. |
pg_buffercache / pg_walinspect / pgstattuple | PostgreSQL contrib | Permissive. |
TimescaleDB | Apache 2.0 (community) + Timescale License (TSL, source-available) for some features | Mixed — see Timescale's docs for which features are TSL-gated. |
Apache AGE | Apache 2.0 | Permissive. |
pg_search (ParadeDB) | AGPL-3.0 | Operators running a network service that lets users interact with |
This matrix is a starting point — for the binding answer on your specific deployment, consult the extension's upstream LICENSE file and (if it matters legally) your own counsel.
Disclaimer. Best efforts have been made to bring MCPg to production grade, but it remains an actively developed project and may contain issues. See the License terms for indemnity details.
Available Tools
191 toolsanalyze_distance_metricAnalyze distance metricARead-only
Recommend a pgvector distance metric (cosine | l2 | inner_product) from the embedding-magnitude distribution. Samples up to sample_size non-NULL rows of schema.table.column, computes each embedding's L2 norm, and applies a small heuristic: pre-normalised (CV < 5% and mean ≈ 1.0) → inner_product; nearly-constant magnitude but not unit-norm → cosine (same ranking as L2, safer default); variable magnitude → cosine (normalises out heterogeneous sources). Returns the metric + a rationale + the underlying distribution stats. Reports available=false if the pgvector extension is not installed.
Inputs: table (required), column (required), schema (required), database, +1 more. Returns: available, rationale, magnitude_cv, sampled_rows, +4 more
analyze_hnsw_recallAnalyze HNSW recallBRead-only
Sweeps ef_search values to measure the latency and recall trade-off curve for a given pgvector query vector against exact brute-force ground truth. Requires the vector extension. Returns a list of objects with ef_search, recall_at_k, mean_latency_ms, and p95_latency_ms — one row per ef_search value tested.
Inputs: table (required), column (required), schema (required), query_vector (required), +3 more. Returns: result
analyze_lock_hotspotsAnalyze lock hotspotsARead-only
Rank PG 19 pg_stat_lock rows by wait dominance and surface stable reason codes. Read-only — never modifies state. Pair with find_blocking_chains for the active culprits on a specific hot lock_type. Returns an object with available (bool), server_version_num, detail, and hotspots — a list of objects with lock_type, waits, wait_time_us, reason (one of contention_dominant / high_wait_time / high_wait_count / low_contention), and suggested_followup (a human-readable next-step string).
Example: analyze_lock_hotspots()
Inputs: database. Returns: detail, hotspots, available, server_version_num
analyze_mpp_query_planAnalyze MPP query planARead-only
Run EXPLAIN (ANALYZE, FORMAT JSON) on sql and roll up MPP-specific facts: slice count, motion nodes (Redistribute Motion / Broadcast Motion / Gather Motion), and per-motion metadata (senders, receivers, estimated rows). Uses the same safety pre-flight as analyze_query_plan(io=True) — writes / DDL stay rejected. redistribute_count flags 'data is not co-located with the join key'. On vanilla PG returns available=false.
Example: analyze_mpp_query_plan(sql='SELECT * FROM big JOIN small ON big.k = small.k')
Inputs: sql (required), database. Returns: detail, motions, available, slice_count, +4 more
analyze_query_planAnalyze query planARead-only
Summarise a query's execution plan: total estimated cost, estimated rows, node types used, and any sequentially-scanned tables. Set io=true to run EXPLAIN (ANALYZE, BUFFERS, TIMING) instead of the plan-only variant — adds actual_total_time_ms, shared_blocks_read/hit, io_read_time_ms, io_write_time_ms, and (PG 19) aio_read_blocks / aio_write_blocks rolled up across the plan tree. Reasoning about AIO needs io=true.
Example: analyze_query_plan(sql='SELECT * FROM orders WHERE customer_id = 42', io=true)
Inputs: sql (required), io, database. Returns: node_types, total_cost, actual_rows, estimated_rows, +8 more
analyze_reranker_liftAnalyze reranker liftARead-only
Per-query Spearman + Kendall correlation between bi-encoder and cross-encoder ranks, aggregated across queries in the window. Low correlation = the reranker is actively reordering (doing real work); high correlation = the reranker mostly confirms the bi-encoder order. Optional model / retrieval_index filters. Surfaces reranker_idle (WARNING) when the reranker rarely changes ordering. Reads from mcpg_rag.rerank_events; returns a report with zero counts when the table doesn't exist or the window is empty.
Inputs: days, model, database, retrieval_index. Returns: model, findings, query_count, window_days, +6 more
analyze_rerank_ndcgAnalyze rerank NDCGARead-only
NDCG@k under bi-encoder ordering vs cross-encoder ordering, averaged across labeled queries (ground_truth_relevance IS NOT NULL). Reports the delta (cross - bi) — positive = the rerank is adding real ranking quality, negative = it's hurting. Surfaces rerank_hurts_ndcg (CRITICAL) or rerank_lifts_ndcg (GOOD evidence). Reads from mcpg_rag.rerank_events; returns zero counts when no labeled rows exist in the window.
Inputs: k, days, model, database, +1 more. Returns: k, delta, model, findings, +5 more
analyze_rerank_score_distributionAnalyze rerank score distributionARead-only
Equal-width histogram of cross_encoder_score values over the window plus the top-decile share. Surfaces score_clustering (WARNING) when the reranker isn't discriminating (more than half of scores land in the top decile of the range). Reads from mcpg_rag.rerank_events. Returns an object with window_days, event_count, histogram (list of counts), bucket_edges (list of bucket boundaries), top_decile_share, and findings (list of advisory findings).
Inputs: days, model, database, n_buckets, +1 more. Returns: model, findings, histogram, event_count, +4 more
analyze_session_costAnalyze session costARead-only
Surface hot-path inefficiencies from the audit log. Reads mcpg_audit.events over the last lookback_minutes (default 60, capped at 1440) and flags tools called more than hot_threshold times (default 10). Catalogue-listing tools (list_tables / list_schemas / list_indexes / etc.) get a redundant_listing finding pointing at get_compact_schema; other tools get a hot_repeated_call finding suggesting caching. Idle sessions get an idle_session finding. When mcpg_audit.events doesn't exist (audit subsystem off) returns audit_table_present=False with a diagnostic. Returns an object with audit_table_present (bool), events_examined (int), lookback_minutes, findings (list of objects with reason, tool, call_count, suggestion), and detail.
Example: analyze_session_cost(lookback_minutes=30, hot_threshold=15)
Inputs: database, hot_threshold, lookback_minutes. Returns: detail, findings, events_examined, lookback_minutes, +1 more
analyze_table_bloatAnalyze table bloatARead-only
Rank a schema's tables and indexes by estimated bloat, worst first. By default uses a cheap catalog-only estimate (relpages vs a reltuples/row-width floor) plus the dead-tuple ratio from pg_stat_user_tables. Set precise=true to use pgstattuple / pgstatindex for an exact (but I/O-heavy) read when the extension is installed — it falls back to the estimate and reports method='estimate' if it isn't. Returns tables and indexes (each capped at limit) with per-object est_bloat_pct, plus available and method.
Example: analyze_table_bloat(schema='public', limit=20, precise=false)
Inputs: schema (required), limit, precise, database. Returns: detail, method, schema, tables, +2 more
analyze_topk_stabilityAnalyze top-k stabilityBRead-only
Jaccard overlap between top-K-by-bi-rank and top-K-by-cross-rank per query, aggregated. High mean Jaccard means the reranker isn't actually changing the top-K membership. Surfaces topk_stable (WARNING) when the rerank is barely earning its place at this K. Reads from mcpg_rag.rerank_events; returns a report with zero counts when the table doesn't exist or the window is empty.
Inputs: k, days, model, database, +1 more. Returns: k, model, findings, p25_jaccard, +5 more
analyze_vector_search_efficiencyAnalyze vector search efficiencyARead-only
Cross-backend retrieval-quality report for a pgvector or pg_turboquant ANN index. Detects the backend (HNSW / IVFFlat / turboquant), sweeps the matching per-backend knob (ef_search / probes / candidate_limit) across a multiplier curve, computes recall@k vs a brute-force exact baseline, Spearman + Kendall rank correlation, per-query p50/p95 wall-clock latency, and (for turboquant) the page-pruning ratio from tq_last_scan_stats. Emits findings: baseline_recall_low (CRITICAL), rerank_lift_flat / rerank_lift_steep / ranking_degraded / pruning_ineffective (WARNING). Burns sample_size x (1 + len(candidate_multipliers)) queries; ad-hoc diagnostic, not a cron tool. Requires the vector extension; turboquant-arm metrics require pg_turboquant.
Inputs: table (required), column (required), schema (required), id_column (required), +6 more. Returns: k, table, column, metric, +10 more
analyze_workloadAnalyze workloadARead-only
Return the slowest queries by mean execution time, via the pg_stat_statements extension. Reports availability=false if the extension is not installed.
Example: analyze_workload(limit=10)
Inputs: limit, database. Returns: available, slow_queries
audit_databaseAudit databaseARead-only
Run a deep, comprehensive DBA-level database performance, logs, and health audit over the specified schema. Scans memory, checkpoints, temp file spills, contention locks, dead tuple cleanliness, and optionally scans custom logging tables. Set fresh=true to bypass the cache and re-read live (e.g. after a schema change). Returns an object with timestamp, database, version, overall_health ('GOOD' / 'WARNING' / 'CRITICAL'), health_score (int), categories (per-area results), top_issues, recommendations, and raw_stats_snapshot.
Inputs: schema (required), fresh, database, log_table. Returns: version, database, timestamp, categories, +5 more
audit_sequencesAudit sequencesARead-only
Flag sequences nearing their ceiling — serial / identity / explicit sequences whose last_value / max_value exceeds warning_pct (default 80) or critical_pct (default 95). Sequence overflow is catastrophic and silent until the next nextval() raises 'reached maximum value' — the int4 serial ceiling (2^31-1) is hit far more often than expected. Pure read; available=false on PG < 10 (no pg_sequences). Returns an object with available, total_examined, warning_pct, critical_pct, detail, and sequences (at-risk only, sorted by used_pct desc — each with schema, sequence, last_value, max_value, used_pct, remaining, status).
Example: audit_sequences(warning_pct=80, critical_pct=95)
Inputs: database, warning_pct, critical_pct. Returns: detail, available, sequences, warning_pct, +2 more
audit_settingsAudit settingsARead-only
Sanity-sweep postgresql.conf via pg_settings. Flags dangerous toggles (fsync=off, full_page_writes=off, autovacuum=off, synchronous_commit=off), cross-setting issues (maintenance_work_mem < work_mem, tiny shared_buffers, low checkpoint_completion_target), and — when total_ram_mb is supplied — RAM-relative ratios for shared_buffers / effective_cache_size (PostgreSQL can't see host RAM itself). Pure read. Returns an object with ram_aware (bool), examined_settings (list), detail, and findings (tripped rules only — each with code, setting, current, status, suggestion).
Example: audit_settings(total_ram_mb=16384)
Inputs: database, total_ram_mb. Returns: detail, findings, ram_aware, examined_settings
check_database_healthCheck database healthBRead-only
Run database health checks: connection utilisation, buffer cache hit ratio, tables needing vacuum, and invalid indexes. Returns an object with status ('ok' / 'warning' / 'critical') and checks (a list of {name, status, detail} per check).
Example: check_database_health()
Inputs: database. Returns: checks, status
check_pitr_readinessCheck PITR readinessARead-only
Assess whether the cluster is ready for point-in-time recovery (PITR) — the one-call 'could I actually recover to an arbitrary point right now, and if not what's missing?' check. Composes get_wal_archive_status (5.2) with the GUCs that gate PITR: continuous archiving must be healthy, wal_level >= replica, max_wal_senders >= 1 (so pg_basebackup can stream a base backup), and full_page_writes on (torn-page safety during replay). Read-only advisor — changes nothing, emits no secrets. Returns an object with available, ready (bool — true only when all gates pass), wal_level, archiving_healthy, gates (list of objects with name, ok, observed, remediation), remediation (ordered fixes for failing gates), and detail.
Example: check_pitr_readiness()
Inputs: database. Returns: gates, ready, detail, available, +3 more
check_segment_healthCheck segment healthARead-only
Walk gp_segment_configuration and surface MPP segment posture. Returns per-segment status ('u' = up), mode ('s' = sync / 'n' = not-in-sync / 'c' = changetracking), and role vs preferred_role to detect post-failover state. Top-level unhealthy_count + out_of_sync_count let agents branch without walking the segments array. Read-only. On vanilla PG returns available=false.
Example: check_segment_health()
Inputs: database. Returns: detail, segments, available, healthy_count, +3 more
close_cursorClose cursorBRead-only
Close a server-side cursor and release its dedicated connection. Idempotent — returns closed=false when the cursor was not open (already closed, expired, or never existed).
Inputs: cursor_id (required). Returns: object
cluster_vectorsCluster vectorsARead-only
k-means cluster a pgvector column. Samples up to sample_size (default 5000) non-NULL rows of schema.table.embedding_column, runs Lloyd's algorithm with k-means++ seeding (seed for determinism), and returns centroids (one per cluster, with size) + assignments (per-row cluster index + distance). When id_column is set each assignment carries that column's value; otherwise the row's positional sample index. metric='l2' (default — squared Euclidean) or 'cosine' (vectors normalised; centroids re-normalised every iteration). k >= 2 and there must be at least 2k parseable rows. Reports available=false if pgvector is not installed.
Example: cluster_vectors(schema='public', table='docs', embedding_column='embedding', k=8, metric='cosine')
Inputs: k (required), table (required), schema (required), embedding_column (required), +6 more. Returns: metric, inertia, available, centroids, +5 more
compare_schemasCompare schemasARead-only
Return the structural diff between two schemas — tables/columns/indexes/constraints/foreign-keys added, removed, or changed. Base tables only; views and custom types are not compared. Renames surface as a paired add + remove.
Example: compare_schemas(left_schema='public', right_schema='staging')
Inputs: left_schema (required), right_schema (required), database. Returns: left_schema, right_schema, tables_added, tables_changed, +1 more
cross_table_similarityCross table similarityARead-only
Find the k rows in target_schema.target_table most similar to a specific row in source_schema.source_table. Locates the source row via source_id_column = source_id_value, reads its embedding from source_embedding_column, then issues a pgvector k-NN query against target_embedding_column. Both columns must be vector(N) of the same N — verified from the catalog up front so a mismatch fails with a clear error rather than a cast error. Useful for entity-resolution / linking across tables whose embeddings come from different models but share a dimension. Returns source_embedding_found=false when no row matches the id value. Reports available=false if pgvector is not installed.
Inputs: source_table (required), target_table (required), source_schema (required), target_schema (required), +7 more. Returns: matches, available, source_dimension, source_embedding_found
describe_ao_tableDescribe AO tableARead-only
Describe append-optimized (AO) / append-optimized columnar (AO/CO) storage metadata for one table: row vs column orientation, compression_type, compression_level, block_size, checksum. Reads pg_appendonly. Returns is_ao=false cleanly when the table is a regular heap. Read-only. On vanilla PG returns available=false.
Example: describe_ao_table(schema='public', table='events_ao')
Inputs: table (required), schema (required), database. Returns: is_ao, table, detail, schema, +5 more
describe_graphDescribe graphBRead-only
Describe the schema structure, vertex labels, and edge labels of a specific property graph. Returns an object with graph_name, vertex_labels, and edge_labels.
Inputs: graph_name (required). Returns: object
describe_property_graphDescribe property graphARead-only
Describe one SQL/PGQ property graph by schema-qualified name. Requires PG 19+; raises an error otherwise. Useful when an agent has located a graph via list_property_graphs and needs the full membership before composing a run_pgq query. Returns an object with schema, name, vertex_tables (list of schema.table strings), and edge_tables (same shape).
Example: describe_property_graph(schema='public', name='org_chart')
Inputs: name (required), schema (required), database. Returns: name, schema, edge_tables, vertex_tables
describe_redis_cache_tableDescribe Redis cache tableARead-only
Describe one foreign table backed by redis_fdw: which server it's mapped to, the Redis-side key structure (hash / list / string / set / zset), key-prefix, TTL, and SQL-side column shape. Raises an error when the table doesn't exist or isn't backed by redis_fdw. Returns an object with schema, name, server, key_type, key_prefix, ttl_seconds, columns (list of {name, data_type}), and options (the full foreign-table options dict).
Example: describe_redis_cache_table(schema='public', table='sessions_cache')
Inputs: table (required), schema (required), database. Returns: name, schema, server, columns, +4 more
describe_selfDescribe selfARead-only
Return a high-level summary of what mcpg can do, organised into capability buckets (schema introspection, query execution, vector search, RAG telemetry, audit trail, migrations, time-series, etc.). Call this first when discovering mcpg's surface — it's much more compact than walking the full tool catalogue. Returns an object with headline, version, tool_count, capability_count, and a capabilities list, where each capability has id, name, summary, detail, headline_tools (top 3-6 tools to reach for first), tool_count, and all_tools (the full list in that bucket). Read-only; no database access. Pair with list_tools (MCP-protocol) when you need every tool's full schema.
Inputs: no named parameters. Returns: object
describe_tableDescribe tableARead-only
Describe the columns of a table, in ordinal order. Set fresh=true to bypass the cache and re-read live (e.g. after a schema change). Returns a list of objects with name, data_type, nullable, default, and vector_dimension (set only for pgvector vector(N) columns).
Example: describe_table(schema='public', table='users')
Inputs: table (required), schema (required), fresh, database. Returns: result
describe_toolDescribe toolARead-only
Return the full registered schema for one MCP tool by name — description, input_schema, output_schema, and which capability bucket it belongs to. Use this when an agent hits a tool error and needs to verify the call shape without re-walking the full describe_self payload (handy when the transport surfaces only tools/call, not tools/list). Returns registered=false plus a did_you_mean suggestion list when the name isn't on this server. Read-only; no database access. Example: describe_tool(name='run_select')
Inputs: name (required). Returns: object
detect_n_plus_oneDetect n plus oneARead-only
Surface query templates in pg_stat_statements that look like an N+1 loop: hundreds of calls, each returning at most a row or two, with meaningful total wall-clock time spent. Returns the candidates sorted by total time descending so the worst offender appears first. Thresholds (min_calls, max_rows_per_call, min_total_ms) are tunable. Treat results as candidates for investigation, NOT verdicts — a hot cache-miss pattern on a primary-key lookup can trip the same shape. Reports availability=false if pg_stat_statements is not installed.
Inputs: limit, database, min_calls, min_total_ms, +1 more. Returns: available, candidates, thresholds
detect_vector_outliersDetect vector outliersARead-only
Flag pgvector rows whose embedding sits far from any cluster centroid. Samples up to sample_size (default 5000) non-NULL rows of schema.table.embedding_column, clusters them with k-means (same engine as cluster_vectors), then per cluster computes a z-score on the distance from each row to its centroid and flags rows whose z-score exceeds zscore_threshold (default 3.0). Per-cluster scoring catches rows that are weird-for-their-group rather than weird-overall, which is usually what 'find outliers' should mean. Returns outliers sorted by z-score descending (capped at max_results), total_outliers (the unclipped count), and cluster_stats (per-cluster mean / std of within-cluster distances). When id_column is set each outlier carries that column's value; otherwise the row's positional sample index. k >= 2 and there must be at least 2k parseable rows. Reports available=false if pgvector is not installed.
Inputs: table (required), schema (required), embedding_column (required), k, +8 more. Returns: k, metric, outliers, available, +5 more
explain_queryExplain queryARead-only
Return the PostgreSQL execution plan for a query. By default uses EXPLAIN (FORMAT JSON) — plan only, the query is not executed. Set io=true to switch to EXPLAIN (ANALYZE, BUFFERS, TIMING) — runs the query and includes buffer + I/O timing per node (PG 19 additionally surfaces asynchronous-I/O block counts). Validated by the same safety allowlist as run_select, so writes / DDL are rejected.
Example: explain_query(sql='SELECT * FROM orders WHERE customer_id = 42', io=true)
Inputs: sql (required), io, database. Returns: plan
export_queryExport queryARead-only
Run a read-only SQL query and serialise its rows to CSV or JSON. Reuses the SQL-safety checks of run_select. Truncates at limit rows and flags it in the result so callers can paginate.
Example: export_query(sql='SELECT id, email FROM users', format='csv', limit=10000)
Inputs: sql (required), limit, format, database. Returns: format, content, row_count, truncated
export_tableExport tableARead-only
Serialise every row in schema.table (up to limit) to CSV or JSON. Schema and table names must be plain identifiers. Returns an object with format, row_count, truncated (bool — true when the row count hit limit), and content (the serialised payload as a string).
Inputs: table (required), schema (required), limit, format, +1 more. Returns: format, content, row_count, truncated
fetch_cursorFetch cursorARead-only
Fetch the next batch from an open server-side cursor. exhausted=true means the FETCH returned fewer rows than requested — stop polling. batch_size defaults to 100; hard cap is 10000 per call.
Inputs: cursor_id (required), batch_size. Returns: object
find_blocking_chainsFind blocking chainsBRead-only
Return (blocked, blocking) backend pairs via pg_blocking_pids. Each row pairs a backend waiting on a Lock with one PID holding the lock that's preventing progress. Cycles are possible (A blocks B, B blocks A); render with care. Read-only.
Inputs: limit, database. Returns: result
find_sensitive_columnsFind sensitive columnsARead-only
Flag columns whose names or types look like they hold sensitive data (passwords, tokens, PII, financial info, health records). Pure heuristic — no row sampling, no value introspection. Categories: credential, financial, contact, identifier, health, government_id, location. Each finding carries a confidence (high / medium / low) so an agent can filter for a first review pass. Treat as a SIGNAL, not a verdict — a column named email_template_id matches the email pattern but isn't itself an email address. Returns an object with findings (list of {schema, table, column, data_type, category, confidence, matched_pattern}) and summary counts by category.
Inputs: schema (required), database. Returns: schema, columns
find_unused_objectsFind unused objectsARead-only
Find tables and indexes with zero scans since pg_stat was last reset — a strong signal of dead code, but NOT a verdict. Tables report seq+idx scan counts, write counts, and estimated row count; indexes report size and definition. Excludes PRIMARY KEY and UNIQUE indexes (PG needs those regardless of scans). Run this after the database has been hot for a meaningful period — fresh stats produce false positives. Returns an object with tables (list of candidate tables with their stats) and indexes (list of candidate indexes with size and definition).
Inputs: schema (required), database. Returns: schema, tables, indexes
full_text_searchFull text searchARead-only
Rank a text column's documents against a full-text query using PostgreSQL's built-in tsvector/tsquery. The query accepts web-search syntax (quoted phrases, or, - exclusion). Returns a list of objects with the matched row's primary key columns plus rank (ts_rank score, higher = better match).
Example: full_text_search(schema='public', table='articles', column='body', search_query='"new york" OR -draft')
Inputs: table (required), column (required), schema (required), search_query (required), +3 more. Returns: result
fuzzy_searchFuzzy searchARead-only
Rank a text column's values by pg_trgm trigram similarity to a search term. mode='word' (default) matches fragments within longer text; mode='full' compares whole strings. Reports available=false if pg_trgm is not installed. Returns an object with available (bool), matches (list of {value, similarity} ranked by similarity descending), and mode.
Example: fuzzy_search(schema='public', table='users', column='name', term='janne', mode='word')
Inputs: term (required), table (required), column (required), schema (required), +4 more. Returns: matches, available
generate_diesel_schemaGenerate Diesel schemaARead-only
Read a PostgreSQL schema and emit a Diesel ORM (Rust) schema.rs. One table! macro per table with column SQL types, Nullable<T> for nullable columns, plus joinable! declarations for single-column intra-schema FKs and an allow_tables_to_appear_in_same_query! macro so multi-table joins type-check. Enum types are emitted as Text-backed wrapper enums in a pg_enum module so the output works without diesel_derive_enum. Composite FKs are a documented v1 gap. Schema/table/column names must be plain identifiers ([A-Za-z_][A-Za-z0-9_]*); delimited names (hyphens, spaces, mixed-case-only) are not supported here because they become source identifiers in generated code — use SQL tools (export_table, dump_database) for those objects. See docs/identifier-policy.md.
Inputs: schema (required), database. Returns: result
generate_drizzle_schemaGenerate Drizzle schemaARead-only
Read a PostgreSQL schema and emit a Drizzle ORM TypeScript schema string (drizzle-orm/pg-core). Covers tables, columns with PG-native types, primary/foreign keys, unique constraints, indexes, defaults, and enums. Single-column FKs emit column-level .references(); composite FKs are a documented v1 gap. Views, foreign tables, partitions, triggers, and functions are out of scope. Returns the rendered TypeScript schema.ts source as a single string. Schema/table/column names must be plain identifiers ([A-Za-z_][A-Za-z0-9_]*); delimited names (hyphens, spaces, mixed-case-only) are not supported here because they become source identifiers in generated code — use SQL tools (export_table, dump_database) for those objects. See docs/identifier-policy.md.
Inputs: schema (required), database. Returns: result
generate_ecto_schemasGenerate Ecto schemasARead-only
Read a PostgreSQL schema and emit Ecto (Elixir) schema modules — one .ex file per table, named after the singularised table. Each module uses Ecto.Schema with field declarations, belongs_to for single-column intra-schema FKs, and timestamps() when both inserted_at and updated_at exist. The Elixir top-level module is configurable via app_module (default MyApp). Returns a JSON object {filename: source} so the agent can write each file. Schema/table/column names must be plain identifiers ([A-Za-z_][A-Za-z0-9_]*); delimited names (hyphens, spaces, mixed-case-only) are not supported here because they become source identifiers in generated code — use SQL tools (export_table, dump_database) for those objects. See docs/identifier-policy.md.
Inputs: schema (required), database, app_module. Returns: object
generate_ent_schemasGenerate Ent schemasARead-only
Read a PostgreSQL schema and emit Ent (Go) Schema struct files — one .go file per table. Each file exports a struct that lists field.X(...) calls for every column, edge.To(...) for single-column intra-schema FKs, and field.Enum().Values() for enum-typed columns. Composite FKs are a documented v1 gap. Returns a JSON object {filename: source} so the agent can write each file. Schema/table/column names must be plain identifiers ([A-Za-z_][A-Za-z0-9_]*); delimited names (hyphens, spaces, mixed-case-only) are not supported here because they become source identifiers in generated code — use SQL tools (export_table, dump_database) for those objects. See docs/identifier-policy.md.
Inputs: schema (required), database. Returns: object
generate_fk_cascade_graphGenerate FK cascade graphARead-only
Build a Mermaid graph LR of foreign-key cascade chains in a schema. Each edge runs from the referencing table to the referenced table, labelled with the cascade action(s) on DELETE / UPDATE. By default only FKs with at least one CASCADE / SET NULL / SET DEFAULT action are included — those are the ones that produce a write blast radius. Pass include_all=true to include NO ACTION / RESTRICT FKs too (full FK topology view). Cross-schema FK targets are rendered as separate nodes prefixed with their schema. Returns the Mermaid graph LR diagram as a string.
Inputs: schema (required), database, include_all. Returns: result
generate_graph_diagramGenerate graph diagramBRead-only
Generate a Mermaid flowchart diagram representing nodes and relationships in a property graph to visualize its schema and topology. Returns the Mermaid flowchart as a string.
Inputs: graph_name (required), limit. Returns: result
generate_graph_projectionGenerate graph projectionARead-only
Generate openCypher CREATE/MERGE statements that project a relational schema into an Apache AGE property graph — rows become vertices (one label per table), foreign keys become edges. EMITS the Cypher for review; NEVER executes it (like generate_test_data). With row_limit=0 (default) it returns a schema-level template plan (one CREATE per label, one MERGE per edge type, $prop placeholders) reading only the catalog. With row_limit>0 it also emits concrete per-row statements (values escaped, NULLs omitted, capped at 1000 rows/table). Tables without a primary key still get node CREATEs but their edges are skipped (they can't be reliably MATCHed). NOTE: AGE materialises the data (this is a LOAD, not a virtual view); run the node statements before the edge statements; the projection is 1-hop faithful to the FK graph. Returns an object with available (AGE installed, advisory), schema, graph_name, row_limit, node_labels (list of label, source_table, key_columns, property_columns), edge_types (list of edge_type, from_label, to_label, from_key, to_key, fk_name), cypher_statements (generated, never executed), warnings, and detail.
Example: generate_graph_projection(schema='public', graph_name='g', row_limit=0)
Inputs: schema (required), tables, database, row_limit, +1 more. Returns: detail, schema, warnings, available, +5 more
generate_jooq_configGenerate jOOQ configARead-only
Read a PostgreSQL schema and emit a jooq-codegen configuration XML pointing at it. Unlike the other exporters, jOOQ generates Java code itself from a live database — the artefact here is the configuration file the user feeds to mvn jooq-codegen:generate (or the Gradle task). The XML lists every base table explicitly via an regex, excludes MCPg's bookkeeping tables, and emits a for every json / jsonb column so they map to org.jooq.JSON / org.jooq.JSONB out of the box. Default Java package is com.example.jooq; override via the target_package arg. Schema/table/column names must be plain identifiers ([A-Za-z_][A-Za-z0-9_]*); delimited names (hyphens, spaces, mixed-case-only) are not supported here because they become source identifiers in generated code — use SQL tools (export_table, dump_database) for those objects. See docs/identifier-policy.md.
Inputs: schema (required), database, target_package, target_directory. Returns: result
generate_prisma_schemaGenerate Prisma schemaARead-only
Read a PostgreSQL schema and emit a valid Prisma .prisma schema string (mirrors prisma db pull). Covers tables, columns, primary/foreign keys, unique constraints, indexes, and enums. Views, foreign tables, partitions, triggers, functions, and policies are out of scope; unmappable types fall back to Unsupported("..."). Returns the rendered schema.prisma source as a single string. Schema/table/column names must be plain identifiers ([A-Za-z_][A-Za-z0-9_]*); delimited names (hyphens, spaces, mixed-case-only) are not supported here because they become source identifiers in generated code — use SQL tools (export_table, dump_database) for those objects. See docs/identifier-policy.md.
Inputs: schema (required), database. Returns: result
generate_schema_diagramGenerate schema diagramARead-only
Render a Mermaid ER diagram for a schema. Views and foreign tables are excluded; partitions are excluded by default — pass include_partitions=true to draw each partition as its own entity. Returns the Mermaid erDiagram as a string ready to paste into a Markdown block.
Example: generate_schema_diagram(schema='public', include_partitions=false)
Inputs: schema (required), database, include_partitions. Returns: result
generate_schema_docsGenerate schema docsARead-only
Generate a detailed Markdown reference of a schema's tables, columns, constraints, indexes, views, foreign tables, and custom enums along with comments / descriptions. Optional include_samples fetches a few distinct, non-null values for each column. Returns a single Markdown document as a string.
Example: generate_schema_docs(schema='public', include_samples=true)
Inputs: schema (required), database, include_samples. Returns: result
generate_sqlalchemy_modelsGenerate SQLAlchemy modelsARead-only
Read a PostgreSQL schema and emit a SQLAlchemy 2.0 declarative models file (DeclarativeBase + Mapped[T] + mapped_column). Covers tables, columns with PG-native types (incl. jsonb via sqlalchemy.dialects.postgresql.JSONB), primary keys, single-column FKs via ForeignKey(), unique constraints (column-level + composite via table_args), defaults, and enums (emitted as Python enum.Enum classes). Composite FKs are a documented v1 gap. Returns the rendered Python models.py source as a single string. Schema/table/column names must be plain identifiers ([A-Za-z_][A-Za-z0-9_]*); delimited names (hyphens, spaces, mixed-case-only) are not supported here because they become source identifiers in generated code — use SQL tools (export_table, dump_database) for those objects. See docs/identifier-policy.md.
Inputs: schema (required), database. Returns: result
generate_sqlc_schemaGenerate sqlc schemaARead-only
Read a PostgreSQL schema and emit a sqlc-friendly schema.sql (plain DDL). Order: CREATE SCHEMA, CREATE TYPE for each enum, CREATE TABLE statements (columns only), ALTER TABLE ADD CONSTRAINT (PK / unique / check / foreign key in that order), then CREATE INDEX for non-constraint indexes. The file replays cleanly against an empty database so FKs land after all referenced tables exist. In-process — no MCPG_ALLOW_SHELL needed. Returns the rendered schema.sql text as a single string. Schema/table/column names must be plain identifiers ([A-Za-z_][A-Za-z0-9_]*); delimited names (hyphens, spaces, mixed-case-only) are not supported here because they become source identifiers in generated code — use SQL tools (export_table, dump_database) for those objects. See docs/identifier-policy.md.
Inputs: schema (required), database. Returns: result
generate_test_dataGenerate test dataARead-only
Generate synthetic INSERT statements for a table — typed values respecting column type, NOT NULL, and DEFAULT. Returns the SQL as strings; does NOT execute it. Useful for seeding dev / staging environments. The generator is deterministic when a seed is provided. Foreign keys are NOT resolved — the caller must pre-seed referenced rows or drop the FK before applying. Hard cap of 10000 rows per call. Pure read (the actual writes go through run_write under unrestricted mode).
Inputs: table (required), schema (required), rows, seed, +1 more. Returns: table, schema, statements, rows_generated, +1 more
generate_test_row_forGenerate test row forARead-only
Generate ONE realistic test row for a table — catalogue-aware. Skips identity / generated columns (server fills them in), samples one existing row from each referenced table for FK columns (so the row inserts cleanly), and uses column-name heuristics (*_email → user_N@example.com, *_url → https://example.com/r/N, *_at → recent timestamp, etc.) to make values look like data. Sibling of generate_test_data (bulk) — designed for the shadow-migration workflow where a single realistic row matters more than volume. Returns an object with insert_sql (one ready-to-execute INSERT), columns (per-column ColumnFill with sql_literal + heuristic explanation), schema, table. Does NOT execute the INSERT — caller applies via run_write when ready.
Example: generate_test_row_for(schema='public', table='orders', seed=42)
Inputs: table (required), schema (required), seed, database, +1 more. Returns: table, schema, columns, insert_sql
geo_searchGeo searchBRead-only
Find the rows nearest to a lon/lat point by PostGIS distance. Reports available=false if the postgis extension is not installed.
Inputs: table (required), column (required), schema (required), latitude (required), +3 more. Returns: matches, available
get_aio_statusGet AIO statusARead-only
Report whether PG 19's async-I/O subsystem is usable. On PG < 19 returns available=false with a diagnostic pointing the agent at the existing read_pg_stat_io / run_maintenance tools. Never raises — driver-level errors during the version or settings probe also surface as available=false. Returns an object with available (bool), server_version_num (int), server_version, io_method ('sync' / 'worker' / 'io_uring' / null), io_min_workers, io_max_workers, and detail (a guidance string).
Example: get_aio_status()
Inputs: database. Returns: detail, available, io_method, io_max_workers, +3 more
get_compact_schemaGet compact schemaARead-only
Return a highly condensed, token-efficient text summary of a schema's tables, columns, primary keys, nullability, and relations to save context window tokens. Set fresh=true to bypass the cache and re-read live (e.g. after a schema change).
Inputs: schema (required), fresh, database. Returns: result
get_current_wal_lsnGet current WAL LSNARead-only
Return the current WAL LSN — write-side on a primary (pg_current_wal_lsn()) or replay-side on a standby (pg_last_wal_replay_lsn()). Natural pairing for the read-your-writes workflow: capture on the primary right after a write, then pass to wait_for_lsn on the standby session before the follow-up read. Works on every supported PG version. Returns an object with role ('primary' or 'standby') and lsn (PostgreSQL LSN literal, e.g. '0/1234ABCD').
Example: get_current_wal_lsn()
Inputs: database. Returns: lsn, role
get_database_ddlGet database DDLARead-only
Return the CREATE DATABASE DDL for a named database using PG 19's pg_get_databasedef(oid) function. Returns found=false with an empty ddl when the database doesn't exist. Requires PG 19+. Returns an object with object_type ('database'), object_name, found, and ddl.
Example: get_database_ddl(database_name='analytics')
Inputs: database_name (required), database. Returns: ddl, found, object_name, object_type
get_data_checksums_statusGet data checksums statusARead-only
Report whether PG 19's online data_checksums toggle is usable + the current setting. Never raises — driver-level errors surface as available=false. On PG ≤ 18 reports available=false but still surfaces the current state (set at initdb time) so the agent has context, and points at the offline pg_checksums fallback. Returns an object with available (bool), server_version_num (int), server_version, enabled (bool / null), and detail (guidance string).
Example: get_data_checksums_status()
Inputs: database. Returns: detail, enabled, available, server_version, +1 more
get_hypertable_statsGet hypertable statsARead-only
Size and compression statistics for one TimescaleDB hypertable: total/compressed chunk counts, approximate row count, table/index/toast/total bytes, and bytes before/after compression. Errors if the table is not a hypertable; available=false when the timescaledb extension is not installed.
Inputs: table (required), schema (required), database. Returns: table, schema, available, index_bytes, +8 more
get_logical_replication_statusGet logical replication statusARead-only
Report whether PG 19's on-demand wal_level flip is usable, plus the configured wal_level, the new PG 19 effective_wal_level preset GUC, and max_replication_slots. When configured and effective diverge the agent can tell that an ALTER SYSTEM has been done but a reload is still pending. Never raises. Returns an object with available (bool), server_version_num, server_version, wal_level, effective_wal_level, max_replication_slots, and detail.
Example: get_logical_replication_status()
Inputs: database. Returns: detail, available, wal_level, server_version, +3 more
get_metrics_expositionGet metrics expositionARead-only
Return the in-process Prometheus-format metrics for this MCPg server. Three series: mcpg_tool_calls_total (counter by tool / status), mcpg_tool_duration_seconds (histogram by tool with sum and count). Useful when the HTTP transport's /metrics endpoint is unreachable (e.g. running over stdio) or to fetch via the MCP protocol itself.
Inputs: no named parameters. Returns: result
get_pg19_ddl_statusGet PG 19 DDL statusARead-only
Report whether PG 19's pg_get_roledef() / pg_get_databasedef() / pg_get_tablespacedef() DDL-dump functions are usable on this server. Never raises — driver-level errors surface as available=false. On PG ≤ 18 reports available=false and points the agent at pg_dumpall --roles-only / --globals-only / --tablespaces-only as the fallback. Returns an object with available (bool), server_version_num (int), server_version, has_pg_get_roledef (bool), has_pg_get_databasedef (bool), has_pg_get_tablespacedef (bool), and detail (guidance string).
Example: get_pg19_ddl_status()
Inputs: database. Returns: detail, available, server_version, has_pg_get_roledef, +3 more
get_pg19_partitions_statusGet PG 19 partitions statusARead-only
Report whether PG 19's ALTER TABLE … MERGE PARTITIONS and ALTER TABLE … SPLIT PARTITION forms are usable on this server. Never raises — driver-level errors surface as available=false. On PG ≤ 18 reports available=false and points the agent at the detach / create / attach fallback path. Returns an object with available (bool), server_version_num (int), server_version, and detail (guidance string).
Example: get_pg19_partitions_status()
Inputs: database. Returns: detail, available, server_version, server_version_num
get_pg19_stats_statusGet PG 19 stats statusARead-only
Report whether PG 19's pg_stat_lock and pg_stat_recovery views are usable on this server. Never raises — driver-level errors surface as available=false. On PG < 19 returns available=false with a diagnostic pointing the agent at find_blocking_chains / pg_stat_replication. Returns an object with available (bool), server_version_num (int), server_version, has_pg_stat_lock (bool), has_pg_stat_recovery (bool), and detail (guidance string).
Example: get_pg19_stats_status()
Inputs: database. Returns: detail, available, server_version, has_pg_stat_lock, +2 more
get_pgq_statusGet PGQ statusARead-only
Report whether SQL/PGQ (the SQL standard for property graph queries, new in PG 19) is usable on this server. SQL/PGQ coexists with the AGE-style graph_operations bucket — get_pgq_status is the agent's hint about which surface to reach for. Never raises; on PG < 19 reports available=false with a diagnostic pointing at run_cypher. Returns an object with available (bool), server_version_num (int), server_version (the human-readable string), and detail (a guidance string the agent can surface to the user).
Example: get_pgq_status()
Inputs: database. Returns: detail, available, server_version, server_version_num
get_pg_search_index_metadataGet PG search index metadataARead-only
Fetch the parsed reloptions for a single BM25 index (schema.index). Same shape as one entry of list_pg_search_indexes — typed accessors for the 13 documented options plus the raw index_options dict. Raises when the extension is not installed or no BM25 index by that name exists. Returns an object with schema, index, the typed option fields, and index_options (raw reloptions dict for forward-compat).
Inputs: index (required), schema (required), database. Returns: index, table, schema, columns, +14 more
get_prewarm_extension_statusGet prewarm extension statusARead-only
Report whether pg_prewarm (and the supporting pg_buffercache) are installed, and whether pg_prewarm is listed in shared_preload_libraries (the autoprewarm worker requires it). Returns an object with pg_prewarm_installed (bool), pg_buffercache_installed (bool), autoprewarm_libraries_present (bool), and shared_preload_libraries (the raw setting).
Example: get_prewarm_extension_status()
Inputs: database. Returns: pg_prewarm_installed, pg_buffercache_installed, shared_preload_libraries, autop…
get_redis_cache_statsGet Redis cache statsARead-only
Best-effort cache metrics for a redis_fdw server. redis_fdw does not ship a uniform stats SQL surface across versions, so the tool validates that the server exists and otherwise reports available=false with a diagnostic. Operators wanting live metrics should query Redis directly (INFO / DBSIZE). Returns an object with server, available (bool), key_count, used_memory_bytes, and detail (a human-readable note).
Example: get_redis_cache_stats(server='redis_primary')
Inputs: server (required), database. Returns: detail, server, available, key_count, +1 more
get_repack_statusGet repack statusARead-only
Report whether PG 19's in-server REPACK command is usable. On PG < 19 returns available=false with a diagnostic pointing the agent at the long-standing pg_repack extension shell-out path so the fallback is clear. The in-server REPACK CONCURRENTLY is the headline PG 19 operational win — online table rebuild with no blocking writers. Returns an object with available (bool), server_version_num (int), server_version (the human-readable string), and detail (a guidance string the agent can surface to the user).
Example: get_repack_status()
Inputs: database. Returns: detail, available, server_version, server_version_num
get_role_ddlGet role DDLARead-only
Return the CREATE ROLE DDL for a named role using PG 19's pg_get_roledef(oid) function — no shell-out to pg_dumpall --roles-only required. Returns found=false with an empty ddl when the role doesn't exist. Requires PG 19+; raises on older servers (pair with get_pg19_ddl_status to feature-detect). Returns an object with object_type ('role'), object_name, found (bool), and ddl (the verbatim CREATE statement).
Example: get_role_ddl(role_name='app_user')
Inputs: role_name (required), database. Returns: ddl, found, object_name, object_type
get_server_infoGet server infoARead-only
Return the MCPg server version, access mode, transport, database connection status, and PostgreSQL wal_level / effective_wal_level (the latter is None on PG ≤ 18 where the GUC doesn't exist; on PG 19+ a divergence between the two indicates a reload is still pending).
Inputs: no named parameters. Returns: object
get_skip_scan_statusGet skip scan statusARead-only
Report whether PG 19's B-tree skip-scan optimisation is the planner default on this server. Never raises — driver-level errors surface as available=false. On PG ≤ 18 reports available=false and points the agent at the standard 'add a dedicated single-column index' fallback. Returns an object with available (bool), server_version_num (int), server_version, and detail (guidance string).
Example: get_skip_scan_status()
Inputs: database. Returns: detail, available, server_version, server_version_num
get_tablespace_ddlGet tablespace DDLARead-only
Return the CREATE TABLESPACE DDL for a named tablespace using PG 19's pg_get_tablespacedef(oid) function. Returns found=false with an empty ddl when the tablespace doesn't exist. Requires PG 19+. Returns an object with object_type ('tablespace'), object_name, found, and ddl.
Example: get_tablespace_ddl(tablespace_name='fast_ssd')
Inputs: tablespace_name (required), database. Returns: ddl, found, object_name, object_type
get_timescaledb_telemetry_reportGet timescaledb telemetry reportARead-only
Return the usage report TimescaleDB builds about this database (get_telemetry_report()): versions, relation counts and sizes, feature usage. It is generated locally from catalog data and nothing is sent by this call (the periodic upload is a separate background job governed by timescaledb.telemetry_level). Contains instance metadata such as the database UUID, so treat it as sensitive.
Inputs: database. Returns: report, available
get_turboquant_heap_statsGet TurboQuant heap statsBRead-only
Return the exact heap row count tq_index_heap_stats() reports for a single turboquant index (schema.index). The raw upstream payload is preserved in raw for any extra counters upstream may add. Requires the pg_turboquant extension.
Inputs: index (required), schema (required), database. Returns: raw, index, schema, row_count
get_turboquant_index_metadataGet TurboQuant index metadataARead-only
Fetch the tq_index_metadata payload for a single turboquant index (schema.index). Documented fields are surfaced as typed attributes; the full upstream payload is preserved in raw_metadata so advisors can reach unanticipated fields. Raises when the extension is not installed or no turboquant index by that name exists. Returns an object with schema, index, algorithm_version, quantizer_family, residual_sketch_kind, fast_path_eligible, capability_flags, delta_state, maintenance_recommended, and raw_metadata (full upstream payload).
Inputs: index (required), schema (required), database. Returns: index, table, column, schema, +18 more
get_turboquant_last_scan_statsGet TurboQuant last scan statsARead-only
Return the backend-local JSON tq_last_scan_stats() reports for the most recent turboquant scan: score_mode, simd_kernel, pages_scanned, pages_pruned, plus the raw payload. Returns null when the extension is absent or no turboquant scan has run on this connection yet.
Inputs: database. Returns: result
get_wait_for_lsn_statusGet wait for LSN statusARead-only
Report whether PG 19's WAIT FOR LSN is usable on this server. Also reports whether the current backend is a standby (the only context where the wait does meaningful work). Never raises. On PG ≤ 18 returns available=false and points at the poll-loop fallback. Returns an object with available (bool), server_version_num (int), server_version, is_in_recovery (bool), and detail.
Example: get_wait_for_lsn_status()
Inputs: database. Returns: detail, available, is_in_recovery, server_version, +1 more
get_wal_archive_statusGet WAL archive statusARead-only
Report WAL-archiving health from pg_stat_archiver + the archive-mode GUCs — the early-warning signal for a failing archive_command / archive_library (full archive volume, bad object-store credentials, network partition), which otherwise silently accumulates WAL in pg_wal/ until the volume fills. Companion to read_pg_wal_records (which inspects WAL records); this covers the WAL archive. Read-only; never raises. The archive_command string is NOT echoed (it can embed credentials) — only a boolean archive_command_set. Returns an object with available, archiving_enabled, archive_mode, archive_command_set, archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, stats_reset, healthy (bool — false when archiving is on and the latest attempt failed), and detail.
Example: get_wal_archive_status()
Inputs: database. Returns: detail, healthy, available, stats_reset, +9 more
get_warehousepg_statusGet WarehousePG statusARead-only
Probe the connected server for the WarehousePG (Greenplum-derived MPP) signature. Reports available=true only when BOTH the version string mentions WarehousePG / Greenplum AND the gp_segment_configuration catalog view exists. Surfaces coordinator_role, segment_count (primary segments only), and mirroring (bool). On vanilla PostgreSQL clusters returns available=false with a clean diagnostic — the rest of the mcpg.warehousepg.* family advertise themselves inert via this probe. Read-only; never raises.
Example: get_warehousepg_status()
Inputs: database. Returns: detail, version, available, mirroring, +2 more
hybrid_bm25_vector_searchHybrid BM25 vector searchARead-only
Combine a BM25 search and a pgvector search via Reciprocal Rank Fusion — the canonical v2 pattern ParadeDB documents in the 2025-10-22 'Hybrid Search Missing Manual' blog post. Returns hits as {id, score, bm25_rank, vector_rank}. score is the summed sum(weight * 1.0 / (k + rank)) across both legs; per-leg ranks are surfaced for transparency (either can be NULL if a row only appeared in one leg's top-K). distance_op is the pgvector operator ('<=>'/'<->'/'<#>' — RRF is operator-agnostic). bm25_columns=None searches the whole BM25 index; bm25_columns=["col"] restricts the BM25 leg to a single field. Defaults mirror upstream's demonstrated form (cosine, k=60, equal weights, per_leg_limit=20). Requires the pg_search and pgvector extensions.
Inputs: table (required), schema (required), key_field (required), query_text (required), +10 more. Returns: result
hybrid_searchHybrid searchARead-only
Combine vector and full-text ranking via reciprocal-rank fusion (RRF) — pulls candidates from each source, then fuses them so rows ranked highly in EITHER source surface. Closes the gap between pure vector (misses keyword/identifier matches) and pure full-text (misses semantic synonyms). Parameters: vector_column, text_column, query_vector, text_query, plus metric / text_config / limit / candidate_pool / rrf_k tunables. Each match carries vector_rank, fts_rank, the fused rrf_score, and (when present) the original distance + ts_rank values.
Example: hybrid_search(schema='public', table='docs', vector_column='embedding', text_column='body', query_vector=[0.1, ...], text_query='postgresql tuning')
Inputs: table (required), schema (required), text_query (required), text_column (required), +7 more. Returns: matches, available
inspect_gucInspect gucARead-only
Inspect one PostgreSQL GUC via pg_settings: live value, unit, context (postmaster/sighup/user/…), pending_restart, vartype, and whether ALTER SYSTEM can change it. Use this before alter_system to see whether a reload or restart is required. Read-only.
Inputs: name (required). Returns: name, unit, detail, source, +13 more
lint_naming_conventionsLint naming conventionsARead-only
Lint table / column / index naming in a schema. Detects the majority case style (snake_case / camelCase / PascalCase / SCREAMING_SNAKE) per schema and per table, then flags outliers. Also flags indexes whose names do not start with a conventional prefix (idx_, ix_, pk_, uq_, fk_ by default). Findings carry the offender's style and the detected majority — agents can use the style field to filter for renames vs accept-as-is. Pure read. Returns an object with schema_style (detected majority), findings (list of style outliers), and index_prefix_findings (indexes with non-conventional prefixes).
Inputs: schema (required), database. Returns: schema, findings, schema_majority_style
list_active_queriesList active queriesARead-only
List the queries currently running on the server, with each backend's wait event, duration, and the PIDs blocking it. Returns a list of objects with pid, username, application, state, wait_event (null when not waiting), duration_seconds, query, and blocked_by (list of PIDs holding locks this backend is waiting on).
Inputs: database. Returns: result
list_audit_eventsList audit eventsARead-only
List recent rows from mcpg_audit.events (newest first). Returns an empty list when MCPG_AUDIT_PERSIST has never been turned on (no audit table yet). Optionally filter by tool name.
Inputs: tool, limit, database. Returns: result
list_autowarm_jobsList autowarm jobsARead-only
List the pg_cron jobs MCPg registered for autowarm (jobname LIKE 'mcpg_autowarm%'). Returns an empty list when pg_cron is not installed. Returns a list of objects with jobid, jobname, schedule (the cron expression), and command (the SELECT the job runs).
Example: list_autowarm_jobs()
Inputs: database. Returns: result
list_available_extensionsList available extensionsARead-only
List every extension available to the database, with whether it is installed. Returns a list of objects with name, default_version, installed_version (null when not installed), and installed (bool).
Inputs: database. Returns: result
list_chunksList chunksARead-only
List the chunks of a TimescaleDB hypertable with each chunk's range_start / range_end and whether it has been compressed. Empty list when the table is not a hypertable. Returns an object with available (bool) and chunks (list of {chunk_name, range_start, range_end, is_compressed, total_size_bytes}).
Inputs: table (required), schema (required), database. Returns: chunks, available
list_composite_typesList composite typesBRead-only
List the standalone composite types in a schema with their attributes. Returns a list of objects with name and attributes (list of {name, data_type} for each field).
Inputs: schema (required), database. Returns: result
list_constraintsList constraintsARead-only
List a table's constraints — primary/foreign keys, unique, check, exclusion. Set fresh=true to bypass the cache and re-read live (e.g. after a schema change). Returns a list of objects with name, type, and definition (the constraint SQL).
Example: list_constraints(schema='public', table='orders')
Inputs: table (required), schema (required), fresh, database. Returns: result
list_continuous_aggregatesList continuous aggregatesBRead-only
List TimescaleDB continuous aggregates with their source hypertable, materialized_only flag and compression flag.
Inputs: database. Returns: available, continuous_aggregates
list_cron_jobsList cron jobsARead-only
List the pg_cron jobs registered in the database. Returns an empty list when pg_cron is not installed.
Inputs: database. Returns: result
list_cursorsList cursorsARead-only
List every currently-open server-side cursor with its SQL, rows_returned so far, age in seconds, and the TTL after which it'll be auto-closed.
Inputs: no named parameters. Returns: result
list_databasesList databasesARead-only
List every database this MCPg server is configured to serve: the primary (the default target of every tool) plus any read-only secondaries from MCPG_SECONDARY_DATABASE_URLS. Read-capable tools accept an optional database argument naming one of these ids; omitting it targets the primary. Secondaries are read-only (PostgreSQL-enforced) — writes / DDL / shell / migrate always run against the primary. Returns an object with primary_id, database_ids (primary first), and databases — a list of objects with id, is_primary, read_only, reachable (a live SELECT 1 probe), and detail (an error string when unreachable).
Inputs: no named parameters. Returns: databases, primary_id, database_ids
list_distribution_policiesList distribution policiesARead-only
List the data-distribution policy for each table in a WarehousePG schema (HASH(col,...), RANDOM, or REPLICATED). Joins gp_distribution_policy to pg_attribute for the distribution-key column names in catalog order. schema=None returns every non-system schema. Read-only. On vanilla PG returns available=false with a diagnostic.
Example: list_distribution_policies(schema='public')
Inputs: schema, database. Returns: detail, policies, available
list_domainsList domainsBRead-only
List the domain types in a schema, with base type, default, and check constraints. Returns a list of objects with name, base_type, nullable, default, and constraints (list of CHECK clauses).
Inputs: schema (required), database. Returns: result
list_enumsList enumsBRead-only
List the enum types in a schema, with their labels in sort order. Returns a list of objects with name and values (list of label strings, in the order defined).
Inputs: schema (required), database. Returns: result
list_extensionsList extensionsARead-only
List the extensions installed in the database. Returns a list of objects with name and version.
Inputs: database. Returns: result
list_foreign_data_wrappersList foreign data wrappersBRead-only
List the foreign-data wrappers installed in the database. Returns a list of objects with name, handler (qualified function name), validator, and options (dict of wrapper-specific options).
Inputs: database. Returns: result
list_foreign_keysList foreign keysARead-only
List foreign keys in a schema, resolved to columns and referenced table. Set fresh=true to bypass the cache and re-read live (e.g. after a schema change). Returns a list of objects with name, from_table, from_columns, to_schema, to_table, to_columns.
Example: list_foreign_keys(schema='public')
Inputs: schema (required), fresh, database. Returns: result
list_foreign_serversList foreign serversARead-only
List the foreign servers defined in the database, with their FDW and options. Returns a list of objects with name, wrapper (foreign-data wrapper name), type, version, and options (dict of server options).
Inputs: database. Returns: result
list_foreign_tablesList foreign tablesARead-only
List the foreign tables in a schema, with their server and options. Returns a list of objects with name, server (foreign-server name), and options (dict of per-table options).
Inputs: schema (required), database. Returns: result
list_functionsList functionsARead-only
List the functions and procedures defined in a schema. Returns a list of objects with name, kind ('function' or 'procedure'), arguments (signature string), returns (return-type string), and language (plpgsql / sql / c / etc.).
Inputs: schema (required), database. Returns: result
list_generated_columnsList generated columnsARead-only
List every GENERATED ALWAYS AS (...) STORED column in a schema, with its data type, the underlying expression, and whether it's stored or virtual. PostgreSQL today supports only the stored form; the kind field is reported anyway so the response shape is forward-compatible when PG adds virtual columns. Returns a list of objects with schema, table, column, data_type, expression, kind ('stored' today; reserved for 'virtual').
Inputs: schema (required), database. Returns: result
list_grantsList grantsARead-only
List the privileges granted on a table — who may do what to it. Returns a list of objects with grantee, privilege (SELECT / INSERT / UPDATE / DELETE / TRUNCATE / REFERENCES / TRIGGER), grantable (bool — may the grantee regrant), and grantor.
Inputs: table (required), schema (required), database. Returns: result
list_graphsList graphsARead-only
List all active Apache AGE property graphs in the database. Returns a list of objects with name (graph name) and oid.
Inputs: no named parameters. Returns: result
list_hypertablesList hypertablesARead-only
List every TimescaleDB hypertable visible to the current role, with chunk count, compression flag, and total size. Reports available=false when the timescaledb extension is not installed. Returns an object with available (bool) and hypertables (list of {schema, table, num_chunks, compression_enabled, total_size_bytes}).
Inputs: database. Returns: available, hypertables
list_indexesList indexesARead-only
List the indexes defined on a table. Set fresh=true to bypass the cache and re-read live (e.g. after a schema change). Returns a list of objects with name, method (btree / gin / gist / brin / hash / spgist / hnsw / ivfflat / …), definition (the CREATE INDEX statement), and partitioned.
Example: list_indexes(schema='public', table='users')
Inputs: table (required), schema (required), fresh, database. Returns: result
list_locksList locksBRead-only
List currently-held and waiting locks, joined with backend state from pg_stat_activity. Ordered by (granted ASC, pid) so waiting locks float to the top. Returns lock type, mode, qualified relation name when applicable, transaction / virtualxid, the application_name + state + wait event of the owning backend, and the first 200 chars of its query. Read-only.
Inputs: limit, database. Returns: result
list_partitionsList partitionsBRead-only
Describe how a table is partitioned (strategy and bounds) and list its partitions. Returns an object with partitioned (bool), strategy ('range' / 'list' / 'hash' or null), and partitions (a list of {name, bounds} for each partition).
Inputs: table (required), schema (required), database. Returns: strategy, partitions, partitioned
list_pg_search_indexesList PG search indexesARead-only
List every pg_search BM25 index in the database along with the parsed reloptions (the WITH (...) config) for each. Surfaces the 13 documented bm25 options (key_field, the six *_fields jsonb configs, layer_sizes, background_layer_sizes, target_segment_count, mutable_segment_rows, sort_by, search_tokenizer). The full parsed dict is preserved in index_options so unsurfaced or future options stay reachable. Returns an empty list when the pg_search extension is not installed.
Inputs: database. Returns: result
list_policiesList policiesARead-only
List the Row-Level-Security policies on a table, and whether row security is enabled. Returns an object with rls_enabled (bool) and policies — a list of {name, command (SELECT/INSERT/UPDATE/DELETE/ALL), permissive (bool), roles, using_expression, check_expression}.
Inputs: table (required), schema (required), database. Returns: policies, rls_enabled
list_prewarmed_relationsList prewarmed relationsARead-only
Report current shared-buffer residency per relation, ranked by blocks-cached descending. Requires the pg_buffercache extension; returns an empty list when it's missing. Returns a list of objects with schema, table, blocks_cached (8 KiB pages currently in shared buffers), total_blocks (the relation's on-disk size in the same unit), pct_cached (the residency ratio rounded to 2 decimals), and dirty_blocks (pages with pending writes).
Example: list_prewarmed_relations(schema='public', limit=50)
Inputs: limit, schema, database. Returns: result
list_property_graphsList property graphsARead-only
List SQL/PGQ property graphs defined in the database (reads information_schema.sql_property_graphs). Returns an empty list on PG < 19 or when the catalog view is missing (early Beta builds may not expose it yet — pair with get_pgq_status to disambiguate). Returns a list of objects with schema, name, vertex_tables (list of schema.table strings), and edge_tables (same shape).
Example: list_property_graphs()
Inputs: database. Returns: result
list_publicationsList publicationsARead-only
List logical-replication publications with the tables and operations they include. Returns a list of objects with name, owner, all_tables (bool), publishes_insert / publishes_update / publishes_delete / publishes_truncate (bools), and tables (list of schema.table strings).
Inputs: database. Returns: result
list_redis_foreign_serversList Redis foreign serversARead-only
List the foreign servers backed by redis_fdw — the FDW that exposes a Redis instance as SQL-queryable foreign tables. Reports each server's connection address, port, database, TLS posture, and whether a user mapping (credential) is configured. Returns an empty list when the redis_fdw extension is not installed. Returns a list of objects with name, address, port, database, tls (bool), password_configured (bool), and options (the full server-options dict).
Example: list_redis_foreign_servers()
Inputs: database. Returns: result
list_replicasList replicasARead-only
Report the health of every configured read replica. Each entry shows index, password-obfuscated DSN, whether the replica is currently degraded (skipped from routing), the last error that took it out, and how many seconds remain before it's re-probed. Returns an empty list when no replicas are configured.
Inputs: no named parameters. Returns: result
list_resource_groupsList resource groupsARead-only
List configured WarehousePG resource groups + their utilisation. Reads gp_toolkit.gp_resgroup_status for concurrency, cpu_max_percent, cpu_weight, memory_limit, memory_shared_quota, plus live num_running / num_queueing. Pairs with analyze_workload for 'where's my workload time going' diagnosis. Read-only. On vanilla PG returns available=false.
Example: list_resource_groups()
Inputs: database. Returns: detail, groups, available
list_rolesList rolesARead-only
List the database roles and their attributes, excluding PostgreSQL's own roles unless include_system is true. Returns a list of objects with name, superuser, create_role, create_db, can_login, replication, bypass_rls, connection_limit, member_of.
Inputs: database, include_system. Returns: result
list_schemasList schemasARead-only
List database schemas, excluding PostgreSQL's own schemas unless include_system is true. Returns a list of objects with name.
Example: list_schemas(include_system=false)
Inputs: database, include_system. Returns: result
list_sequencesList sequencesARead-only
List the sequences defined in a schema, with their range, increment, and last value. Returns a list of objects with name, data_type, start_value, min_value, max_value, increment, cycle (bool), last_value.
Inputs: schema (required), database. Returns: result
list_subscriptionsList subscriptionsARead-only
List logical-replication subscriptions; requires superuser to see any rows.
Inputs: database. Returns: result
list_tablesList tablesBRead-only
List the tables and views in a schema, flagging partitioned tables and partitions. Returns a list of objects with name, type ('table' or 'view'), partitioned, is_partition.
Example: list_tables(schema='public')
Inputs: schema (required), database. Returns: result
list_timescale_jobsList timescale jobsARead-only
List TimescaleDB background jobs (retention / compression / refresh / reorder policies and user jobs) with schedule, next start, last run status and run/failure counts. Job ids below 1000 are TimescaleDB system jobs.
Inputs: database. Returns: jobs, available
list_triggersList triggersBRead-only
List the user-defined triggers on a table. Returns a list of objects with name, function (the called function's qualified name), and definition (the CREATE TRIGGER SQL).
Inputs: table (required), schema (required), database. Returns: result
list_turboquant_indexesList TurboQuant indexesARead-only
List every pg_turboquant ANN index in the database along with the metadata payload that tq_index_metadata() reports for it: algorithm_version, quantizer_family, residual_sketch_kind, fast_path_eligible, capability_flags, delta_state, and maintenance_recommended. Returns an empty list when the pg_turboquant extension is not installed.
Inputs: database. Returns: result
list_user_mappingsList user mappingsBRead-only
List role-to-foreign-server mappings; the catch-all appears as user='public'. Returns a list of objects with user (role name or 'public'), server (foreign-server name), and options (dict of mapping options, e.g. credentials).
Inputs: database. Returns: result
list_viewsList viewsARead-only
List the views and materialized views in a schema, with their definitions. Returns a list of objects with name, materialized (bool), and definition (the SELECT SQL).
Inputs: schema (required), database. Returns: result
migrate_vector_to_halfvecMigrate vector to halfvecARead-only
Generate a DDL plan that converts a pgvector vector(N) column to halfvec(N) — halving per-element storage (4 → 2 bytes) with typically negligible recall impact at d ≥ 768. Reads the column's current type + dimension from the catalog, finds every index on the column, and emits an ordered migration_sql plan: DROP each affected index, ALTER COLUMN to halfvec(N) via a USING cast, then recreate each index with its halfvec opclass. Also returns a mirror rollback_sql that restores the original vector(N) type plus the original index definitions. Nothing is executed — feed the plan through the shadow-migration workflow (prepare_migration / validate_migration_schema) before applying. Returns already_halfvec=true (and an empty plan) when the column is already halfvec, and refuses any index whose opclass has no halfvec sibling rather than rewriting it incorrectly. Requires the vector extension.
Inputs: table (required), column (required), schema (required), database. Returns: notes, indexes, available, dimension, +8 more
mmr_searchMMR searchARead-only
Diversity-aware vector search: fetch fetch_k nearest candidates by pgvector distance, then re-rank with Maximal Marginal Relevance to return k rows that are relevant but not near-duplicates — better LLM context than raw top-k. lambda_mult in [0,1] trades relevance (1.0) for diversity (0.0); default 0.5. Relevance + diversity are cosine similarities computed over candidate embeddings, so the result is independent of the recall-pass metric. Each hit carries its relevance, mmr_score, and selection rank. Reports available=false if the pgvector extension is not installed.
Example: mmr_search(schema='public', table='docs', column='embedding', query_vector=[0.1, ...], k=10, lambda_mult=0.5)
Inputs: table (required), column (required), schema (required), query_vector (required), +5 more. Returns: matches, available
monitor_embedding_driftMonitor embedding driftARead-only
Compare two time windows of a pgvector column and flag distributional drift. Samples up to sample_size (default 5000) non-NULL embeddings from each window (filtered by timestamp_column), computes the centroid (per-dimension mean vector) and L2-norm distribution of each, then reports the cosine distance between the two centroids (the main drift signal), the relative change in mean / std of the L2-norm distribution, and a boolean drift_detected that flips when cosine distance exceeds drift_threshold (default 0.05). Each window is treated as a half-open [start, end) interval. Useful for ops monitoring of embedding pipelines — an upstream model swap typically shows up as a large centroid cosine distance even if the norm distribution looks stable. insufficient_data is returned distinctly from drift_detected=false when either window is empty. Reports available=false if pgvector is not installed.
Example: monitor_embedding_drift(schema='public', table='docs', embedding_column='embedding', timestamp_column='created_at', baseline_start='2026-01-01', baseline_end='2026-02-01', current_start='2026-02-01', current_end='2026-03-01')
Inputs: table (required), schema (required), current_end (required), baseline_end (required), +7 more. Returns: notes, current, baseline, available, +7 more
monitor_index_buildMonitor index buildARead-only
Surface every active CREATE INDEX and its progress from pg_stat_progress_create_index (PG12+, no extension). One row per build with pid, schema.relation.index_name, the command, phase label, blocks_done/total, tuples_done/total, and a computed progress_pct (blocks first, tuples as fallback, null when neither phase reports a denominator). Useful next to list_active_queries when an HNSW / IVFFlat build on a big table is taking longer than expected. Returns a list of objects with pid, schema, relation, index_name, command, phase, blocks_done, blocks_total, tuples_done, tuples_total, and progress_pct (null when no denominator is reported).
Inputs: database. Returns: result
open_cursorOpen cursorARead-only
Open a server-side cursor for a SELECT query. The cursor holds the result set on the server side so an agent can page through millions of rows without loading them all. SQL is validated by the same safety allowlist as run_select. Returns the cursor_id; fetch the rows with fetch_cursor and close with close_cursor (or let the 5-minute TTL clean up). Hard cap of 16 concurrent cursors.
Inputs: sql (required), database. Returns: object
optimize_queryOptimize queryBRead-only
Analyze a SQL query for syntax anti-patterns and performance issues using EXPLAIN plan costs and index scans, returning an optimized version.
Inputs: sql (required), database. Returns: findings, rationale, original_sql, optimized_sql, +1 more
pg_search_more_like_thisPG search more like thisARead-only
Find rows similar to a seed document via pdb.more_like_this + @@@. document_id is the value of key_field for the seed row. All nine documented pdb.more_like_this tuning args (fields jsonb, min_doc_frequency, max_doc_frequency, min_term_frequency, max_query_terms, min_word_length, max_word_length, boost_factor, stop_words) are optional kwargs — when omitted the wrapper does not mention them in the SQL so upstream's defaults apply. Returns the same {id, score} hit shape as pg_search_run. Requires the pg_search extension.
Inputs: limit (required), table (required), schema (required), key_field (required), +11 more. Returns: result
pg_search_parse_queryPG search parse queryARead-only
Parse a query string through pdb.parse and return its canonical text form for debugging — useful for confirming the parser interpreted a phrase as expected. lenient=True relaxes syntax checking; conjunction_mode=True treats space-separated terms as AND-joined rather than OR-joined. Requires the pg_search extension.
Inputs: query_string (required), lenient, database, conjunction_mode. Returns: parsed
pg_search_runPG search runARead-only
Run a BM25 keyword search against a pg_search-indexed table. Returns hits as {id, score, snippets} where id is the value of the caller-supplied key_field and score is pdb.score(t). columns=None searches the whole index; columns=["col"] restricts to a single text field. Multi-column search needs the pdb.parse per-field config JSON and is deferred to a follow-up phase. return_snippets=True requires snippet_field and projects pdb.snippets over that column. Requires the pg_search extension. SECURITY: snippet_start_tag / snippet_end_tag are not sanitized (they pass through to upstream as-is). The defaults match pg_search's HTML defaults; if callers forward untrusted values and a downstream consumer renders snippets as HTML, that's an XSS vector — output escaping is the renderer's responsibility.
Inputs: limit (required), query (required), table (required), schema (required), +8 more. Returns: result
read_autovacuum_priorityRead autovacuum priorityARead-only
Return the tables most urgently needing autovacuum, ranked by how close their dead-tuple count is to the per-table autovacuum threshold (autovacuum_vacuum_threshold + autovacuum_vacuum_scale_factor * reltuples, honouring per-table reloptions overrides). Each row carries priority ('overdue' if past the threshold, 'watchlist' if within 50%, 'borderline' otherwise) plus the inputs (n_dead_tup, vacuum_threshold, last_autovacuum, autovacuum_enabled) so the agent can explain why a table landed on the shortlist. Top-level overdue_count lets an agent branch without walking the list. Read-only catalog query.
Example: read_autovacuum_priority(limit=25)
Inputs: limit, database. Returns: rows, detail, available, overdue_count, +1 more
read_migration_historyRead migration historyARead-only
Query and summarize historical migrations applied to the database by popular migration frameworks (Alembic, Flyway, Diesel, Django, Prisma, Golang Migrate, Goose, Sequelize). Allows filtering by schema. Returns an object with one optional list per detected framework: alembic, flyway, diesel, django, prisma, golang_migrate, goose, sequelize. Each entry is null when the framework's table isn't present; otherwise it carries the framework-specific row shape (e.g. alembic has {version_num}; flyway has {installed_rank, version, description, type, ...}).
Inputs: schema, database. Returns: goose, diesel, django, flyway, +4 more
read_pg_buffercache_relationsRead PG buffercache relationsARead-only
Read the list of database relations taking up the most space in the PostgreSQL shared buffer cache. Reports buffered size, percentage of shared buffers, percent of relation buffered, average usage count, and dirty pages. Allows filtering by schema. Requires the pg_buffercache extension. If not installed, returns available=false.
Inputs: limit, schema, database. Returns: available, relations
read_pg_buffercache_summaryRead PG buffercache summaryARead-only
Read a high-level summary of the PostgreSQL shared buffer cache usage. Reports total buffers, free/used buffers, dirty buffers, and average usage count. Requires the pg_buffercache extension. If not installed, returns available=false.
Inputs: database. Returns: available, free_buffers, used_buffers, dirty_buffers, +2 more
read_pg_stat_ioRead PG stat IOARead-only
Read the pg_stat_io view (PostgreSQL 16+). Reports per (backend_type, object, context) cumulative I/O activity — reads, writes, extends, evictions, hits, fsyncs. Useful for spotting buffer-cache misses and write amplification. On PostgreSQL 14 / 15 the view doesn't exist, so the tool returns available=false and an empty list.
Inputs: database. Returns: rows, available, server_version
read_pg_stat_lockRead PG stat lockARead-only
Return every row from PG 19's pg_stat_lock view (per-lock-type acquire / wait / wait-time counters since the most recent pg_stat_reset). Empty list on PG < 19 or when the view isn't present. Returns a list of objects with lock_type (relation / page / tuple / xid / virtualxid / advisory / ...), acquires, waits, and wait_time_us.
Example: read_pg_stat_lock()
Inputs: database. Returns: result
read_pg_stat_recoveryRead PG stat recoveryARead-only
Return rows from PG 19's pg_stat_recovery view — replay progress, lag, and startup state for a standby. Empty list on PG < 19, when the view isn't present, or when the server isn't in recovery (a primary running standalone returns no rows). Returns a list of objects with replay_lsn, replay_lag_seconds, last_replayed_at, and startup_state (any of which may be null when not applicable).
Example: read_pg_stat_recovery()
Inputs: database. Returns: result
read_pg_wal_recordsRead PG WAL recordsARead-only
Read Write-Ahead Log (WAL) records information over a specified LSN range. Requires the pg_walinspect extension. If not installed, returns available=false.
Inputs: start_lsn (required), limit, end_lsn, database. Returns: records, available
read_pg_wal_statsRead PG WAL statsBRead-only
Read Write-Ahead Log (WAL) record statistics over a specified LSN range, grouped by resource manager or record type. Requires the pg_walinspect extension. If not installed, returns available=false.
Inputs: start_lsn (required), end_lsn, database, per_record. Returns: stats, available
recommend_efficiency_thresholdsRecommend efficiency thresholdsARead-only
Compute corpus-percentile thresholds from accumulated mcpg_rag.efficiency_observations history. Phase E currently adapts three thresholds: baseline_recall_low (p10 of recall_baseline), ranking_degraded_spearman (p10 of spearman), and pruning_ineffective (p10 of pages_pruned_ratio_p50). The remaining four thresholds stay at their hardcoded defaults. Filters by days window + optional backend / metric / k so callers can ask 'what's normal for HNSW+cosine+k=10 in this deployment' vs 'what's normal globally'. Falls back to defaults (with derived_from_corpus=false) when the corpus is smaller than the minimum required. Returns an object with corpus_size, derived_from_corpus (bool), and the threshold fields (baseline_recall_low, baseline_recall_low_adapted, ranking_degraded_spearman, ranking_degraded_spearman_adapted, pruning_ineffective, pruning_ineffective_adapted, rerank_lift_flat_delta, rerank_lift_steep_low, rerank_lift_steep_high, and ranking_degraded_recall).
Inputs: k, days, metric, backend, +1 more. Returns: corpus_size, baseline_recall_low, derived_from_corpus, pruning_ineffective, +8…
recommend_headline_toolsRecommend headline toolsARead-only
Empirically curate describe_self's per-bucket headline_tools from the audit log. Reads mcpg_audit.events over the last lookback_days (default 7, capped at 90), groups successful calls by capability bucket, and reports the top-top_n (default 6) tools per bucket with newcomers (recommended but not in the hand-curated current list) and departures (currently headlined but not in the recommendation). The output is a REVIEWABLE recommendation, not an auto-applied override — operators decide whether to update mcpg.about.CAPABILITIES. Returns audit_table_present=False with a diagnostic when the audit subsystem is off. Returns an object with audit_table_present, lookback_days, top_n, events_examined, detail, and buckets (list of objects with bucket_id, current, recommended, newcomers, departures, call_counts).
Example: recommend_headline_tools(lookback_days=14, top_n=6)
Inputs: top_n, database, lookback_days. Returns: object
recommend_hnsw_ef_searchRecommend HNSW ef searchARead-only
Recommend an hnsw.ef_search value for a target recall@k — the actionable companion to analyze_hnsw_recall. Samples sample_queries rows (default 10) as query vectors, builds an exact brute-force top-k ground truth per query, sweeps ef_values (default 16/32/64/128/256) measuring mean recall@k and p50/p95 latency at each, and recommends the smallest value clearing target_recall (default 0.95). Unlike the single-query curve tool, this VERIFIES an HNSW index actually exists on the column (returns has_hnsw_index=false with guidance otherwise — a sweep without one just measures sequential scans). The query row is excluded from its own results. Requires the vector extension. Returns an object with available, has_hnsw_index, index_name, metric, k, target_recall, sample_queries, recommended_ef_search (int or null), detail, and sweep (list of objects with ef_search, mean_recall_at_k, p50_latency_ms, p95_latency_ms, meets_target).
Example: recommend_hnsw_ef_search(schema='public', table='docs', column='embedding', k=10, target_recall=0.95)
Inputs: table (required), column (required), schema (required), k, +4 more. Returns: k, sweep, detail, metric, +6 more
recommend_index_dropsRecommend index dropsARead-only
Sibling of recommend_indexes for indexes to remove. Walks pg_stat_user_indexes + pg_stat_user_tables for existing indexes that look like pure cost — large on disk but never (or barely) scanned. Three reason codes, descending strength: never_used (no recorded idx_scans since the last stats reset — candidate for drop, but verify before removal), scan_no_fetch (planner picks it but it returns no rows — usually existence-check pattern), rarely_used (scan rate below low_scan_ratio of the table's total scan activity). Primary-key / unique / exclusion-constraint indexes are excluded (dropping those would be a schema change, not a performance win); indexes below min_index_size_bytes are skipped too. Returns a ready-to-run DROP INDEX CONCURRENTLY statement per candidate. Read-only advisor — execution is on the operator.
Example: recommend_index_drops(schema='public', min_index_size_bytes=1000000, low_scan_ratio=0.01)
Inputs: schema, database, low_scan_ratio, min_index_size_bytes. Returns: result
recommend_indexesRecommend indexesARead-only
Recommend tables that may benefit from indexing — large tables read mostly by sequential scan. Set fresh=true to bypass the cache and re-read live (e.g. after a schema change). Returns a list of objects with schema, table, live_tuples, sequential_scans, index_scans, and a reason explaining why the table is a candidate.
Example: recommend_indexes(min_live_tuples=10000)
Inputs: fresh, database, min_live_tuples. Returns: result
recommend_io_methodRecommend IO methodARead-only
Recommend a PG 19 io_method ('sync' / 'worker' / 'io_uring') for the current workload. Reads pg_stat_database aggregates (blks_read / blks_hit / stats_reset) and the current setting, then maps the workload signals to one of: high_concurrent_read_load (→ io_uring), bursty_io_with_cache_pressure (→ worker), low_io_pressure (→ sync), current_setting_optimal (no change), or insufficient_stats (window too short). Read-only — never invokes ALTER SYSTEM; emits a ready_to_run_sql snippet the operator can paste when the recommendation differs from the current setting. Returns an object with available (bool), server_version_num, detail, and recommendations — a list of objects with recommended_method, reason, current_method, cache_miss_ratio, reads_per_second, stats_window_seconds, and ready_to_run_sql (null when no change suggested).
Example: recommend_io_method()
Inputs: database. Returns: detail, available, recommendations, server_version_num
recommend_ivfflat_probesRecommend IVFFlat probesARead-only
Recommend an ivfflat.probes value for a target recall@k — the IVFFlat analogue of recommend_hnsw_ef_search. Samples sample_queries rows (default 10) as query vectors, builds an exact brute-force top-k ground truth per query, sweeps probe_values (default 1/2/5/10/20/50) measuring mean recall@k and p50/p95 latency at each, and recommends the smallest value clearing target_recall (default 0.95). VERIFIES an IVFFlat index actually exists on the column (returns has_ivfflat_index=false with guidance otherwise — a sweep without one just measures sequential scans). The query row is excluded from its own results. Requires the vector extension. Returns an object with available, has_ivfflat_index, index_name, metric, k, target_recall, sample_queries, recommended_probes (int or null), detail, and sweep (list of objects with probes, mean_recall_at_k, p50_latency_ms, p95_latency_ms, meets_target).
Example: recommend_ivfflat_probes(schema='public', table='docs', column='embedding', k=10, target_recall=0.95)
Inputs: table (required), column (required), schema (required), k, +4 more. Returns: k, sweep, detail, metric, +6 more
recommend_pg_search_maintenanceRecommend PG search maintenanceARead-only
Walk every pg_search BM25 index and emit advisor findings. Rules currently surfaced: missing_key_field (CRITICAL — the key_field reloption is required by upstream; an index without it can't satisfy queries) and no_field_configs (WARNING — none of the six *_fields reloptions are set, so the index falls back to default tokenization for every indexed column). Each finding carries a ready-to-run suggested_action SQL statement. Returns an empty list when the extension is not installed. Also feeds the pg_search BM25 Indexes category in audit_database.
Inputs: database. Returns: result
recommend_postgres_confRecommend Postgres confARead-only
Compute pgtune-style postgresql.conf recommendations. Pure calculator — touches no database. Given total_ram_mb (required), cpu_count (default 4), workload (one of web/oltp/dw/desktop/mixed, default mixed), storage (one of ssd/hdd/san, default ssd), and an optional max_connections override, returns recommended values for shared_buffers, effective_cache_size, work_mem, maintenance_work_mem, wal_buffers, min_wal_size/max_wal_size, checkpoint_completion_target, default_statistics_target, random_page_cost, effective_io_concurrency, and the parallel-worker knobs. Memory fields are postgres-ready strings; settings is the same data as a flat {guc: value} dict for direct rendering. Pair with audit_settings (audit first, then size).
Example: recommend_postgres_conf(total_ram_mb=16384, cpu_count=8, workload='oltp', storage='ssd')
Inputs: total_ram_mb (required), storage, workload, cpu_count, +1 more. Returns: object
recommend_prewarm_targetsRecommend prewarm targetsARead-only
Recommend relations whose first-query latency would benefit from pg_prewarm. Inspects pg_stat_user_tables + pg_statio_user_tables to find high cold-miss-rate / seq_scan-dominant relations, and caps the cumulative cost at shared_buffers_budget_pct * shared_buffers so the recommendation never silently exceeds shared_buffers. The advisor is read-only — never invokes pg_prewarm itself. Returns an object with shared_buffers_blocks (configured shared_buffers in 8 KiB pages), budget_blocks (the cap), total_cost_blocks (sum of recommendations actually returned), and candidates — a list of objects with schema, relation, reason (seq_scan_dominant / high_cold_miss_rate / small_hot_relation_uncached / index_in_critical_path), prewarm_mode, estimated_buffer_cost, heap_blks_read, heap_blks_hit, cache_miss_ratio, and ready_to_run_sql.
Example: recommend_prewarm_targets(shared_buffers_budget_pct=60.0, limit=10)
Inputs: limit, database, prewarm_mode, min_heap_blks_read, +1 more. Returns: candidates, budget_blocks, total_cost_blocks, shared_buffers_blocks
recommend_read_your_writesRecommend read your writesARead-only
Advise whether the caller should use WAIT FOR LSN for read-your-writes consistency. Combines server role (primary vs standby), replay lag, and PG version into a structured recommendation. Never raises. reason is one of primary_no_wait_needed, standby_no_lag, standby_lag_unknown, standby_with_lag, standby_pg18_or_older, unavailable. Returns an object with recommend_use (bool), reason, is_in_recovery, server_version_num, current_lag_bytes (int / null), and detail.
Example: recommend_read_your_writes()
Inputs: database. Returns: detail, reason, recommend_use, is_in_recovery, +2 more
recommend_redis_cache_targetsRecommend Redis cache targetsARead-only
Recommend tables that would benefit from a Redis cache layer. Inspects pg_stat_user_tables for read-heavy, low-write relations whose working set fits comfortably in Redis (default: read/write ratio ≥ 10, ≥ 1000 reads, ≤ 1M rows). When server is provided the generated ready_to_run_sql stub targets that server name; otherwise the stub uses a placeholder operators must substitute. Advisor is read-only — never touches Redis itself. Returns an object with server and candidates — a list of objects with schema, table, reads, writes, read_write_ratio, estimated_row_count, reason (read_only_lookup_table / small_hot_relation / read_heavy_low_write / moderate_read_dominant), and ready_to_run_sql (a CREATE FOREIGN TABLE stub).
Example: recommend_redis_cache_targets(server='redis_primary', limit=10)
Inputs: limit, server, database, max_rows, +2 more. Returns: server, candidates
recommend_redistributeRecommend redistributeARead-only
Distribution-skew advisor for a hash-distributed table. Reads pg_stats.n_distinct for every column on the table and suggests a better hash key when the current one is low-cardinality. Pure catalog read — no per-segment scans. Returns ranked candidates, optional recommendation, and ready-to-review suggested_ddl (ALTER TABLE … SET WITH (REORGANIZE=TRUE) DISTRIBUTED BY (col)). Diagnosis-only — never executes. On vanilla PG returns available=false.
Example: recommend_redistribute(schema='public', table='fact_sales')
Inputs: table (required), schema (required), database. Returns: table, detail, schema, available, +5 more
recommend_rerank_strategyRecommend rerank strategyARead-only
Roll-up advisor over the four analytics for one window. Returns a single headline summary + the full list of findings. Built from whichever combination of reranker_idle / topk_stable / score_clustering / rerank_hurts_ndcg / rerank_lifts_ndcg fires. Also feeds the RAG Reranker Pipeline category in audit_database. Reads from mcpg_rag.rerank_events.
Inputs: days, database, retrieval_index. Returns: summary, findings, window_days, retrieval_index
recommend_skip_scan_indexesRecommend skip scan indexesARead-only
Find composite B-tree indexes whose leading column has low NDV — these are the ones PG 19's skip-scan optimisation unlocks. Each candidate's trailing columns can now be served by the composite index alone, so any dedicated single-column indexes on those trailing columns become review candidates for recommend_index_drops. Returns an empty list on PG ≤ 18 or driver failure — pair with get_skip_scan_status for the diagnostic. max_leading_ndv (default 1000) caps the leading-column NDV that's considered low enough for skip-scan to be profitable. Returns a list of objects with schema, table, index_name, leading_column, trailing_columns (list of strings), estimated_leading_ndv (int), and rationale (human-readable explanation).
Example: recommend_skip_scan_indexes()
Inputs: database, max_leading_ndv. Returns: result
recommend_turboquant_maintenanceRecommend TurboQuant maintenanceARead-only
Walk every pg_turboquant index and emit advisor findings. Rules currently surfaced: prerequisites_unmet (CRITICAL — pgvector is missing) and delta_tier_large (WARNING — upstream's own delta_health.merge_recommended=true advisory, emits a tq_maintain_index suggested_action). Each finding carries a ready-to-run suggested_action SQL statement. Returns an empty list when the extension is not installed. Also feeds the pg_turboquant Indexes category in audit_database.
Inputs: database. Returns: result
recommend_turboquant_query_knobsRecommend TurboQuant query knobsARead-only
Run tq_recommended_query_knobs — per-query knob advisor. Two modes: plain (just candidate_limit + optional final_limit) gives generic recommendations; index-aware (supply both index_schema and index_name, plus optional filter_selectivity) specialises the recommendations to the named index's catalog state. Returns probes, oversample_factor, max_visited_codes, max_visited_pages — pass these to turboquant_approx_candidates / turboquant_rerank_candidates. Requires pg_turboquant.
Inputs: candidate_limit (required), database, index_name, final_limit, +2 more. Returns: probes, max_visited_codes, max_visited_pages, oversample_factor
recommend_vector_quantizationRecommend vector quantizationARead-only
Scan a schema for vector(N) columns whose storage could be halved by switching to pgvector v0.7+'s halfvec(N) type (16-bit float). Returns one recommendation per qualifying column with current vs suggested bytes, the savings ratio, and a one-line rationale. Skips columns that are already non-vector and small tables where the absolute saving wouldn't justify the migration.
Inputs: schema (required), database. Returns: result
retrieve_with_contextRetrieve with contextARead-only
Context-packed k-NN retrieval (a one-shot RAG building block). Runs a pgvector k-NN against schema.table.embedding_column for a caller-supplied query_vector (no embedding model needed), then expands each hit one hop along foreign keys and returns the hit row + its related parent / child records in one object. Parents (when include_parents, default true) are the rows a hit references via outbound FKs; children (when include_children, default true) are rows referencing the hit via inbound FKs, capped at max_related (default 5) per FK. Limitations: 1 hop only; inbound (child) expansion is same-schema only. The embedding column is dropped from every returned row. Requires the vector extension. Returns available, dimension, detail, and hits (each with distance, row, and related — a list of fk_name/direction/related_schema/related_table/rows).
Example: retrieve_with_context(schema='public', table='docs', embedding_column='embedding', query_vector=[0.1, 0.2, 0.3], k=5)
Inputs: table (required), schema (required), query_vector (required), embedding_column (required), +6 more. Returns: hits, detail, available, dimension
run_advisorsRun advisorsBRead-only
Run a set of catalog-driven advisor rules against a schema and return the aggregated findings. Rules cover missing primary keys, unindexed foreign keys, duplicate indexes, and nullable timestamps without time zone. Advisory only — no writes.
Inputs: schema (required), database. Returns: schema, findings, rules_run
run_analytical_queryRun analytical queryARead-only
Run a read-only SELECT that may take longer than the standard limit — for genuine analytical work (large aggregations, multi-table joins, window functions, DISTINCT/GROUP BY over millions of rows). Validated by the same allowlist as run_select, but executed on a DEDICATED connection pool (isolated from the fast-path tools) with an elevated, bounded timeout. Prefer run_select for ordinary queries; reach for this only when a query legitimately needs more time. timeout_ms overrides the per-call budget (clamped to the server's configured maximum, MCPG_ANALYTICAL_MAX_TIMEOUT_MS); work_mem (e.g. '256MB') elevates sort/hash memory for this statement. Runs against the primary database. Returns an object with columns, rows, row_count, and truncated (true when more rows than max_rows were produced) — same shape as run_select.
Example: run_analytical_query(sql='SELECT c, count(*) FROM big GROUP BY c', timeout_ms=180000)
Inputs: sql (required), max_rows, work_mem, timeout_ms. Returns: rows, columns, row_count, truncated
run_cypherRun CypherBRead-only
Execute an openCypher query on a specific graph database. Supports read queries (MATCH) and write/modifying queries (CREATE, SET, DELETE, MERGE, REMOVE). Returns an object with columns (list of result column names) and rows (list of result rows as dicts keyed by column).
Inputs: graph_name (required), cypher_query (required). Returns: object
run_pgqRun PGQARead-only
Execute a SQL/PGQ SELECT ... GRAPH_TABLE query and return the rows. The query must be a single SELECT (or WITH ... SELECT) statement that references GRAPH_TABLE — anything else is refused at the boundary (use run_select for non-graph reads). max_rows caps the result set; when the cap is hit, truncated=true. Requires PG 19+. Returns an object with columns (list of column names from the query's COLUMNS (...) clause), rows (list of dicts keyed by those columns), row_count, and truncated (bool).
Example: run_pgq(query="SELECT * FROM GRAPH_TABLE (org_chart MATCH (e:Employee)-[:REPORTS_TO]->(m:Manager) COLUMNS (e.name AS employee, m.name AS manager))", max_rows=50)
Inputs: query (required), database, max_rows. Returns: rows, columns, row_count, truncated
run_selectRun SELECTBRead-only
Validate and run a read-only SQL query. Writes, DDL, and other unsafe statements are rejected before execution.
Example: run_select(sql='SELECT id, email FROM users LIMIT 10', max_rows=1000)
Inputs: sql (required), database, max_rows. Returns: rows, columns, row_count, truncated
run_select_parallelRun SELECT parallelARead-only
Run up to parallel_limit read-only SELECTs concurrently. Each statement is validated by the same safety allowlist as run_select; one bad query does not abort the others — its error is captured in its own outcome slot. Useful for dashboard-style fan-out where round-trip latency dominates (e.g. fetching counters / aggregates from several tables at once). Each outcome includes an index so the caller can correlate results without relying on ordering.
Inputs: statements (required), database, max_rows, parallel_limit. Returns: outcomes
run_select_tunedRun SELECT tunedARead-only
Run a read-only SELECT with an elevated, bounded work_mem (and optionally maintenance_work_mem) for THIS statement only. Useful for heavy analytical SELECTs (large sorts / hash joins / GROUP BY) that spill to disk under the default work_mem. The knob is set via SET LOCAL inside the same read-only transaction, so it never leaks back into the pool. Both knobs must match ^\d+(kB|MB|GB)$ and are hard-capped at 2GB (unbounded values are an OOM risk). SQL is validated read-only by the same allowlist as run_select. SET LOCAL only affects transactional statements — non-transactional maintenance (CREATE INDEX CONCURRENTLY, VACUUM) is out of scope.
Example: run_select_tuned(sql='SELECT a, count(*) FROM big GROUP BY a', work_mem='256MB')
Inputs: sql (required), work_mem (required), database, max_rows, +1 more. Returns: rows, columns, row_count, truncated
summarize_tableSummarize tableARead-only
Return a one-stop snapshot of a table: columns, primary key, foreign keys, every other constraint, indexes, storage + row-count + last-vacuum/analyze stats, and (optionally) a short sample of rows. Replaces what would otherwise be 4-5 individual tool calls. Set sample_rows=0 on wide / jsonb-heavy tables where the sample isn't useful.
Example: summarize_table(schema='public', table='users', sample_rows=5)
Inputs: table (required), schema (required), database, sample_rows. Returns: stats, table, schema, columns, +5 more
test_rls_for_roleTest RLS for roleARead-only
Test what an RLS-bound role can read from a table. Reports whether RLS is enabled on the table, lists the policies that apply to the given role, counts the rows the role can read, and returns up to sample_size rows so the agent can inspect them. Runs as the target role inside a READ ONLY transaction — no writes can leak. Pure read.
Inputs: role (required), table (required), schema (required), database, +1 more. Returns: role, table, sample, schema, +4 more
translate_nl_to_sqlTranslate NL to SQLARead-only
Translate a natural-language question into a read-only PostgreSQL query against schema. The LLM provider (anthropic / openai / gemini / deepseek / qwen / openrouter / perplexity, plus any operator-declared custom OpenAI-compatible provider) sees a compact brief of the schema (tables, columns, foreign keys) and is instructed to return JSON with sql and explanation. When execute=true, the generated SQL goes through the SAME safety allowlist as run_select before running — writes / DDL / multi-statement input are rejected even if the model produced them. Returns the SQL, model rationale, and (when executed) rows / columns / row_count. table_filter narrows the brief to a known subset when the question is clearly scoped. provider, when supplied, selects which configured LLM provider to call (use this to route between the configured vendors per-call when multiple are configured); when omitted, MCPg uses the default (MCPG_NL2SQL_PROVIDER, otherwise the first available in preference order anthropic → openai → gemini → deepseek → qwen → openrouter → perplexity). Call get_server_info to see which providers are configured.
Example: translate_nl_to_sql(question='top 10 customers by revenue last month', schema='public', execute=true)
Inputs: schema (required), question (required), execute, database, +4 more. Returns: sql, rows, error, model, +10 more
tune_vector_indexTune vector indexARead-only
Recommend an ivfflat or hnsw configuration for a pgvector column. Reads the live row count and column dimension, applies the standard pgvector heuristics, and returns the parameters plus a ready-to-run CREATE INDEX statement. Requires the vector extension.
Inputs: table (required), column (required), schema (required), metric, +2 more. Returns: dimension, rationale, row_count, index_type, +2 more
turboquant_approx_candidatesTurboQuant approx candidatesARead-only
Run tq_approx_candidates against a turboquant index — approximate k-NN retrieval, no exact rerank. metric is 'cosine' | 'inner_product' | 'l2' (mapped to upstream's runtime metric text). half_precision=True switches to the halfvec overload. probes / oversample_factor are optional per-query knobs (consider calling recommend_turboquant_query_knobs first). Requires the pg_turboquant extension. Returns a list of candidate objects with candidate_id, approximate_distance, and approximate_rank.
Inputs: table (required), metric (required), schema (required), id_column (required), +7 more. Returns: result
turboquant_rerank_candidatesTurboQuant rerank candidatesBRead-only
Run tq_rerank_candidates against a turboquant index — approximate retrieval followed by SQL-side exact rerank to final_limit results. Returns the candidates with both approximate and exact ranks / distances. half_precision=True switches to the halfvec overload. Requires the pg_turboquant extension.
Inputs: table (required), metric (required), schema (required), id_column (required), +8 more. Returns: result
vector_range_searchVector range searchARead-only
Return every row within max_distance of a query vector (a threshold-based query rather than top-k). Useful for de-dup, similarity gating, and clustering pre-passes. Still ordered by distance and capped at limit to avoid pulling huge result sets. Reports available=false if the pgvector extension is not installed.
Inputs: table (required), column (required), schema (required), max_distance (required), +4 more. Returns: matches, available
vector_recall_at_kVector recall at kARead-only
Measure recall@k of an existing pgvector index against a brute-force ground truth (function-form distance, which pgvector documents as non-indexed). Returns the mean overlap over a sample of rows from the table. Requires the vector extension.
Inputs: table (required), column (required), schema (required), id_column (required), +4 more. Returns: k, metric, mean_recall, sample_size
vector_searchVector searchARead-only
Find the rows nearest to a query vector by pgvector distance (metric: l2, cosine, or inner_product). Reports available=false if the pgvector extension is not installed.
Example: vector_search(schema='public', table='docs', column='embedding', query_vector=[0.1, 0.2, ...], metric='cosine', limit=10)
Inputs: table (required), column (required), schema (required), query_vector (required), +3 more. Returns: matches, available
verify_audit_chainVerify audit chainARead-only
Verify the HMAC-SHA256 signature chain of persisted audit events in mcpg_audit.events. Returns an object with verified (bool), events_checked (int), the first_event_id and last_event_id covered by the walk, and (on failure) error and first_invalid_id pointing at where the chain broke.
Inputs: database. Returns: object
verify_connection_encryptionVerify connection encryptionARead-only
Report whether MCPg's own connection to PostgreSQL is TLS-encrypted, including the negotiated protocol version, cipher, and key bits (from pg_stat_ssl). Also returns a cluster-wide tally of encrypted vs unencrypted backends (a lower bound under non-superuser privileges). Complements the startup TLS-enforcement check by confirming the live connection actually came up encrypted.
Inputs: database. Returns: ssl, bits, cipher, version, +3 more
wait_for_lsnWait for LSNARead-only
Issue WAIT FOR LSN '<lsn>' TIMEOUT <ms> and block until WAL replay catches up on the connected backend. timeout_ms defaults to 0 (wait indefinitely); a positive value bounds the wait — on timeout the helper returns timed_out=true rather than raising so the caller can decide whether to retry or fall through. LSN format is strictly validated (hex/hex) before any SQL is composed. Requires PG 19+; raises on older servers with the poll-loop fallback in the message. Returns an object with lsn, timeout_ms (int), timed_out (bool), and wait_sql (the rendered statement).
Example: wait_for_lsn(lsn='0/1234ABCD', timeout_ms=5000)
Inputs: lsn (required), database, timeout_ms. Returns: lsn, wait_sql, timed_out, timeout_ms
walk_blocking_chainsWalk blocking chainsCRead-only
Walk and reconstruct the lock-wait graph of the database. Detects deadlock cycles, traces linear blocking paths to their root blockers, and renders a Mermaid flowchart representing the lock dependency graph. Read-only. Returns an object with cycles (list of detected cycle PID lists), paths (linear blocking paths as PID lists), roots (root blocker PIDs), nodes (dict keyed by PID with per-backend lock detail), and mermaid (the pre-rendered flowchart string).
Inputs: limit, database. Returns: nodes, paths, roots, cycles, +1 more
why_is_this_slowWhy is this slowARead-only
Diagnose why a SQL query might be slow, in one call. Runs EXPLAIN (FORMAT JSON) — does NOT execute the query — walks the plan tree, snapshots concurrent active queries + blocking lock pairs, reads the cluster-wide cache hit ratio, and produces categorised suggestions (plan / contention / cache / maintenance). Read-only; safe to run on a statement the agent doesn't want to materialise yet.
Example: why_is_this_slow(sql='SELECT * FROM orders WHERE customer_id = 42')
Inputs: sql (required), database. Returns: sql, suggestions, explain_plan, plan_summary, +3 more
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 191 tools
The surface contains many overlapping clusters: run_select / run_analytical_query / run_select_tuned / run_select_parallel, explain_query / analyze_query_plan / why_is_this_slow / optimize_query, and numerous recommend_* / audit_* / status-probe tools. Descriptions are detailed and often cross-reference each other, but with 191 tools the boundaries are still hard for an agent to hold reliably, leading to likely misselection.
All tool names use snake_case and the dominant pattern is verb_noun (list_tables, describe_table, recommend_indexes, get_server_info). There are minor noun-first deviations such as vector_search, hybrid_search, and pg_search_run, but the overall convention remains readable and mostly consistent.
191 tools is an extreme mismatch for a single MCP server surface, even for a broad PostgreSQL administration product. The catalogue should be split into focused servers or packs; as one set, discovery and selection cost is overwhelming and each tool no longer clearly earns its place.
The read-only introspection, advisor, and diagnostics surface is extremely deep, but core lifecycle operations are absent: there are no write/DDL/transaction tools. Multiple descriptions explicitly point agents to run_write, prepare_migration, validate_migration_schema, alter_system, run_maintenance, and list_tools, none of which appear in this catalogue, creating dead ends.
Maintenance
Related MCP Connectors
Hosted PostgreSQL MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
Analytical memory for AI agents: a real Postgres queried in plain English over MCP. One command.
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
Versioned agent memory in your own Postgres: portable context, permissioned, audit trail.
Related MCP Servers
- AlicenseBqualityAmaintenanceUniversal database MCP server connecting to MySQL, PostgreSQL, SQLite, DuckDB and etc.217 npm3,855MIT
- AlicenseBqualityDmaintenanceA Model Context Protocol server that enables powerful PostgreSQL database management capabilities including analysis, schema management, data migration, and monitoring through natural language interactions.184,718 npm204AGPL 3.0

Prisma MCP Serverofficial
AlicenseNot gradedqualityBmaintenanceManage Prisma Postgres databases with ease41 npm47,670Apache 2.0- AlicenseNot gradedqualityDmaintenanceA Model Context Protocol server that provides AI assistants with secure, read-only access to PostgreSQL databases while offering comprehensive tools for schema exploration, query validation, and performance optimization.MIT