Skip to main content
Glama
harutlc

SQL MCP Server

by harutlc

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); рекомендуется v24

  • npm: версия 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-ключа, без затрат, мгновенно:

Инструмент

Что делает

Нужен провайдер

list_tables

Каждая таблица с пояснением на простом языке, что она содержит, количеством строк и столбцов, а также связи между таблицами и соглашение о выручке, используемое в этой базе данных.

Нет

describe_table

Одна таблица полностью — столбцы с типами, ключами и описаниями, внешние ключи, оператор CREATE TABLE, предостережения и диапазон дат, который фактически покрывают столбцы дат.

Нет

execute_sql

Любой SELECT только для чтения, возвращающий структурированные строки JSON и имена столбцов. Поддерживает постраничный вывод с limit / offset. Это инструмент для аналитической работы, которой вы хотите управлять самостоятельно.

Нет

query_database

Принимает вопрос на естественном языке, генерирует и выполняет соответствующий 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 и сообщением, на которое вызывающий агент может отреагировать, а не как ошибки транспортного уровня.

Вы отправляете

Вы получаете

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.

Запрос на естественном языке на удаление данных

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

Этим текстом управляют два правила:

  • Собственное сообщение 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, а не макета, поэтому они завершаются ошибкой, если схема и документация расходятся.

Файл

Что покрывает

tests/sql-guard.test.ts

Все способы, которыми запись может быть протащена мимо защиты только для чтения: ведущие комментарии, WITH x AS (…) DELETE, составные операторы, DML в markdown-блоках. Плюс обратное — что replace(), ключевое слово внутри строкового литерала и идентификатор в кавычках, названный в честь ключевого слова, не отклоняются.

tests/database.test.ts

Ограничение строк, постраничный вывод с offset, offset за концом, неконтролируемое перекрёстное соединение, которое не должно материализоваться, имена столбцов при пустом результате, отказ в записи, оставляющий базу данных неизменной, сохранение сообщения SQLite.

tests/errors.test.ts

Что вызывающему разрешено видеть: действенные сообщения проходят, неизвестные ошибки сворачиваются, а путь к базе данных / корень проекта / домашний каталог редактируются в обоих.

tests/schema-metadata.test.ts

Что каждая таблица и столбец в живой базе данных имеют письменное описание, что ни одно описание не ссылается на несуществующую таблицу и что соглашение о выручке указано.

Набор тестов защиты — самый важный: это граница, которая делает «только чтение» истинным, а не просто задуманным, и один из его случаев — реальный ложноположительный результат, который он поймал во время разработки.


🐳 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.json

  • Windows: %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
  1. Откройте URL инспектора в браузере (например, http://localhost:5173).

  2. Нажмите Connect.

  3. В разделе Tools выберите query_database, введите свой вопрос и нажмите Run Tool.

Все npm-скрипты

Script

Does

npm run build / npm run clean

Компиляция в dist/ · удаление

npm start

Запуск собранного сервера через stdio

npm run dev

Запуск из исходников с перезагрузкой (tsx watch)

npm test / npm run test:watch

Автоматические тесты

npm run typecheck

tsc --noEmit

npm run query -- "…"

Задать вопрос из терминала

npm run inspect / npm run inspect:dev

MCP Inspector для dist/ · для исходников


🔧 Справочник по конфигурации

Каждая переменная необязательна; значения по умолчанию используются, если ничего не задано.

Variable

Default

Purpose

DATABASE_PATH

db/shop.db

Расположение базы данных. Абсолютный путь или относительный к корню проекта — никогда к рабочей директории.

DATABASE_MAX_ROWS

100

Жёсткий предел на количество строк, возвращаемых за вызов, и на строки, отправляемые LLM. limit в execute_sql может только уменьшить его.

LLM_TIMEOUT_MS

60000

Предел на один запрос к LLM. Вопрос требует двух последовательных вызовов, поэтому без этого зависший провайдер заблокирует вызов инструмента.

LLM_PROVIDER

auto-detected

anthropic | ollama | openai | custom. Обычно определяется по тому, какие ключи вы задали.

ANTHROPIC_API_KEY / ANTHROPIC_MODEL

— / claude-opus-5

Провайдер Anthropic.

OPENAI_API_KEY / OPENAI_MODEL / OPENAI_BASE_URL

— / gpt-4o-mini / OpenAI

OpenAI и любой совместимый с OpenAI endpoint.

OLLAMA_BASE_URL / OLLAMA_MODEL

http://localhost:11434 / llama3.2

Локальный Ollama.

DEBUG

unset

sql-mcp:* или одно пространство имён: server, query-engine, database, llm, tools.

Некорректное значение выводится в 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. В частности, каждый вызов отправляет:

  1. Схему вашей базы данных — имена таблиц, имена и типы столбцов, количество строк — для генерации SQL.

  2. Строки, возвращённые запросом (до 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

📚 Техническая документация

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