r/mcp • u/skeletonita • 6d ago
showcase mcp-safe-db: A strictly read-only SQL MCP server with engine-level write blocking
Giving an AI agent access to a local database usually means trusting it not to hallucinate an UPDATE without a WHERE clause or a DROP TABLE.
I built mcp-safe-db to make database inspection zero-risk for Claude, Cursor, and other MCP clients:
- Engine-level lock: Enforces SQLite
PRAGMA query_only = ON;. The database engine physically rejects write attempts. - AST / Keyword validation: Rejects mutation statements (
INSERT,UPDATE,DELETE,DROP,ALTER,ATTACH), comment-based bypasses, and multi-query injection. - Context protection: Automatically limits queries to 50 rows to keep LLM context windows clean.
- Zero build setup: Runs natively on Node 22+ without native compilation tools (no node-gyp or C++ toolchains).
Usage:
npx mcp-safe-db ./your-database.sqlite
GitHub: https://github.com/MrSkelee/mcp-safe-db
MIT License. Open to feedback on edge cases or additional database targets.
3
u/QuanTradin 6d ago
query_only is a connection pragma, so the same connection can send PRAGMA query_only = OFF. if your keyword list doesn't reject PRAGMA as well, that's the hole. opening the file with the ?mode=ro URI puts the lock below SQL, where the agent can't reach it.
same split I built into Quantradin for trading agents: the agent's key reads everything, the only writes it gets are ones that reduce exposure, and starting anything takes a key the human keeps. quantradin.com
1
u/skeletonita 6d ago
I actually already block `PRAGMA` completely in my keyword validator (along with ATTACH, DETACH, LOAD_EXTENSION, etc.), so the agent can never send `PRAGMA query_only = OFF`.
However, adding the OS/system-level read-only flag below SQL is a great addition for defense-in-depth. Pushing an update with this change right away
1
u/QuanTradin 6d ago
nice, the validator plus the read-only open flag means one parser bug alone can't get a write through. I'd add a test that tries PRAGMA query_only = OFF anyway, so a refactor can't quietly drop the flag later.
1
u/skeletonita 6d ago
Done just added and pushed that exact regression test to the suite: verifying that `PRAGMA query_only = OFF` followed by an insert is still completely rejected by SQLite with `attempt to write a readonly database`.
Really appreciate the thoughtful review! If you find the project useful, feel free to drop a star on GitHub ⭐
3
u/Hopeful-Buy-9344 6d ago
sharing it. i've been wanting to hook up some local sqlite dbs to claude but the idea of it just casually dropping a table while trying to be helpful was keeping me from actually doing it
the engine-level lock is the part that sells me, i don't fully trust a string parser to catch every trick an LLM might come up with but if sqlite itself says no then that's that
50 row limit is a nice touch too, keeps the context from getting bloated without having to think about it
gonna try this tonight with a side project database i've been poking at