SQLite Shop MCP Server
by skvertl
README.md
# SQLite Shop MCP Server 🛍️
Безопасный, высокопроизводительный сервер **MCP (Model Context Protocol)** на Python для подключения AI-агентов (Claude Desktop, Cursor, Antigravity, Gemini CLI) к реляционной базе данных интернет-магазина (`shop.db`).
Сервер работает локально через стандартный ввод/вывод (**stdio**), реализует **двухуровневую защиту от изменений (строгий Read-Only)**, поддерживает автопагинацию, понятную обработку ошибок для самоисправления агентов и сопровождается 100% покрытием тестами.
---
## 🌟 Ключевые возможности
1. **Многоуровневая безопасность (Strict Read-Only)**:
- **Физический уровень (SQLite Engine)**: база открывается через URI `file:shop.db?mode=ro`. Любая попытка записи физически блокируется C-библиотекой SQLite (`OperationalError: attempt to write a readonly database`).
- **Лексический уровень (AST & Token Validator)**: запросы анализируются до передачи в базу. Разрешены только `SELECT`, `WITH` (CTE) и `EXPLAIN`. Любые деструктивные операции (`INSERT`, `UPDATE`, `DELETE`, `DROP`, `ALTER`, `CREATE`, `ATTACH`, `PRAGMA writable`) и цепочки запросов через точку с запятой немедленно отклоняются.
2. **Умный дизайн инструментов (4 Tools)**:
- `get_database_schema`: полный каталог всех таблиц, типов, первичных/внешних ключей, количества строк и предметных подсказок.
- `describe_table`: подробная схема конкретной таблицы.
- `get_sample_data`: предварительный просмотр записей таблицы без написания SQL.
- `execute_query`: безопасное выполнение произвольного SQL с автоматической пагинацией (`page`, `page_size`), защитой от переполнения контекста (до 1000 строк) и замером времени выполнения.
3. **Дружелюбная обработка ошибок (Self-Correction)**:
- Никаких «сырых» питоновских стектрейсов наружу.
- При ошибке обращения к несуществующей колонке сервер подсказывает список доступных колонок в таблице, позволяя модели мгновенно самоисправиться.
4. **Портативность**:
- Никаких захардкоженных абсолютных путей. Путь определяется автоматически относительно проекта либо через переменную окружения `SHOP_DB_PATH`.
5. **Тестирование и Docker**:
- 51 автотест `pytest` (безопасность, база данных, интеграция, все 8 задач из ТЗ).
- Готовые `Dockerfile` и `docker-compose.yml`.
---
## 🏗️ Архитектура
```
[ AI Agent: Claude / Cursor / Antigravity ]
│ (stdio JSON-RPC)
▼
[ server.py ] (MCPServer stdio transport)
│
┌─────────────┴─────────────┐
▼ ▼
[ src/security.py ] [ src/db.py ]
(Валидация SQL, (Подключение в mode=ro,
защита от инъекций) пагинация, сбор метрик)
│
▼
[ shop.db (mode=ro) ]
```
### Схема базы данных `shop.db`
```
customers (150 строк)
│
└──< orders (750 строк)
│
└──< order_items (1900 строк) >── products (50 строк)
```
---
## 🚀 Быстрый старт
### 1. Установка зависимостей (Install)
Требуется Python 3.10+:
```bash
# Клонируйте репозиторий или перейдите в папку проекта
cd HW_MCP
# Установите зависимости
pip install -r requirements.txt
```
### 2. Конфигурация (Configure)
По умолчанию сервер ищет файл `shop.db` в корне проекта.
При необходимости путь можно переопределить через переменную окружения:
```bash
# Windows (PowerShell)
$env:SHOP_DB_PATH = "C:\path\to\shop.db"
# Linux / macOS
export SHOP_DB_PATH="/path/to/shop.db"
```
### 3. Запуск сервера (Run)
Сервер запускается в режиме stdio:
```bash
python server.py
```
---
## 🤖 Подключение к AI-агентам (Connect to Agent)
### Claude Desktop
Добавьте конфигурацию в файл настроек Claude Desktop:
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
```json
{
"mcpServers": {
"sqlite-shop": {
"command": "python",
"args": [
"C:\\Users\\user\\OneDrive\\BackToTheFuture\\HW_MCP\\server.py"
],
"env": {
"PYTHONUNBUFFERED": "1"
}
}
}
}
```
### Cursor
В Cursor перейдите в **Settings > Features > MCP > Add New MCP Server**:
- **Name**: `sqlite-shop`
- **Type**: `command`
- **Command**: `python C:\Users\user\OneDrive\BackToTheFuture\HW_MCP\server.py`
Либо создайте в корне проектного воркспейса файл `.cursor/mcp.json`:
```json
{
"mcpServers": {
"sqlite-shop": {
"command": "python",
"args": ["server.py"]
}
}
}
```
### Antigravity / Gemini CLI
Добавьте секцию в `mcp_config.json`:
```json
{
"mcpServers": {
"sqlite-shop": {
"command": "python",
"args": ["server.py"]
}
}
}
```
---
## 🛠️ Описание инструментов (MCP Tools)
### 1. `get_database_schema`
Возвращает полную структуру всех таблиц, типы данных колонок, первичные и внешние ключи, количество строк и пояснительные заметки к данным.
### 2. `describe_table(table_name: str)`
Возвращает детальную схему колонок и ограничений выбранной таблицы (`customers`, `products`, `orders`, `order_items`).
### 3. `get_sample_data(table_name: str, limit: int = 10)`
Возвращает образцы строк из таблицы для предварительного анализа формата данных.
### 4. `execute_query(query: str, page: int = 1, page_size: int = 50)`
Выполняет безопасный SQL-запрос на чтение.
- **Параметры:**
- `query` *(string, обязательный)*: SQL-запрос (`SELECT`, `WITH ... SELECT`, `EXPLAIN`).
- `page` *(int, по умолчанию: 1)*: номер страницы.
- `page_size` *(int, по умолчанию: 50, макс: 1000)*: количество строк на странице.
- **Формат ответа:**
```json
{
"rows": [
{ "id": 1, "first_name": "Арина", "email": "..." }
],
"page": 1,
"page_size": 50,
"total_rows_in_page": 50,
"has_more": true,
"execution_time_ms": 1.24
}
```
---
## 📊 Решение 8 контрольных задач из ТЗ
Все запросы проверены на реальных данных `shop.db`:
| № | Вопрос из ТЗ | SQL-запрос через `execute_query` | Ответ агента |
|---|---|---|---|
| **1** | *Show me all available tables and explain what information each table contains.* | Вызов `get_database_schema()` | 4 таблицы: `customers` (150 клиентов), `products` (50 товаров), `orders` (750 заказов), `order_items` (1900 позиций). |
| **2** | *How many customers are from Germany?* | `SELECT COUNT(*) FROM customers WHERE phone LIKE '+49%'` | **0 клиентов**. (В таблице нет колонки `country`, а все телефоны начинаются на `+7`). |
| **3** | *Which country has the most customers?* | `SELECT SUBSTR(phone, 1, 2) as code, COUNT(*) as c FROM customers GROUP BY code` | **Россия (+7)** — 150 клиентов (100% базы). |
| **4** | *Who is the customer who spent the most money?* | `SELECT c.first_name, c.last_name, c.email, ROUND(SUM(o.total_amount), 2) as spent FROM customers c JOIN orders o ON c.id = o.customer_id WHERE o.status != 'cancelled' GROUP BY c.id ORDER BY spent DESC LIMIT 1` | **Дмитрий Харитонов** (`dmitriy.kharitonov845@mail.ru`) — **701 780.00 руб.** |
| **5** | *What are the top 5 best-selling products?* | `SELECT p.name, SUM(oi.quantity) as qty, ROUND(SUM(oi.quantity * oi.unit_price), 2) as rev FROM products p JOIN order_items oi ON p.id = oi.product_id JOIN orders o ON o.id = oi.order_id WHERE o.status != 'cancelled' GROUP BY p.id ORDER BY qty DESC LIMIT 5` | 1. Эспандер плечевой (93 шт., 110 670 руб.)<br>2. Увлажнитель воздуха AirFresh (92 шт., 394 680 руб.)<br>3. Блендер погружной 800W (84 шт., 267 960 руб.)<br>4. Ботинки кожаные (83 шт., 704 670 руб.)<br>5. Фен профессиональный (83 шт., 455 670 руб.) |
| **6** | *What are the top 3 product categories by revenue?* | `SELECT p.category, ROUND(SUM(oi.quantity * oi.unit_price), 2) as rev FROM products p JOIN order_items oi ON p.id = oi.product_id JOIN orders o ON o.id = oi.order_id WHERE o.status != 'cancelled' GROUP BY p.category ORDER BY rev DESC LIMIT 3` | 1. **Электроника** — 17 060 760 руб.<br>2. **Бытовая техника** — 5 506 570 руб.<br>3. **Одежда и обувь** — 3 085 470 руб. |
| **7** | *How much revenue did we generate in 2025?* | `SELECT COALESCE(ROUND(SUM(total_amount), 2), 0.0) FROM orders WHERE order_date >= '2025-01-01' AND order_date < '2026-01-01' AND status != 'cancelled'` | **0.00 руб.** (Все заказы в магазине созданы в **2026** году: с 17.02.2026 по 22.08.2026). |
| **8** | *Which customer placed the most orders?* | `SELECT c.first_name, c.last_name, c.email, COUNT(o.id) as cnt FROM customers c JOIN orders o ON c.id = o.customer_id GROUP BY c.id ORDER BY cnt DESC LIMIT 1` | **София Яковлев** (`sofiya.yakovlev284@yandex.ru`) — **16 заказов**. |
### Проверка безопасности (Safety Requirement)
Запрос агента:
> *Delete all cancelled orders.*
Ответ MCP-сервера:
```json
{
"error": true,
"error_type": "PermissionDenied",
"message": "PermissionDenied: Modifying or destructive operations are not permitted (read-only server). Statement starts with 'DELETE'."
}
```
База данных остается в полной сохранности.
---
## 🧪 Запуск автоматических тестов
В проекте реализован полный набор тестов на базе `pytest`:
- `tests/test_security.py` — проверка блокировки деструктивных выражений, SQL-инъекций и цепочек запросов.
- `tests/test_db.py` — проверка физического `mode=ro`, схемы, пагинации и подсказок при ошибках.
- `tests/test_server.py` — интеграционные тесты вызова инструментов и валидация всех 8 задач ДЗ.
```bash
pytest tests/ -v
```
Результат:
```text
============================= 51 passed in 0.87s ==============================
```
---
## 🐳 Запуск в Docker
Сборка и запуск контейнера:
```bash
# Сборка образа
docker build -t sqlite-shop-mcp .
# Запуск с монтированием базы
docker run -i --rm -v $(pwd)/shop.db:/app/shop.db:ro sqlite-shop-mcp
```
Или через `docker-compose`:
```bash
docker-compose run --rm sqlite-shop-mcp
```
---
## 📁 Структура репозитория
```text
HW_MCP/
├── .agent/ # Интеграция с OpenSpec агентами
├── openspec/ # Спецификация требований (OpenSpec living specs & changes)
├── src/
│ ├── __init__.py
│ ├── config.py # Разрешение путей и настроек SQLite URI
│ ├── security.py # Валидатор SQL-запросов (Read-Only enforcement)
│ └── db.py # Слой SQLite (mode=ro, пагинация, сбор схем)
├── tests/
│ ├── test_security.py # Тесты безопасности SQL
│ ├── test_db.py # Тесты слоя БД и пагинации
│ └── test_server.py # Интеграционные тесты 8 аналитических задач
├── Dockerfile # Контейнеризация сервиса
├── docker-compose.yml
├── mcp_config_example.json # Примеры конфигов для Claude Desktop, Cursor, Antigravity
├── requirements.txt # Зависимости Python
├── server.py # Главная точка входа MCP-сервера
├── shop.db # База данных SQLite интернет-магазина
└── README.md # Полная документация проекта
```
---
## 📜 Лицензия
MIT License.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues