Skip to main content
Glama
JuanPinilla198

mcp-sql-metrics

mcp-sql-metrics

An MCP server that exposes read-only SQL queries as typed tools.

You declare your queries in a YAML file. The server turns each one into an MCP tool with a real argument schema, runs it as a parameterized read against PostgreSQL, and returns the rows as JSON.

Why this exists

The intuitive way to let a language model answer questions about your data is to export the data and put it in the prompt. That approach breaks down for three reasons:

  • The context window doesn't fit a real history. A year of orders is not going in a prompt.

  • Cost scales with the size of the dump, not with the size of the answer.

  • Models make arithmetic errors. Asking one to sum a column is asking for a wrong number that looks right.

The approach that works is the opposite: give the model tools, not data. The model decides which question to ask and interprets the result; PostgreSQL does the arithmetic, because PostgreSQL does not make arithmetic mistakes.

This server is that pattern, packaged. It also means the model never sees a full table — only the aggregated result of a query it asked for, which is a meaningful difference when the underlying data is sensitive.

Related MCP server: FastAPI Database MCP Server

Install

pip install mcp-sql-metrics

Use

Write a query catalogue:

queries:
  - name: daily_sales
    description: >
      Returns total revenue, order count and units sold for a single day.
      Use it when the user asks how a specific date performed.
    params:
      - name: day
        type: string
        description: The date to report on, in YYYY-MM-DD format.
    sql: |
      SELECT
        COUNT(*)                AS orders,
        COALESCE(SUM(total), 0) AS revenue
      FROM orders
      WHERE DATE(created_at) = %(day)s

Run it:

export DATABASE_URL="postgresql://user:pass@host/db"
export QUERIES_FILE="queries.yaml"
mcp-sql-metrics

Or point an MCP client at it:

{
  "mcpServers": {
    "sql-metrics": {
      "command": "mcp-sql-metrics",
      "env": {
        "DATABASE_URL": "postgresql://user:pass@host/db",
        "QUERIES_FILE": "/path/to/queries.yaml"
      }
    }
  }
}

To explore the tools interactively:

uv run mcp dev src/mcp_sql_metrics/server.py

Safety model

Read-only is enforced in three independent places, because one check is a single point of failure:

  1. At load time, every statement must start with SELECT or WITH, must be a single statement, and must not contain a write or DDL keyword. A bad query stops the server from starting rather than failing later.

  2. At execution time, the connection is put in read-only mode for the transaction, so a write cannot happen even if a statement slipped past the first check.

  3. Arguments are always bound as query parameters, never interpolated into the SQL string. There is no code path that builds a statement by concatenation.

Two more limits protect the caller rather than the database:

  • Row cap per query (default 200). When a result is capped, the response says so explicitly, so the model knows to narrow its filters instead of assuming it saw everything.

  • Statement timeout per query (default 10s), set with SET LOCAL so it cannot leak to another transaction.

Error handling

Errors are returned to the model as structured JSON rather than raised, and they are written so the model can correct itself:

{
  "error": "missing required argument 'day'",
  "expected": ["day"]
}

A model that gets "expected": ["day"] back will usually fix the call on its own. A model that gets a stack trace will not.

Configuration reference

Field

Required

Default

Notes

name

yes

Becomes the tool name; must be a valid identifier

description

yes

What the model reads to decide when to call the tool

sql

yes

A single SELECT or WITH … SELECT

params

no

[]

name, type, description; default makes it optional

max_rows

no

200

Rows returned before the result is marked truncated

timeout_ms

no

10000

Per-statement timeout

Parameter types: string, integer, number, boolean. The set is deliberately small — every type the model can send maps to something the driver binds safely.

Environment

Variable

Required

Notes

DATABASE_URL

yes

PostgreSQL DSN. The server exits at startup if unset.

QUERIES_FILE

no

Path to the catalogue. Defaults to queries.yaml.

Point it at a database role with SELECT-only grants. The read-only transaction is a safety net, not a substitute for correct permissions.

Development

pip install -e ".[dev]"
pytest
ruff check .

License

MIT

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    -
    quality
    A
    maintenance
    Provides a read-only PostgreSQL SQL surface for LLM agents via MCP, with defense-in-depth security layers for safe database queries.
    3
    MIT
  • F
    license
    -
    quality
    D
    maintenance
    Provides read-only SQL query access to Postgres and DuckDB databases via MCP tools, with extensive security hardening for public endpoints.
    1
  • F
    license
    A
    quality
    C
    maintenance
    Enables read-only exploration and querying of PostgreSQL or MySQL databases via MCP, with schema discovery, safe SQL validation, natural language to SQL conversion, and CSV export.
    11
    1

View all related MCP servers

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/JuanPinilla198/mcp-sql-metrics'

If you have feedback or need assistance with the MCP directory API, please join our Discord server