Skip to main content
Glama
harutlc

SQL MCP Server

by harutlc

SQL MCP Server

Un servidor Model Context Protocol (MCP) con IA que te permite consultar y analizar una base de datos SQLite de comercio electrónico usando lenguaje natural.

Haz preguntas como:

  • "¿Quiénes son nuestros 5 mejores clientes por gasto total?"

  • "Muestra todos los productos de la categoría Electrónica con stock inferior a 50"

  • "¿Cuál fue nuestro ingreso total por pedidos completados en 2026?"

Cuatro herramientas, tres de las cuales no necesitan ninguna clave API. Solo lectura en dos niveles independientes, resultados paginados, el texto de error propio de SQLite se devuelve al llamador, y 74 pruebas automatizadas.

ContenidoInicio rápido · Configurar un proveedor · Herramientas · Paginación · Errores · Pruebas · Docker · Clientes MCP · Configuración · Seguridad · Salida de datos · Estructura del proyecto


🚀 Inicio rápido

1. Requisitos previos

  • Node.js: v22.5.0 o superior (para el módulo integrado node:sqlite); se recomienda v24

  • npm: v11.0.0 o superior

2. Instalación

Clona este repositorio e instala las dependencias:

npm install
cp .env.example .env
npm run build

Eso es suficiente para conectar el servidor a un cliente y usar list_tables, describe_table y execute_sql. Solo se necesita un proveedor para la herramienta de lenguaje natural — ver más abajo.


Related MCP server: Shop SQLite MCP

🔑 Configura tu proveedor de IA

Abre el archivo .env y configura tu modelo de IA preferido. El servidor detecta automáticamente tu proveedor según las variables que establezcas:

Opción A: Anthropic Claude (Recomendado)

ANTHROPIC_API_KEY=sk-ant-api03-...
ANTHROPIC_MODEL=claude-opus-5

Opción B: Ollama local (Gratis y sin conexión)

OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=llama3.2

Nota: Asegúrate de que Ollama esté en ejecución (ollama serve) y de haber descargado el modelo (ollama pull llama3.2).

Opción C: OpenAI

OPENAI_API_KEY=sk-proj-...
OPENAI_MODEL=gpt-4o-mini

Opción D: Personalizado / Terceros (Groq, DeepSeek, OpenRouter)

OPENAI_API_KEY=your_api_key
OPENAI_BASE_URL=https://api.groq.com/openai/v1
OPENAI_MODEL=llama-3.3-70b-versatile

🛠 Herramientas disponibles

Tres de las cuatro hablan directamente con SQLite — sin clave API, sin costo, al instante:

Herramienta

Qué hace

Necesita un proveedor

list_tables

Cada tabla con una explicación en lenguaje sencillo de qué contiene, su número de filas y columnas, además de las relaciones entre tablas y la convención de ingresos que usa esta base de datos.

No

describe_table

Una tabla completa: columnas con tipos, claves y descripciones, claves foráneas, la sentencia CREATE TABLE, advertencias y el rango de fechas que realmente cubren las columnas de fecha.

No

execute_sql

Cualquier SELECT de solo lectura, devolviendo filas JSON estructuradas y nombres de columnas. Admite paginación con limit / offset. Esta es la herramienta a usar para trabajo analítico que quieras controlar tú mismo.

No

query_database

Toma una pregunta en lenguaje natural, genera y ejecuta el SQL apropiado, y devuelve una respuesta escrita con información.

La descripción de cada herramienta le dice al agente llamador no solo qué hace, sino cuándo no usarla — query_database indica que devuelve prosa en lugar de valores, cuesta dinero y hace dos llamadas a la LLM, y señala a execute_sql para cualquier cosa que el agente pretenda calcular. Ambas herramientas indican el límite de filas y la convención de ingresos en línea, para que el agente no tenga que descubrirlos por prueba y error.

Ejemplo: describe_table

// describe_table { "table_name": "orders" } — abridged
{
  "table": "orders",
  "purpose": "Order headers — one row per order placed by a customer, carrying its date, lifecycle status and total.",
  "rowCount": 750,
  "columns": [
    { "name": "status", "type": "TEXT", "primaryKey": false, "notNull": true, "default": null,
      "description": "Lifecycle stage, one of: new, processing, shipped, completed, cancelled. Determines whether the order counts as revenue." }
  ],
  "foreignKeys": [
    { "column": "customer_id", "referencesTable": "customers", "referencesColumn": "id", "onDelete": "CASCADE" }
  ],
  "notes": ["Revenue convention: count every order whose status is not 'cancelled' …"],
  "dataCoverage": { "order_date": { "min": "2026-02-17 18:53:30", "max": "2026-08-22 17:06:30" } },
  "createStatement": "CREATE TABLE orders ( … )"
}

dataCoverage está ahí para que un agente pueda distinguir un resultado vacío de una pregunta fuera de rango: preguntar por 2025 devuelve "los datos van de … a …" en lugar de un cero desnudo que parezca un error.


📄 Paginación de resultados grandes

Cada resultado está limitado — a DATABASE_MAX_ROWS (por defecto 100), o a un limit menor que pases. Un limit mayor se ajusta en lugar de rechazarse, por lo que un llamador siempre recibe filas.

execute_sql acepta limit y offset y te dice si hay más:

// execute_sql { "sql": "SELECT id, name FROM products ORDER BY id", "limit": 2, "offset": 2 }
{
  "columns": ["id", "name"],
  "rows": [
    { "id": 3, "name": "Ноутбук UltraBook 15" },
    { "id": 4, "name": "Умные часы FitWatch" }
  ],
  "rowCount": 2,
  "offset": 2,
  "hasMore": true,
  "nextOffset": 4,
  "note": "More rows matched than were returned. Call again with offset=4 for the next page.",
  "executionTimeMs": 0.09
}

Sigue llamando con offset: nextOffset hasta que hasMore sea false. Cuando un resultado cabe en una página, hasMore es false y totalAvailableRows informa el total real.

El límite se aplica mientras se recorre la sentencia, no recortando un resultado terminado: el servidor se detiene una fila después del límite y nunca materializa el resto. El SQL es generado por el modelo, por lo que una unión cruzada accidental podría traer millones de filas a la memoria antes de descartar alguna. La paginación también se realiza durante la iteración en lugar de añadir LIMIT/OFFSET al SQL, lo que tendría que sobrevivir a lo que ya termine la sentencia generada.

query_database comparte el límite de filas pero no pagina — resume en prosa, donde un número de página no tiene a qué adjuntarse. Usa execute_sql para cualquier cosa mayor que una página.


🚦 Cómo se ve un error

Los fallos vuelven como resultados normales de herramientas MCP con isError: true y un mensaje sobre el que el agente llamador puede actuar, en lugar de fallos a nivel de transporte.

Lo que envías

Lo que recibes

SELECT nope FROM products

Query execution failed: no such column: nope

DELETE FROM orders

Only read-only queries are permitted. A statement must begin with SELECT, WITH or VALUES, but this one begins with "DELETE".

SELECT 1; SELECT 2

Only a single SQL statement may be executed. Multiple statements were provided.

describe_table {"table_name": "custmers"}

No table named "custmers". Available tables: customers, order_items, orders, products.

Una solicitud en lenguaje natural para borrar datos

This request asks to modify the database, which is not permitted … No changes were made. You can still ask about the same records: …

Dos reglas gobiernan ese texto:

  • El mensaje propio de SQLite se conserva. "no such column: nope" es lo más útil que se le puede decir a un agente, porque es suficiente para reescribir la consulta y reintentar. Nunca se aplana a "consulta fallida".

  • El detalle del host nunca escapa. Los errores no reconocidos — que pueden llevar un seguimiento de pila — se colapsan a una línea genérica, y todo lo que sale se limpia de la ruta de la base de datos, la raíz del proyecto y el directorio personal. El detalle completo permanece en los registros del servidor. Esto está cubierto por su propio archivo de prueba.


🧪 Pruebas automatizadas

npm test          # 74 tests across 4 files, runs in well under a second
npm run test:watch
npm run typecheck

node --test simple con tsx — sin dependencia de framework de pruebas. Las suites se ejecutan contra la base de datos real db/shop.db, no un simulacro, por lo que fallan si el esquema y la documentación se separan.

Archivo

Cubre

tests/sql-guard.test.ts

Cada forma en que una escritura podría colarse más allá del guardián de solo lectura: comentarios iniciales, WITH x AS (…) DELETE, sentencias apiladas, DML encerrado en bloques de código Markdown. Además lo contrario — que replace(), una palabra clave dentro de un literal de cadena y un identificador entre comillas nombrado como una palabra clave no se rechacen.

tests/database.test.ts

Límite de filas, paginación con offset, un offset más allá del final, una unión cruzada descontrolada que no debe materializarse, nombres de columnas en un resultado vacío, escrituras rechazadas que dejan la base de datos sin cambios, el mensaje de SQLite sobreviviendo.

tests/errors.test.ts

Lo que un llamador puede ver: los mensajes accionables pasan, los errores desconocidos se colapsan, y la ruta de la base de datos / raíz del proyecto / directorio personal se redactan de ambos.

tests/schema-metadata.test.ts

Que cada tabla y columna en la base de datos en vivo tenga una descripción escrita, que ninguna descripción se refiera a una tabla que ya no existe, y que la convención de ingresos esté declarada.

La suite del guardián es la más importante: es el límite que hace que "solo lectura" sea verdadero en lugar de meramente intencionado, y uno de sus casos es un falso positivo real que detectó durante el desarrollo.


🐳 Docker

docker build -t sql-mcp .

La imagen incluye la base de datos, por lo que no necesita montar un volumen. Como este es un servidor stdio, debe ejecutarse con -i y sin TTY — la entrada y salida estándar del contenedor transportan el flujo JSON-RPC:

docker run -i --rm -e ANTHROPIC_API_KEY sql-mcp

Conéctalo a un cliente con examples/claude_desktop_config.docker.json. Elimina el -e ANTHROPIC_API_KEY para ejecutarlo sin credenciales — list_tables, describe_table y execute_sql funcionan sin proveedor.

La construcción es de múltiples etapas: TypeScript se compila en un constructor node:24-alpine, y solo dist/, db/ y las dependencias de producción se copian a la imagen de ejecución. Se ejecuta como el usuario no privilegiado node, nunca se copia ningún .env (las credenciales vienen de -e), y no hay complementos nativos que compilar porque SQLite viene dentro del propio Node.


🔌 Conexión a clientes MCP

Los archivos de configuración listos para usar están en examples/ — copia el que coincida con tu cliente y reemplaza la ruta. examples/claude_desktop_config.no-api-key.json ejecuta el servidor sin credenciales en absoluto, lo que es suficiente para list_tables, describe_table y execute_sql.

Configuración de Claude Desktop

Añade este servidor a tu archivo de configuración de Claude Desktop (claude_desktop_config.json):

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

(Asegúrate de ejecutar npm run build una vez antes de conectar)

Ejemplo 1: Anthropic Claude (Predeterminado)

{
  "mcpServers": {
    "sql-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/sql-mcp/dist/index.js"],
      "env": {
        "ANTHROPIC_API_KEY": "sk-ant-api03-your-key-here",
        "ANTHROPIC_MODEL": "claude-opus-5"
      }
    }
  }
}

Ejemplo 2: Ollama local (Gratis y sin conexión)

{
  "mcpServers": {
    "sql-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/sql-mcp/dist/index.js"],
      "env": {
        "OLLAMA_BASE_URL": "http://localhost:11434",
        "OLLAMA_MODEL": "llama3.2"
      }
    }
  }
}

Ejemplo 3: OpenAI

{
  "mcpServers": {
    "sql-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/sql-mcp/dist/index.js"],
      "env": {
        "OPENAI_API_KEY": "sk-proj-your-key-here",
        "OPENAI_MODEL": "gpt-4o-mini"
      }
    }
  }
}

Ejemplo 4: Personalizado / Groq / OpenRouter / DeepSeek

{
  "mcpServers": {
    "sql-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/sql-mcp/dist/index.js"],
      "env": {
        "OPENAI_API_KEY": "gsk_your_groq_api_key",
        "OPENAI_BASE_URL": "https://api.groq.com/openai/v1",
        "OPENAI_MODEL": "llama-3.3-70b-versatile"
      }
    }
  }
}

El servidor resuelve db/shop.db relativo a su propia ubicación, por lo que DATABASE_PATH no es necesario en ninguno de estos — los clientes MCP lanzan servidores desde un directorio de trabajo de su elección, y el servidor no depende de él.


🔎 Probarlo localmente

Prueba instantánea en terminal

Puedes probar preguntas en lenguaje natural directamente en tu terminal:

npm run query -- "Show top 3 products by price"

Inspector web visual

Prueba las herramientas de forma interactiva en tu navegador usando el Inspector MCP oficial:

npm run inspect:dev
  1. Abre la URL del inspector en tu navegador (por ejemplo, http://localhost:5173).

  2. Haz clic en Conectar.

  3. En Herramientas, selecciona query_database, ingresa tu pregunta y haz clic en Ejecutar herramienta.

Todos los scripts de npm

Script

Función

npm run build / npm run clean

Compilar a dist/ · eliminarlo

npm start

Ejecutar el servidor compilado sobre stdio

npm run dev

Ejecutar desde el código fuente con recarga (tsx watch)

npm test / npm run test:watch

Pruebas automatizadas

npm run typecheck

tsc --noEmit

npm run query -- "…"

Hacer una pregunta desde la terminal

npm run inspect / npm run inspect:dev

MCP Inspector contra dist/ · contra el código fuente


🔧 Referencia de configuración

Todas las variables son opcionales; los valores predeterminados son los que se usan si no configuras nada.

Variable

Valor predeterminado

Propósito

DATABASE_PATH

db/shop.db

Ubicación de la base de datos. Absoluta o relativa a la raíz del proyecto, nunca al directorio de trabajo.

DATABASE_MAX_ROWS

100

Límite máximo de filas devueltas por llamada y de filas enviadas al LLM. El limit de execute_sql solo puede reducirlo.

LLM_TIMEOUT_MS

60000

Tope por solicitud para las llamadas al LLM. Una pregunta hace dos llamadas secuenciales, así que sin esto un proveedor bloqueado cuelga la llamada a la herramienta.

LLM_PROVIDER

detección automática

anthropic | ollama | openai | custom. Normalmente se infiere de qué claves configuras.

ANTHROPIC_API_KEY / ANTHROPIC_MODEL

— / claude-opus-5

Proveedor Anthropic.

OPENAI_API_KEY / OPENAI_MODEL / OPENAI_BASE_URL

— / gpt-4o-mini / OpenAI

OpenAI y cualquier endpoint compatible con OpenAI.

OLLAMA_BASE_URL / OLLAMA_MODEL

http://localhost:11434 / llama3.2

Ollama local.

DEBUG

sin definir

sql-mcp:*, o un solo espacio de nombres: server, query-engine, database, llm, tools.

Un valor mal formado se notifica en stderr y se recurre al valor predeterminado en lugar de aceptarse en silencio: un error tipográfico en el bloque env de un cliente aparece al iniciar en lugar de comportarse como si la variable nunca se hubiera definido. Los registros de DEBUG incluyen cada pregunta formulada y cada sentencia generada, y bajo un cliente MCP terminan en los archivos de registro persistentes del cliente, así que permanecen desactivados salvo que optes por activarlos.


🔒 Seguridad

La base de datos se abre en modo solo lectura a nivel del controlador, y cada sentencia se valida antes de ejecutarse: debe ser una única sentencia SELECT/WITH/VALUES, sin ninguna palabra clave que escriba datos, altere el esquema o cambie el estado de la conexión. Ninguna de las dos comprobaciones puede desactivarse mediante configuración. Una solicitud como "eliminar todos los pedidos cancelados" se rechaza en lugar de ejecutarse.

El validador trabaja sobre una vista tokenizada de la sentencia en lugar del texto bruto, por lo que los comentarios, los literales de cadena y los identificadores entre comillas no pueden usarse para ocultar una palabra clave: /* c */ DELETE FROM orders y WITH x AS (SELECT 1) DELETE FROM orders se rechazan ambos, mientras que SELECT replace(name, 'a', 'b') no se rechaza.

El texto que este servidor no ha escrito — tu pregunta y los valores leídos de la base de datos — se delimita en los prompts con un marcador infalsificable por solicitud, de modo que un producto llamado Widget (SYSTEM: ignore prior instructions…) no pueda escapar al contexto de instrucciones. Eso importa más allá de este proceso: la respuesta viaja de vuelta al agente que llama como salida de la herramienta, un salto más allá.


🔐 Qué se envía y adónde

Este servidor responde preguntas llamando a un LLM, así que el contenido de la base de datos sale de tu máquina en cada llamada a query_database. Concretamente, cada llamada envía:

  1. El esquema de tu base de datos — nombres de tablas, nombres y tipos de columnas, y recuentos de filas — para generar el SQL.

  2. Las filas que devolvió la consulta (hasta DATABASE_MAX_ROWS, 100 por defecto) — para convertirlas en una respuesta escrita.

En la base de datos de tienda incluida, esas filas incluyen nombres de clientes, direcciones de correo electrónico y números de teléfono. Van al proveedor que configures, en el endpoint que nombre OPENAI_BASE_URL — que para Groq, OpenRouter o DeepSeek es un tercero bajo sus propios términos.

Si eso no es aceptable para tus datos:

  • Usa las otras tres herramientas. list_tables, describe_table y execute_sql no hacen ninguna llamada de red — nada sale de la máquina.

  • Usa Ollama. Se ejecuta localmente, así que nada sale de la máquina.

  • Restringe las consultas. Las preguntas agregadas ("ingresos por categoría") devuelven filas de resumen en lugar de registros de clientes.

  • Reduce DATABASE_MAX_ROWS para limitar cuántos datos de filas se envían por consulta.

El servidor nunca envía el archivo de la base de datos, y solo puede leer — consulta Seguridad.


📁 Estructura del proyecto

src/
  index.ts                  MCP server entry point (stdio transport)
  cli.ts                    Terminal harness: npm run query -- "…"
  config/                   Env parsing, provider detection, path resolution
  tools/                    The four MCP tools and their descriptions
  services/
    database.service.ts     SQLite access, row capping, paging, introspection
    sql-guard.ts            Read-only enforcement (tokenizing validator)
    errors.ts               Caller-safe messages, path redaction
    schema-metadata.ts      Human-written meaning the schema cannot record
    query-engine.service.ts NL → SQL → execute → prose pipeline
    llm/                    Anthropic / OpenAI / Ollama behind one interface
  prompts/                  SQL generation, humanization, untrusted-input framing
tests/                      node --test suites (see Automated Tests)
db/                         shop.db and its schema documentation
docs/                       Architecture and sequence diagrams
examples/                   Ready-to-paste client configurations

📚 Documentación técnica

Install Server
F
license - not found
A
quality
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 natural-language sales queries against a SQLite database, generating and executing read-only SQL through a secure MCP server with table listing, schema description, and query execution.
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables safe, read-only analysis of an online store's SQLite database, providing schema introspection, restricted SELECT queries, and specialized analytics tools through MCP.
  • F
    license
    A
    quality
    C
    maintenance
    Enables read-only interaction with an online store's SQLite database over MCP stdio, including table listing, schema inspection, safe read-only SQL execution, and sales analytics. It rejects mutating SQL operations to keep data intact.
    4
  • F
    license
    A
    quality
    C
    maintenance
    Enables AI agents to read-only query an online store's SQLite database, listing tables, inspecting schemas, and running SELECT queries over customers, products, orders, and order items.
    3

View all related MCP servers

Related MCP Connectors

  • Connect e-commerce and marketing data to AI assistants via MCP.

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

  • GibsonAI MCP server: manage your databases with natural language

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

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