SQLGuard MCP
SQLGuard MCP
Eine Sicherheits- und Governance-Hülle für den Agentenzugriff auf SQL-Warehouses.
Jeder Warehouse-MCP-Server nimmt heute eine SQL-Zeichenkette von einem Modell und führt sie aus. Die Verbindung war nie der schwierige Teil. Der schwierige Teil ist alles drumherum: nachweisen, dass die Abfrage nur liest, wissen, was sie kosten wird, bevor man dafür bezahlt, sie an die Berechtigungen des Aufrufers binden statt an die des Dienstkontos, ein Ergebnis zurückgeben, über das ein Agent tatsächlich nachdenken kann, und eine Aufzeichnung hinterlassen, die ein Mensch später überprüfen kann.
SQLGuard sitzt zwischen dem Modell und dem Warehouse und setzt alle fünf Punkte durch.
model ──▶ AST guard ──▶ policy ──▶ cost estimate ──▶ budget ──▶ warehouse
│ │ │ │
└── read-only └── identity └── dry run └── ceilings
proof scoped or bound + session cap
│
governed results ◀──────┘
(capped, summarized, cursored)
│
append-only audit log
(including refusals, with intent)Echte Ausgabe von python scripts/demo.py – nichts in diesem Transkript ist nachgestellt.
Das Ergebnis, das das Design motiviert hat
Das Korpus besteht aus 76 beschrifteten Abfragen: 46 Angriffe und 30 Stücke legitimer Analytik. „Bypass" bedeutet, dass ein Angriff erlaubt wurde. „Fehlalarm" bedeutet, dass echte Arbeit blockiert wurde.
Schutz | Bypasses | Fehlalarme | F1 | p50-Latenz |
| 17/46 (37%) | 0/30 | 0.773 | <0.01 ms |
Keyword-Denylist (Regex) | 12/46 (26%) | 5/30 (17%) | 0.800 | <0.01 ms |
Präfix + Semikolons ablehnen | 13/46 (28%) | 0/30 | 0.835 | <0.01 ms |
AST-Parse, nur Wurzelknoten | 12/46 (26%) | 0/30 | 0.850 | 0.04 ms |
SQLGuard (Wurzel + vollständiger Durchlauf) | 0/46 (0%) | 0/30 (0%) | 1.000 | 0.11 ms |
Reproduzierbar mit python evals/run_eval.py.
Die vierte Zeile ist die interessante. Das SQL ordentlich zu parsen und den Typ des obersten Knotens zu prüfen – der ausgefeilt wirkende Ansatz – übersieht immer noch ein Viertel des Korpus. Drei Anweisungen sind der Grund:
WITH d AS (DELETE FROM orders RETURNING *) SELECT * FROM d -- Postgres
SELECT * INTO staging_copy FROM orders -- T-SQL / PG
SELECT * FROM orders FOR UPDATE -- row locksAlle drei parsen mit Select an der Wurzel. Die erste löscht die Tabelle. Die Durchsetzung von Nur-Lesen muss den gesamten Baum durchlaufen, nicht nur seine Spitze inspizieren.
Was es durchsetzt
1. Nur-Lesen, auf AST-Ebene. Zwei unabhängige Schichten, und eine Anweisung muss beide überstehen: eine Whitelist für Wurzelknoten und einen vollständigen Baumdurchlauf gegen eine Verbotsmenge, die DML, DDL, Sitzungsänderung, Transaktionssteuerung, Datenabfluss (COPY TO, EXPORT DATA), Katalogänderung, SELECT ... INTO, Sperrklauseln und Funktionen mit Seiteneffekten abdeckt. Alles, was der Parser nicht modellieren kann, fällt auf einen generischen Befehls-Knoten zurück und wird auf dieser Grundlage abgelehnt – unbekannt bedeutet abgelehnt, was EXECUTE IMMEDIATE, CALL und Herstellererweiterungen stoppt.
2. Kostenobergrenzen, in drei Bereichen und zwei Dimensionen. Bei BigQuery ist die Schätzung ein echter Trockenlauf: exakte Bytes, kostenlos, bevor irgendetwas abgerechnet wird. Abfragen über der Obergrenze werden mit einer strukturierten Nutzlast abgelehnt, die die Schätzung, das Limit, die Überschreitung und eine aus dem eigenen AST der Abfrage abgeleitete Abhilfe nennt. Eine Sitzungsobergrenze akkumuliert über Aufrufe hinweg, weil die Fehlerart des Agenten Wiederholung ist, nicht Größe.
Die zweite Dimension ist die Ausgabekardinalität, und sie existiert wegen einer Abfrage, die jede Byte-Prüfung bestand: ein Self-Join mit ON 1=1 scannt 15 MB und erzeugt 14,4 Milliarden Zeilen. Gescannte Bytes begrenzen I/O, nicht Arbeit.
3. Identitätsbezogene Richtlinie. Tabellen sind auf einer Whitelist, eingeschränkte Spalten werden bei Referenz abgelehnt, und Zeilenfilter werden in den AST injiziert – jede überwachte Tabelle wird als gefilterte Unterabfrage neu geschrieben, sodass das Prädikat Joins, Unions und Verschachtelungen übersteht. Das String-Verknüpfen einer WHERE-Klausel würde durch das erste OR 1=1 zunichte gemacht, das auftaucht.
Identität ist Konfiguration, niemals ein Tool-Parameter. Kein Tool akzeptiert ein principal-Argument, und es gibt einen Test, der bestätigt, dass keines jemals eines akzeptieren wird. Ein Agent, der seinen eigenen Prinzipal benennen kann, hat keinen Prinzipal.
4. Ergebnis-Governance. Ergebnisse sind begrenzt, die Kürzung wird explizit angegeben statt stillschweigend, und die Fortsetzung verwendet einen serverseitigen Cursor-Handle. Der Cursor ist eine undurchsichtige ID in einen Speicher, in den das Modell nicht schreiben kann – es kann „mehr davon" sagen, aber nie beeinflussen, was „das" war. Jede Seite wird neu geschätzt und neu berechnet, weil das Paging auf den meisten Warehouses erneut scannt.
5. Prüfpfad, einschließlich Ablehnungen. Append-only JSONL, pro Datensatz fsynced. Jeder Aufruf trägt eine intent-Zeichenkette – die eigene Aussage des Modells, warum es die Abfrage ausgeführt hat, zum Zeitpunkt des Aufrufs erforderlich. Ein Warehouse-Log sagt, dass ein Dienstkonto 4 TB der Zahlungstabelle um 03:14 gescannt hat. Dieses sagt, dass ein Agent sie gescannt hat, weil er eine Rückerstattungsdifferenz abglich. Nur eines ist überprüfbar.
Die Tool-Oberfläche
Fünf Tools, nicht vierzig. Ein Server, der ein Tool pro Tabelle bereitstellt, verschlechtert die Tool-Auswahl und frisst den Kontextfenster, bevor das Modell das Schema gelesen hat.
Tool | Zweck |
| Lesbare Tabellen, dann die Spalten einer Tabelle. Progressive Offenlegung. |
| Validieren und bepreisen ohne Ausführung. Kostenlos. |
| Die vollständige Pipeline. Das einzige Tool, das Geld kostet. |
| Ein abgeschnittenes Ergebnis fortsetzen. |
| Verbleibendes Budget, damit der Agent seine Arbeit dimensionieren kann. |
plan_query ist das Tool, das das Agentenverhalten am meisten verändert. Mit einer kostenlosen Möglichkeit zu fragen „Wäre das erlaubt, und was würde es kosten", nutzt ein Modell es – und seine teuren Fehler werden zu billigen Ablehnungen, gegen die es iterieren kann. Ohne sie ist der einzige Weg, herauszufinden, dass eine Abfrage zu teuer ist, dafür abgerechnet zu werden.
Schnellstart
pip install "sqlguard-mcp[duckdb] @ git+https://github.com/Advaith789/ast-level-sql-mcp"Oder aus einem Klon, um die Tests und die Auswertung auszuführen:
python -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/python examples/seed_demo.py # builds a 120k-row demo warehouse
.venv/bin/python -m pytest -q # 73 tests
.venv/bin/python evals/run_eval.py # the table above
.venv/bin/python scripts/demo.py # the walkthrough pictured aboveBei einem MCP-Client registrieren:
{
"mcpServers": {
"sqlguard": {
"command": "/path/to/.venv/bin/sqlguard-mcp",
"args": ["--config", "/path/to/examples/policy.example.yaml"]
}
}
}Richtlinie
dialect: bigquery
driver:
name: bigquery
project: my-project
principal: analyst@example.com # never a tool parameter
roles:
analyst:
tables: ["analytics.*"]
denied_columns:
analytics.customers: [ssn, email]
row_filters:
analytics.orders: "region = 'US'" # injected into the AST
budget:
per_query_bytes: 50GB # one catastrophic scan
per_session_bytes: 500GB # one runaway conversation
per_day_bytes: 2TB # durable: survives restarts
max_estimated_rows: 10000000 # output size, not just input
max_rows: 200Kombinationsregeln, wenn ein Prinzipal mehrere Rollen innehat: Grants vereinigen (Tabellen, Zeilensichtbarkeit, Budgets), Denials vereinigen (eine Spalte, die von einer Rolle abgelehnt wird, bleibt abgelehnt). Ablehnung gewinnt. Bereitstellungsstandards füllen nur nicht gesetzte Felder – sie erweitern niemals eine Obergrenze, die eine Rolle gesetzt hat, was ein echter Fehler war, der beim Testen gefunden wurde und jetzt einen Regressionstest hat.
Was dies nicht tut
Klar ausgedrückt, weil die Grenzen bestimmen, wo es sicher zu verwenden ist.
Das Korpus ist nicht unabhängig. Ich habe die Angriffe und die Wache geschrieben. Es demonstriert die Klasse von Bypass, die einfachere Ansätze besiegt; es ist kein Anspruch auf Vollständigkeit gegen einen adaptiven Angreifer. Beigetragene Angriffsfälle sind der nützlichste mögliche Beitrag.
Die Sicherheit der Wache ist durch den Parser von sqlglot begrenzt. Ein Dialektkonstrukt, das sqlglot falsch in einen harmlosen Knoten parst, würde nicht erfasst. Konstrukte, die es nicht parsen kann, werden abgelehnt, sodass die Fehlerart in Richtung Ablehnung voreingenommen ist, aber „in Richtung sicher voreingenommen" ist nicht „sicher".
Der BigQuery-Treiber ist gegen die dokumentierte API geschrieben und wurde nicht gegen ein Live-Projekt ausgeführt. Der DuckDB-Pfad ist vollständig durch Tests abgedeckt.
Nicht qualifizierte Spaltenreferenzen schlagen fehl. Ohne schema-bewusste Namensauflösung wird ein nacktes
ssnin einer Multi-Tabellen-Abfrage abgelehnt, wenn eine Tabelle im Gültigkeitsbereich es einschränkt. Über-Ablehnung ist durch Qualifizieren der Spalte behebbar; Unter-Ablehnung würde leaken.DuckDB-Kostenschätzungen sind obere Grenzen, keine Trockenläufe – vollständige Scans jeder referenzierten Tabelle, keine Gutschrift für Pushdown. Nur BigQuery liefert exakte Zahlen vor der Ausführung.
Spaltenbezogene Richtlinie maskiert nicht, sie lehnt ab. Das stille Zurückgeben anderer Spalten als der vom Modell angeforderten erzeugt Analysen, die auf eine Weise falsch sind, die niemand sehen kann.
Layout
src/sqlguard/
ast_guard.py read-only enforcement (the core)
policy.py identity-scoped table/column/row policy
cost.py estimation, budgets, actionable refusals
governance.py result caps, summaries, cursors
audit.py append-only JSONL trail
spend.py durable per-principal spend ledger (SQLite)
errors.py structured refusals
server.py the five MCP tools
drivers/ duckdb (offline) + bigquery (dry run)
evals/ labeled corpus, baselines, metrics runner
tests/ 73 tests: adversarial corpus + end-to-end pipeline
scripts/ demo walkthrough + SVG renderer
.github/ CI: tests on 3.10-3.12, evaluation, package buildBeiträge willkommen – siehe CONTRIBUTING.md. Der nützlichste ist ein Angriff, der durchkommt.
Apache-2.0.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
See, price, and control every tool call your AI agents make: policy checks, cost, and audit tools.
The WAF for agents. Pattern-based + heuristic firewall scans prompts, RAG documents, tool argume...
Query PostgreSQL databases in plain English — LLM-generated, safety-validated SQL.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Advaith789/ast-level-sql-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server