shop-sql-mcp
shop-sql-mcp
一个小型 MCP 服务器,通过 stdio 为 AI 代理提供对 shop.db SQLite 数据库的只读分析访问。
该服务器只做三件事,不多做:它列出表、描述表结构,并在每次调用时运行一条只读 SQL 语句,且由服务器强制分页。所有推理——做哪些 JOIN、如何聚合、何时查看 schema——都由代理负责。
AI Agent
|
| MCP over stdio
v
shop-sql-mcp
|
+-- list_tables
+-- describe_table
+-- query_database
|
v
read-only SQLite connection
|
v
shop.db要求
Node.js 22.5 或更新版本(推荐 24+)。该服务器使用内置的
node:sqlite模块,所以没有需要编译的原生 SQLite 依赖。没有其他运行时依赖。
Related MCP server: MCP SQLite Server (Read-Only)
安装
npm install配置
配置是可选的。默认情况下,服务器在项目根目录打开 shop.db。
变量 | 默认值 | 含义 |
|
| SQLite 文件的路径。相对路径基于项目根目录解析,因此服务器不依赖于启动时的工作目录。 |
如果想保留本地覆盖配置,请将 .env.example 复制为 .env。服务器本身读取普通环境变量;.env.example 中的 ANTHROPIC_API_KEY、EVAL_MODEL 和 EVAL_MAX_STEPS 仅由 npm run eval 使用。
构建
npm run build将 src/ 编译到 dist/。
运行
npm start # runs the built server (dist/index.js)
npm run dev # runs src/index.ts directly, no build step服务器在 stdin/stdout 上进行 MCP 通信,并且只在 stderr 上打印诊断信息,因此在终端中运行它看起来像卡住了——这是正常现象。它应由 MCP 宿主启动。
连接 MCP 代理
将下面内容添加到你的 MCP 宿主配置中(Claude Desktop 的 claude_desktop_config.json、Claude Code 的 .mcp.json,或你的宿主对应的配置文件),并使用项目的绝对路径:
{
"mcpServers": {
"shop-sql": {
"command": "node",
"args": ["/absolute/path/to/shop-sql-mcp/dist/index.js"]
}
}
}若要直接从源码运行而不先构建,请指向 TypeScript 入口点——Node 会直接执行它:
{
"mcpServers": {
"shop-sql": {
"command": "node",
"args": ["/absolute/path/to/shop-sql-mcp/src/index.ts"]
}
}
}要读取其他位置的数据库:
{
"mcpServers": {
"shop-sql": {
"command": "node",
"args": ["/absolute/path/to/shop-sql-mcp/dist/index.js"],
"env": { "DATABASE_PATH": "/absolute/path/to/other.db" }
}
}
}对于 Claude Code,你还可以从命令行注册它:
claude mcp add shop-sql -- node /absolute/path/to/shop-sql-mcp/dist/index.js工具
list_tables
无参数。返回用户表;内部 sqlite_* 表会被隐藏。
{
"tables": [
{ "name": "customers" },
{ "name": "order_items" },
{ "name": "orders" },
{ "name": "products" }
]
}describe_table
{ table: string }实时从 SQLite 读取表结构——没有硬编码内容——报告列、类型、可空性、主键和外键:
{
"table": "order_items",
"columns": [
{ "name": "id", "type": "INTEGER", "nullable": false, "primaryKey": true },
{ "name": "order_id", "type": "INTEGER", "nullable": false, "primaryKey": false }
],
"foreignKeys": [
{ "column": "order_id", "referencesTable": "orders", "referencesColumn": "id" },
{ "column": "product_id", "referencesTable": "products", "referencesColumn": "id" }
]
}未知名称是可恢复的错误,不会导致崩溃:
{ "error": { "code": "TABLE_NOT_FOUND", "message": "TABLE_NOT_FOUND: Table \"foo\" does not exist." } }注意:INTEGER PRIMARY KEY 列会被报告为 nullable: false。SQLite 的 table_info 会返回不同的结果,但这种列是 rowid 的别名,永远不可能为 NULL。
query_database
{ sql: string; limit?: number; offset?: number }运行一条只读语句——SELECT ... 或 WITH ... SELECT ...——支持 JOIN、WHERE、GROUP BY、HAVING、ORDER BY、子查询、聚合以及日期过滤。
{
"columns": ["category", "revenue"],
"rows": [["Electronics", 1234567.89]],
"returnedRows": 1,
"limit": 100,
"offset": 0,
"hasMore": false
}行是按照 columns 顺序排列的值数组。这让结果数据保持紧凑,并且在查询产生两个同名列时也不会产生歧义。
失败会作为普通工具结果返回,设置 isError,并附带简短、可操作的信息,让代理能够修复其 SQL 并重试:
{ "error": { "code": "SQL_ERROR", "message": "no such column: total" } }错误代码:SQL_ERROR、READ_ONLY_VIOLATION、MULTIPLE_STATEMENTS、TABLE_NOT_FOUND、INVALID_ARGUMENT、DATABASE_UNAVAILABLE。堆栈跟踪永远不会返回。
分页
分页由服务器强制执行,而不是由模型的 SQL 控制。
limit默认为 100,最大 500;offset默认为 0。代理的查询会被包装为
SELECT * FROM (<your sql>) LIMIT ? OFFSET ?,因此即使查询自带LIMIT 100000,返回的行数也不会超过limit。服务器内部会获取
limit + 1行来判断hasMore,不需要第二次计数查询,并且最多返回limit行。因此单次调用永远不会返回超过 500 行,这样宽范围的
SELECT *就不会淹没模型的上下文。
要分页遍历结果,请保持 SQL 不变(使用确定性的 ORDER BY),并在 hasMore 为 true 时让 offset 按 limit 递增。
只读安全性
两层独立防护,因此没有任何一层需要单独负责。
1. SQL 验证(src/sqlSafety.ts)。一个小型词法分析器跳过注释、字符串字面量和带引号的标识符,然后要求:
语句以
SELECT或WITH开头——简单的startsWith("SELECT")会拒绝合法的只读 CTE;只能有一条语句(第一个
;之后的所有内容都会被拒绝,字面量或注释中的;不算分隔符);任何地方都不能出现禁止的关键字——包括嵌套在 CTE 内部:
INSERT、UPDATE、DELETE、CREATE、DROP、ALTER、REPLACE、ATTACH、DETACH、VACUUM、REINDEX、PRAGMA、ANALYZE、BEGIN、COMMIT、ROLLBACK、SAVEPOINT、load_extension、writable_schema。
禁止的 SQL 总是会被显式错误拒绝——绝不会被静默忽略,也绝不会被部分执行。REPLACE(a, b, c) 作为标量函数仍然是允许的,因为只有 REPLACE INTO 语句才是写操作。
2. SQLite 连接本身。shop.db 使用 new DatabaseSync(path, { readOnly: true }) 打开。即使写操作绕过 SQL 验证,SQLite 也会以 "attempt to write a readonly database" 拒绝它。测试套件通过绕过验证器直接在连接上执行写操作来验证这种行为。
错误或禁止的查询会作为工具错误返回,并且绝不会导致进程终止,因此会话可以承受任意多次失败尝试。
运行测试
npm test只运行 确定性 测试套件——无网络、无 API 密钥、无 LLM。Node 内置测试运行器直接执行 TypeScript 源码。覆盖范围包括:list_tables、describe_table(列、类型、可空性、主键、外键、未知表)、简单 SELECT、过滤、聚合、连接、GROUP BY、只读 CTE、日期过滤、分页(默认 limit、最大 limit、offset、hasMore 边界)、无效 SQL、未知列和表、拒绝 INSERT/UPDATE/DELETE/CREATE/DROP/ALTER/REPLACE/ATTACH/DETACH/VACUUM/REINDEX/PRAGMA 和多个语句、证明每次写入被拒绝后数据库内容完全一致,以及通过 stdio 进行端到端 MCP 调用确认服务器在错误后仍然可用。
手动运行 eval
export ANTHROPIC_API_KEY=sk-...
npm run eval请手动启动它。 它特意被排除在 npm test 之外,因为它会通过 stdio 驱动真实 LLM 对接真实 MCP 服务器,并产生付费 API 调用。
它会启动服务器,把三个 MCP 工具以及一个 submit_answer 工具交给模型,后者的 JSON schema 针对每个任务固定,并将结构化答案与直接从 SQLite 计算的参考值进行比较——而不是与自然语言文本进行比较。任务覆盖:表发现、多步 schema 发现、过滤、聚合、连接、客户总消费、客户订单数、产品销量、类别收入、2025 年收入,以及一个必须被拒绝的破坏性请求(检查还会验证数据库在之后没有被修改)。
可选配置:EVAL_MODEL(默认为 claude-sonnet-5)和 EVAL_MAX_STEPS(默认为 12)。如果任何任务失败,退出码非零。
目录结构
src/
index.ts MCP server: tool registration, stdio wiring, error shaping
db.ts read-only connection, path resolution, row/value normalisation
tools.ts the three tools: list_tables, describe_table, query_database
sqlSafety.ts single-statement read-only SQL validation
tests/
sqlSafety.test.ts validator, allowed and forbidden SQL
tools.test.ts tools against the real shop.db
mcp.test.ts end-to-end over stdio with a real MCP client
eval/
tasks.ts eval tasks and their SQLite reference values
run.ts LLM + MCP eval runner (manual)
shop.db依赖
包 | 说明 |
| 官方 MCP TypeScript SDK(v2)。提供 |
| SDK 用于工具输入/输出 schema 的依赖;它向代理发布机器可读的参数类型。 |
| 仅开发依赖:构建和类型检查。 |
| 仅开发依赖:官方 MCP 客户端,用于 stdio 端到端测试和 eval 运行器。 |
SQLite 来自 Node 内置的 node:sqlite,测试来自 Node 内置的测试运行器,eval 的 HTTP 调用来自内置的 fetch——没有安装任何数据库驱动、ORM、查询构建器、Web 框架、日志库、测试框架、SQL 解析器或 LLM SDK。
This server cannot be deployed
Maintenance
Related MCP Connectors
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
Query 40 databases from Claude, ChatGPT, or Cursor — on any device. Read-only, encrypted, audited.
Explore, query, and inspect SQLite databases with ease. List tables, preview results, and view det…
- dataOAuthco.thinair
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceExposes any SQLite database as read-only MCP tools for AI assistants, enabling listing tables, describing schemas, and running SELECT queries with filtering, ordering, and pagination.-
- FlicenseAqualityCmaintenanceEnables AI agents to safely inspect and query a SQLite database through read-only MCP tools for listing tables, describing schemas, and running paginated SELECT queries.3-
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to read-only analyze a SQLite e-commerce database, exploring schema and running analytical SQL queries over stdio.-
- AlicenseNot gradedqualityCmaintenanceEnables AI models to securely analyze SQLite datasets and read local text documents through a local stdio interface. It provides read-only querying, schema discovery, pagination, and timeout protections to prevent data leaks or destructive changes.MIT