Skip to main content
Glama

shop-mcp

Un servidor MCP (Model Context Protocol) local y de solo lectura que permite a un agente de IA analizar una base de datos SQLite de comercio electrónico (shop.db) — clientes, productos, pedidos y artículos de pedido — a través del transporte stdio. Sin servidor HTTP, sin proceso de base de datos separado: el servidor abre shop.db directamente y expone dos herramientas pequeñas y de propósito general que un agente puede usar para explorar el esquema y ejecutar su propio SQL analítico.

Construido con el SDK oficial de Python para MCP (mcp en PyPI).

Estructura del proyecto

mcp-sql/
├── server.py                    # the MCP server (stdio transport)
├── shop.db                      # SQLite database (not modified by this project)
├── requirements.txt
├── .env.example
├── mcp-config.example.json
├── tests/
│   ├── conftest.py
│   ├── test_server.py           # unit tests (call tool functions directly)
│   └── test_stdio_integration.py# protocol-level test (spawns server.py over stdio)
└── README.md

Esquema de la base de datos (tal como se encuentra realmente en shop.db)

customers(id PK, first_name, last_name, email UNIQUE, phone, created_at)
products(id PK, name, category, price, stock_quantity, created_at)
orders(id PK, customer_id -> customers.id, order_date, status, total_amount)
order_items(id PK, order_id -> orders.id, product_id -> products.id, quantity, unit_price)

orders.status está restringido a: new, processing, shipped, completed, cancelled. products.category tiene actualmente 5 valores distintos. Claves foráneas: orders.customer_id → customers.id, order_items.order_id → orders.id, order_items.product_id → products.id. El servidor deriva todo esto de la base de datos en vivo en el momento de la consulta (a través de sqlite_master / PRAGMA table_info / PRAGMA foreign_key_list) — nada aquí está codificado, así que si shop.db se reemplaza por otro archivo con un esquema diferente, get_database_schema lo reflejará automáticamente.

Características de datos conocidas del shop.db proporcionado: customers no tiene columna country, por lo que preguntas del tipo "clientes de Alemania" no se pueden responder — la herramienta de esquema hace que esto sea descubrible, y query_database devuelve un error claro no such column: country en lugar de adivinar. Los 750 pedidos actualmente en la base de datos están fechados en 2026 (ninguno en 2025), por lo que una consulta de "ingresos en 2025" devuelve correctamente 0/null, no un error.

Instalación

cd mcp-sql
python3 -m venv .venv
source .venv/bin/activate        # on Windows: .venv\Scripts\activate
pip install -r requirements.txt

Configuración

La ruta de la base de datos nunca está codificada en el código fuente. Se resuelve como:

  1. la variable de entorno SHOP_DB_PATH, si está configurada;

  2. de lo contrario, shop.db junto a server.py.

Copia .env.example a .env y edítalo si quieres apuntar el servidor a un archivo de base de datos diferente (tendrás que cargarlo en tu shell/lanzador de agente tú mismo, por ejemplo export $(cat .env | xargs), o simplemente configurar SHOP_DB_PATH directamente):

cp .env.example .env
# edit .env, or simply:
export SHOP_DB_PATH=/absolute/path/to/shop.db

Ejecutar

source .venv/bin/activate
python server.py

El proceso habla MCP sobre stdio y espera a un cliente — parecerá "atascado" sin salida, lo cual es esperado: conecta un cliente MCP (un agente de IA, o mcp-inspector, ver más abajo) en lugar de ejecutarlo de forma independiente en una terminal.

Comprobación manual rápida con el Inspector MCP oficial (sin necesidad de instalación):

npx @modelcontextprotocol/inspector --cli .venv/bin/python server.py --method tools/list

Conectar a un agente de IA

La mayoría de los clientes compatibles con MCP (Claude Desktop, Claude Code, etc.) leen un bloque de configuración JSON como mcp-config.example.json:

{
  "mcpServers": {
    "shop-mcp": {
      "command": "/absolute/path/to/mcp-sql/.venv/bin/python",
      "args": ["/absolute/path/to/mcp-sql/server.py"],
      "env": {
        "SHOP_DB_PATH": "/absolute/path/to/mcp-sql/shop.db"
      }
    }
  }
}

Notas:

  • Usa la ruta absoluta al intérprete de Python del venv (como arriba) para que el paquete mcp se encuentre sin activar el venv manualmente; usar un python3 simple también funciona si mcp está instalado en el entorno al que resuelve.

  • SHOP_DB_PATH es opcional — omítelo para usar el shop.db incluido.

  • Las rutas absolutas pertenecen a este archivo de configuración, proporcionado por quien conecta el servidor — nunca dentro de server.py mismo.

  • La ubicación específica de este bloque varía según el cliente (por ejemplo, Claude Desktop usa claude_desktop_config.json con la misma forma mcpServers; otros clientes pueden querer solo el objeto interno {"command": ..., "args": ..., "env": ...}). Consulta la documentación de tu cliente para saber dónde vive el archivo.

Pruebas

source .venv/bin/activate
python -m pytest tests/ -v

Esto ejecuta 48 pruebas, incluyendo:

  • descubrimiento de esquema (tablas, columnas, PK/FK, relaciones, recuentos de filas);

  • SELECT, JOIN, WHERE, GROUP BY, ORDER BY, agregados (COUNT/SUM/AVG/MIN/MAX), subconsultas, un CTE seguro WITH ... SELECT, y filtrado por fecha (strftime);

  • limitación del límite de filas y paginación basada en offset;

  • manejo amigable de errores para SQL inválido, tablas/columnas desconocidas, una consulta vacía y un archivo de base de datos faltante;

  • seguridad de solo lectura: cada tipo de declaración listado en la asignación (DELETE, UPDATE, DROP, CREATE, INSERT, además de ALTER, REPLACE, TRUNCATE, ATTACH, DETACH, VACUUM, REINDEX, un PRAGMA destructivo, un SELECT 1; DROP TABLE ... apilado, y un WITH x AS (...) DELETE ... con CTE disfrazado) es rechazado, y se verifica que los recuentos de filas y el hash SHA-256 del archivo de base de datos no cambien después;

  • tests/test_stdio_integration.py lanza server.py como un subproceso real y lo maneja a través del SDK de cliente MCP real sobre stdio (initializelist_toolscall_tool), en lugar de llamar a funciones de Python directamente — este es el mismo camino que usa un agente real.

Herramientas MCP

get_database_schema()

Sin parámetros. Llama a esto primero siempre que no conozcas los nombres exactos de tablas/columnas — no los adivines. Devuelve, por tabla: row_count, columns (nombre, tipo SQLite, not_null, default_value, is_primary_key), primary_key, foreign_keys (columna, tabla/columna referenciada, ON DELETE/ON UPDATE), y algunas sample_rows para que el agente pueda ver formatos de fecha reales, valores de estado, magnitudes de precios, etc. Una lista relationships de nivel superior da cadenas tabla.columna -> otra_tabla.columna derivadas de las claves foráneas en vivo.

query_database(sql, limit=100, offset=0)

Ejecuta una declaración SQL de solo lectura (SELECT, o WITH ... SELECT) y devuelve {columns, rows, row_count, limit, offset, truncated, total_matching_rows}. Soporta JOIN, WHERE, GROUP BY, ORDER BY, funciones agregadas, subconsultas y CTEs. limit se limita a 1..500 (por defecto 100); usa offset para paginar a través de resultados más grandes. total_matching_rows y truncated le dicen al llamador si la página actual es el resultado completo o si hay más para obtener. Los errores (sintaxis incorrecta, tabla/columna desconocida, o un intento de escritura rechazado) se lanzan como un mensaje corto y específico — nunca un traceback de Python crudo.

Seguridad: cómo se aplica el modo de solo lectura

La asignación pide explícitamente no depender de una sola verificación de regex/palabra clave, por lo que este servidor superpone cuatro defensas independientes — verificadas en tests/test_server.py:

  1. Manejador de archivo de solo lectura a nivel de sistema operativo. El archivo SQLite se abre con la URI file:<ruta>?mode=ro. SQLite mismo entonces rechaza cualquier escritura (OperationalError: attempt to write a readonly database) sin importar qué SQL se ejecute — esto se mantiene incluso si cada verificación a continuación tiene un error.

  2. PRAGMA query_only = ON se establece en cada conexión como una segunda protección independiente a nivel de SQLite contra escrituras.

  3. Una devolución de llamada de autorizador sqlite3 (Connection.set_authorizer) permite solo las acciones SELECT / READ / FUNCTION / RECURSIVE a nivel del motor SQLite y niega todo lo demás — INSERT, UPDATE, DELETE, DROP, ALTER, CREATE, REPLACE, TRUNCATE, ATTACH, DETACH, VACUUM, REINDEX, PRAGMA, transacciones, etc. Esto se ejecuta sobre la declaración analizada, por lo que también detecta el bypass clásico de CTE WITH x AS (SELECT 1) DELETE FROM ... que una verificación de texto ingenua "debe comenzar con SELECT" pasaría por alto.

  4. Comprobaciones de forma de declaración en server.py: el texto enviado debe comenzar con SELECT/WITH (rechazo rápido y amigable antes de tocar SQLite), y cada consulta se ejecuta envuelta como SELECT * FROM (<consulta>) LIMIT :limit OFFSET :offset — se requiere una sola declaración para que esto se analice, por lo que un SELECT 1; DROP TABLE customers apilado se convierte en un error de sintaxis SQL simple en lugar de dos declaraciones ejecutadas.

Debido a que la capa 1 (mode=ro) es aplicada por SQLite/el sistema operativo independientemente de la lógica de este servidor, shop.db no puede modificarse a través de este servidor incluso si existiera un error en las capas 2-4.

Limitaciones conocidas

  • customers no tiene columna country/ubicación en el shop.db proporcionado, por lo que preguntas como "clientes de Alemania" no se pueden responder a partir de estos datos — la herramienta de esquema lo hace evidente en lugar de que el servidor invente una columna.

  • Todos los pedidos en los datos proporcionados están fechados en 2026; una consulta de ingresos de 2025 devuelve correctamente 0 en lugar de un error.

  • total_matching_rows en query_database se calcula con un segundo COUNT(*) envolviendo la misma consulta; para consultas muy costosas esto aproximadamente duplica el trabajo. Dado el tamaño de esta base de datos (cientos a unos pocos miles de filas por tabla), esto no es una preocupación práctica.

-
license - not tested
Not graded
quality - not tested
C
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 Connectors

  • Run AI customer support from your terminal: conversations, knowledge base, and chat widget.

  • Read-only bank access for your AI agent. Connects Claude, ChatGPT, Cursor, Gemini, Codex.

  • Query PostgreSQL databases in plain English — LLM-generated, safety-validated SQL.

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/AndrewKonst/shop-mcp'

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