QuestLLens
QuestLLens
Geben Sie KI Augen für Ihre Zeitreihen
Der selbst-dokumentierende QuestDB-MCP-Server, der jede QuestDB-Instanz in eine reichhaltige, abfragbare Wissensquelle für KI-Agenten verwandelt – mit erstklassiger Kenntnis von Partitionen, Symbolen, Dedup-Keys, WAL-Zustand, Ingestions-Health und Speicherlayout.
Erste Schritte · Tools · Konfiguration · Docker · Sicherheit · Domänenkontext
Warum QuestLLens?
KI-Modelle sind leistungsfähig – aber sie sind blind für Ihre Zeitreihen-Datenbank. Sie kennen weder Ihren designierten Zeitstempel, noch Ihre Partitionsstrategie, Ihre Symbol-Kardinalität oder welche Tabellen beim WAL-Apply hinterherhinken.
QuestLLens behebt das. Es verbindet jede QuestDB-Instanz über das Model Context Protocol (MCP) mit KI-Assistenten und gibt ihnen 18 zweckgebundene Tools, um Ihre Daten zu entdecken, zu verstehen und abzufragen – sicher, im Nur-Lese-Modus, ohne jedes Risiko versehentlicher Schreibvorgänge.
Wie das zum integrierten MCP-Server von QuestDB passt
QuestDB liefert einen eigenen MCP-Server in der Web-Konsole mit, und für interaktive Arbeit am Schreibtisch ist er das bessere Werkzeug – er hat Notebooks, Diagramme, SQL-/Funktionsdokumentation und eine Zwei-Wege-Übergabe an die bereits geöffnete Konsole. Nutzen Sie ihn dafür.
Er löst ein anderes Problem als dieses hier:
QuestDB-Web-Konsolen-MCP | QuestLLens | |
Transport | WebSocket, nur Loopback | HTTP/SSE, remote erreichbar |
Benötigt eine aktive Browser-Sitzung | Ja – Pairing und Zustimmung erfolgen in der Konsole | Nein |
Schreibzugriff | Ja – DDL/DML auf der Berechtigungsstufe „Write" | Nein – Nur-Lesen prozessintern erzwungen |
Authentifizierung für Remote-Clients | Konsolen-Sitzung / Enterprise-SSO | OAuth 2.1 + PKCE, oder keine für lokale Nutzung |
Notebooks, Diagramme, Dokumentationssuche | Ja | Nein |
Partition-, WAL-, Dedup-, Symbol-, Ingestions-Health-Tools | Nein | Ja |
Domänenkontext-Injektion in Tool-Beschreibungen | Nein | Ja |
Greifen Sie zu QuestLLens, wenn der Agent nicht an Ihrem Browser sitzt: ein Headless-Assistent, ein Container hinter einem Tunnel, ein gemeinsamer Team-Endpunkt – oder überall dort, wo Sie eine harte Nur-Lese-Garantie statt einer Berechtigungseinstellung benötigen.
Was QuestLLens besonders macht
Zeitreihen-nativ – Anders als generische SQL-MCP-Server spricht QuestLLens QuestDB. Designierte Zeitstempel, Zeitpartitionen, Symbol-Kapazität, Dedup-Keys und WAL-Zustand sind erstklassige Konzepte, über die Ihr KI-Assistent nachdenken kann.
Selbst-dokumentierend – Extrahiert automatisch Tabellenmetadaten, Spaltentypen, Partitionen, Indizes und Materialized-View-Definitionen. Ihr KI-Assistent versteht Ihr Schema so, wie Ihr Team es tut.
Domänenbewusst – Injizieren Sie eine einfache Markdown-Datei mit Geschäftskontext (was Tabellen bedeuten, häufige
SAMPLE BY-Muster, Stolperfallen) und QuestLLens webt sie in jede Tool-Antwort ein.Nicht-invasiv – Steckt in jede QuestDB-Instanz über das standardmäßige PostgreSQL-Wire-Protokoll. Keine Agenten, keine Erweiterungen, keine QuestDB-Konfigurationsänderungen. Nur ein Nur-Lese-Benutzer.
Sicherheit zuerst – Verteidigung in der Tiefe: SQL-Keyword-Blockierung, abgestimmt auf die vollständige DDL-Oberfläche von QuestDB, Statement-Timeouts, Zeilenlimits und optionales OAuth mit Rate-Limiting. Ihre Daten bleiben sicher.
Related MCP server: django-mcp-sql
Erste Schritte
Voraussetzungen
Node.js 20+
QuestDB 7.4+ (jede gehostete oder selbstverwaltete Instanz – WAL-Tabellen wurden in 7.4 zum Standard)
Ein QuestDB-Benutzer mit
SELECT-Berechtigungen (Nur-Lesen empfohlen; siehe Sicherheit)
Schnellstart (npm)
# Clone and install
git clone https://github.com/DMDuFresne/questllens.git
cd questllens
npm install
# Configure
cp .env.example .env
cp context.md.example context.md
# Edit .env with your QUESTDB_URL
# Build and run
npm run build
npm startQuestLLens läuft jetzt unter http://localhost:3000 mit dem MCP-Endpunkt unter /mcp.
Schnellstart (Docker)
docker run -p 3000:3000 \
-e QUESTDB_URL="postgresql://admin:quest@host:8812/qdb" \
ghcr.io/dmdufresne/questllens:1.0.0Verbindung mit Claude Desktop
Fügen Sie QuestLLens zu Ihrer Claude-Desktop-Konfiguration hinzu:
{
"mcpServers": {
"questllens": {
"url": "http://localhost:3000/mcp"
}
}
}Mit aktiviertem OAuth:
{
"mcpServers": {
"questllens": {
"url": "http://localhost:3000/mcp",
"authorizationUrl": "http://localhost:3000/oauth/authorize",
"tokenUrl": "http://localhost:3000/oauth/token",
"registrationUrl": "http://localhost:3000/oauth/register"
}
}
}Verbindung mit Claude Code
{
"mcpServers": {
"questllens": {
"type": "url",
"url": "http://localhost:3000/mcp"
}
}
}Skills
skills/ bündelt vier Claude-Skills,
die Claude beibringen, QuestLLens zu bedienen, statt nach Tool-Namen zu raten:
Skill | Verwendung |
| Das orientierende Skill – Nur-Lese-Haltung, die vier Zeitreihen-Konzepte, die jede Abfrage verändern (designierter Zeitstempel, Partitionen, SYMBOL, WAL), Discovery-first-Workflow und Weiterleitung an die anderen drei. Hier beginnen. |
| Orientierung in einer unbekannten Instanz: Inventar, Bedeutung, Zeitabdeckung, Kardinalität, Partitionen, MV-Graph. |
| Triage-geordneter Ingestions-Sweep: WAL-Lag vs. Veraltung, ausgesetzte Tabellen, Speicher, laufende Abfragen. |
| Die |
Kopieren Sie die vier Verzeichnisse unter skills/ in das Verzeichnis .claude/skills/ Ihres Projekts
(oder dorthin, wo Ihr Client Skills lädt), um sie verfügbar zu machen; Claude Code
zeigt automatisch das richtige Skill basierend auf den Trigger-Phrasen im
Frontmatter des jeweiligen Skills an.
Tools
QuestLLens stellt 18 MCP-Tools bereit, organisiert in sechs Kategorien. Die Tools wurden zuerst für KI-Agenten entworfen – Markdown-Ausgabe für Token-Dichte, Beschreibungen, die erklären, wann man welches verwendet, und zusammengesetzte Diagnosen, die Fragen in einem Round-Trip statt in dreien beantworten.
Abfrage
Tool | Beschreibung |
| Führt schreibgeschützte SQL-SELECT-Abfragen aus. Ergebnisse werden als Markdown-Tabellen mit Zeilenanzahl und Kürzungswarnungen zurückgegeben. |
| QuestDB-Ausführungsplan für ein SELECT. Nach einer langsamen |
| Empfiehlt ein SAMPLE BY-Intervall anhand von Tabelle, Bereich und Ziel-Bucket-Anzahl. Verhindert, dass Agenten bei einem Jahr Daten |
Schema-Erkennung
Tool | Beschreibung |
| Jede Tabelle mit designiertem Zeitstempel, Partitionseinheit, WAL-Flag, Dedup-Keys und Spaltenanzahl. Materialized Views erscheinen hier ebenfalls. |
| Komplettbeschreibung für eine Tabelle oder Materialized View: Spalten, Dedup-Keys, Partitionseinheit. Optionale Flags fügen Zeitbereich ( |
| Findet Spalten nach Namensmuster über alle Tabellen. Groß-/Kleinschreibung-unabhängige Teilstring-Übereinstimmung. |
| Round-trip-fähiges |
| Ingestions-Einstellungen pro Tabelle: |
| Erzwingt manuell ein Neuladen des Schema-Caches. Normalerweise unnötig – |
Datenerkundung
Tool | Beschreibung |
| 1–20 Beispielzeilen. Übergeben Sie |
| Zeilenanzahl, Null-%, Distinct-Anzahl pro Spalte – gebündelt in einem SQL. Übergeben Sie |
Speicher & Partitionen
Tool | Beschreibung |
| Auflistung pro Partition mit Parquet-/Aktiv-/Read-only-Flags. Übergib |
| Top-N-Tabellen nach Speicherverbrauch mit Aufteilung Parquet vs. nativ. Ein einzelner Aufruf, um Speicher-Hotspots zu finden, ohne |
Operationen
Tool | Beschreibung |
| WAL-Anwendungsstatus pro Tabelle: Sequenzertransaktion, Writer-Transaktion, Verzögerung, „suspended-Flag“. |
| Zusammengesetzte Ingestionsdiagnose: WAL-Verzögerung und Status „suspended“ sowie Veraltung des neuesten Zeitstempels in einem Aufruf. Erste Anlaufstelle für „Warum kommen keine Daten an?“ |
| Momentan ausgeführte Abfragen über |
| Abhängigkeitsgraph materialisierter Sichten mit Rückwärtsindex („Welche Sichten hängen von Tabelle X ab?“). Einstieg in eine einzelne Sicht mit ihrer SQL-Definition. Erfordert QuestDB 8.x. |
Server
Werkzeug | Beschreibung |
| Version, Build, Edition, Betriebszeit plus Feature-Erkennung für |
Konfiguration
QuestLLens wird über Umgebungsvariablen konfiguriert. Lege eine .env-Datei an oder übergib sie direkt.
Erforderlich
Variable | Beschreibung | Beispiel |
| QuestDB-Verbindungszeichenfolge (PostgreSQL-Wire-Protokoll) |
|
Die Standard-PG-Wire-Anmeldedaten von QuestDB sind
admin/questauf Port8812. Ändere sie und erstelle einen Benutzer mit ausschließlich Lesezugriff – siehe Sicherheit.
Optional
Variable | Standard | Beschreibung |
|
| HTTP-Server-Port |
|
| Maximale Abfrageausführungszeit (ms) |
|
| Maximale Anzahl von Zeilen pro Abfrage |
|
| Aktualisierungsintervall des Schema-Cache (ms) |
| — | Pfad zu einer Markdown-Datei mit Fachbereichskontext |
| — | Inline-Fachbereichskontext-String (Alternative zur Datei) |
OAuth-Optionen (bei Ausführung mit --oauth)
Variable | Standard | Beschreibung |
| — | Passwort für das OAuth-Anmeldeformular |
|
| Öffentliche URL (für Betrieb hinter einem Proxy) |
| leer – alle Origins erlaubt | Kommagetrennte CORS-Zulassungsliste für Browser Origins (z. B. |
|
| Tokenlebensdauer in Sekunden (Standard: 7 Tage) |
|
| Maximale Anmeldeversuche pro Zeitfenster |
|
| Rate-Limit-Zeitfenster (ms, Standard: 15 Min.) |
|
| Leitet die Client-IP aus |
Docker
Pull
docker pull ghcr.io/dmdufresne/questllens:1.0.0Build
docker build -t questllens .Run
# Without OAuth (local development, trusted networks)
docker run -p 3000:3000 \
-e QUESTDB_URL="postgresql://readonly:password@host:8812/qdb" \
questllens
# With OAuth (production, Claude Desktop)
docker run -p 3000:3000 \
-e QUESTDB_URL="postgresql://readonly:password@host:8812/qdb" \
-e MCP_AUTH_PASSWORD="your-secure-password" \
questllens node dist/index.js --oauth
# With custom domain context
docker run -p 3000:3000 \
-e QUESTDB_URL="postgresql://readonly:password@host:8812/qdb" \
-v ./my-context.md:/app/context.md \
-e DOMAIN_CONTEXT_FILE="context.md" \
questllensDocker Compose
services:
questllens:
image: ghcr.io/dmdufresne/questllens:1.0.0
ports:
- "3000:3000"
environment:
QUESTDB_URL: postgresql://readonly:password@questdb:8812/qdb
MAX_ROWS: 500
volumes:
- ./context.md:/app/context.md
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stoppedImage-Details
Basis:
node:20-alpine(Multi-Stage-Build)Größe: ~80MB
Benutzer: Non-Sqrt (SuperUser
nodejs:1001)Healthcheck: Integriert über den
/health-Endpunkt
Sicherheit
Melden von Schwachstellen und auch, was im und was nicht im Scope liegt, finden du in SECURITY.md. Die Kurzfassung: die Read-only-Garantie und der OAuth-Flow sind im Scope; alles was mit legitim erteiltem Lesezugriff erreichbar ist, ist nicht – nutze eine Datenbankrolle mit minimalen Rechten.
QuestList ist von Konstruktion her read-only und verwendet Defense-in-Depth. Die Anwendungsschicht allein ist nicht ausreichend – eine Read-only-Datenbankrolle und Netzwerkisolation sind erforderlich, keine Optionen. Die Abschnitte unten beschreiben die einzelnen Schichten.
Erforderlich: Read-Only-Datenbankrolle
QuestDB unterstützt kein BEGIN READ ONLY von PostgreSQL. Die Datenbank ist deine einzige durchsetzbare Schreibbarriere. Betreibe QuestLLens mit einem Read-only-Benutzer:
QuestDB Enterprise (RBAC pro Benutzer):
CREATE USER questllens_readonly WITH PASSWORD 'your-secure-password';
GRANT SELECT ON ALL TABLES TO questllens_readonly;QuestDB Open Source (noch ohne RBAC pro Benutzer):
OSS hat kein RBAC pro Benutzer, daher kann die Anwendungsschicht das Schreiben nicht vollständig isolieren. Erforderliche Maßnahmen:
Die Standard-Zugangsdaten
admin/questsofort ändern.Den PG-Wire-Port (
8812) per Netzwerk isolieren, sodass nur QuestLLens ihn erreichen kann. Nicht auf Workstations der Justiziere jegentäglichen Zugriff weitergeben.Spät-Buch: Betreibe QuestLLens mit OAuth (
--oauth), damit MCP-Clients auch auf Anwendungsebene abgesichert werden.
Falls du die Punkte (1) und (2) nicht erfüllen kannst, verwende QuestLLens nicht gegen eine OSS-Produktionsinstanz.
Read-only-Pfad auf Anwendungsebene (Defense-in-Depth)
Jede benutzerprovidierte SQL-Anweisung durchläuft einen echten Tonizer (behandelt '…' mit ''-Escapes, $tag$…$tag$, --, /* */) und wird geprüft gegen:
Allowlist für das einleitende Verb – nur
SELECT,WITH,EXPLAIN,SHOWoderTABLESerlaubt.Multistatement-Reject – alles nach einem
;wird abgelehnt. Der simple-Query-Pfad von PG-Wire führt mehrere Anweisungen aus; die Sicherheitsprüfung macht diesen Weg unerreichbar.Verbotene-Wörter-Scan auf tokenisiertem Input –
INSERT·UPDATE·DELETE·DROP·CREATE·ALTER·TRUNCATE·RENAME·REINDEX·VACUUM· BACKUP·SNAPSHOT·COPY·ATTACH·DETACH·GRANT·REVOKE·SET·RESET·RESUME·SUSPEND·CHECKPOINT·CANCEL·KILL·SQUASH·CONVERT·DEDUPETE·REFRESH·CALL·EXECUTE·PREPARE·DEALLOCATE. Da die Eingabe tokenisiert wird, löstWHERE message LIKE '%DROP%'` den Scan nicht aus.
Interne Introspectionsabfragen (tables(), wal_tables(), SHOW CREATE TABLE, …) umgehen die Sicherheitsprüfung über ein explizites internal: true-Flag im Datenbankclient. Jede interne Aufrufstelle ist ein Prüfpunkt; Benutzereingaben erreichen dieses Pfad nie.
Statement Timeouts
Das statement_timeout pro Abfrage wird bei jedem Checkout der Verbindung neu gesetzt (QuestDB hat kein SET LOCAL), so kein früherer interner Aufruf kann einen veralteten Wert auf einer Pool-Verbindung hinterlassen. Standard: 30 Sekunden.
Zeilengrenzen
Ergebnisse werden auf eine maximal konfiguriertes Maximum gedeckelt (Standard: 1.000 Zeilen) mit Warnung bei Abschneidung.
OAuth (wenn --oauth aktiviert ist)
Beim Ausführen mit --oauth bietet QuestLLens:
But hold on, the original German translation I've drafted makes some errors. I see I wrote "Einzel zu" but I only list the output text. Let me fix those typos. Since the final should be polished.
Let me review my draft for possible mistakes (I added some translations like "按" and mixed code errors throughout). I will correct these before final. Probably I should silently produce a clean final. Let me do that.
Some key corrections:
Header line: "Werkzeug" in the third table. Original uses "Tool"; I'll use "Tool" in German? I wrote "Werkzeug" in the Server table. Fine.
For "Tool column header in first table: "Ver****"? I wrote "Tool". Good.
"User maintenance: "Non-Root (Superroot)". Ich will "Benutzer: Kein Root-Benutzer (
nodejs:1001)" — hmm. Let's use "Non-Root-Benutzer (nodejs:1001)" or "Benutzer: non-root (nodejs:1001)".Admin user works as: "Ändere die Standard-
admin/quest-Zugangsdaten sofort aus." I had nonsense "die Standard ... ändern" multiple clauses.Oracle: Yes.
I need to carefully rebuild final text with no weird outputs ("Spiele", "GX".
I'll write a final translation now cleanly.
Note the original first table has **... rows with code. Keep backticks.
Let me write| Tool | Beschreibung |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| get_partitions | Auflistung pro Partition mit Parquet-/Aktiv-/Read-only-Flags. Übergib from/to, um Tabellen mit langer Aufbewahrungsdauer einzuschränken, oder summary=true für eine Zusammenfassung (Anzahl, erste/letzte, Aufteilung nativ vs. Parquet). |
| get_storage_summary | Top-N-Tabellen nach Speicherverbrauch mit Aufteilung Parquet vs. nativ. Ein einziger Aufruf, um Speicher-Hotspots zu finden, ohne get_partitions pro Tabelle auszuführen. |
Operationen
Tool | Beschreibung |
| WAL-Anwendungszustand pro Tabelle: Sequencer-Transaktion, Writer-Transaktion, Verzögerung, Suspend-Flag. |
| Zusammengesetzte Ingestionsdiagnose: WAL-Verzögung + Suspend-Status + Altere des neuesten Zeitstempels in einem Aufruf. Erste Anlaufstelle bei „Warum kommen keine Daten an?“. |
| Derzeit ausgeführte Abfragen über |
| Abhängigkeitsgraph materialisierter Sichten mit umgekehrtem Index („Welche Sichten hängen von Tabelle X ab?“). Detailansicht einer einzelnen Sicht inklusive SQL-Definition. Erfordert QuestDB 8.x. |
Server
Tool | Beschreibung |
| Version, Build, Edition, Betriebszeit plus Feature-Erkennung für |
Konfiguration
QuestLLens wird über Umgebungsvariablen konfiguriert. Erstelle eine .env-Datei oder übergib diese direkt.
Erforderlich
Variable | Beschreibung | Beispiel |
| QuestDB-Verbindungszeichenfolge (PostgreSQL-Wire-Protokoll) |
|
Die Standard-PG-Wire-Zugangsdaten von QuestDB sind
admin/questauf Port8812. Ändere sie und erstelle einen Read-only-Benutzer – siehe Sicherheit.
Optional
Variable | Standard | Beschreibung |
|
| HTTP-Server-Port |
|
| Maximale Abfrageausführungszeit (ms) |
|
| Maximale Zeilenanzahl pro Abfrage |
|
| Aktualisierungsintervall des Schema-Cache (ms) |
| — | Pfad zu einer Markdown-Datei mit Domänenkontext |
| — | Inline-Domänenkontext-Zeichenk folie (Alternative zur Datei) |
OAuth-Optionen (bei Ausführung mit --oauth)
Variable | Standard | Beschreibung |
| — | Passwort für das OAuth-Login-Formular |
|
| Öffentliche URL (für den Betrieb hinter einem Proxy) |
| leer – alle Origins erlaubt | Kommagetrennte CORS-Allowlist für Browser-Origins (z. B. |
|
| Token-Lebensdauer in Sekunden (Standard: 7 Tage) |
|
| Maximale Login-Versuche pro Fenster |
|
| Rate-Limit-Fenster (ms, Standard: 15 Min.) |
|
| Client-IP wird aus |
Docker
Pull
docker pull ghcr.io/dmdufresne/questllens:1.0.0Build
docker build -t questllens .Run
# Without OAuth (local development, trusted networks)
docker run -p 3000:3000 \
-e QUESTDB_URL="postgresql://readonly:password@host:8812/qdb" \
questllens
# With OAuth (production, Claude Desktop)
docker run -p 3000:3000 \
-e QUESTDB_URL="postgresql://readonly:password@host:8812/qdb" \
-e MCP_AUTH_PASSWORD="your-secure-password" \
questllens node dist/index.js --oauth
# With custom domain context
docker run -p 3000:3000 \
-e QUESTDB_URL="postgresql://readonly:password@host:8812/qdb" \
-v ./my-context.md:/app/context.md \
-e DOMAIN_CONTEXT_FILE="context.md" \
questllensDocker Compose
services:
questllens:
image: ghcr.io/dmdufresne/questllens:1.0.0
ports:
- "3000:3000"
environment:
QUESTDB_URL: postgresql://readonly:password@questdb:8812/qdb
MAX_ROWS: 500
volumes:
- ./context.md:/app/context.md
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stoppedImage-Details
Basis:
node:20-alpine(Multi-Stage-Build)Größe: ~80MB
Benutzer: Non-root (
nodejs:1001)Healthcheck: Integriert über
/health-Endpunkt
Sicherheit
Meldung von Schwachstellen und was im Scope liegt und was nicht, findest du in SECURITY.md. Die Kurzfassung: die Read-only-Garantie und der OAuth-Flow sind im Scope; alles, was mit legitim eingeräumtem Lesezugriff erreichbar ist, nicht – verwende eine Datenbankrolle mit Minimalrechten.
QuestLLens ist von Design her read-only und nutzt Defense-in-Depth. Die Anwendungsschicht allein ist nicht ausreichend – eine Read-only-Datenbankrolle und Netzwerk-Isolation sind erforderlich, nicht optional. Die folgenden Abschnitte beschreiben die Schichten im Detail.
Erforderlich: Read-only-Datenbankrolle
QuestDB unterstützt kein PostgreSQL-BEGIN READ ONLY. Die Datenbank ist die einzige durchsetzbare Schreibbarriere. Betreibe QuestLLens mit einem read-only-Benutzer:
QuestDB Enterprise (per-user RBAC):
CREATE USER questllens_readonly WITH PASSWORD 'your-secure-password';
GRANT SELECT ON ALL TABLES TO questllens_readonly;QuestDB Open Source (noch kein per-user RBAC):
OSS hat kein per-User-RBAC; die Anwendungsschicht kann Schreibzugriffe daher nicht vollständig isolieren. Erforderliche Gegenmaßnahmen:
Ändere sofort die Standard-Zugangsdaten
admin/quest.Isoliere den PG-Wire-Port (
8812) über das Netzwerk, sodass nur QuestLLens ihn erreichen kann. Setze ihn weder für Operator-Workstations noch für andere Dienste frei.Betreibe QuestLLens hinter OAuth (
--oauth), damit MCP-Clients auch auf Anwendungsebene abgesichert sind.
Wenn du (1) und (2) nicht erfüllen kannst, betreibe QuestLLens nicht gegen eine OSS-Produktionsinstanz.
Application-Layer-Read-only-Pfad als Security-in-Depth
Jede von Benutzern bereitgestellte SQL-Statement läuft durch einen echten Tokenizer (behandelt '…' mit ''-Escapes, $tag$…$tag$, --, /* */) und wird geprüft gegen:
Allowlist Schema of leading verb – nur
SELECT,WITH,EXPLAIN,SHOWoderTABLESwerden akzeptiert.Multi-Statement-Ablehnung – alles nach einem
;wird abgewiesen. Der Simple-Query-Pfad von PG-Wire führt mehrere Anweisungen aus; durch die Safety-Check ist dieser Pfad unerreichbar.Verbotene-Schlüsselwort-Scan im tokenisierten Input –
INSERT·UPDATE·DELETE·DROP·CREATE·ALTER·TRUNCATE·RENAME·REINDEX·VACUUM·BACKUP·SNAPSHOT·COPY·ATTACH·DETACH·GRANT·REVOKE·SET·RESET·RESUME·SUSPEND·CHECKPOINT·CANCEL·KILL·SQUASH·CONVERT·DEDUP·REFRESH·CALL·EXECUTE·PREPARE·DEALLOCATE. Da die Eingabe tokenisiert ist, lässtWHERE messageLIKE '%DROP%'den Scan nicht auslösen.
Interne Introspection-Queries (tables(), wal_tables(), SHOW CREATE TABLE, …) umgehen die Sicherheitsprüfung über ein explizites internal: true-Flag im Datenbankklienten. Jede interne Aufrufstelle ist ein Prüfpunkt; Benutzereingaben erreichen diesen Pfad nie.
Statement-Timeouts
Der statement_timeout wird pro Query bei jedem Connection-Checkout neu gesetzt (QuestDB has no SET LOCAL), sodass ein zufällig vorher interner Aufruf keinen veralteten Wert auf einer gepoolen Verbindung hinterlassen kann. Stand: 30 Sekunden.
Zeilengrenzen
Ergebnisse sind auf ein konfigurierbares Maximum begrenzt (Standard: 1.000 Zeilen) mit Hinweis der Abschneidung
OAuth – wenn (Standard: --oauth aktiviert)
When running with --oauth, QuestLLens provides:
Bei Ausführung mit --oauth bietet QuestLLens:
RFC 7591 Dynamic Client Registration
PKCE S256 — erforderlich, wenn der Client einen
code_challengesendet; der Verifier wird am Token-Endpunkt mit einem Vergleich in konstanter Zeit geprüftAuthorization-Code-Bindung — der Code ist an seine
client_idundredirect_urigebunden; eine Abweichung beim Einlösen wird abgelehntRedirect-URI-Validierung — nur registrierte URIs werden akzeptiert; das Schema ist auf
httpsbeschränkt (oderhttp://localhost/127.0.0.1für die Entwicklung)CORS-Allowlist —
MCP_ALLOWED_ORIGINS(kommagetrennt) legt fest, welche Browser-Origins den Server aufrufen dürfen. Wenn leer, sind alle Origins erlaubt, was hier sicher ist, da jede Tool-Route ein Bearer-Token statt eines Cookies erfordert — eine Cross-Origin-Seite hat keine ambienten Anmeldedaten. Setzen Sie es, wenn Sie Browser-Origins einschränken möchtenRate-Limiting für Passwortversuche (standardmäßig 5 pro 15 Minuten)
Timing-sicherer Passwortvergleich
Bearer-Token-Validierung auf allen MCP-Endpunkten; abgelaufene Token werden aus dem In-Memory-Speicher entfernt
In sich geschlossene Zustimmungsseite — die Anmeldeseite lädt keine Schriftarten, Skripte oder Assets von Drittanbietern, sodass eine Authentifizierungsaufforderung niemals eine Anfrage an ein CDN leakt
Sicherheits-Header auf jeder Antwort —
Content-Security-Policy: default-src 'none'(nur Inline-Stile,frame-ancestors 'none',base-uri 'none'), plusX-Content-Type-Options,X-Frame-Options: DENY,Referrer-Policy: no-referrerundCross-Origin-Opener-Policy. Keinform-action: Die 302 des Zustimmungsformulars geht an die registrierteredirect_urides Clients, die bei einem nativen Client ein Loopback-Port ist — eine andere Origin, die Browser unterform-action 'self'blockieren. Das Redirect-Ziel wird stattdessen serverseitig gegen die registrierten URIs des Clients eingeschränkt1-MB-Anfragekörper-Grenze sowohl für JSON- als auch für formularcodierte Körper
Token und Autorisierungscodes werden im Speicher gehalten; sie überleben keinen Serverneustart. Persistieren Sie sie extern, wenn Sie langlebige Sitzungen über Neustarts hinweg benötigen.
Hinter einem Proxy oder Tunnel: setzen Sie
TRUST_PROXY_HEADERS=true, sonst sieht der Rate-Limiter jede Anfrage als von der einzelnen Adresse des Proxys kommend, und die fehlgeschlagenen Anmeldungen eines Angreifers sperren jeden Client aus. Setzen Sie es nur, wenn dieser Proxy der einzige Weg zum Server ist.
Domänenkontext
Das ist QuestLLens' Geheimwaffe. Während Schema-Introspection der KI was Ihre Tabellen aussehen lässt, sagt ihr der Domänenkontext, was sie bedeuten — und, für Zeitreihendaten, wie man sie gut abfragt.
So funktioniert es
Kopieren Sie die Vorlage und beschreiben Sie die Geschäftslogik Ihrer Datenbank, dann weisen Sie QuestLLens darauf hin:
cp context.md.example context.mdcontext.md ist gitignored — hier lebt Ihr proprietäres Domänenwissen, sodass es nie committet wird.
# Via environment variable
DOMAIN_CONTEXT_FILE=context.md
# Or inline
DOMAIN_CONTEXT="This database stores sensor telemetry from industrial PLCs. Use SAMPLE BY for downsampled queries; never SELECT * across more than 1 hour of raw data."QuestLLens injiziert diesen Kontext in Tool-Beschreibungen, sodass Ihr KI-Assistent Ihre Domäne von der ersten Interaktion an versteht.
Beispiel context.md
# Industrial Telemetry Database
## Key Concepts
- Every table is partitioned by **DAY** with designated timestamp `ts`
- The `device_id` column is a SYMBOL — always filter on it before time ranges
- We use `LATEST ON ts PARTITION BY device_id` to get the most recent reading per device
- Hot data lives in the last 7 days; older partitions are detached to cold storage
## Common Queries
- 1-minute downsample: `SELECT ts, avg(value) FROM readings SAMPLE BY 1m`
- Latest per device: `SELECT * FROM readings LATEST ON ts PARTITION BY device_id`
- Aligned multi-sensor: `ASOF JOIN` on `ts`
## Gotchas
- The `value` column is in raw ADC counts, not engineering units — multiply by `scale` from `device_config`
- `ts` is always UTC; the device-local time is in `local_ts`
- Never run `SELECT *` on the `raw_packets` table — it's billions of rowsWas angereichert wird
Der Domänenkontext wird eingewoben in:
Die
query-Tool-Beschreibung (damit die KI besseres SQL schreibt)Die Ergebnisse von
get_partitionsunddescribe_table --with_time_range(damit die KI den Datenlebenszyklus versteht)Die Ausgabe von
describe_table --with_symbol_stats(damit die KI Kardinalitätsbeschränkungen respektiert)Schema-Discovery-Antworten (damit die KI bessere Folgefragen stellt)
API-Referenz
Health Check
GET /healthGibt Serverstatus und Version zurück:
{
"status": "healthy",
"server": "questllens",
"version": "1.0.0"
}MCP-Endpunkt
POST /mcp → JSON-RPC 2.0 request
GET /mcp → Server-Sent Events (SSE) stream
DELETE /mcp → Session terminationDie gesamte MCP-Kommunikation verwendet Streamable HTTP Transport mit Sitzungsverwaltung über den mcp-session-id-Header.
OAuth-Endpunkte (wenn --oauth aktiviert)
GET /.well-known/oauth-protected-resource → Resource metadata
GET /.well-known/oauth-authorization-server → Server metadata
POST /oauth/register → Dynamic client registration
GET /oauth/authorize → Login form
POST /oauth/authorize → Authenticate
POST /oauth/token → Token exchangeEntwicklung
# Install dependencies
npm install
# Run in dev mode (hot reload)
npm run dev
# Run with OAuth in dev mode
npm run dev:oauth
# Type check
npm run typecheck
# Run tests (read-only SQL boundary, config validation, identifier quoting)
npm test
# Build for production
npm run buildProjektstruktur
src/
├── index.ts # Entry point
├── config.ts # Environment config with Zod validation
├── server.ts # Express + MCP server, OAuth, session management
├── database/
│ ├── client.ts # PG-wire connection pool, query execution
│ ├── schema-loader.ts # QuestDB introspection + cache (auto-refresh on miss)
│ └── sql-safety.ts # Lexer + allowlist enforcing the read-only path
├── tools/
│ ├── index.ts # Executor re-exports
│ ├── _util.ts # Shared identifier quoting
│ ├── query.ts # Execute SELECT queries (markdown output)
│ ├── explain-query.ts # QuestDB EXPLAIN
│ ├── suggest-sample-by.ts # Pick a SAMPLE BY interval for a target bucket count
│ ├── list-tables.ts # Tables with TS / partitioning / WAL flags
│ ├── describe-table.ts # Table or MV detail (with optional time range / symbol stats)
│ ├── search-columns.ts # Cross-table column search
│ ├── get-create-table.ts # Round-trippable CREATE TABLE / CREATE MATERIALIZED VIEW
│ ├── get-table-params.ts # Per-table ingestion knobs (o3MaxLag, maxUncommittedRows, ttl)
│ ├── refresh-schema.ts # Manual cache reload (auto-refresh on miss is the default)
│ ├── get-partitions.ts # Partition list with from/to filter and summary mode
│ ├── get-storage-summary.ts # Top-N tables by disk (parquet vs native)
│ ├── get-sample-data.ts # Sample rows with optional columns/where projection
│ ├── get-table-stats.ts # Per-column null % + distinct (single batched SQL)
│ ├── get-wal-status.ts # WAL apply state, lag, suspended tables
│ ├── get-ingestion-health.ts # Composite WAL lag + latest-row staleness diagnostic
│ ├── get-running-queries.ts # query_activity() wrapper
│ ├── get-mv-dependencies.ts # Materialized view graph (forward + reverse)
│ └── server-info.ts # Version, build, feature detection
├── descriptions/
│ ├── generator.ts # Dynamic description builder
│ └── static.ts # Static description blocks
├── types/
│ └── index.ts # TypeScript interfaces
└── ...
tests/
├── sql-safety.test.ts # Read-only boundary: verbs, literals, injection shapes
├── config.test.ts # Env parsing, limits, domain-context loading
└── identifiers.test.ts # quoteIdent breakout attempts
skills/ # Claude skills — copy into .claude/skills/
├── questllens-using/
├── questllens-explore-a-database/
├── questllens-health-check/
└── questllens-tune-a-query/CI führt Typecheck, Tests und den Build auf Node 20 und 22 aus, baut dann das Image und
prüft, ob die Read-only-Grenze weiterhin gegen einen Live-QuestDB-Container gilt
(siehe .github/workflows/ci.yml).
Anwendungsfälle
Anwendungsfall | Wie QuestLLens hilft |
KI-gestützte Zeitreihenanalyse | Lassen Sie Claude |
Kapazitätsplanung | Kombinieren Sie |
Onboarding in Zeitreihen | Weisen Sie eine KI mit Domänenkontext auf QuestDB hin und lassen Sie sie erklären: „Was bedeutet der designierte Zeitstempel für diese Tabelle?" oder „Warum ist diese Abfrage langsam?". |
Abfrageoptimierung | Verwenden Sie |
Ingestion-Debugging |
|
Datenaufbewahrungsprüfung | Verwenden Sie |
Schema-Portabilität |
|
Kompatibilität
QuestLLens funktioniert mit jedem MCP-kompatiblen Client:
Claude Desktop (mit oder ohne OAuth)
Claude Code (CLI)
Cursor / Windsurf / VS Code (über MCP-Erweiterungen)
Benutzerdefinierte MCP-Clients (jeder Client, der die MCP-Spezifikation implementiert)
Und mit jeder QuestDB-Bereitstellung:
QuestDB Open Source 7.4+
QuestDB Enterprise (empfohlen — ermöglicht benutzerbasiertes RBAC)
QuestDB Cloud
Selbstverwaltetes Docker, Kubernetes oder Bare-Metal
get_mv_dependenciesund der materialisierte-View-Zweig vondescribe_table/get_create_tableerfordern QuestDB 8.x.get_running_querieserfordert eine QuestDB-Version, diequery_activity()bereitstellt. Führen Sieserver_infoaus, um zu sehen, was die verbundene Instanz unterstützt. Alle anderen Tools sind mit 7.4+ kompatibel.
Fehlerbehebung
„Verbindung abgelehnt" auf Port 8812
QuestLLens verbindet sich über das PostgreSQL-Wire-Protokoll auf Port 8812, nicht über die HTTP-API auf 9000. Stellen Sie sicher, dass der PG-Wire-Listener aktiviert ist (pg.enabled=true in server.conf) und erreichbar ist.
„Zugriff verweigert" bei Schema-Introspection
QuestLLens verwendet die Systemfunktionen von QuestDB (tables(), table_columns(), wal_tables(), table_partitions(), materialized_views()). Auf QuestDB OSS sind diese für jeden authentifizierten Benutzer verfügbar. Auf QuestDB Enterprise stellen Sie sicher, dass Ihrer Rolle die erforderlichen Leseberechtigungen erteilt wurden:
GRANT SELECT ON ALL TABLES TO questllens_readonly;get_mv_dependencies gibt leer zurück
Materialisierte Views erfordern QuestDB 8.x. Wenn Sie auf 7.x sind, gibt dieses Tool ein leeres Ergebnis mit einem Hinweis zurück — aktualisieren Sie auf 8.0+, um MVs zu verwenden.
get_wal_status zeigt „WAL nicht aktiviert"
WAL-Tabellen wurden in QuestDB 7.4 zum Standard. Tabellen, die auf älteren Versionen erstellt wurden, können weiterhin Nicht-WAL sein; sie erscheinen in list_tables mit wal_enabled = false und werden nicht in get_wal_status aufgenommen.
Schemaänderungen werden nicht übernommen
QuestLLens cached Schema-Metadaten. Warten Sie entweder auf den nächsten Aktualisierungszyklus (Standard: 5 Minuten) oder rufen Sie refresh_schema auf, um den MCP-Cache sofort zu aktualisieren.
OAuth-Anmeldung schlägt fehl
Überprüfen Sie, ob MCP_AUTH_PASSWORD gesetzt ist und der Rate-Limiter nicht ausgelöst hat (standardmäßig 5 Versuche pro 15 Minuten). Überprüfen Sie die Server-Logs für Details.
Lizenz
Apache-2.0. Frei zu verwenden, zu modifizieren und mit Namensnennung zu verbreiten; enthält eine ausdrückliche Patentgewährung. Siehe LICENSE für die Bedingungen und NOTICE für Lizenzen von Drittanbietern, den QuestDB-Marken-Haftungsausschluss und die Abelara-Marken-Asset-Ausnahme — die Logos und Markenkunstwerke sind nicht durch Apache-2.0 abgedeckt.
Bereitgestellt „wie besehen" ohne jegliche Garantie — Nutzung auf eigenes Risiko.
Erstellt von Abelara
QuestLLens ist Teil des Abelara-Toolkits für industrielle KI und Edge-Computing, neben PgLLens für PostgreSQL.
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 Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to securely query VAST Data databases for schema, metadata, and sample data via read-only SQL and MCP resources.MIT
- AlicenseNot gradedqualityAmaintenanceProvides a read-only PostgreSQL SQL surface for LLM agents via MCP, with defense-in-depth security layers for safe database queries.3MIT
- AlicenseNot gradedqualityBmaintenanceProvides read-only access to databases for MCP-compatible AI tools, allowing schema exploration and SELECT queries without exposing credentials or risking data changes.513MIT
- AlicenseNot gradedqualityBmaintenanceProvides read-only access to PostgreSQL databases via MCP, enforcing least-privilege roles, row-level security, masked views, and SQL AST guardrails to prevent data leakage and unauthorized operations, enabling AI agents to safely query sensitive production data.MIT
Related MCP Connectors
Read-only MCP access to sessions, funnels, campaigns, errors, live visitors, and anomalies.
Analytical memory for AI agents: a real Postgres queried in plain English over MCP. One command.
Read-only Dant3 MCP for public rooms, agents, jobs and provisional machine onboarding.
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/DMDuFresne/questllens'
If you have feedback or need assistance with the MCP directory API, please join our Discord server