Skip to main content
Glama
Eshanya1

sql-specialist-mcp

by Eshanya1

sql-specialist-mcp

Ein kleines, feinabgestimmtes Open-Weight-Modell, das natürliche Sprachfragen zu einer SQLite-Datenbank beantwortet und als MCP-Tool bereitgestellt wird, das jeder MCP-Client (Claude Desktop, Claude Code, benutzerdefinierte Agenten) direkt aufrufen kann – unterstützt durch eine ausführungsgenaue Eval-Harness, die den Spezialisten gegen das Prompting eines Frontier-Modells auf Genauigkeit, Latenz und Kosten benchmarkt.

Der Sinn dieses Projekts ist nicht „eine Text-zu-SQL-Demo bauen“ – es geht darum, die Teile des LLM-Engineerings zu zeigen, die unterhalb des Promptings liegen: ein kleines Modell nehmen, es über LoRA an eine Aufgabe anpassen, es effizient servieren und mit einer echten, ausführungsbasierten Eval beweisen, dass ein günstiger Spezialist für diese enge Aufgabe mit dem Prompting eines Frontier-Modells konkurrieren kann (oder besser ist).

Interaktive Demo ausprobieren – alle 28 echten Eval-Fragen durchklicken und das tatsächlich generierte SQL, die Latenz und die Ergebniszeilen des Spezialisten neben der Frontier-Baseline sehen. Keine Installation erforderlich.

Warum es das gibt

Die meisten „AI-Portfolio“-Text-zu-SQL-Projekte sind LangChain-Schnellstarts. Zwei Dinge hier sollen anders sein:

  1. Die Eval ist rigoros, nicht Bauchgefühl. Jede Gold-Abfrage wird beim Erstellen des Datensatzes gegen die Datenbank ausgeführt (139/139 validiert), und die Bewertung vergleicht Ergebnismengen, nicht den Abfragetext – eine semantisch korrekte Abfrage mit anderer Spaltenreihenfolge wird trotzdem als korrekt bewertet. Ein Prädiktor, der nur das Gold-SQL wiedergibt, erzielt 100 %; ein Prädiktor, der immer eine trivial falsche Abfrage zurückgibt, erzielt 0 %. Beides ist als Sanity-Test eingecheckt (tests/test_harness_oracle.py), damit die Korrektheit der Harness selbst nicht vorausgesetzt wird.

  2. Es wird als etwas Nutzbares ausgeliefert, nicht nur als Demo-Repo. Das feinabgestimmte Modell wird als echtes MCP-Tool (nl_to_sql) bereitgestellt – Claude Desktop oder Claude Code auf mcp_server/server.py zeigen und es kann die Datenbank tatsächlich als Teil einer Konversation abfragen.

Related MCP server: mcp-sqlite-chat

Ergebnisse

Die vollständige Pipeline wurde auf echter Hardware Ende-zu-Ende ausgeführt, beide Seiten: echtes LoRA-Feintuning, echtes Merge, echte GGUF-Quantisierung, echtes Ollama-Serving, echte Eval – und eine echte Frontier-Baseline gegen die Live-Claude-API. Basismodell: Qwen/Qwen2.5-Coder-0.5B-Instruct (gewählt für eine schnelle Iterationsschleife auf einem Laptop; siehe Feintuning unten für den 1.5B-Pfad).

Prädiktor

Genauigkeit

n

p50-Latenz

p95-Latenz

Kosten / 1k Aufrufe

Frontier: Claude Haiku 4.5 (gepromptet)

53,6 %

28

1055 ms

1884 ms

1,06 $

sql-specialist (feinabgestimmt, quantisiert, lokal)

92,9 %

28

207 ms

371 ms

0,00 $

Lies das mit der Einschränkung, nicht nur mit der Schlagzeile. Ich habe jede der 13 gemessenen „Fehlschläge“ von Claude Haiku gegen diesen Eval-Satz manuell geprüft: Null davon waren SQL-Logikfehler. Alle 13 waren Spaltenauswahl- oder Zeilenreihenfolge-Konventionsabweichungen – z. B. die Rückgabe von (name, email), wenn die Gold-Antwort nur (name) war, oder korrekte Zeilen in einer anderen Reihenfolge als ein ORDER BY, das die ursprüngliche Frage nie spezifiziert hatte. Die strenge Ausführungsgenauigkeitsmetrik (eval/execution.py vergleicht Ergebniszeilen Spalte für Spalte) bewertet diese identisch zu einer wirklich falschen Abfrage, was der feinabgestimmte Spezialist nie produziert, weil er die genauen Konventionen dieses Datensatzes aus 111 Trainingsbeispielen auswendig gelernt hat – etwas, das ein Frontier-Modell, das zero-shot gepromptet wird, nicht wissen kann. Vollständige Fehler-für-Fehler-Taxonomie in COMPARISON.md.

Also: Die Genauigkeitslücke ist real, aber teilweise ein Artefakt dessen, was die Eval belohnt, nicht rein eine Denklücke. Die Latenz- und Kostenlücke ist kein Artefakt – 207 ms/lokal/kostenlos vs. 1055 ms/1,06 $ pro 1k Aufrufe ist das tatsächliche, ungeschönte Ergebnis, ein quantisiertes 0.5B-Modell lokal auszuführen, statt eine API aufzurufen, und es ist der Vergleich, auf dem die Prämisse dieses Projekts tatsächlich beruht.

Die eigenen 2 Fehler des Spezialisten (von 28) waren echte Logikfehler, keine Formatierungsabweichungen – eine plausible orders.total-Spalte halluziniert, die in diesem Schema nicht existiert, und ein Tabellenqualifizierer in einem Multi-Tabellen-SELECT weggelassen. Das Training konvergierte sauber über 3 Epochen (Eval-Loss 0,060 → 0,048 → 0,008), und das quantisierte Modell (988 MB f16 → 373 MB q4_k_m) wird über Ollama in ~200 ms bedient.

Was hier echt ist

Ehrlich zu sein, ist wichtiger, als es aussieht – es ist der Unterschied zwischen einem Projekt, dem ein Recruiter vertrauen kann, und einem, das sich wie Marketing liest.

  • Die synthetische Datenbank und der Datensatz sind nachweislich korrekt. shopsphere.db wird deterministisch geseedet (seed=42); jedes der 139 Gold-Paare (Frage, SQL) in data/*.jsonl wird aus parametrisierten Vorlagen generiert und zur Build-Zeit gegen die echte Datenbank ausgeführt – eine Vorlage, die ungültiges SQL produziert, lässt den Build fehlschlagen, sie liefert nicht stillschweigend ein schlechtes Label.

  • Die Korrektheit der Eval-Harness ist selbst getestet, nicht vorausgesetzt – tests/test_harness_oracle.py stellt sicher, dass ein Orakel-Prädiktor (gibt Gold-SQL wörtlich zurück) genau 100 % erzielt und ein absichtlich falscher Prädiktor ~0 %, bevor die Zahl eines echten Prädiktors vertraut wird.

  • Ausführungsgenauigkeit, nicht String-Match. eval/execution.py vergleicht Ergebnismengen (reihenfolgeunabhängig, es sei denn, die Gold-Abfrage hat ORDER BY), sodass eine anders geschriebene, aber semantisch äquivalente Abfrage trotzdem als korrekt bewertet wird.

  • Das Feintuning ist echt, auf dieser Maschine, verifiziert konvergierend. LoRA (8,8 M trainierbare Parameter, 1,75 % des Modells) über 3 Epochen, Eval-Loss sinkt monoton in jeder Epoche. Siehe Engineering-Notizen unten für zwei echte Bugs, die dabei gefunden und behoben wurden.

  • SQL-Ausführung ist wirklich sandboxed, nicht nur dazu gepromptt, sich zu verhalten: Leseabfragen werden gegen eine Regex-Allowlist validiert und gegen eine echte schreibgeschützte SQLite-Verbindung ausgeführt (mode=ro auf OS-Ebene) – ein Bug im Regex-Guard kann trotzdem nicht zu einem Schreibzugriff führen. Das ist über die Eval-Harness hinaus wichtig, weil derselbe Guard im MCP-Server läuft, wo das SQL von einem Modell stammt, das auf eine Agentenfrage antwortet, nicht aus einem kuratierten Eval-Satz.

  • Der MCP-Server ist ein echtes, aufrufbares Tool, das das echte feinabgestimmte Modell bedient, Ende-zu-Ende verifiziert: nl_to_sql("Which employees have no manager assigned?") → generiert SQL über das quantisierte Modell über Ollama → führt es schreibgeschützt aus → gibt echte Zeilen zurück → protokolliert Latenz/Kosten in die Observability.

  • Observability ist selbstgebaut und ohne Abhängigkeitenobservability/logger.py protokolliert jeden Aufruf (Latenz, Tokens, geschätzte Kosten, Erfolg/Fehler) in eine lokale SQLite-Datei, kein externes Konto nötig, gleiches Muster wie pr-review-agent.

  • Die Frontier-Baseline ist auch echteval/baseline_frontier.py lief gegen die Live-Claude-API (Claude Haiku 4.5), nicht nur sauber importiert. Ihre „Fehler“ entpuppten sich als echter Eval-Methodik-Befund – siehe Ergebnisse oben und COMPARISON.md für die vollständige manuelle Fehlerprüfung.

Engineering-Notizen: zwei echte Bugs, die beim echten Ausführen gefunden wurden

Das tatsächliche Ausführen des Feintunings (statt es als „sollte in der Theorie funktionieren“ zu belassen) brachte zwei echte PyTorch-Speicherbugs ans Licht, beide im aktuellen Code behoben:

  1. MPS-Caching-Allocator-Ausreißer. Das Training auf dem MPS-Backend von Apple Silicon über transformers.Trainer ließ den Prozess auf 23 GB RSS anwachsen und hängen, bei dynamischem Pro-Batch-Padding – jede unterschiedliche (Batch, seq_len)-Form bekommt ihren eigenen Speicherpool im MPS-Allocator von PyTorch, der freigegebenen Speicher nicht an das OS zurückgibt. Fix: --device cpu-Override in finetune.py, und grundsätzlicher: festes Padding (unten), damit diese Bug-Klasse auf keinem Backend wieder auftreten kann.

  2. Trainer/DataLoader-Overhead, nicht das Modell. Ein direkter Forward+Backward-Pass wurde mit 1,6 s/Beispiel gemessen; dieselbe Berechnung über transformers.Trainer ließ den Prozess Minuten zwischen protokollierten Schritten ohne entsprechende Rechenleistung im Leerlauf. Root-Cause durch Isolieren des tatsächlichen Modell+LoRA-Forward/Backward mit manuellem Timing, bevor angenommen wurde, der Bug sei im Modellcode. Fix: Trainer durch eine ~40-zeilige manuelle Trainingsschleife ersetzt (training/finetune.py) – gleiches LoRA-Setup, direkte Kontrolle über die Batch-Schleife, kein unerklärlicher Overhead. Außerdem die Batch-Kollation von dynamisch-pro-Batch auf feste Länge umgestellt (jeder Batch identisch geformt), was unabhängig das Allocator-Fragmentierungsmuster aus Bug #1 behob.

Keiner der Fixes ist ein Workaround, der obendrauf gepackt ist – beide sind in training/finetune.py als die einzige Implementierung sichtbar, nicht als alternativer Pfad.

Architektur

data/build_dataset.py ──▶ data/{train,eval}.jsonl   (139 examples, template-generated,
                                                       every gold SQL executed at build time)
                              │
        ┌─────────────────────┼─────────────────────┐
        ▼                     ▼                      ▼
training/finetune.py   eval/baseline_frontier.py   tests/test_harness_oracle.py
  (LoRA on a small        (prompt Claude Haiku/       (sanity-checks the harness
   open model)             Sonnet as the baseline)     itself before trusting scores)
        │                     │
        ▼                     │
training/merge_and_quantize.py
        │                     │
        ▼                     ▼
serving/ollama_predictor.py ──┴──▶ eval/harness.py ──▶ eval/report.py ──▶ COMPARISON.md
        │                          (execution-accuracy scoring,
        │                           same logic for every predictor)
        ▼
mcp_server/server.py  (nl_to_sql tool -- installable in Claude Desktop/Code)
        │
        ▼
observability/logger.py  (latency, tokens, cost -- local SQLite, no external account)

Projektstruktur

schema/           synthetic "ShopSphere" e-commerce DB (7 tables) + seeded generator
data/              templated gold (question, SQL) dataset -- every query build-time validated
eval/              execution-accuracy harness, frontier baseline, comparison report
training/          LoRA fine-tuning pipeline + LoRA-merge/quantize script
serving/           Ollama-backed and in-process HF predictors, Ollama Modelfile template
mcp_server/        the installable MCP tool (nl_to_sql)
observability/     self-built call logging (latency/tokens/cost), no external account
tests/             harness sanity checks (oracle predictor must score 100%)

Einrichtung

python3.11 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt          # base: anthropic, mcp, requests
python schema/generate_data.py           # build the seeded database
python data/build_dataset.py             # build + validate the gold dataset
python tests/test_harness_oracle.py      # confirm the eval harness itself is sound

requirements-train.txt fügt torch/transformers/peft/trl für den Feintuning-Pfad hinzu – schwerer, separat gehalten, damit der Eval/Serving/MCP-Pfad schnell installiert.

Die vollständige Pipeline ausführen

1. Frontier-Baseline (benötigt ANTHROPIC_API_KEY):

export ANTHROPIC_API_KEY="..."
python -m eval.baseline_frontier --model claude-haiku-4-5
# writes eval/results_claude-haiku-4-5.json

2. Den Spezialisten feinabstimmen (das ist, was tatsächlich ausgeführt wurde, um die obigen Ergebnisse zu erzeugen – dauert ~15 Minuten aktive Rechenzeit auf einer Laptop-CPU, obwohl die Wanduhrzeit stark mit der Systemlast variiert; eine GPU ist viel schneller, siehe unten):

pip install -r requirements-train.txt
python -m training.finetune --base-model Qwen/Qwen2.5-Coder-0.5B-Instruct --device cpu
python -m training.merge_and_quantize --base-model Qwen/Qwen2.5-Coder-0.5B-Instruct
# then follow the printed llama.cpp + ollama create instructions

3. Den Spezialisten auf dieselbe Weise bewerten wie die Baseline:

python -c "
from eval.harness import run_eval, report_to_dict
from serving.ollama_predictor import OllamaPredictor
import json
report = run_eval(OllamaPredictor())
json.dump(report_to_dict(report), open('eval/results_specialist.json', 'w'), indent=2)
"

4. Den Vergleichsbericht generieren:

python -m eval.report eval/results_claude-haiku-4-5.json eval/results_specialist.json

Feintuning: Skalierung

Die obigen Ergebnisse verwenden Qwen2.5-Coder-0.5B-Instruct auf der CPU, für eine schnelle lokale Iterationsschleife. training/finetune.py --base-model akzeptiert jedes HF-Causal-LM-Repo (oder ein lokales Verzeichnis) – Qwen2.5-Coder-1.5B-Instruct ist ein einfacher Tausch für bessere Qualität, und eine einzelne Cloud-GPU (eine T4 reicht für diese Datensatzgröße) trainiert beide Größen in ein paar Minuten statt ~15:

pip install -r requirements-train.txt
python -m training.finetune \
  --base-model Qwen/Qwen2.5-Coder-1.5B-Instruct \
  --epochs 3

--device {cuda,mps,cpu} überschreibt die Auto-Erkennung. MPS wird auf Apple Silicon automatisch erkannt, aber für diese Aufgabe noch nicht empfohlen – siehe Engineering-Notizen oben.

MCP-Server

# Backend defaults to a locally-served model via Ollama:
python -m mcp_server.server

# Or run against a prompted frontier model instead (no fine-tune needed --
# useful for trying the tool before training anything):
SQL_SPECIALIST_BACKEND=frontier SQL_SPECIALIST_MODEL=claude-haiku-4-5 \
  ANTHROPIC_API_KEY=... python -m mcp_server.server

Zur MCP-Konfiguration von Claude Desktop hinzufügen (claude_desktop_config.json):

{
  "mcpServers": {
    "sql-specialist": {
      "command": "/absolute/path/to/sql-specialist-mcp/.venv/bin/python",
      "args": ["-m", "mcp_server.server"],
      "cwd": "/absolute/path/to/sql-specialist-mcp"
    }
  }
}

Dann Claude etwas fragen wie „Mit dem sql-specialist-Tool, welche Kunden haben noch nie eine Bestellung aufgegeben?“ – es ruft nl_to_sql auf, bekommt echte Zeilen aus der Datenbank zurück und antwortet, gestützt auf die tatsächlichen Daten.

Sicherheitshinweise

  • SQL-Ausführung ist auf zwei unabhängigen Ebenen schreibgeschützt: ein Regex-Guard, der alles außer SELECT/WITH ablehnt, und eine echte OS-Level-schreibgeschützte SQLite-Verbindung (file:...?mode=ro) als Backstop.

  • Der MCP-Server führt nie etwas aus, das der Guard ablehnt, unabhängig davon, was das Modell oder der aufrufende Agent verlangt hat.

  • Keine Geheimnisse sind in diesem Repo gespeichert. ANTHROPIC_API_KEY wird nur aus der Umgebung gelesen.

Was ich als Nächstes bauen würde

  • Die Eval für Spalten-Obermengen normalisieren – eine Vorhersage als korrekt bewerten, wenn die Werte der von der Gold-Abfrage angeforderten Spalten vorhanden sind, statt eine exakte Spalte-für-Spalte-Übereinstimmung zu verlangen. Das ist der Fix, der aus der Fehler-Taxonomie in COMPARISON.md impliziert wird; er würde sehr wahrscheinlich den größten Teil der gemessenen 53,6 %→92,9 %-Lücke schließen und einen Vergleich erzeugen, der tatsächliche Denkfähigkeit von Konventionsabgleich isoliert.

  • eval/baseline_frontier.py auch gegen Claude Sonnet ausführen, für einen Vergleichspunkt mit stärkerem Modell (Haiku ist die günstige/schnelle Stufe; Sonnet ist die Frage „wie viel schließt Modellstärke allein die Lücke“).

  • Qwen2.5-Coder-1.5B-Instruct auf einer GPU feintunen und die Genauigkeit mit dem 0.5B-Ergebnis (92,9 %) vergleichen, um den Größe/Qualitäts-Kompromiss direkt zu quantifizieren.

  • DPO, das auf die beiden bekannten Fehlermodi des Spezialisten abzielt (halluzinierte Spalten, weggelassene Tabellenqualifizierer bei Multi-Joins), jetzt, wo echte Fehlerdaten existieren.

  • vLLM-Serving-Pfad für einen Durchsatzvergleich gegen den Ollama/GGUF-Pfad.

F
license - not found
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables querying and managing a SQLite database using natural language, with an MCP server and Groq LLM.
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to query a SQLite database using natural language through the Model Context Protocol (MCP). Includes security guardrails that block destructive SQL operations.
  • A
    license
    Not graded
    quality
    D
    maintenance
    MCP tool server providing SQLite database access for AI agents.
    MIT

View all related MCP servers

Related MCP Connectors

  • GibsonAI MCP server: manage your databases with natural language

  • Analytical memory for AI agents: a real Postgres queried in plain English over MCP. One command.

  • Free OpenAI-compatible inference with signed provenance receipts and 3 focused MCP tools.

View all MCP Connectors

Latest Blog Posts

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/Eshanya1/sql-specialist-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server