From Theory Delta | Methodology | Published 2026-02-24
MCP database servers advertise a "read-only mode" that restricts agents to SELECT queries, preventing data modification. The official Anthropic MCP SQLite reference server and community implementations all offer this as a safety feature for connecting agents to production databases.
Every MCP database server reviewed implements read-only enforcement as a string prefix check. None use SQL AST parsing. Here is the actual code:
executeautomation/mcp-database-server (source, security advisory GHSA-65hm-pwj5-73pw):
// index.ts:272-291
if (!query.trim().toLowerCase().startsWith("select")) {
throw new Error("Only SELECT queries are allowed with read_query");
}
modelcontextprotocol/servers mcp-server-sqlite (issue #3314):
# mcp_server_sqlite/server.py:326
results = db._execute_query(
f"PRAGMA table_info({arguments['table_name']})"
)
The table_name parameter is interpolated directly into the PRAGMA statement without sanitization. Input like users); DROP TABLE users; -- executes arbitrary SQL. The reference implementation that builders copy from has an open SQL injection.
This means:
WITH ... AS (...) SELECT ...) are blocked because they start with WITH, not SELECT. Legitimate read-only queries fail silently.WITH deleted AS (DELETE FROM ...) SELECT ...) start with WITH but mutate data. If the guard allows WITH to fix the above, it opens a write path.SELECT INTO OUTFILE passes the prefix check in haxzie/sequel-mcp -- confirmed, not theoretical. Starts with SELECT, writes to the filesystem.SELECT 1; DROP TABLE users passes the prefix check because only the first statement is inspected. The pg driver supports multi-query execution when statements are semicolon-terminated.The NL2SQL correctness ceiling compounds the problem: SOTA on enterprise schemas (Spider 2.0) is ~17% for o1-preview, ~10% for GPT-4o. Spider 1.0's commonly cited 86.6% uses toy schemas and is a misleading baseline.
describe_table and any PRAGMA-using path before deploying.list_tables in executeautomation (issue #23, open). Agents silently fall back to raw information_schema queries, bypassing the tool abstraction.| Tool | Version | Result |
|---|---|---|
| executeautomation/mcp-database-server | latest (Feb 2026) | startsWith('select') prefix check confirmed |
| modelcontextprotocol/servers mcp-server-sqlite | v2025.4.25 | PRAGMA injection via f-string confirmed |
| haxzie/sequel-mcp | latest (Feb 2026) | SELECT INTO OUTFILE passes prefix check |
| vanna-ai/vanna | v0.7.x | NL2SQL pipeline reviewed |
| Canner/WrenAI | latest (Feb 2026) | NL2SQL pipeline reviewed |
| Snowflake-Labs/ReFoRCE | latest (Feb 2026) | Benchmark reviewed |
| xlang-ai/Spider2 | latest (Feb 2026) | Enterprise accuracy benchmarks reviewed |
Confidence: empirical -- source code reviewed and vulnerability confirmed across 3 MCP database servers, benchmarks reviewed across 4 additional tools. Security advisory GHSA-65hm-pwj5-73pw independently confirms the finding.
Open questions: Does any MCP database server implement AST-based read-only enforcement? Are there production deployments using parameterized queries through MCP tool calls? Has anyone shipped a sandboxed execution path for NL2SQL visualization code?
Seen different? Contribute your evidence -- theory delta is what makes this knowledge base work.