Multi-database PostgreSQL MCP server. One server, many databases. Supports per-project isolation via --label filter.
The server defines 5 tools with consistent naming (verb_noun pattern) and generally clear descriptions. All tools have input schemas with type definitions and parameter descriptions. However, output schemas are completely undocumented, LLMs cannot plan what to expect from responses. Error handling is minimal and non-actionable. Security is well-handled (no secrets in params, connection pooling), but descriptions lack depth on WHEN to use each tool and lack dependency hints. The query/execute tools expose SQL injection risks without validation guidance in descriptions. No pagination support despite potentially returning large result sets (list_tables, describe_table). Average tool description length is 87 chars (baseline 194), indicating descriptions are terse.
Describe a table's structure (columns, types, constraints)
Execute a write SQL statement on a database (INSERT, UPDATE, DELETE, CREATE, ALTER, DROP). Requires readOnly=false in config.
List all available databases configured for this server (filtered by --label if set)
List all tables in a database
Execute a read-only SQL query on a database
Output schemas completely undocumented. LLMs cannot determine what fields are returned from query, execute, list_tables, describe_table. For example, does query() return rows as array of objects? What fields? Are there error details? Without documented schemas, agents cannot chain tools or extract required IDs for downstream calls.
SQL injection risk. query() and execute() accept free-form SQL strings with no validation guidance in descriptions. Description should warn: 'SQL must be parameterized. Pass untrusted user input as query parameters, not interpolated in the SQL string.' and validate inputs server-side.
No pagination support for list_tables. If a database has hundreds of tables, the full list enters the context window, diluting signal and wasting tokens. Baseline: tools returning lists should support limit/offset and return total count. Missing pagination invites context explosion.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 49 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 0 | - | v1 |
Terse descriptions lack WHEN guidance. 'Execute a read-only SQL query' tells LLM WHAT but not WHEN to use it vs other tools, dependencies, or failure modes. Baseline descriptions are 194 chars; these average 87. Descriptions should answer: When should I use this? What happens if it fails? What do I get back?
No error classification or recovery guidance. If query() fails due to syntax error, permission error, or timeout, the description provides no guidance on what the LLM should try next. Error handling should categorize failures and suggest recovery steps (e.g., 'If permission denied, check database role grants').
execute() description lacks data-loss warning. Description says 'Requires readOnly=false in config' but does not explicitly state this tool MODIFIES data and changes are IRREVERSIBLE. Description should warn: 'This tool executes INSERT, UPDATE, DELETE, CREATE, ALTER, DROP statements. Changes cannot be undone. Verify SQL before executing.'
No dry-run or confirmation pattern. Agents can invoke execute() and drop tables by accident. Pattern recommendation: add a 'dry_run' parameter (bool, default true) so agents can preview impact before committing. Or require a separate confirm_execute() call.
database parameter not described as enum or with validation rules. Both query and execute accept a 'database' string. Description should state: 'Must be a label from config.json. Valid options returned by list_databases(). If unsure, call list_databases() first.' Agents will guess invalid database names without guidance.
No tool chaining hints. Descriptions do not say: 'Call list_databases() first if you need to discover available databases' or 'Call describe_table() before querying to understand schema'. Missing dependency guidance forces agents to discover chains via trial-and-error.