MCP server that lets AI agents query a SQL database in natural language, safely and read-only.
dbridge-mcp demonstrates solid definition quality across 11 database introspection and query tools. Naming is consistently verb-first and clear (list_, describe_, sample_, count_, run_, explain_, column_, index_, test_, slow_, get_). All tools have descriptions averaging ~130 chars, well within the 10-1024 char baseline. Input schemas use Zod validation with type declarations and parameter descriptions for all parameters. However, output schemas are not documented in the tool definitions, the response structure is not explicitly declared in the MCP registration. Error handling is minimal: no recovery guidance, no error categorization. Tool descriptions are descriptive but lack the 'when to use' and 'what it returns' structure that LLMs use for selection. Several tools (test_index, slow_queries) have domain-specific prerequisites not clearly stated.
Returns per-column cardinality (distinct values) and null fraction for a table. Use it to judge whether a column is selective enough to be worth indexing or grouping by.
Returns the exact number of rows in a table.
Returns the columns of a table (name, type, nullability). Use it before writing a query.
Returns the query plan and estimated cost without running the query. Use it to check a query is cheap before running it.
Returns the safety limits in effect (row cap, timeout, cost/rate limits, hidden and masked columns, table allow/block lists).
Lists indexes with their columns, size, and scan counts, flagging unused, duplicate, and invalid indexes. Use it to spot dead weight before recommending a new index.
Output schemas not documented in tool definitions. Tool descriptions state what they return (rows, plan, count, etc.) but the MCP tool registration does not include structured output schema declarations. LLMs cannot plan downstream operations or validate response structure.
Descriptions lack 'when to use' guidance and explicit return structure. Descriptions state WHAT (e.g. 'Returns the first rows'), but not WHEN the LLM should call this tool or WHY it's distinct from similar tools. test_index requires hypopg PostgreSQL extension, not mentioned. slow_queries depends on pg_stat_statements or performance_schema, not mentioned.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 68 | 2026-07-28+ | v2 |
Lists every table in the connected database. Call this first to discover what data is available.
Runs a single read-only SELECT or WITH statement and returns the rows as JSON. Writes are rejected and results are capped.
Returns the first rows of a table as a quick preview, to understand the data before querying.
Returns the most expensive statements recorded by the database (PostgreSQL pg_stat_statements, MySQL performance_schema), with call counts and total/mean times. Use it to decide what is worth optimizing.
Simulates a CREATE INDEX without building it (PostgreSQL with the hypopg extension) and reports whether the planner would use it for a given query, with before/after cost estimates. Use this to validate an index idea before recommending it.
Error handling provides no recovery guidance. None of the 11 tools include error categorization (retryable vs user-fixable vs fatal) or actionable messages. E.g., if run_query fails on a write statement, the response should tell the LLM 'Writes rejected. Call explain_query() to validate the SELECT syntax first.' Currently no such guidance is visible in the code.
Capability-gated tools (column_stats, index_health, test_index) use requireCapability() to check if the driver supports them, but the tool description does not warn the LLM which databases support the tool. test_index explicitly requires 'PostgreSQL with the hypopg extension', good. But column_stats and index_health lack this clarity, leaving the LLM to discover via failure.
Parameter format constraints missing from descriptions. sample_table.limit is 'default 10' but also bounded to max 50 (per .max(50) in code), not stated in description. This forces the LLM to test limits via failure instead of reading the constraint upfront.
Missing idempotency guarantees. describe_table, count_rows, and list_tables are idempotent read-only operations, but this is not declared via tool annotations (idempotentHint). LLMs may assume the worst (destructive) and avoid safe retries.