Skip to main content
Glama
harutlc

SQL MCP Server

by harutlc

SQL MCP 服务器

一个由 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-db MCP Server

🔑 配置你的 AI 提供商

打开 .env 文件并设置你偏好的 AI 模型。服务器会根据你设置的变量自动检测你的提供商:

选项 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 年会返回"数据范围从……到……",而不是一个看起来像 bug 的裸零。


📄 浏览大量结果

每个结果都有上限——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 是由模型生成的,因此意外的交叉连接否则会在丢弃任何行之前将数百万行拉入内存。分页同样在迭代期间完成,而不是通过向 SQL 追加 LIMIT/OFFSET——后者必须能兼容生成的语句已有的结尾。

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

使用 tsx 的纯 node --test——无测试框架依赖。测试套件针对真实的 db/shop.db 运行,而不是模拟数据,因此如果模式与文档脱节,测试就会失败。

文件

覆盖内容

tests/sql-guard.test.ts

写入操作可能绕过只读防护的每一种方式:前导注释、WITH x AS (…) DELETE、堆叠语句、markdown 围栏中的 DML。以及反向情况——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"

可视化 Web 检查器

使用官方 MCP Inspector 在浏览器中交互式测试工具:

npm run inspect:dev
  1. 在浏览器中打开 inspector URL(例如 http://localhost:5173)。

  2. 点击 Connect。

  3. 在 Tools 下,选择 query_database,输入你的问题,然后点击 Run Tool。

所有 npm 脚本

脚本

作用

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

针对 dist/ 的 MCP Inspector · 针对源码


🔧 配置参考

每个变量都是可选的;默认值就是你不做任何设置时运行所用的值。

变量

默认值

用途

DATABASE_PATH

db/shop.db

数据库位置。绝对路径,或相对于项目根目录的路径——绝不相对于工作目录。

DATABASE_MAX_ROWS

100

每次调用返回行数的硬上限,也是发送给 LLM 的行数上限。execute_sql 的 limit 只能降低它。

LLM_TIMEOUT_MS

60000

LLM 调用的单次请求超时上限。一个问题会发起两次顺序调用,因此没有这个设置时,卡住的提供商会让工具调用一直挂起。

LLM_PROVIDER

自动检测

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 的端点。

OLLAMA_BASE_URL / OLLAMA_MODEL

http://localhost:11434 / llama3.2

本地 Ollama。

DEBUG

未设置

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)——用于将其转化为书面答案。

对于内置的商店数据库,这些行包含客户姓名、电子邮件地址和电话号码。它们会被发送到你配置的任何提供商,发送到 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.

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.

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.

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.

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.

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

TDQS

A4.6/5.0

Scored across 4 tools

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

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • 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
    -
  • F
    license
    A
    quality
    C
    maintenance
    Enables AI agents to analyze an SQLite e-commerce database via secure read-only SQL queries, providing tools for table inspection and analytical requests.
    2
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to query an SQLite e-commerce database read-only, supporting analytical questions about customers, products, orders, and revenue.
    -