Skip to main content
Glama
lampmaster

shop-sql-mcp

by lampmaster

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: mcpserve-py

安装

npm install

配置

配置是可选的。默认情况下,服务器在项目根目录打开 shop.db

变量

默认值

含义

DATABASE_PATH

<project>/shop.db

SQLite 文件的路径。相对路径基于项目根目录解析,因此服务器不依赖于启动时的工作目录。

如果想保留本地覆盖配置,请将 .env.example 复制为 .env。服务器本身读取普通环境变量;.env.example 中的 ANTHROPIC_API_KEYEVAL_MODELEVAL_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 ...——支持 JOINWHEREGROUP BYHAVINGORDER 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_ERRORREAD_ONLY_VIOLATIONMULTIPLE_STATEMENTSTABLE_NOT_FOUNDINVALID_ARGUMENTDATABASE_UNAVAILABLE。堆栈跟踪永远不会返回。

分页

分页由服务器强制执行,而不是由模型的 SQL 控制。

  • limit 默认为 100,最大 500offset 默认为 0

  • 代理的查询会被包装为 SELECT * FROM (<your sql>) LIMIT ? OFFSET ?,因此即使查询自带 LIMIT 100000,返回的行数也不会超过 limit

  • 服务器内部会获取 limit + 1 行来判断 hasMore,不需要第二次计数查询,并且最多返回 limit 行。

  • 因此单次调用永远不会返回超过 500 行,这样宽范围的 SELECT * 就不会淹没模型的上下文。

要分页遍历结果,请保持 SQL 不变(使用确定性的 ORDER BY),并在 hasMore 为 true 时让 offsetlimit 递增。

只读安全性

两层独立防护,因此没有任何一层需要单独负责。

1. SQL 验证src/sqlSafety.ts)。一个小型词法分析器跳过注释、字符串字面量和带引号的标识符,然后要求:

  • 语句以 SELECTWITH 开头——简单的 startsWith("SELECT") 会拒绝合法的只读 CTE;

  • 只能有一条语句(第一个 ; 之后的所有内容都会被拒绝,字面量或注释中的 ; 不算分隔符);

  • 任何地方都不能出现禁止的关键字——包括嵌套在 CTE 内部:INSERTUPDATEDELETECREATEDROPALTERREPLACEATTACHDETACHVACUUMREINDEXPRAGMAANALYZEBEGINCOMMITROLLBACKSAVEPOINTload_extensionwritable_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_tablesdescribe_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

依赖

说明

@modelcontextprotocol/server

官方 MCP TypeScript SDK(v2)。提供 McpServer 和 stdio 传输,因此协议不是手动实现的。

zod

SDK 用于工具输入/输出 schema 的依赖;它向代理发布机器可读的参数类型。

typescript, @types/node

仅开发依赖:构建和类型检查。

@modelcontextprotocol/client

仅开发依赖:官方 MCP 客户端,用于 stdio 端到端测试和 eval 运行器。

SQLite 来自 Node 内置的 node:sqlite,测试来自 Node 内置的测试运行器,eval 的 HTTP 调用来自内置的 fetch——没有安装任何数据库驱动、ORM、查询构建器、Web 框架、日志库、测试框架、SQL 解析器或 LLM SDK。

F
license - not found
Not graded
quality - not tested
C
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

  • A
    license
    Not graded
    quality
    D
    maintenance
    Exposes SQLite database query tools and markdown document resources over JSON-RPC 2.0 stdio transport, enabling AI assistants to read and search documents and execute read-only SQL queries.
    1
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Lets AI agents query local SQLite database files read-only using Node's built-in sqlite module, providing tools for listing tables, describing schemas, and running SQL queries.
    3
    15
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Exposes 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.

View all related MCP servers

Related MCP Connectors

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/lampmaster/shop-sql-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server