A secure SQL proxy that sits between Claude and your production databases. It translates natural language questions into SQL using Claude with prompt caching, then validates every query at the AST level to block anything that isn't a SELECT. You get per-agent row-level security with table whitelists and injected WHERE clauses, plus an append-only audit log that stores metadata but never actual row data. The MCP integration exposes three tools: query_database for natural language, query_database_sql for raw SELECT statements, and get_audit_log. Reach for this when you want agents querying enterprise databases without handing them connection strings or trusting them to write safe SQL on their own.
Secure SQL proxy between AI agents and enterprise databases.
Agents call a single endpoint in plain English (or structured SQL). QueryShield:
SELECT is allowed, no
stacked statements, no forbidden functions, LIMIT required.WHERE clause injection.Agents never see connection strings.
pip install -r requirements.txt
cp .env.example .env
# Set ANTHROPIC_API_KEY, DATABASE_URL, VAULT_KEY (see below)
python -m queryshield.start
Generate a Fernet key for VAULT_KEY once and never lose it:
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
# 1) Boot a tenant. Returns the admin API key — copy it.
curl -X POST localhost:8000/v1/tenants?name=Acme
# 2) Register the customer DB. Connection string is encrypted at rest.
curl -X POST localhost:8000/v1/databases \
-H 'X-Admin-Key: qs_...' \
-H 'Content-Type: application/json' \
-d '{
"alias": "prod",
"db_type": "postgresql",
"connection_string": "postgresql://reader:secret@db.acme.internal:5432/app",
"allowed_tables": ["users", "orders"]
}'
# 3) Provision a scoped agent (different from admin) for your AI app.
curl -X POST localhost:8000/v1/agents \
-H 'X-Admin-Key: qs_...' \
-H 'Content-Type: application/json' \
-d '{ "name": "reporting", "tenant_id": "<tenant>" }'
# 4) Set the agent's RLS policy.
curl -X POST localhost:8000/v1/policies \
-H 'X-Admin-Key: qs_...' \
-H 'Content-Type: application/json' \
-d '{
"agent_id": "<agent>",
"database_alias": "prod",
"allowed_tables": ["users", "orders"],
"row_filters": { "users": "tenant_id = 42" }
}'
# 5) The agent queries.
curl -X POST localhost:8000/v1/query \
-H 'X-API-Key: qs_...' \
-H 'Content-Type: application/json' \
-d '{
"database_alias": "prod",
"query": "how many active users do we have?",
"mode": "nl",
"max_rows": 10
}'
Listed in the official MCP Registry as io.github.bch1212/queryshield.
Install the client:
pip install queryshield-mcp
Then drop this into your Claude Desktop / Cursor / agent config:
{
"queryshield": {
"command": "queryshield-mcp",
"env": { "QUERYSHIELD_API_KEY": "qs_..." }
}
}
Source for the standalone PyPI package lives in packages/queryshield-mcp/.
Drop this into any MCP-aware client (Claude Desktop, Cursor, custom agents):
{
"queryshield": {
"command": "python",
"args": ["-m", "queryshield.mcp_server"],
"env": {
"QUERYSHIELD_API_KEY": "qs_...",
"QUERYSHIELD_BASE_URL": "https://api.queryshield.io"
}
}
}
Tools exposed:
query_database(database_alias, question, max_rows) — natural-languagequery_database_sql(database_alias, sql, max_rows) — pre-built SELECTget_audit_log(limit) — recent attempts for the calling agent| Threat | Defense |
|---|---|
Agent crafts a DROP TABLE | sqlglot AST refuses non-SELECT |
Agent sneaks ; and a second statement | parser rejects len(statements) > 1 |
Agent uses pg_sleep, xp_cmdshell, ... | function deny-list at the AST node level |
| Agent reads tables outside its scope | RLS schema + table whitelist |
| Agent reads other tenants' rows | row_filters injected via AST .where() |
| Connection string leaks via stack traces | Fernet-encrypted, never returned in any API |
| Audit log becomes the data exfil vector | only metadata is stored — never rows |
VAULT_KEY rotation | re-encrypt rows under new key (script-driven) |
safety.py is the single most important module. Every additional check
that lands there should ship with a test in tests/test_safety.py.
| Tier | Monthly | Databases | Queries / month | Notes |
|---|---|---|---|---|
| Starter | $500 | 3 | 1,000,000 | |
| Pro | $1,500 | 10 | 10,000,000 | audit export |
| Enterprise | $3,500 | unlimited | unlimited | SSO, SIEM webhook |
Targets $32.5K MRR @ 15 customers (10 Pro + 5 Enterprise).
The repo is Railway-ready. python -m queryshield.start is the entrypoint
(reads PORT via os.getenv, since Railway exec's the start command without
a shell). Provision Postgres + (optionally) Redis from Railway's marketplace
and the rest is env vars.
railway up
/health is the liveness check. /ready returns 503 if the control-plane
DB is unreachable.
pip install pytest
python -m pytest tests/
42 tests cover:
QUERYSHIELD_API_KEY*secretAgent API key issued by QueryShield.
QUERYSHIELD_BASE_URLOverride the default endpoint.
hovecapital/read-only-local-postgres-mcp-server
cocaxcode/database-mcp
io.github.infoinlet-marketplace/mcp-mysql
io.github.cybeleri/database-admin
io.github.yash-0620/postgres-mcp-secured