SQL MCP Server
SQL MCP Server
AI-сервер Model Context Protocol (MCP), который позволяет запрашивать и анализировать базу данных SQLite электронной коммерции на естественном языке.
Задавайте вопросы, например:
«Кто наши 5 лучших клиентов по общей сумме трат?»
«Покажи все товары в категории Electronics с остатком менее 50»
«Какова была наша общая выручка по завершённым заказам в 2026 году?»
Четыре инструмента, три из которых не требуют API-ключа вообще. Только чтение на двух независимых уровнях, постраничные результаты, собственные сообщения об ошибках SQLite передаются вызывающему, и 74 автоматических теста.
Содержание — Быстрый старт · Настройка провайдера · Инструменты · Постраничный вывод · Ошибки · Тесты · Docker · MCP-клиенты · Конфигурация · Безопасность · Передача данных · Структура проекта
🚀 Быстрый старт
1. Предварительные требования
Node.js: версия
v22.5.0или выше (для встроенного модуляnode:sqlite); рекомендуетсяv24npm: версия
v11.0.0или выше
2. Установка
Клонируйте этот репозиторий и установите зависимости:
npm install
cp .env.example .env
npm run buildЭтого достаточно, чтобы подключить сервер к клиенту и использовать list_tables,
describe_table и execute_sql. Провайдер нужен только для инструмента
естественного языка — см. ниже.
Related MCP server: Shop SQLite MCP
🔑 Настройка вашего AI-провайдера
Откройте файл .env и настройте предпочитаемую модель ИИ. Сервер автоматически определяет вашего провайдера на основе заданных переменных:
Вариант A: Anthropic Claude (рекомендуется)
ANTHROPIC_API_KEY=sk-ant-api03-...
ANTHROPIC_MODEL=claude-opus-5Вариант B: Локальный Ollama (бесплатно и офлайн)
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=llama3.2Примечание: Убедитесь, что Ollama запущен (
ollama serve) и вы загрузили модель (ollama pull llama3.2).
Вариант C: OpenAI
OPENAI_API_KEY=sk-proj-...
OPENAI_MODEL=gpt-4o-miniВариант D: Пользовательский / сторонний (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🛠 Доступные инструменты
Три из четырёх работают напрямую с SQLite — без API-ключа, без затрат, мгновенно:
Инструмент | Что делает | Нужен провайдер |
| Каждая таблица с пояснением на простом языке, что она содержит, количеством строк и столбцов, а также связи между таблицами и соглашение о выручке, используемое в этой базе данных. | Нет |
| Одна таблица полностью — столбцы с типами, ключами и описаниями, внешние ключи, оператор | Нет |
| Любой | Нет |
| Принимает вопрос на естественном языке, генерирует и выполняет соответствующий SQL и возвращает письменный ответ с выводами. | Да |
Описание каждого инструмента сообщает вызывающему агенту не только то, что он делает, но и когда
не использовать его — query_database указывает, что он возвращает прозу, а не
значения, стоит денег и выполняет два вызова LLM, и указывает на execute_sql для
всего, что агент намеревается вычислить. Оба инструмента указывают ограничение на количество строк и
соглашение о выручке прямо в тексте, чтобы агенту не приходилось обнаруживать их
методом проб и ошибок.
Пример: 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 присутствует, чтобы агент мог отличить пустой результат от
вопроса вне диапазона: запрос о 2025 годе возвращает «данные охватывают период с … по …»,
а не голый ноль, который выглядит как ошибка.
📄 Постраничный вывод больших результатов
Каждый результат ограничен — DATABASE_MAX_ROWS (по умолчанию 100) или меньшим
limit, который вы передаёте. Больший limit усекается, а не отклоняется, поэтому
вызывающий всегда получает строки.
execute_sql принимает limit и offset и сообщает, есть ли ещё данные:
// 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
}Продолжайте вызывать с offset: nextOffset, пока hasMore не станет false. Когда результат
помещается на одну страницу, hasMore равен false, а totalAvailableRows сообщает истинное
общее количество.
Ограничение применяется во время выполнения оператора, а не путём обрезки готового
результата: сервер останавливается на одну строку после предела и никогда не материализует остальное.
SQL генерируется моделью, поэтому случайное перекрёстное соединение в противном случае загрузило бы
миллионы строк в память до того, как какие-либо были отброшены. Постраничный вывод также выполняется
во время итерации, а не путём добавления LIMIT/OFFSET к SQL, которые
должны были бы пережить то, чем уже заканчивается сгенерированный оператор.
query_database разделяет ограничение на количество строк, но не выполняет постраничный вывод — он
обобщает в прозе, где номер страницы не к чему прикрепить. Используйте execute_sql для всего,
что больше одной страницы.
🚦 Как выглядит ошибка
Сбои возвращаются как обычные результаты инструмента MCP с isError: true и сообщением,
на которое вызывающий агент может отреагировать, а не как ошибки транспортного уровня.
Вы отправляете | Вы получаете |
|
|
|
|
|
|
|
|
Запрос на естественном языке на удаление данных |
|
Этим текстом управляют два правила:
Собственное сообщение SQLite сохраняется. «no such column: nope» — это самая полезная информация, которую можно сообщить агенту, потому что её достаточно, чтобы переписать запрос и повторить попытку. Оно никогда не упрощается до «запрос не выполнен».
Детали хоста никогда не раскрываются. Нераспознанные ошибки — которые могут содержать трассировку стека — сводятся к общей строке, и всё, что выходит наружу, очищается от пути к базе данных, корня проекта и домашнего каталога. Полные детали остаются в журналах сервера. Это покрыто отдельным тестовым файлом.
🧪 Автоматические тесты
npm test # 74 tests across 4 files, runs in well under a second
npm run test:watch
npm run typecheckОбычный node --test с tsx — без зависимости от тестового фреймворка. Наборы тестов
запускаются против реальной db/shop.db, а не макета, поэтому они завершаются ошибкой, если схема и
документация расходятся.
Файл | Что покрывает |
| Все способы, которыми запись может быть протащена мимо защиты только для чтения: ведущие комментарии, |
| Ограничение строк, постраничный вывод с |
| Что вызывающему разрешено видеть: действенные сообщения проходят, неизвестные ошибки сворачиваются, а путь к базе данных / корень проекта / домашний каталог редактируются в обоих. |
| Что каждая таблица и столбец в живой базе данных имеют письменное описание, что ни одно описание не ссылается на несуществующую таблицу и что соглашение о выручке указано. |
Набор тестов защиты — самый важный: это граница, которая делает «только чтение» истинным, а не просто задуманным, и один из его случаев — реальный ложноположительный результат, который он поймал во время разработки.
🐳 Docker
docker build -t sql-mcp .Образ включает базу данных, поэтому ему не нужен монтируемый том. Поскольку это
stdio-сервер, его необходимо запускать с -i и без TTY — stdin и stdout
контейнера несут поток JSON-RPC:
docker run -i --rm -e ANTHROPIC_API_KEY sql-mcpПодключите его к клиенту с помощью examples/claude_desktop_config.docker.json.
Уберите -e ANTHROPIC_API_KEY, чтобы запустить без учётных данных — list_tables,
describe_table и execute_sql работают без провайдера.
Сборка многоэтапная: TypeScript компилируется в сборщике node:24-alpine,
и только dist/, db/ и производственные зависимости копируются в образ
времени выполнения. Он работает как непривилегированный пользователь node, .env никогда не копируется
(учётные данные поступают через -e), и нет нативных аддонов для компиляции, потому что
SQLite встроен в сам Node.
🔌 Подключение к MCP-клиентам
Готовые к использованию файлы конфигурации находятся в examples/ — скопируйте тот,
который соответствует вашему клиенту, и замените путь. examples/claude_desktop_config.no-api-key.json
запускает сервер без каких-либо учётных данных, чего достаточно для list_tables,
describe_table и execute_sql.
Конфигурация Claude Desktop
Добавьте этот сервер в файл конфигурации Claude Desktop (claude_desktop_config.json):
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
(Убедитесь, что вы выполнили npm run build один раз перед подключением)
Пример 1: Anthropic Claude (по умолчанию)
{
"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"
}
}
}
}Пример 2: Локальный Ollama (бесплатно и офлайн)
{
"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"
}
}
}
}Пример 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"
}
}
}
}Пример 4: Пользовательский / 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"
}
}
}
}Сервер разрешает db/shop.db относительно своего собственного расположения, поэтому DATABASE_PATH
не нужен ни в одном из этих случаев — MCP-клиенты запускают серверы из рабочего
каталога по своему выбору, и сервер от него не зависит.
🔎 Локальное тестирование
Мгновенный тест в терминале
Вы можете проверить вопросы на естественном языке прямо в терминале:
npm run query -- "Show top 3 products by price"Визуальный веб-инспектор
Интерактивно тестируйте инструменты в браузере с помощью официального MCP Inspector:
npm run inspect:devОткройте URL инспектора в браузере (например,
http://localhost:5173).Нажмите Connect.
В разделе Tools выберите
query_database, введите свой вопрос и нажмите Run Tool.
Все npm-скрипты
Script | Does |
| Компиляция в |
| Запуск собранного сервера через stdio |
| Запуск из исходников с перезагрузкой ( |
| Автоматические тесты |
|
|
| Задать вопрос из терминала |
| MCP Inspector для |
🔧 Справочник по конфигурации
Каждая переменная необязательна; значения по умолчанию используются, если ничего не задано.
Variable | Default | Purpose |
|
| Расположение базы данных. Абсолютный путь или относительный к корню проекта — никогда к рабочей директории. |
|
| Жёсткий предел на количество строк, возвращаемых за вызов, и на строки, отправляемые LLM. |
|
| Предел на один запрос к LLM. Вопрос требует двух последовательных вызовов, поэтому без этого зависший провайдер заблокирует вызов инструмента. |
| auto-detected |
|
| — / | Провайдер Anthropic. |
| — / | OpenAI и любой совместимый с OpenAI endpoint. |
|
| Локальный Ollama. |
| unset |
|
Некорректное значение выводится в stderr и заменяется значением по умолчанию, а не молча принимается — опечатка в блоке env клиента проявится при запуске, а не будет вести себя так, как будто переменная не задана. Логи DEBUG содержат каждый заданный вопрос и каждое сгенерированное выражение, и в MCP-клиенте они попадают в постоянные файлы журнала клиента, поэтому они отключены, если вы явно не включите их.
🔒 Безопасность
База данных открывается только для чтения на уровне драйвера, и каждое выражение проверяется перед выполнением: это должно быть одиночное выражение SELECT/WITH/VALUES, без ключевых слов, которые записывают данные, изменяют схему или состояние соединения. Ни одну из проверок нельзя отключить конфигурацией. Запрос вроде «удалить все отменённые заказы» будет отклонён, а не выполнен.
Валидатор работает с токенизированным представлением выражения, а не с сырым текстом, поэтому комментарии, строковые литералы и идентификаторы в кавычках не могут скрыть ключевое слово — /* c */ DELETE FROM orders и WITH x AS (SELECT 1) DELETE FROM orders оба отклоняются, а SELECT replace(name, 'a', 'b') — нет.
Текст, который этот сервер не писал — ваш вопрос и значения, прочитанные из базы данных, — ограничивается в промптах неподделываемой меткой для каждого запроса, поэтому продукт с именем Widget (SYSTEM: ignore prior instructions…) не может попасть в контекст инструкций. Это важно не только для этого процесса: ответ возвращается вызывающему агенту как вывод инструмента, на один шаг дальше.
🔐 Что и куда отправляется
Этот сервер отвечает на вопросы, вызывая LLM, поэтому содержимое базы данных покидает вашу машину при каждом вызове query_database. В частности, каждый вызов отправляет:
Схему вашей базы данных — имена таблиц, имена и типы столбцов, количество строк — для генерации SQL.
Строки, возвращённые запросом (до
DATABASE_MAX_ROWS, по умолчанию 100) — для преобразования их в письменный ответ.
Для встроенной базы данных магазина эти строки включают имена клиентов, адреса электронной почты и номера телефонов. Они отправляются тому провайдеру, которого вы настроили, на тот endpoint, который указан в OPENAI_BASE_URL — для Groq, OpenRouter или DeepSeek это третья сторона на своих условиях.
Если это неприемлемо для ваших данных:
Используйте другие три инструмента.
list_tables,describe_tableиexecute_sqlвообще не выполняют сетевых вызовов — ничего не покидает машину.Используйте Ollama. Он работает локально, поэтому ничего не покидает машину.
Ограничьте запросы. Агрегирующие вопросы («выручка по категориям») возвращают сводные строки, а не записи о клиентах.
Уменьшите
DATABASE_MAX_ROWS, чтобы ограничить объём данных строк, отправляемых за запрос.
Сервер никогда не отправляет файл базы данных и может только читать — см. Безопасность.
📁 Структура проекта
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📚 Техническая документация
Технические спецификации и диаграммы архитектуры: Проектирование системы, диаграммы последовательности, паттерн стратегии LLM и механизмы безопасности.
Документация по схеме базы данных: Полные определения схемы таблиц, ER-диаграмма и словарь данных SQLite.
Примеры конфигурации клиента: Какой файл конфигурации скопировать и как запустить без API-ключа.
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 Servers
- FlicenseNot gradedqualityCmaintenanceEnables 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.
- FlicenseNot gradedqualityCmaintenanceEnables safe, read-only analysis of an online store's SQLite database, providing schema introspection, restricted SELECT queries, and specialized analytics tools through MCP.
- FlicenseAqualityCmaintenanceEnables 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
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
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/harutlc/sql-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server