MCP server that gives Claude a DuckDB analytics sandbox: load CSV/Parquet, run SQL, get summary stats.
Five tools with complete schemas and descriptions, but significant gaps in error guidance, output documentation, and parameter constraints. Tool names follow verb_noun convention (load_, list_, query, schema, summary). Descriptions are present (avg ~120 chars) but lack actionable error recovery hints. Parameters have types and basic descriptions, but missing enums for constrained inputs (e.g., file extensions, SQL statement types). Output schemas are not formally documented, LLMs must infer structure from markdown/string returns. No pagination, no per-item error reporting, no idempotency guarantees. Security: path traversal risk in load_dataset despite _safe_ident sanitization; SQL injection risk in query() despite 'read-only' claim (UNION attacks possible).
List all loaded tables with row counts.
Load a CSV or Parquet file into DuckDB as a queryable table.
Run a read-only SQL query against the loaded tables. Only SELECT and WITH statements are accepted. The result is capped at `limit` rows (default 100) and returned as a markdown table.
Show column names and types for a loaded table.
Per-column summary statistics for a loaded table. Uses DuckDB's SUMMARIZE: count, distinct count, null %, min, max, mean, std, and q25/q50/q75 quantiles. Useful as a first-pass profiling step.
Output schemas not documented. Tools return markdown strings or pandas DataFrames converted to markdown, but LLMs cannot parse structure without explicit schema. Agents cannot reliably extract column names, data types, or row counts for downstream reasoning.
query() accepts arbitrary SQL despite 'read-only' claim. Regex check (startswith 'select'|'with') is bypassable via comments, whitespace, or UNION/subquery injection. No actual query validation or sandboxing.
load_dataset path traversal: _safe_ident() only sanitizes table names, not file paths. Path.resolve() prevents ../ escapes, but symlink attacks and permission bypasses remain possible. No validation that path is within an allowed directory.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 56 | 2026-07-28+ | v2 |
No error recovery guidance. Errors return bare messages ('Error: file not found', 'Query error: ...') without actionable next steps. LLMs cannot distinguish retryable from fatal failures or know which tool to call next.
Missing parameter constraints. 'limit' in query() accepts 1 - 10000 but no enum/range validation in schema. File extension in load_dataset not constrained to ['.csv', '.parquet']. LLMs may pass invalid values.