Skip to main content
Glama
MCPg - Production-grade PostgreSQL MCP Server

MCPg - Production-grade PostgreSQL MCP Server

MCPg

MCP Toplist

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.

PyPI version Python versions License: MIT CI OpenSSF Scorecard OpenSSF Best Practices Stars MCPg MCP server AllMCPs Verified MCPVault: claimed Listed on MCP ServerList MCP Tutorial

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

pip install mcpg

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/NOTIFY are off until you opt in. Every tool publishes MCP ToolAnnotations (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 psycopg3 directly, speaks every pg_* system view, integrates with TimescaleDB, pgvector, PostGIS, Apache AGE, and pg_stat_statements where they're available, and degrades gracefully when they aren't.

  • Production-shaped, not demo-shaped. Connection pooling, per-request SET ROLE multi-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 /metrics endpoint on the HTTP transport surfaces mcpg_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

pip install mcpg
# or, in an isolated venv exposed globally:
uv tool install mcpg

Verify:

mcpg --version

Docker

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:latest

On 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.git

Multi-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 sync

uv 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: Add to Cursor Install in VS Code Claude Desktop — 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 --demo

One 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 \
mcpg

Then 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

MCPG_DATABASE_URL

Read-write app data access

MCPG_ACCESS_MODE=restricted

DBA toolkit (DDL, vacuum, etc.)

MCPG_ACCESS_MODE=unrestricted + MCPG_ALLOW_DDL=true

HTTP transport with bearer auth

MCPG_TRANSPORT=streamable-http + MCPG_HTTP_AUTH_TOKEN=…

Multi-tenant SaaS

MCPG_DEFAULT_ROLE=tenant_a + MCPG_ALLOWED_ROLES=tenant_a,tenant_b,…

Read-replica fan-out

MCPG_REPLICA_URLS=postgresql://…?sslmode=require,postgresql://…?sslmode=require

NL→SQL — single provider

Set any one vendor key (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, XAI_API_KEY, GROQ_API_KEY, HF_TOKEN, … — 22 built-in providers). MCPg auto-picks the default.

NL→SQL — multiple providers, caller picks

Set all vendor keys you want active. Each call to translate_nl_to_sql can pass provider="…" (any configured built-in or custom).

Full reference

Core

Variable

Default

Description

MCPG_DATABASE_URL

required

Primary PostgreSQL DSN. Supports URI (postgresql://…) and keyword (host=… user=…) forms. Remote hosts require sslmode=require (or stronger).

MCPG_ACCESS_MODE

read-only

read-only | restricted (allows write tools) | unrestricted (also unlocks DBA tools when paired with the gate vars).

MCPG_TRANSPORT

stdio

stdio (default, for Claude Desktop) | streamable-http | sse.

MCPG_LOG_LEVEL

INFO

DEBUG | INFO | WARNING | ERROR | CRITICAL.

MCPG_HTTP_HOST

127.0.0.1

Bind address for HTTP transports. Set to 0.0.0.0 inside containers.

MCPG_HTTP_PORT

8000

Listen port for HTTP transports (1–65535).

Capability gates (opt-in for higher-blast-radius tools)

Variable

Default

Description

MCPG_ALLOW_DDL

false

Expose DDL tools (run_ddl, create_graph, drop_graph, hypertable tools, migration tools). Requires MCPG_ACCESS_MODE=unrestricted.

MCPG_ALLOW_SHELL

false

Expose subprocess-backed tools (dump_database, restore_database, run_pg_binary). Required PG client binaries must be on PATH.

MCPG_ALLOW_TIMESCALEDB_ADMIN

false

With unrestricted mode + MCPG_ALLOW_DDL, expose the destructive / heavy TimescaleDB tools (drop_chunks, compress_chunk, decompress_chunk, reorder_chunk, merge_chunks, refresh_continuous_aggregate, run_job, alter_job, delete_job); each needs dry_run then confirm=true + confirmation_token. See docs/timescaledb.md.

MCPG_ALLOW_ALTER_SYSTEM

false

Expose alter_system, alter_system_reset_all, reload_config (unrestricted mode only; two-step confirm=true flow — see docs/alter-system.md). MCPG_ALTER_SYSTEM_ALLOWLIST / MCPG_ALTER_SYSTEM_DENYLIST (comma-separated GUC names) narrow or extend the built-in denylist.

MCPG_ALLOW_LISTEN

false

Expose LISTEN/NOTIFY tools (subscribe_channel, poll_notifications, unsubscribe_channel, list_notification_subscriptions).

Authentication (HTTP transports only)

Variable

Default

Description

MCPG_AUTH_MODE

static

static (compare bearer to MCPG_HTTP_AUTH_TOKEN) | oidc (full JWT validation).

MCPG_HTTP_AUTH_TOKEN

—

Required bearer token when MCPG_AUTH_MODE=static. Constant-time compare. The HTTP transport refuses to start (ConfigError) unless this, MCPG_AUTH_MODE=oidc, or MCPG_HTTP_ALLOW_UNAUTHENTICATED=true is set.

MCPG_HTTP_ALLOW_UNAUTHENTICATED

false

Explicit opt-out of the HTTP transport's fail-closed auth check. Loudly logged on every startup when set; not recommended.

MCPG_OIDC_ISSUER

—

OIDC issuer URL (required when MCPG_AUTH_MODE=oidc).

MCPG_OIDC_AUDIENCE

—

Expected aud claim (required when MCPG_AUTH_MODE=oidc).

MCPG_OIDC_JWKS_URL

discovered

Override JWKS endpoint (auto-discovered from issuer's .well-known otherwise).

MCPG_OIDC_ROLE_CLAIM

—

JWT claim whose value becomes the per-request PG role (SET LOCAL ROLE). Composes with the tenancy driver.

HTTP hardening (HTTP transports only)

Variable

Default

Description

MCPG_HTTP_MAX_BODY_BYTES

1048576

(1 MiB) Request bodies above this get a 413. Counts streamed bytes, so a missing/lying Content-Length can't bypass it.

MCPG_HTTP_ALLOWED_ORIGINS

—

Comma-separated CORS allowlist. Unset = no CORS middleware (no cross-origin headers emitted).

MCPG_HTTP_HSTS_MAX_AGE

63072000

Strict-Transport-Security max-age (2 years, OWASP's current recommendation). 0 disables the HSTS header. Security headers (CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy) are always added unless the app already set them.

MCPG_HTTP_REQUEST_TIMEOUT_SECONDS

0

Per-request wall-clock cap (504 on expiry). 0 = disabled. Leave off if you rely on long-lived SSE / streamable-http streams — a hard cap also severs those.

MCPG_HTTP_TRUSTED_HOSTS

—

Comma-separated list of allowed Host header values (wildcards like *.example.com supported). Unset = no host-header validation (current behaviour). When set, requests with a non-matching Host get a 400 via Starlette's TrustedHostMiddleware.

Multi-tenancy (SET ROLE)

Variable

Default

Description

MCPG_DEFAULT_ROLE

—

Static PG role applied to every query. Identifier-validated.

MCPG_ALLOWED_ROLES

—

Comma-separated allowlist. When set, the X-MCPG-Role header / OIDC role claim must be in this list.

Read replicas

Variable

Default

Description

MCPG_REPLICA_URLS

—

Comma-separated replica DSNs. force_readonly queries round-robin across healthy replicas; primary fallback on failure; 30 s degraded-replica retry window.

Multiple databases (read-only secondaries)

Variable

Default

Description

MCPG_SECONDARY_DATABASE_URLS

—

Comma- or newline-separated name=dsn entries naming additional read-only databases this one server can serve (e.g. analytics=postgresql://…?sslmode=require,reporting=postgresql://…?sslmode=require). Read-capable tools accept an optional database argument selecting a secondary by name; omit it for the primary. Secondaries are read-only — PostgreSQL-enforced (every query runs in a READ ONLY transaction), so writes / DDL / shell / migrate always target the primary. Names must be simple identifiers ([a-z0-9_]+), unique, and not primary (the reserved id of MCPG_DATABASE_URL). Same TLS rules as the primary DSN. Call list_databases to discover the configured ids and their reachability.

Pool / timeouts / TLS

Variable

Default

Description

MCPG_POOL_MIN_SIZE

1

Minimum pool connections.

MCPG_POOL_MAX_SIZE

5

Maximum pool connections. Must be ≥ MCPG_POOL_MIN_SIZE.

MCPG_STATEMENT_TIMEOUT_MS

30000

Per-session statement_timeout set on connection checkout. Runaway queries self-terminate.

MCPG_LOCK_TIMEOUT_MS

5000

Per-session lock_timeout. Hanging lock waits self-terminate.

MCPG_ENABLE_ANALYTICAL_QUERIES

true

Expose run_analytical_query (long-running reads on an isolated pool). Set false to withdraw the tool.

MCPG_ANALYTICAL_TIMEOUT_MS

120000

Default per-call budget for run_analytical_query (2 min).

MCPG_ANALYTICAL_MAX_TIMEOUT_MS

600000

Hard ceiling for run_analytical_query; a per-call timeout_ms is clamped to this (10 min). Must be ≥ MCPG_ANALYTICAL_TIMEOUT_MS.

MCPG_ANALYTICAL_MAX_CONCURRENCY

2

Size of the isolated analytical pool — max simultaneous run_analytical_query calls.

MCPG_ALLOW_INSECURE_TLS

false

Bypass the startup TLS check that refuses remote DSNs without sslmode=require (or stronger). Loopback hosts are always exempt.

MCPG_SHUTDOWN_DRAIN_SECONDS

30

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

MCPG_SHELL_TIMEOUT_SEC

60

Max wall-clock for pg_dump / pg_restore / psql invocations.

MCPG_SHELL_MAX_OUTPUT_BYTES

67108864

(64 MiB) Cap on captured stdout per subprocess call.

MCPG_SUBPROCESS_BIN_ALLOWLIST

—

Comma-separated absolute dirs the resolved pg_dump / pg_restore / psql must live under. Empty = trust PATH. Defeats a PATH-shim of these binaries.

MCPG_SUBPROCESS_CPU_SECONDS

—

Per-child RLIMIT_CPU (seconds). POSIX only; unset = inherit.

MCPG_SUBPROCESS_MEMORY_MB

—

Per-child RLIMIT_AS (MiB). POSIX only; unset = inherit.

LISTEN/NOTIFY (MCPG_ALLOW_LISTEN=true only)

Variable

Default

Description

MCPG_LISTEN_QUEUE_MAX

1000

Per-channel buffer; oldest notifications dropped on overflow.

Audit

Variable

Default

Description

MCPG_AUDIT_PERSIST

false

When true, every run_write / run_ddl call persists to a mcpg_audit.events table (auto-created idempotently).

MCPG_AUDIT_REDACT_KEYS

—

Comma-separated regex fragments added to the secret-name pattern (defaults already cover password, passwd, secret, token, api[_-]?key, bearer, authorization, database_url, dsn, conninfo).

MCPG_AUDIT_INTEGRITY

false

When true, each persisted event is signed with an HMAC chained over the previous event; the verify_audit_chain tool walks the chain and reports the first break. Requires MCPG_AUDIT_HMAC_KEY.

MCPG_AUDIT_HMAC_KEY

—

Secret key for the audit HMAC chain. Required when MCPG_AUDIT_INTEGRITY=true. Never appears in repr/logs.

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

MCPG_SECRETS_BACKEND

env

env (read every secret from the environment) | file (overlay a secrets file on top of the environment).

MCPG_SECRETS_FILE_PATH

—

Required when MCPG_SECRETS_BACKEND=file. Path to a flat name → value map: JSON always, or YAML (.yaml/.yml) when PyYAML is installed. Covers ANTHROPIC_API_KEY / OPENAI_API_KEY / GEMINI_API_KEY / GOOGLE_API_KEY / MCPG_NL2SQL_API_KEY, MCPG_HTTP_AUTH_TOKEN, and MCPG_AUDIT_HMAC_KEY.

Rate limiting

Variable

Default

Description

MCPG_RATE_LIMIT_ENABLED

true

Token-bucket per-tool rate limiting. Set to false to restore the pre-breaking-change unlimited behavior.

MCPG_RATE_LIMIT_MAX_REQUESTS

60

Global cap per window across all tools.

MCPG_RATE_LIMIT_WINDOW_SECONDS

60

Window length for the global quota.

MCPG_RATE_LIMIT_HEAVY_MAX

5

Cap for heavy tools (run_write, run_ddl, dump_database, etc.).

MCPG_RATE_LIMIT_HEAVY_WINDOW

60

Window length for the heavy-tool quota.

Caching & Feature flags

Variable

Default

Description

MCPG_CACHE_ENABLED

true

Enable or disable the adaptive cache layer.

MCPG_CACHE_TTL_SECONDS

300

Default cache Time-To-Live in seconds.

MCPG_CACHE_MAXSIZE

1024

Maximum LRU capacity bound for the memory cache.

MCPG_REDIS_URL

—

Optional Redis backend connection string for external, multi-node caching.

MCPG_ENABLE_HEAVY_DIAGNOSTICS

true

Toggle computationally heavy diagnostic, diagram, and advisor tools.

MCPG_ELICIT_CONFIRM_WRITES

false

When true, every write/DDL/shell/listen/migrate-tier tool call (any tool whose readOnlyHint annotation isn't true) requires an accepted interactive confirmation (ctx.elicit()) before running. Best-effort, not an enforcement boundary: it only engages for clients that both pass a request context and declare the elicitation capability during initialize — a client that omits either silently bypasses the gate and the tool runs as normal.

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

<VENDOR>_API_KEY

—

Setting a vendor's conventional key enables that provider. Standard slugs: ANTHROPIC_API_KEY, OPENAI_API_KEY, DEEPSEEK_API_KEY, OPENROUTER_API_KEY, PERPLEXITY_API_KEY, XAI_API_KEY, GROQ_API_KEY, MISTRAL_API_KEY, TOGETHER_API_KEY, FIREWORKS_API_KEY, CEREBRAS_API_KEY, NEBIUS_API_KEY, SAMBANOVA_API_KEY, MOONSHOT_API_KEY.

(keys that deviate)

—

A few vendors don't follow <VENDOR>_API_KEY: Gemini → GEMINI_API_KEY or GOOGLE_API_KEY; Qwen → DASHSCOPE_API_KEY or QWEN_API_KEY; Hugging Face → HF_TOKEN; GitHub Models → GITHUB_TOKEN; DeepInfra → DEEPINFRA_TOKEN.

MCPG_NL2SQL_PROVIDER

auto-picked

Any built-in slug (listed above) or a custom name. Pins the default provider used when the tool is called without provider=. Unset + any vendor key present → MCPg auto-picks in registry order.

MCPG_NL2SQL_API_KEY

—

Explicit key for the configured MCPG_NL2SQL_PROVIDER. Overrides the vendor-conventional env var for that provider only. Requires MCPG_NL2SQL_PROVIDER to be set.

MCPG_NL2SQL_MODEL

provider default

Override the default model (e.g. claude-sonnet-4-6, gpt-4o-mini, grok-3-mini). Applies only to the default provider.

MCPG_NL2SQL_BASE_URL

—

Endpoint override for the default provider (private gateways / regional endpoints).

MCPG_NL2SQL_CUSTOM_PROVIDERS

—

Bring your own provider — no code change. Comma/newline-separated name=base_url|model entries declaring extra OpenAI-compatible providers beyond the built-ins (local Ollama / vLLM / LM Studio, or any niche vendor). Key from <NAME>_API_KEY by convention, or append |KEY_ENV_VAR for ones that deviate; keyless allowed for loopback endpoints. Each name becomes callable via provider=.

MCPG_NL2SQL_MAX_TOKENS

2048

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 public schema, 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 ANALYZE shows a sequential scan over orders (4.7M rows) filtered by created_at. There's no index on orders.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). Run validate_migration on 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 public schema.

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 — see optimize_query).

Run a guarded write

You: Soft-delete every order older than 5 years.

Agent (using run_write with MCPG_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) to mcpg_audit.events for 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 of ON DELETE CASCADE), generate_graph_diagram (Apache AGE property graphs).

  • Structural diff & migrations — compare_schemas, validate_migration, staged prepare_migration / complete_migration / cancel_migration workflow.

  • 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_cursors for 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_subscriptions bridging PostgreSQL LISTEN/NOTIFY into the MCP poll model.

  • Observability — Prometheus /metrics endpoint + get_metrics_exposition tool for stdio; structured audit trail with regex-based credential redaction.


Documentation


Security

  • Vulnerability reporting: see SECURITY.md. 90-day coordinated-disclosure window; reports to devopam@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.md for 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 pg_search are subject to AGPL's network clause — typically the obligation to offer the source of pg_search (and any modifications) to those users. MCPg's wrappers don't extend that obligation to MCPg itself; you take on the obligation when you deploy and "convey" the extension over a network. If your service redistribution model is incompatible with AGPL's network clause, pick a different BM25 implementation (the BM25 plan lists alternatives).

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 tools
analyze_distance_metricAnalyze distance metricA
Read-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 recallB
Read-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 hotspotsA
Read-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 planA
Read-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 planA
Read-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 liftA
Read-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 NDCGA
Read-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 distributionA
Read-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 costA
Read-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 bloatA
Read-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 stabilityB
Read-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 efficiencyA
Read-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 workloadA
Read-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 databaseA
Read-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 sequencesA
Read-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 settingsA
Read-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 healthB
Read-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 readinessA
Read-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 healthA
Read-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 cursorB
Read-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 vectorsA
Read-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 schemasA
Read-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 similarityA
Read-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 tableA
Read-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 graphB
Read-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 graphA
Read-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 tableA
Read-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 selfA
Read-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 tableA
Read-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 toolA
Read-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 oneA
Read-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 outliersA
Read-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 queryA
Read-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 queryA
Read-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 tableA
Read-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 cursorA
Read-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 chainsB
Read-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 columnsA
Read-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 objectsA
Read-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

generate_diesel_schemaGenerate Diesel schemaA
Read-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 schemaA
Read-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 schemasA
Read-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 schemasA
Read-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 graphA
Read-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 diagramB
Read-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 projectionA
Read-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 configA
Read-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 schemaA
Read-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 diagramA
Read-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 docsA
Read-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 modelsA
Read-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 schemaA
Read-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 dataA
Read-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 forA
Read-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

get_aio_statusGet AIO statusA
Read-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 schemaA
Read-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 LSNA
Read-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 DDLA
Read-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 statusA
Read-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 statsA
Read-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 statusA
Read-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 expositionA
Read-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 statusA
Read-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 statusA
Read-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 statusA
Read-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 statusA
Read-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 metadataA
Read-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 statusA
Read-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 statsA
Read-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 statusA
Read-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 DDLA
Read-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 infoA
Read-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 statusA
Read-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 DDLA
Read-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 reportA
Read-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 statsB
Read-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 metadataA
Read-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 statsA
Read-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 statusA
Read-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 statusA
Read-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 statusA
Read-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

inspect_gucInspect gucA
Read-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 conventionsA
Read-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 queriesA
Read-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 eventsA
Read-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 jobsA
Read-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 extensionsA
Read-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 chunksA
Read-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 typesB
Read-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 constraintsA
Read-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 aggregatesB
Read-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 jobsA
Read-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 cursorsA
Read-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 databasesA
Read-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 policiesA
Read-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 domainsB
Read-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 enumsB
Read-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 extensionsA
Read-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 wrappersB
Read-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 keysA
Read-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 serversA
Read-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 tablesA
Read-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 functionsA
Read-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 columnsA
Read-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 grantsA
Read-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 graphsA
Read-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 hypertablesA
Read-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 indexesA
Read-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 locksB
Read-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 partitionsB
Read-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 indexesA
Read-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 policiesA
Read-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 relationsA
Read-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 graphsA
Read-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 publicationsA
Read-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 serversA
Read-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 replicasA
Read-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 groupsA
Read-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 rolesA
Read-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 schemasA
Read-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 sequencesA
Read-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 subscriptionsA
Read-only

List logical-replication subscriptions; requires superuser to see any rows.

Inputs: database. Returns: result

list_tablesList tablesB
Read-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 jobsA
Read-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 triggersB
Read-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 indexesA
Read-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 mappingsB
Read-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 viewsA
Read-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 halfvecA
Read-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

monitor_embedding_driftMonitor embedding driftA
Read-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 buildA
Read-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 cursorA
Read-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 queryB
Read-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 thisA
Read-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 queryA
Read-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 runA
Read-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 priorityA
Read-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 historyA
Read-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 relationsA
Read-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 summaryA
Read-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 IOA
Read-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 lockA
Read-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 recoveryA
Read-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 recordsA
Read-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 statsB
Read-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 thresholdsA
Read-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 toolsA
Read-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_index_dropsRecommend index dropsA
Read-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 indexesA
Read-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 methodA
Read-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 probesA
Read-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 maintenanceA
Read-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 confA
Read-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 targetsA
Read-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 writesA
Read-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 targetsA
Read-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 redistributeA
Read-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 strategyA
Read-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 indexesA
Read-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 maintenanceA
Read-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 knobsA
Read-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 quantizationA
Read-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 contextA
Read-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 advisorsB
Read-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 queryA
Read-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 CypherB
Read-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 PGQA
Read-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 SELECTB
Read-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 parallelA
Read-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 tunedA
Read-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 tableA
Read-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 roleA
Read-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 SQLA
Read-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 indexA
Read-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 candidatesA
Read-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 candidatesB
Read-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_recall_at_kVector recall at kA
Read-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

verify_audit_chainVerify audit chainA
Read-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 encryptionA
Read-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 LSNA
Read-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 chainsC
Read-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 slowA
Read-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

    B3.2/5.0

    Scored across 191 tools

    Disambiguation2/5

    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.

    Naming Consistency4/5

    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.

    Tool Count1/5

    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.

    Completeness2/5

    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

    ActivityNo data
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      B
      quality
      D
      maintenance
      A Model Context Protocol server that enables powerful PostgreSQL database management capabilities including analysis, schema management, data migration, and monitoring through natural language interactions.
      18
      4,718 npm
      204
      AGPL 3.0
    • A
      license
      Not graded
      quality
      D
      maintenance
      A 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