Skip to main content
Glama
query-executor

query-executor

Query Executor MCP Server

A Model Context Protocol server that gives AI agents read (and optionally write) access to one or more PostgreSQL databases. Each database is registered as a named project — the agent picks the right one per call via project_id.


How it works

flowchart TD
    A[AI Agent\nClaude / Cursor / etc.] -->|MCP stdio| B[Query Executor\nMCP Server]

    B --> C{Resolve project_id}
    C -->|default| D[(default DB)]
    C -->|project-alpha| E[(project-alpha DB)]
    C -->|project-beta| F[(project-beta DB)]

    subgraph Tools
        T1[describe_postgres_schema]
        T2[execute_postgres]
        T3[explain_postgres]
        T4[pg_stat_statements]
    end

    B --> Tools
    Tools --> C
sequenceDiagram
    participant Agent
    participant Server as MCP Server
    participant Config as databases.json
    participant DB as PostgreSQL

    Agent->>Server: tool call (project_id, sql)
    Server->>Config: resolve project_id → DSN + mode
    Config-->>Server: { dsn, mode }
    alt mode = readonly
        Server->>Server: assert first token is SELECT/WITH
    end
    Server->>DB: execute query
    DB-->>Server: rows
    Server-->>Agent: JSON { rows, row_count }

Related MCP server: mcp-postgres

Features

  • Multi-project — connect to any number of PostgreSQL databases simultaneously; each call targets one via project_id

  • Per-project mode — readonly blocks all writes at the first SQL token; readwrite allows all SQL

  • Safe fallback — omitting project_id routes to the configured default project

  • Four tools — schema inspection, query execution, EXPLAIN ANALYZE, and slow-query analysis

  • stdio transport — works with any MCP client (Claude Desktop, Cursor, Claude Code, etc.)

  • Docker-ready — single image, credentials baked in at build time from gitignored files


Project layout

query-executor/
├── Dockerfile
├── Makefile
├── pyproject.toml
├── uv.lock
├── main.py                     # connection check entrypoint
├── .env                        # gitignored — copy from .env.example
├── databases.json              # gitignored — copy from databases.example.json
├── .env.example
├── databases.example.json
└── query_executor/
    ├── config.py               # loads .env + databases.json; single source of truth
    ├── query_connector.py      # raw asyncpg functions (no MCP imports)
    ├── tools.py                # Pydantic input models + tool implementations
    └── server.py               # FastMCP bootstrap + entrypoint

Quick start

Requires: UV and Docker.

1. Install dependencies

uv sync

2. Configure

cp .env.example .env
cp databases.example.json databases.json

Edit databases.json with your real connection strings:

{
  "default": {
    "dsn": "postgresql://user:password@localhost:5432/mydb",
    "mode": "readonly"
  },
  "staging": {
    "dsn": "postgresql://user:password@staging-host:5432/stagingdb",
    "mode": "readwrite"
  }
}

mode

Behaviour

readonly

Only SELECT / WITH queries are allowed. Any write or DDL raises an error before reaching the database.

readwrite

All SQL is permitted. Use only on non-production databases.

If a project does not specify mode, it defaults to readonly.

3. Check connections

make check
Welcome to Query Executor!
  Default project : default
    • default  [readonly] (default)
    • staging  [readwrite]

Testing database connections...
  [default]  mode=readonly  ... OK — PostgreSQL 15.4
  [staging]  mode=readwrite ... OK — PostgreSQL 15.4

All 2 connection(s) OK.

4. Build the Docker image

make build

MCP client configuration

The server runs over stdio — the MCP client spawns the process and communicates via stdin/stdout.

Claude Desktop

Config file: ~/Library/Application Support/Claude/claude_desktop_config.json

With UV (local):

{
  "mcpServers": {
    "query-executor": {
      "command": "uv",
      "args": ["run", "python", "-m", "query_executor.server"],
      "cwd": "/Users/niteshnandan/workspace/2026/query-executor"
    }
  }
}

With Docker:

{
  "mcpServers": {
    "query-executor": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "query-executor"]
    }
  }
}

Cursor

Global config: ~/.cursor/mcp.json
Project config: .cursor/mcp.json

With UV (local):

{
  "mcpServers": {
    "query-executor": {
      "command": "uv",
      "args": ["run", "python", "-m", "query_executor.server"],
      "cwd": "/Users/niteshnandan/workspace/2026/query-executor"
    }
  }
}

With Docker:

{
  "mcpServers": {
    "query-executor": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "query-executor"]
    }
  }
}

Claude Code

Add to your project's .claude/mcp.json:

With UV (local):

{
  "mcpServers": {
    "query-executor": {
      "type": "stdio",
      "command": "uv",
      "args": ["run", "python", "-m", "query_executor.server"],
      "cwd": "/Users/niteshnandan/workspace/2026/query-executor"
    }
  }
}

With Docker:

{
  "mcpServers": {
    "query-executor": {
      "type": "stdio",
      "command": "docker",
      "args": ["run", "-i", "--rm", "query-executor"]
    }
  }
}

Note: Replace /Users/niteshnandan/workspace/2026/query-executor with the actual path on your machine if sharing config with others.


Tools reference

describe_postgres_schema

Inspect tables, columns, foreign keys, and indexes for a given schema.

Call this first before writing any query — it gives you exact column names and types so you write correct SQL on the first attempt.

Parameter

Type

Default

Description

postgres_schema

string

"public"

Schema to inspect

project_id

string

default project

Target database

Returns { columns, foreign_keys, indexes }.


execute_postgres

Run a SQL query and get rows back as JSON.

Parameter

Type

Required

Description

sql

string

yes

SQL to execute. In readonly mode only SELECT/WITH are allowed.

project_id

string

no

Target database

Returns { rows: [...], row_count: N }.


explain_postgres

Run EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) on a query and return the execution plan.

Parameter

Type

Required

Description

sql

string

yes

SELECT query to analyse (do not include EXPLAIN)

project_id

string

no

Target database

Returns { plan: [...] }. Key things to check in the plan:

  • Seq Scan on a large table → missing index on the WHERE column

  • Actual rows ≫ Plan rows → stale statistics; run ANALYZE <table>

  • High shared_blks_read → I/O-bound; working set does not fit in shared_buffers


pg_stat_statements

Return the top N query patterns ranked by total cumulative execution time.

Parameter

Type

Default

Description

limit

integer

20

Number of queries to return (max 100)

project_id

string

no

Target database

Returns rows with total_exec_sec, mean_exec_sec, max_exec_sec, calls, shared_blks_hit, shared_blks_read.

Requires the pg_stat_statements extension. Enabled by default on AWS RDS, GCP Cloud SQL, and Supabase. On self-hosted Postgres: CREATE EXTENSION pg_stat_statements;


Explore an unknown database

describe_postgres_schema → execute_postgres

Debug a slow query

describe_postgres_schema  (check what indexes exist)
→ explain_postgres        (verify the planner uses them)
→ execute_postgres        (run once plan looks correct)

Performance audit

pg_stat_statements        (find the most expensive patterns)
→ explain_postgres        (drill into the worst offender)
→ describe_postgres_schema (check if a missing index would help)

Environment variables

Variable

Default

Description

DATABASES_FILE

databases.json

Path to the databases registry file

DEFAULT_PROJECT

default

Fallback project when project_id is omitted

LOG_LEVEL

INFO

Python logging level

CONNECT_TIMEOUT

10.0

asyncpg connection timeout in seconds

EXPLAIN_TIMEOUT_MS

30000

Statement timeout for EXPLAIN ANALYZE in milliseconds

STAT_STATEMENTS_DEFAULT_LIMIT

20

Default row limit for pg_stat_statements

Available Tools

5 tools
describe_postgres_schemaA

Inspect a PostgreSQL schema and return its full structure as JSON.

Call this before writing any query, JOIN, or EXPLAIN — it gives you exact table/column names and indexes so you don't guess.

Returns a JSON object:

  • "columns": table_name, column_name, data_type, is_nullable, column_default

  • "foreign_keys": which columns reference which tables (use for JOINs)

  • "indexes": full CREATE INDEX definitions (check before running EXPLAIN)

Large schemas (100+ tables) return a lot of JSON — filter by table_name client-side rather than calling this multiple times.

Inputs: input (required). Returns: result

execute_postgresA

Execute a SQL query against a PostgreSQL database and return rows as JSON.

Returns: {"rows": [...], "row_count": N}

Mode behaviour (per project in databases.json):

  • readonly — only SELECT/WITH accepted; writes are blocked before reaching the DB.

  • readwrite — all SQL allowed; use only on non-production projects.

Call describe_postgres_schema first to confirm table/column names. If row_count equals your LIMIT, there are likely more rows.

Inputs: input (required). Returns: result

explain_postgresA

Run EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) on a query and return the plan.

The query executes to collect real timing; results are discarded — only the plan is returned. A statement timeout prevents runaway queries.

Returns: {"plan": []}

Use before running a slow or unfamiliar query on a large table. Check describe_postgres_schema first to see what indexes exist. Write queries are blocked.

Inputs: input (required). Returns: result

list_projectsA

List all configured database projects and their access modes.

Call this first when you don't know which project_id to use. Returns every project registered in databases.json, including which one is the default (used when project_id is omitted).

Returns a JSON object: { "default_project": "<project_id>", "projects": [ {"project_id": "", "mode": "readonly|readwrite", "is_default": true|false}, ... ] }

Inputs: no named parameters. Returns: result

pg_stat_statementsA

Return the top N most expensive queries from pg_stat_statements.

Best starting point for a performance audit — shows which query patterns cost the most cumulative time across the application.

Returns: {"rows": [{query, calls, total_exec_sec, mean_exec_sec, max_exec_sec, total_rows, shared_blks_hit, shared_blks_read}], "row_count": N}

Query text uses $1/$2 placeholders (pg_stat_statements normalises literals). Requires the pg_stat_statements extension (enabled by default on RDS, Cloud SQL, Supabase; otherwise: CREATE EXTENSION pg_stat_statements).

Inputs: input (required). Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.4/5.0

    Scored across 5 tools

    Disambiguation5/5

    Each tool has a clearly distinct purpose: schema inspection, query execution, explain planning, project listing, and performance analysis. No overlap exists.

    Naming Consistency4/5

    Tools follow a mostly consistent verb_noun pattern (describe_, execute_, explain_, list_), except pg_stat_statements which is a fixed PostgreSQL function name. Overall, naming is clear and predictable.

    Tool Count5/5

    Five tools is ideal for a query executor, covering key operations without unnecessary overhead. Each tool serves a specific need.

    Completeness5/5

    The tool set covers essential operations: schema inspection, query execution with read-only/write modes, explain analysis, project management, and performance monitoring. No obvious gaps for the domain.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI assistants to safely explore, analyze, and maintain PostgreSQL databases with read-only mode by default, SQL injection prevention, query performance analysis, and optional write operations.
      87 npm
      Apache 2.0
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI agents to interact with PostgreSQL databases through schema intelligence, query execution, and DBA tooling including index analysis and health monitoring. Features configurable access levels and audit logging for secure database operations.
      432 npm
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI assistants to safely interact with PostgreSQL databases, perform queries, inspect schemas, and analyze query performance.
      2
      ISC