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

🔑 Настройка вашего 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

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

Available Tools

4 tools
describe_tableDescribe a Database TableA

Returns everything about one table: its purpose, every column with type, nullability, primary key and a plain-language description, its foreign keys, its CREATE TABLE statement, caveats worth knowing before querying it, and — for date columns — the range the data actually covers, so you can tell an empty result from an out-of-range question. Use it before writing SQL against a table you have not queried yet. Reads SQLite directly: no LLM call, no API key. Returns JSON.

ParametersJSON Schema
NameRequiredDescriptionDefault
table_nameYesExact table name, as returned by list_tables (e.g. 'orders', 'order_items').

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full disclosure burden. It states execution mechanics ('Reads SQLite directly'), that no external dependency exists ('no LLM call, no API key'), and the return format ('Returns JSON'). It also explains a non-obvious behavior — returning real data coverage ranges for date columns so empty results can be distinguished from out-of-range questions. The 'describe' verb implies read-only; the description could state non-mutating explicitly but the disclosed details exceed the baseline for an annotation-less tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each earning its place: deliverable list, when-to-use, and execution/return format. The content list is front-loaded ahead of the usage guidance. It is information-dense rather than wasteful, though the long enumerative first sentence could be tightened slightly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description bears full responsibility for explaining return content — it enumerates all major elements including the non-obvious date-range feature. One fully-documented parameter, usage routing against siblings, execution behavior, and return format are all specified. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for the single table_name parameter, which the schema already documents as 'Exact table name, as returned by list_tables (e.g. 'orders', 'order_items').' With full schema coverage the baseline is 3; the description adds no parameter-specific detail beyond hinting that the table must exist (it describes 'one table'). The schema does the heavy lifting, so 3 is correct.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb-resource pair ('Returns everything about one table') and enumerates the exact contents delivered: columns with type/nullability/PK/plain-language, foreign keys, CREATE TABLE, caveats, and date range coverage. It clearly differentiates from siblings — it describes schema rather than querying data (query_database, execute_sql) or listing tables (list_tables).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use instruction: 'Use it before writing SQL against a table you have not queried yet.' This frames it as a prerequisite step and implies the alternative is the SQL/query tools, though it does not name them explicitly or state when-not-to-use. Clear context, slightly implicit on exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

execute_sqlRun a Read-Only SQL QueryA

Runs a single read-only SQL query against the e-commerce SQLite database and returns structured rows plus column names as JSON. Use this to answer analytical questions yourself — joins, aggregates, multi-step work — and when you need the actual values rather than a written summary. Call list_tables and describe_table first if you do not know the schema.

LIMITATIONS: SELECT only. The statement must be a single SELECT (or WITH ... SELECT, or VALUES); anything that writes data, changes schema, or alters connection state is rejected, as is more than one statement per call. SQLite dialect. Results are capped at 100 rows per call — use offset to page through more, and check hasMore in the response. No LLM is involved: no API key needed, no cost, and the result is exact.

Revenue convention: count every order whose status is not 'cancelled' (i.e. new, processing, shipped and completed all count as revenue). Cancelled orders are excluded because the sale did not complete. To count only fully delivered sales instead, filter status = 'completed' and say so in the answer.

ParametersJSON Schema
NameRequiredDescriptionDefault
sqlYesA single read-only SQL SELECT statement in SQLite dialect. Example: "SELECT p.name, SUM(oi.quantity) AS units FROM order_items oi JOIN products p 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 units DESC LIMIT 5"
limitNoMaximum rows to return (default and hard ceiling: 100). Larger values are clamped.
offsetNoRows to skip before returning results. Use with `limit` to page through a large result set.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It thoroughly discloses: read-only and SELECT-only enforcement, single-statement limitation, SQLite dialect, row cap of 100 with offset/hasMore paging, no LLM involvement (no key, no cost, exact results), and the revenue convention (counting non-cancelled orders). This is exemplary transparency for a tool that executes arbitrary SQL.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than a single sentence but every section earns its place: purpose, use case, limitations, and revenue convention are separated and clearly front-loaded. It respects the reader by grouping constraints and providing a concrete example. Slightly verbose but never wasteful.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description correctly explains return format ('structured rows plus column names as JSON') and mentions hasMore. It covers all necessary operational details: single-statement rule, paging, dialect, and domain convention. For a complex SQL tool with no annotations, this is remarkably complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all three parameters (sql, limit, offset). The description reinforces paging behavior ('use offset to page through more') and the revenue convention, but adds no new parameter semantics beyond what the schema provides. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Runs') and resource ('read-only SQL query against the e-commerce SQLite database') and specifies the output shape ('structured rows plus column names as JSON'). It clearly separates itself from sibling tools by instructing to use list_tables and describe_table first when schema is unknown, implying this tool is for querying after schema discovery.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear when-to-use guidance: 'Use this to answer analytical questions yourself' mentioning joins, aggregates, and multi-step work, and when actual values are needed rather than a written summary. It also gives a prerequisite ('Call list_tables and describe_table first if you do not know the schema') and explicit limitations (SELECT only, single statement, paging). However, it does not explicitly name query_database as an alternative, so the situational contrast is slightly weaker than ideal.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_tablesList Database TablesA

Lists every table in the e-commerce database with a plain-language explanation of what it holds, its row count, and its column names. Also returns the relationships between tables and the convention this database uses for revenue. Use this first when you need to know what data exists, or to answer questions about the database's structure. Reads SQLite directly: no LLM call, no API key, no cost, returns immediately. Returns JSON.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses that it reads SQLite directly, makes no LLM call, requires no API key, costs nothing, returns immediately, and returns JSON. This is comprehensive behavioral disclosure beyond what the empty schema provides.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is moderately lengthy but every sentence adds valuable information: primary output, use-case guidance, and technical behavior. It is front-loaded with the main purpose and remains readable without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter tool with no output schema, this description is entirely sufficient. It covers what the tool returns (table lists, explanations, row counts, columns, relationships, revenue convention), when to use it, and how it executes. Nothing an agent needs to decide to call it is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the schema requires no explanation. Baseline for 0 params is 4, and the description appropriately does not invent parameter information. No additional semantics needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb and resource: lists every table in the e-commerce database, with a plain-language explanation of contents, row count, and column names. It also mentions relationships and revenue convention, distinguishing it from sibling tools like describe_table which likely focuses on a single table.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly tells the agent to use this first when needing to know what data exists or answer database structure questions. It does not name sibling tools directly or state when not to use it, but the stated context is sufficient for an agent to decide.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

query_databaseAsk About the Online ShopA

Answers questions about the online shop in plain language: customers, products, stock, orders and sales. Ask it the way a shop owner would ask a colleague — no SQL, no table names, no technical wording needed.

USE THIS for any question about the shop or the business behind it, however casually it is phrased. For example: 'what sells best?', 'how many customers do we have?', 'which products are nearly out of stock?', 'how much did we earn last month?', 'who are our biggest spenders?', 'are any orders stuck in processing?', 'what was in order 42?', 'which category makes the most money?', 'how many orders were cancelled?'.

IT KNOWS ABOUT: customers (names, email, phone, when they signed up), products (name, category, price, stock on hand), orders (date, status — new, processing, shipped, completed, cancelled — and total), and the individual products inside each order (quantity and price paid).

RETURNS: a written answer in everyday language, with Markdown tables when a list or comparison helps. Numbers are read out of the text rather than returned as structured data.

GOOD TO KNOW: it can only look things up — it can never add, change or delete anything, and any request to do so is refused. One answer covers at most 100 rows of data. It asks a language model to write the SQL behind the scenes, so it needs an API key (or a local Ollama) configured, takes a few seconds, and may phrase the same question slightly differently between runs.

ParametersJSON Schema
NameRequiredDescriptionDefault
messageYesThe question about the shop, in plain language — pass the user's own wording where possible (e.g. 'What are our top 5 bestselling products?', 'How many orders were completed in May 2026?', 'Which customers have ordered more than 3 times?', 'What is running low on stock?')
include_sql_detailsNoWhether to show the SQL query and timing details underneath the answer. Set to false for a clean, non-technical answer (default: true)

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It extensively discloses read-only behavior, refusal of write attempts, a 100-row limit, dependence on an LLM/API key or Ollama, variability between runs, and return format (Markdown tables, numbers read out). This goes well beyond typical disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured with clear sections (USE THIS, IT KNOWS ABOUT, RETURNS, GOOD TO KNOW) front-loaded with the core purpose. While lengthy, every sentence adds value and the section headers make it easy to scan. No redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Comprehensive for a natural-language query tool with no annotations and no output schema. It covers scope, entity data, return format, limitations, prerequisites, and refusal behavior. An agent has all necessary information to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema covers 100% of parameters with detailed descriptions. The description adds value by reinforcing plain-language usage and clarifying that numbers are read from text rather than returned as structured data. It also implies the message should be a natural question, which complements the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States that it answers questions about the online shop in plain language, covering customers, products, stock, orders, and sales. Clearly distinguishes itself from siblings by noting no SQL, table names, or technical wording are needed, implying execute_sql and schema tools are for different tasks.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'USE THIS for any question about the shop or the business behind it' and provides numerous examples. However, it does not explicitly name alternative tools or give a when-not-to-use clause; the no-SQL instruction implies but does not explicitly state that execute_sql is for raw queries.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 4 tool updatesv0.1.0
    • First observeddescribe_table
    • First observedexecute_sql
    • First observedlist_tables
    • First observedquery_database

TDQS

A4.6/5.0
Disambiguation5/5

Each tool has a distinct, non-overlapping purpose: raw SQL execution, schema listing, table detail inspection, and natural-language querying. No ambiguity between them.

Naming Consistency5/5

All tools follow a consistent verb_object pattern (execute_sql, list_tables, describe_table, query_database). Naming is uniform and predictable.

Tool Count5/5

Four tools is well-scoped for a read-only SQL MCP server. Each tool adds clear value without redundancy, and the count is ideal for the domain.

Completeness5/5

The server fully covers its read-only analytics purpose: schema exploration (list, describe) and data retrieval (raw SQL and natural language). No missing operations or dead ends within its stated scope.

Maintenance

ActivityMaintained
ResponsivenessNo issues

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

Related MCP Servers

  • 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
    Not graded
    quality
    C
    maintenance
    Enables AI agents to read-only analyze a SQLite e-commerce database, exploring schema and running analytical SQL queries over stdio.
    -
  • F
    license
    A
    quality
    B
    maintenance
    Gives AI agents read-only analytical access to an e-commerce SQLite database (customers, orders, order_items, products) via SQL queries, table listing, and schema inspection.
    3
    -

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