Skip to main content
Glama
Eshanya1

sql-specialist-mcp

by Eshanya1

sql-specialist-mcp

Un modelo pequeño, de pesos abiertos y ajustado finamente que responde preguntas en lenguaje natural sobre una base de datos SQLite, expuesto como herramienta MCP que cualquier cliente MCP (Claude Desktop, Claude Code, agentes personalizados) puede llamar directamente. Está respaldado por un banco de pruebas de evaluación basado en exactitud de ejecución que compara al especialista con la técnica de prompting a un modelo frontera en exactitud, latencia y coste.

El objetivo de este proyecto no es «hacer una demo de texto a SQL»; es mostrar las partes de la ingeniería de LLM que están por debajo del prompting: tomar un modelo pequeño, adaptarlo a una tarea mediante LoRA, servirlo de forma eficiente y demostrar con una evaluación real basada en ejecución que un especialista barato es competitivo con (o mejor que) el prompting de un modelo frontera para esta tarea concreta.

Prueba la demo interactiva — recorre las 28 preguntas reales de la evaluación y mira el SQL real generado por el especialista, la latencia y las filas de resultado junto a la línea base del modelo frontera. No requiere instalación.

Por qué existe esto

La mayoría de los proyectos «text-to-SQL» de portafolio de IA son guías de inicio rápido de LangChain. Hay dos cosas que aquí pretenden ser diferentes:

  1. La evaluación es rigurosa, no una cuestión de impresiones. Cada consulta de referencia (gold) se ejecuta contra la base de datos al construir el conjunto de datos (139/139 validadas), y la puntuación compara conjuntos de resultados, no el texto de la consulta: una consulta semánticamente correcta con un orden de columnas distinto sigue puntuando como correcta. Un predictor que solo repite la SQL de referencia puntúa un 100%; un predictor que siempre devuelve una consulta trivialmente incorrecta puntúa un 0%. Ambos están incluidos como pruebas de cordura (tests/test_harness_oracle.py) para que la corrección del propio banco de pruebas no se dé por supuesta.

  2. Se distribuye como algo utilizable, no solo un repositorio de demostración. El modelo ajustado se expone como una herramienta MCP real (nl_to_sql): apunta Claude Desktop o Claude Code a mcp_server/server.py y puede consultar realmente la base de datos como parte de una conversación.

Related MCP server: mcp-sqlite-chat

Resultados

El pipeline completo se ha ejecutado de extremo a extremo en hardware real, en ambos lados: ajuste fino LoRA real, fusión real, cuantización GGUF real, servicio con Ollama real, evaluación real — y una línea base real de modelo frontera contra la API de Claude en vivo. Modelo base: Qwen/Qwen2.5-Coder-0.5B-Instruct (elegido por su bucle de iteración rápido en un portátil; consulta Ajuste fino más abajo para la ruta de 1.5B).

Predictor

Exactitud

n

latencia p50

latencia p95

Coste / 1k llamadas

frontera: Claude Haiku 4.5 (con prompting)

53.6%

28

1055ms

1884ms

$1.06

sql-specialist (ajustado, cuantizado, local)

92.9%

28

207ms

371ms

$0.00

Léelo teniendo en cuenta la advertencia, no solo el titular. Audité manualmente cada uno de los 13 «fallos» medidos de Claude Haiku con este conjunto de evaluación: cero eran errores de lógica SQL. Los 13 eran desajustes de convención en la selección de columnas o en el orden de las filas — p. ej., devolver (name, email) cuando la respuesta de referencia era solo (name), o filas correctas en un orden distinto al de un ORDER BY que la pregunta original nunca especificaba. La estricta métrica de exactitud de ejecución (eval/execution.py compara filas de resultados columna por columna) puntúa esos casos igual que una consulta realmente errónea, algo que el especialista ajustado nunca produce porque ha memorizado las convenciones exactas de este conjunto de datos a partir de 111 ejemplos de entrenamiento — algo que un modelo frontera con prompting zero-shot no tiene forma de saber. Taxonomía completa fallo por fallo en COMPARISON.md.

Así que: la brecha de exactitud es real, pero en parte es un artefacto de lo que la evaluación premia, no puramente una brecha de razonamiento. La brecha de latencia y coste no es un artefacto — 207ms/local/gratis frente a 1055ms/$1.06-por-cada-1000-llamadas es el resultado real y sin edulcorar de ejecutar un modelo cuantizado de 0.5B en local en lugar de llamar a una API, y es la comparación sobre la que realmente se sustenta la premisa de este proyecto.

Los 2 fallos propios del especialista (de 28) fueron errores lógicos genuinos, no desajustes de formato: alucinar una columna orders.total que no existe en este esquema, y omitir un calificador de tabla en un SELECT de varias tablas. El entrenamiento convergió limpiamente en 3 épocas (pérdida de evaluación 0.060 → 0.048 → 0.008), y el modelo cuantizado (988MB f16 → 373MB q4_k_m) se sirve a través de Ollama en ~200ms.

Qué es real aquí

Ser transparente sobre esto importa más de lo que parece: es la diferencia entre un proyecto en el que un reclutador puede confiar y uno que suena a marketing.

  • La base de datos y el conjunto de datos sintéticos son demostrablemente correctos. shopsphere.db se siembra de forma determinista (seed=42); cada uno de los 139 pares (pregunta, SQL) de referencia en data/*.jsonl se genera a partir de plantillas parametrizadas y se ejecuta contra la base de datos real en tiempo de construcción: una plantilla que produce SQL inválido hace fallar la construcción; no envía silenciosamente una etiqueta incorrecta.

  • La corrección del banco de pruebas de evaluación está a su vez probada, no se da por supuesta: tests/test_harness_oracle.py verifica que un predictor oráculo (que devuelve la SQL de referencia tal cual) puntúe exactamente un 100% y que un predictor deliberadamente incorrecto puntúe ~0%, antes de confiar en la cifra de cualquier predictor real.

  • Exactitud de ejecución, no coincidencia de cadenas. eval/execution.py compara conjuntos de resultados (insensible al orden salvo que la consulta de referencia tenga ORDER BY), de modo que una consulta escrita de forma distinta pero semánticamente equivalente sigue puntuando como correcta.

  • El ajuste fino es real, en esta máquina, y se verificó su convergencia. LoRA (8.8M de parámetros entrenables, el 1.75% del modelo) durante 3 épocas, con la pérdida de evaluación descendiendo de forma monótona en cada época. Consulta Notas de ingeniería más abajo para ver dos errores reales encontrados y corregidos en el camino.

  • La ejecución SQL está realmente aislada (sandboxed), no solo se le pide que se comporte bien: las consultas de lectura se validan contra una lista blanca de regex y se ejecutan contra una conexión SQLite realmente de solo lectura a nivel de sistema operativo (mode=ro) — un fallo en la protección regex no puede acabar en una escritura. Esto importa más allá del banco de pruebas de evaluación, porque la misma protección se ejecuta en el servidor MCP, donde el SQL proviene de un modelo que responde a la pregunta de un agente, no de un conjunto de evaluación curado.

  • El servidor MCP es una herramienta real e invocable que sirve el modelo ajustado real, verificado de extremo a extremo: nl_to_sql("Which employees have no manager assigned?") → genera SQL mediante el modelo cuantizado a través de Ollama → lo ejecuta en solo lectura → devuelve filas reales → registra latencia/coste en observabilidad.

  • La observabilidad está construida a medida y sin dependenciasobservability/logger.py registra cada llamada (latencia, tokens, coste estimado, éxito/fallo) en un archivo SQLite local, sin necesidad de cuenta externa, con el mismo patrón que pr-review-agent.

  • La línea base del modelo frontera también es realeval/baseline_frontier.py se ejecutó contra la API de Claude en vivo (Claude Haiku 4.5), no solo se importó sin problemas. Sus «fallos» resultaron revelar un hallazgo real de metodología de evaluación; consulta Resultados más arriba y COMPARISON.md para la auditoría manual completa de fallos.

Notas de ingeniería: dos errores reales encontrados al ejecutar esto de verdad

Ejecutar de verdad el ajuste fino (en lugar de dejarlo como «debería funcionar en teoría») sacó a la luz dos errores reales de memoria de PyTorch, ambos corregidos en el código actual:

  1. Crecimiento descontrolado del asignador de caché de MPS. Entrenar en el backend MPS de Apple Silicon mediante transformers.Trainer hacía que el proceso se inflara hasta 23GB de RSS y se colgara, con el padding dinámico por lote: cada forma distinta (batch, seq_len) recibe su propio grupo de memoria en el asignador MPS de PyTorch, que no devuelve la memoria liberada al sistema operativo. Solución: --device cpu en finetune.py y, más de fondo, padding de longitud fija (más abajo) para que esta clase de error no pueda repetirse en ningún backend.

  2. Sobrecarga de Trainer/DataLoader, no del modelo. Un pase directo de forward+backward se cronometró en 1.6s/ejemplo; el mismo cálculo a través de transformers.Trainer dejaba el proceso inactivo durante minutos entre pasos registrados, sin cómputo correspondiente. Se encontró la causa raíz aislando el forward/backward real del modelo+LoRA con cronometraje manual antes de asumir que el error estaba en el código del modelo. Solución: se sustituyó Trainer por un bucle de entrenamiento manual de ~40 líneas (training/finetune.py): misma configuración LoRA, control directo sobre el bucle de lotes, sin sobrecarga inexplicable. También se cambió la colación de lotes de dinámica por lote a padding de longitud fija (todos los lotes con la misma forma), lo que por separado corrigió el patrón de fragmentación del asignador del error n.º 1.

Ninguna de las dos soluciones es un parche colocado encima: ambas aparecen en training/finetune.py como la única implementación, no como un camino alternativo.

Arquitectura

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)

Estructura del proyecto

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%)

Configuración

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 añade torch/transformers/peft/trl para la ruta de ajuste fino: es más pesado y se mantiene separado para que la ruta de evaluación/servicio/MCP se instale rápido.

Ejecutar el pipeline completo

1. Línea base del modelo frontera (necesita 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. Ajuste fino del especialista (esto es lo que se ejecutó realmente para producir los resultados anteriores: tarda ~15 min de cómputo activo en una CPU de portátil, aunque el tiempo real transcurrido varía mucho con la carga del sistema; una GPU es mucho más rápida, ver más abajo):

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. Puntúa al especialista de la misma manera que a la línea base:

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. Genera el informe de comparación:

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

Ajuste fino: cómo escalar

Los resultados anteriores usan Qwen2.5-Coder-0.5B-Instruct en CPU, para un bucle de iteración local rápido. training/finetune.py --base-model acepta cualquier repositorio de HF de LM causal (o un directorio local): Qwen2.5-Coder-1.5B-Instruct es un cambio directo para mejor calidad, y una sola GPU en la nube (una T4 es suficiente para este tamaño de conjunto de datos) entrena cualquiera de los dos tamaños en un par de minutos en lugar de ~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} anula la detección automática. MPS se detecta automáticamente en Apple Silicon, pero todavía no se recomienda para esta tarea; consulta Notas de ingeniería más arriba.

Servidor MCP

# 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

Añade lo siguiente a la configuración MCP de Claude Desktop (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"
    }
  }
}

Después pídele a Claude algo como «Usando la herramienta sql-specialist, ¿qué clientes nunca han realizado un pedido?»: llamará a nl_to_sql, recibirá filas reales de la base de datos y responderá basándose en los datos reales.

Notas de seguridad

  • La ejecución SQL es de solo lectura en dos capas independientes: una protección regex que rechaza cualquier cosa que no sea SELECT/WITH, y una conexión SQLite realmente de solo lectura a nivel de sistema operativo (file:...?mode=ro) como respaldo final.

  • El servidor MCP nunca ejecuta nada que la protección rechace, sin importar lo que hayan pedido el modelo o el agente que llama.

  • No se almacenan secretos en este repositorio. ANTHROPIC_API_KEY se lee únicamente de las variables de entorno.

Qué construiría a continuación

  • Normalizar la evaluación para superconjuntos de columnas: puntuar como correcta una predicción si están presentes los valores de las columnas solicitadas en la referencia, en lugar de exigir una coincidencia exacta columna por columna. Esta es la corrección que implica la taxonomía de fallos de COMPARISON.md; muy probablemente cerraría la mayor parte de la brecha medida del 53.6%→92.9% y daría una comparación que aísle la capacidad real de razonamiento del seguimiento de convenciones.

  • Ejecutar también eval/baseline_frontier.py contra Claude Sonnet, como punto de comparación con un modelo más potente (Haiku es el nivel barato/rápido; Sonnet responde a la pregunta de «cuánto cierra la brecha la potencia del modelo por sí sola»).

  • Ajustar finamente Qwen2.5-Coder-1.5B-Instruct en una GPU y comparar su exactitud con el resultado de 0.5B (92.9%) para cuantificar directamente la compensación tamaño/calidad.

  • Aplicar DPO dirigido a los dos modos de fallo conocidos del especialista (columnas alucinadas, calificadores de tabla omitidos en multi-joins), ahora que existen datos reales de fallos.

  • Ruta de servicio con vLLM para comparar el rendimiento con la ruta Ollama/GGUF.

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