shop-mcp
shop-mcp
Локальный MCP-сервер (Model Context Protocol) только для чтения, который позволяет ИИ-агенту анализировать SQLite-базу данных электронной коммерции (shop.db) — клиентов, товары, заказы и позиции заказов — через транспорт stdio. Никакого HTTP-сервера, никакого отдельного процесса базы данных: сервер открывает shop.db напрямую и предоставляет два небольших инструмента общего назначения, которые агент может использовать для изучения схемы и выполнения собственных аналитических SQL-запросов.
Создан с использованием официального Python MCP SDK (mcp на PyPI).
Структура проекта
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Схема базы данных (как она есть в 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 ограничен значениями: new, processing, shipped, completed, cancelled. products.category в настоящее время имеет 5 различных значений. Внешние ключи: orders.customer_id → customers.id, order_items.order_id → orders.id, order_items.product_id → products.id. Сервер получает всё это из живой базы данных во время запроса (через sqlite_master / PRAGMA table_info / PRAGMA foreign_key_list) — здесь ничего не захардкожено, поэтому если shop.db заменить на другой файл с другой схемой, get_database_schema автоматически это отразит.
Известные особенности данных в предоставленном shop.db: в customers нет столбца country, поэтому вопросы типа «клиенты из Германии» не могут быть обработаны — инструмент схемы позволяет это обнаружить, а query_database возвращает понятную ошибку no such column: country вместо предположений. Все 750 заказов в базе данных датированы 2026 годом (ни одного в 2025), поэтому запрос «выручка за 2025» корректно возвращает 0/null, а не ошибку.
Установка
cd mcp-sql
python3 -m venv .venv
source .venv/bin/activate # on Windows: .venv\Scripts\activate
pip install -r requirements.txtКонфигурация
Путь к базе данных никогда не зашит в исходном коде. Он определяется следующим образом:
переменная окружения
SHOP_DB_PATH, если она задана;в противном случае
shop.dbрядом сserver.py.
Скопируйте .env.example в .env и отредактируйте его, если хотите указать серверу на другой файл базы данных (вам нужно будет загрузить его в свою оболочку/лаунчер агента самостоятельно, например export $(cat .env | xargs), или просто установите SHOP_DB_PATH напрямую):
cp .env.example .env
# edit .env, or simply:
export SHOP_DB_PATH=/absolute/path/to/shop.dbЗапуск
source .venv/bin/activate
python server.pyПроцесс общается по MCP через stdio и ожидает клиента — он будет выглядеть «зависшим» без вывода, что ожидаемо: подключите MCP-клиента (ИИ-агента или mcp-inspector, см. ниже), а не запускайте его отдельно в терминале.
Быстрая ручная проверка с помощью официального MCP Inspector (установка не требуется):
npx @modelcontextprotocol/inspector --cli .venv/bin/python server.py --method tools/listПодключение к ИИ-агенту
Большинство MCP-совместимых клиентов (Claude Desktop, Claude Code и т. д.) читают JSON-блок конфигурации, например 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"
}
}
}
}Примечания:
Используйте абсолютный путь к интерпретатору Python в venv (как указано выше), чтобы пакет
mcpбыл найден без ручной активации venv; использование простогоpython3также работает, еслиmcpустановлен в том окружении, на которое он указывает.SHOP_DB_PATHнеобязателен — опустите его, чтобы использовать встроенныйshop.db.Абсолютные пути должны находиться в этом конфигурационном файле, который предоставляет тот, кто подключает сервер, — никогда внутри самого
server.py.Размещение этого блока зависит от конкретного клиента (например, Claude Desktop использует
claude_desktop_config.jsonс той же структуройmcpServers; другим клиентам может понадобиться только внутренний объект{"command": ..., "args": ..., "env": ...}). Проверьте документацию вашего клиента, чтобы узнать, где находится файл.
Тестирование
source .venv/bin/activate
python -m pytest tests/ -vЭто запускает 48 тестов, включая:
обнаружение схемы (таблицы, столбцы, PK/FK, связи, количество строк);
SELECT,JOIN,WHERE,GROUP BY,ORDER BY, агрегатные функции (COUNT/SUM/AVG/MIN/MAX), подзапросы, безопасный CTEWITH ... SELECTи фильтрацию по дате (strftime);ограничение количества строк и постраничную навигацию на основе offset;
понятную обработку ошибок для неверного SQL, неизвестных таблиц/столбцов, пустого запроса и отсутствующего файла базы данных;
безопасность только для чтения: каждый тип оператора, перечисленный в задании (
DELETE,UPDATE,DROP,CREATE,INSERT, а такжеALTER,REPLACE,TRUNCATE,ATTACH,DETACH,VACUUM,REINDEX, разрушительныйPRAGMA, составнойSELECT 1; DROP TABLE ...и удаление, замаскированное под CTEWITH x AS (...) DELETE ...), отклоняется, и после этого проверяется, что количество строк и SHA-256 хэш файла базы данных не изменились;tests/test_stdio_integration.pyзапускаетserver.pyкак реальный подпроцесс и управляет им через настоящий MCP client SDK по stdio (initialize→list_tools→call_tool), а не вызывает функции Python напрямую — это тот же путь, который использует реальный агент.
MCP-инструменты
get_database_schema()
Без параметров. Вызывайте его первым, если вы ещё не знаете точных имён таблиц/столбцов — не угадывайте их. Возвращает для каждой таблицы: row_count, columns (имя, тип SQLite, not_null, default_value, is_primary_key), primary_key, foreign_keys (столбец, ссылающаяся таблица/столбец, ON DELETE/ON UPDATE) и несколько sample_rows, чтобы агент мог увидеть реальные форматы дат, значения статусов, величины цен и т. д. Список relationships верхнего уровня даёт строки table.column -> other_table.column, полученные из живых внешних ключей.
query_database(sql, limit=100, offset=0)
Выполняет один оператор SQL только для чтения (SELECT или WITH ... SELECT) и возвращает {columns, rows, row_count, limit, offset, truncated, total_matching_rows}. Поддерживает JOIN, WHERE, GROUP BY, ORDER BY, агрегатные функции, подзапросы и CTE. limit ограничивается диапазоном 1..500 (по умолчанию 100); используйте offset для постраничного просмотра больших результатов. total_matching_rows и truncated сообщают вызывающей стороне, является ли текущая страница полным результатом или есть ещё данные для получения. Ошибки (неверный синтаксис, неизвестная таблица/столбец или отклонённая попытка записи) выдаются в виде короткого конкретного сообщения — никогда в виде сырого Python traceback.
Безопасность: как обеспечивается режим только для чтения
В задании явно указано не полагаться на одну проверку regex/ключевых слов, поэтому этот сервер использует четыре независимых уровня защиты — проверено в tests/test_server.py:
Файловый дескриптор только для чтения на уровне ОС. Файл SQLite открывается с URI
file:<path>?mode=ro. Затем сам SQLite отказывает в любой записи (OperationalError: attempt to write a readonly database) независимо от выполняемого SQL — это работает, даже если все проверки ниже содержат ошибку.PRAGMA query_only = ONустанавливается на каждом соединении как вторая независимая защита на уровне SQLite от записи.Обратный вызов авторизатора
sqlite3(Connection.set_authorizer) разрешает только действияSELECT/READ/FUNCTION/RECURSIVEна уровне движка SQLite и запрещает всё остальное —INSERT,UPDATE,DELETE,DROP,ALTER,CREATE,REPLACE,TRUNCATE,ATTACH,DETACH,VACUUM,REINDEX,PRAGMA, транзакции и т. д. Это выполняется на разобранном операторе, поэтому также перехватывает классический обход через CTEWITH x AS (SELECT 1) DELETE FROM ..., который наивная текстовая проверка «должен начинаться с SELECT» пропустила бы.Проверки формы оператора в
server.py: отправленный текст должен начинаться сSELECT/WITH(быстрое и понятное отклонение до обращения к SQLite), и каждый запрос выполняется в обёрткеSELECT * FROM (<query>) LIMIT :limit OFFSET :offset— для разбора требуется один оператор, поэтому составнойSELECT 1; DROP TABLE customersстановится обычной синтаксической ошибкой SQL, а не двумя выполненными операторами.
Поскольку уровень 1 (mode=ro) обеспечивается SQLite/ОС независимо от собственной логики сервера, shop.db не может быть изменён через этот сервер, даже если в уровнях 2-4 есть ошибка.
Известные ограничения
В
customersнет столбцаcountry/местоположения в предоставленномshop.db, поэтому вопросы типа «клиенты из Германии» не могут быть обработаны на основе этих данных — инструмент схемы показывает это, а не сервер придумывает столбец.Все заказы в предоставленных данных датированы 2026 годом; запрос выручки за 2025 год корректно возвращает 0, а не ошибку.
total_matching_rowsвquery_databaseвычисляется с помощью второгоCOUNT(*), оборачивающего тот же запрос; для очень дорогих запросов это примерно удваивает работу. Учитывая размер этой базы данных (от сотен до нескольких тысяч строк на таблицу), это не является практической проблемой.
This server cannot be installed
Maintenance
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.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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