不只是一个 MCP Server,而是 AI 与数据库之间的安全执行网关
MySQL MCP Server
AI-to-DB Secure Gateway — 不只是一个 MCP Server,而是 AI 与数据库之间的安全执行网关。
基于 NestJS + TypeScript 构建,通过 MCP 协议为 Claude Code 等 AI 助手提供对 MySQL 数据库的受控访问能力。核心目标是在 AI 的灵活性与数据库的安全性之间建立可信边界。
设计理念
传统数据库工具直接暴露执行能力,对 AI 调用者而言风险极高。本项目的核心设计原则:
- 最小权限:工具按风险分级,高危操作默认关闭
- AST 级校验:不依赖关键字匹配,通过 SQL Parser 解析语法树做严格校验
- 可审计:每次操作完整记录,行为可追溯
- 可控执行:AI 可以分析(EXPLAIN)但不能随意破坏
架构总览
┌─────────────────────────────────────────────────────────────┐
│ Claude Code / AI Client │
└─────────────────────────┬───────────────────────────────────┘
│ MCP Protocol (stdio)
┌─────────────────────────▼───────────────────────────────────┐
│ MCP Transport Layer │
│ (StdioServerTransport) │
└─────────────────────────┬───────────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────────┐
│ NestJS Application │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ McpModule │ │
│ │ ToolsService │ ToolsHandler │ McpService │ │
│ └──────────────────────────┬──────────────────────────┘ │
│ │ │
│ ┌──────────────────────────▼──────────────────────────┐ │
│ │ SecurityModule ← 所有请求必经此处 │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ [Layer 1] ToolLevelGuard 工具级别门控 │ │ │
│ │ │ [Layer 2] AstValidationService AST 校验 │ │ │
│ │ │ [Layer 3] PermissionService 权限校验 │ │ │
│ │ │ [Layer 4] AuditService 审计日志 │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └──────────────────────────┬──────────────────────────┘ │
│ │ │
│ ┌──────────────────────────▼──────────────────────────┐ │
│ │ DatabaseModule │ │
│ │ QueryService │ SchemaService │ DmlService │ │
│ │ DdlService │ TransactionService │ │
│ │ ExplainService │ │
│ │ │ │
│ │ ConnectionPoolService (mysql2) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ConfigModule │ │
│ │ AppConfigService (.env) │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────┬───────────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────────┐
│ MySQL Server │
└─────────────────────────────────────────────────────────────┘
Tool 分级控制
所有工具按操作风险分为三个级别,级别越高默认越收紧。
| 级别 | 说明 | 默认状态 | 开启方式 |
|------|------|----------|----------|
| Level 1 | 只读操作,无副作用 | 始终开放 | — |
| Level 2 | 数据变更,有副作用但可恢复 | 开放,带风险标识 | PERMISSION_MODE=read_write |
| Level 3 | 结构变更或批量操作,风险高 | 默认关闭 | 需显式配置开启 |
工具级别映射
| 工具 | 级别 | riskLevel | 默认开启 | 开启配置项 |
|------|------|-----------|----------|------------|
| mysql_query | Level 1 | low | ✅ | — |
| mysql_list_databases | Level 1 | low | ✅ | — |
| mysql_list_tables | Level 1 | low | ✅ | — |
| mysql_describe_table | Level 1 | low | ✅ | — |
| mysql_explain | Level 1 | low | ✅ | — |
| mysql_execute | Level 2 | medium | ✅ | PERMISSION_MODE=read_write |
| mysql_ddl | Level 3 | high | ❌ | ENABLE_DDL=true |
| mysql_transaction | Level 3 | high | ❌ | ENABLE_TRANSACTION=true |
v1 说明:
mysql_transaction第一版默认关闭。开启后仅允许 INSERT 语句,禁止在事务中执行 UPDATE / DELETE / DDL,降低批量误操作风险。
MCP Tools API
Level 1 — 只读工具
mysql_query
执行 SELECT 查询,返回结果集。
参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| sql | string | ✅ | SELECT 语句,支持 ? 占位符 |
| params | array | ❌ | 占位符参数值 |
| database | string | ❌ | 指定数据库,不填则使用默认库 |
| limit | number | ❌ | 最大返回行数,默认 100,上限 1000 |
返回
{
"rows": [...],
"rowCount": 42,
"fields": ["id", "name", "created_at"],
"truncated": false
}
AST 校验规则
- 语句类型必须为
SELECT,否则拒绝 - 禁止多语句(
;分隔) - 禁止子查询中包含写操作(INSERT / UPDATE / DELETE)
- 禁止危险函数调用:
SLEEP、BENCHMARK、LOAD_FILE、INTO OUTFILE
mysql_explain
对 SELECT 语句执行 EXPLAIN,返回执行计划,用于 AI 自动分析查询性能。
参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| sql | string | ✅ | 待分析的 SELECT 语句 |
| database | string | ❌ | 指定数据库 |
返回
{
"plan": [
{
"id": 1,
"select_type": "SIMPLE",
"table": "users",
"type": "ref",
"possible_keys": "idx_email",
"key": "idx_email",
"rows": 1,
"Extra": "Using index"
}
],
"warnings": ["全表扫描: orders (type=ALL, rows=50000)"]
}
说明
- 内部执行
EXPLAIN <sql>,不实际执行原始 SQL - 对
type=ALL(全表扫描)且rows超过阈值时,在warnings中提示 - 同样经过 AST 校验,确保传入的是合法 SELECT
mysql_list_databases
列出所有可访问的数据库(受白名单过滤)。
参数:无
返回
{ "databases": ["app_db", "test_db"] }
mysql_list_tables
列出指定数据库中的所有表。
参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| database | string | ✅ | 数据库名 |
返回
{
"database": "app_db",
"tables": ["users", "orders", "products"]
}
mysql_describe_table
获取表的字段结构、索引和建表语句。
参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| database | string | ✅ | 数据库名 |
| table | string | ✅ | 表名 |
返回
{
"database": "app_db",
"table": "users",
"columns": [
{ "name": "id", "type": "int(11)", "nullable": false, "key": "PRI", "default": null },
{ "name": "email", "type": "varchar(255)", "nullable": false, "key": "UNI", "default": null }
],
"indexes": [
{ "name": "PRIMARY", "columns": ["id"], "unique": true }
],
"createStatement": "CREATE TABLE `users` ..."
}
Level 2 — 受控写入工具
mysql_execute
执行 DML 语句(INSERT / UPDATE / DELETE)。需要 PERMISSION_MODE=read_write。
参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| sql | string | ✅ | DML 语句,支持 ? 占位符 |
| params | array | ❌ | 占位符参数值 |
| database | string | ❌ | 指定数据库 |
返回
{
"affectedRows": 3,
"insertId": 0,
"changedRows": 3,
"riskLevel": "medium"
}
AST 校验规则
- 语句类型必须为
INSERT/UPDATE/DELETE,否则拒绝 - 禁止多语句
UPDATE/DELETE缺少WHERE子句时,根据REQUIRE_WHERE_CLAUSE配置决定拒绝或警告- 禁止子查询中包含 DDL
Level 3 — 高危工具(默认关闭)
mysql_ddl
执行 DDL 语句(CREATE / ALTER / DROP / TRUNCATE)。需要 ENABLE_DDL=true。
参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| sql | string | ✅ | DDL 语句 |
| database | string | ❌ | 指定数据库 |
返回
{
"success": true,
"message": "Table created successfully",
"riskLevel": "high"
}
AST 校验规则
- 语句类型必须为 DDL 类型
DROP需要额外配置ALLOW_DROP=trueTRUNCATE需要额外配置ALLOW_TRUNCATE=true- 禁止操作系统库:
mysql、information_schema、performance_schema、sys
mysql_transaction
在事务中执行多条语句,全部成功则提交,任意失败则回滚。需要 ENABLE_TRANSACTION=true。
v1 限制:仅允许 INSERT 语句,禁止 UPDATE / DELETE / DDL。
参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| statements | array | ✅ | 语句数组,每项含 sql 和可选 params |
| database | string | ❌ | 指定数据库 |
statements 单项结构
{ "sql": "INSERT INTO orders (user_id, amount) VALUES (?, ?)", "params": [1, 99.9] }
返回
{
"success": true,
"results": [
{ "affectedRows": 1, "insertId": 101 },
{ "affectedRows": 1, "insertId": 102 }
],
"riskLevel": "high"
}
安全设计
AST 级 SQL 校验(核心能力)
使用 node-sql-parser 将 SQL 解析为抽象语法树(AST),基于 AST 做结构性校验,而非脆弱的关键字匹配。
用户传入 SQL
│
▼
node-sql-parser.parse()
│
├─ 解析失败 → 拒绝(语法错误)
│
▼
AST 结构校验
├─ 语句类型是否匹配当前工具?
├─ 是否包含多条语句?
├─ 子查询中是否有写操作?
├─ 是否调用了危险函数?(SLEEP / BENCHMARK / LOAD_FILE)
├─ UPDATE/DELETE 是否缺少 WHERE?
└─ 是否操作了系统库/表?
│
▼
通过 → 参数化执行
为什么必须用 AST 而非关键字检测?
关键字检测可以被绕过,例如:
-- 关键字检测无法识别这类注入
SELECT * FROM users WHERE id = 1; DROP TABLE users; --
SELECT/**/SLEEP(5)
SELECT 1 UNION SELECT password FROM mysql.user
AST 解析后,每个节点的类型、位置、语义都是明确的,无法通过注释、大小写、空白字符绕过。
防护层次
请求进入
│
▼
[Layer 1] Tool 级别门控
│ - 工具是否已启用(ENABLE_DDL / ENABLE_TRANSACTION)
│ - PERMISSION_MODE 是否允许该操作类型
▼
[Layer 2] 参数 Schema 校验(Zod)
│ - 必填字段、类型、字符串长度
▼
[Layer 3] AST 级 SQL 校验(node-sql-parser)
│ - 语句类型、多语句、危险函数、子查询写操作
│ - WHERE 子句检查
▼
[Layer 4] 权限校验
│ - 数据库白名单(ALLOWED_DATABASES)
│ - 系统库保护
▼
[Layer 5] 参数化执行(mysql2)
│ - 所有用户输入通过占位符绑定,禁止字符串拼接
▼
[Layer 6] 结果限制
│ - 自动截断(MAX_QUERY_LIMIT_HARD)
│ - 执行超时(QUERY_TIMEOUT_MS)
▼
[Layer 7] 审计日志
- 工具名、SQL(脱敏)、执行结果、耗时、时间戳
- 写入本地文件,按日期滚动
权限模式
| 模式 | 允许操作 |
|------|----------|
| read_only | Level 1 工具(只读) |
| read_write(默认) | Level 1 + Level 2 工具 |
| full | Level 1 + Level 2 + Level 3(仍需 ENABLE_DDL / ENABLE_TRANSACTION) |
危险操作保护
| 操作 | 默认行为 | 配置项 |
|------|----------|--------|
| DDL 工具整体 | 关闭 | ENABLE_DDL=true |
| Transaction 工具 | 关闭 | ENABLE_TRANSACTION=true |
| DROP TABLE/DATABASE | 拒绝 | ALLOW_DROP=true |
| TRUNCATE | 拒绝 | ALLOW_TRUNCATE=true |
| UPDATE/DELETE 无 WHERE | 拒绝 | REQUIRE_WHERE_CLAUSE=false 关闭 |
AST Validation Rules(执行规范)
ast-validation.service.ts 的校验规则按 SQL 类型分组,开发时直接按此实现,无需临时判断。
SELECT
| 规则 | 说明 |
|------|------|
| 语句类型必须为 SELECT | AST type !== 'select' 时拒绝 |
| 禁止多语句 | AST 解析结果为数组(长度 > 1)时拒绝 |
| 禁止 UNION / UNION ALL | AST 中存在 union 节点时拒绝 |
| 禁止 INTO OUTFILE / INTO DUMPFILE | AST 中存在 into 节点时拒绝 |
| 禁止危险函数调用 | 递归遍历 AST,函数名匹配黑名单:SLEEP、BENCHMARK、LOAD_FILE、GET_LOCK |
| 禁止子查询中包含写操作 | 递归遍历所有子查询节点,类型不得为 insert/update/delete |
| 禁止访问系统库表 | 表名来源(db 字段)不得为 mysql、information_schema、performance_schema、sys |
INSERT
| 规则 | 说明 |
|------|------|
| 语句类型必须为 INSERT | AST type !== 'insert' 时拒绝 |
| 禁止多语句 | 同上 |
| v1:禁止 INSERT ... SELECT | AST 中存在 select 子节点时拒绝(仅允许 VALUES 形式) |
| 禁止向系统库写入 | 目标表的 db 字段不得为系统库 |
UPDATE
| 规则 | 说明 |
|------|------|
| 语句类型必须为 UPDATE | AST type !== 'update' 时拒绝 |
| 禁止多语句 | 同上 |
| 必须包含 WHERE 子句 | AST where === null 时,根据 REQUIRE_WHERE_CLAUSE 拒绝或警告 |
| 禁止恒等 WHERE 条件 | 检测 WHERE 1=1、WHERE true、WHERE 1 等恒真条件,直接拒绝 |
| 禁止危险函数 | 同 SELECT 黑名单 |
DELETE
| 规则 | 说明 |
|------|------|
| 语句类型必须为 DELETE | AST type !== 'delete' 时拒绝 |
| 禁止多语句 | 同上 |
| 必须包含 WHERE 子句 | 同 UPDATE |
| 禁止恒等 WHERE 条件 | 同 UPDATE |
| 禁止系统库操作 | 同上 |
DDL(仅 ENABLE_DDL=true 时生效)
| 规则 | 说明 |
|------|------|
| 语句类型必须为 DDL 类型 | 允许:CREATE、ALTER、DROP、TRUNCATE;其他拒绝 |
| 禁止多语句 | 同上 |
| DROP 需额外开关 | ALLOW_DROP=false 时拒绝所有 DROP 语句 |
| TRUNCATE 需额外开关 | ALLOW_TRUNCATE=false 时拒绝 |
| 禁止操作系统库 | 目标库/表不得为系统库 |
事务中每条语句(仅 ENABLE_TRANSACTION=true 时生效)
| 规则 | 说明 |
|------|------|
| v1:每条语句类型必须为 INSERT | 非 INSERT 语句直接拒绝整个事务 |
| 每条语句独立经过 INSERT 规则校验 | 复用上方 INSERT 规则,不单独实现 |
| 禁止超过最大语句数 | 默认上限 20 条,防止超大事务(TRANSACTION_MAX_STATEMENTS=20) |
Validation Pipeline(校验流水线)
每次工具调用的完整校验执行顺序,任意步骤失败立即返回错误,不继续执行。
工具调用请求
│
▼
Step 1: Tool 级别门控(ToolLevelGuard)
│ 检查 ENABLE_DDL / ENABLE_TRANSACTION 开关
│ 检查 PERMISSION_MODE 是否允许该工具类型
│ ✗ → 返回 "Tool is disabled" 错误
▼
Step 2: 入参 Schema 校验(Zod)
│ 必填字段、类型、字符串长度(sql 最大 10000 字符)
│ ✗ → 返回参数校验错误
▼
Step 3: SQL AST 解析(node-sql-parser)
│ 调用 parser.astify(sql)
│ ✗ 解析失败 → 返回 "Invalid SQL syntax" 错误
▼
Step 4: 语句类型校验
│ AST type 是否与当前工具匹配
│ ✗ → 返回 "Statement type not allowed for this tool" 错误
▼
Step 5: 多语句检测
│ AST 结果是否为数组(多条语句)
│ ✗ → 返回 "Multiple statements are not allowed" 错误
▼
Step 6: 结构性规则校验(按 SQL 类型执行对应规则)
│ UNION / INTO OUTFILE / 危险函数 / 子查询写操作
│ WHERE 子句 / 恒等条件 / 系统库保护
│ ✗ → 返回具体规则违反错误
▼
Step 7: 权限校验(PermissionService)
│ 数据库白名单(ALLOWED_DATABASES)
│ ✗ → 返回 "Database not allowed" 错误
▼
Step 8: 参数化执行(mysql2)
│ 通过占位符绑定参数,执行 SQL
│ ✗ → 返回数据库错误(不暴露内部细节)
▼
Step 9: 结果处理 + 审计日志
截断超限结果(MAX_QUERY_LIMIT_HARD)
写入审计日志(工具名、SQL hash、结果行数、耗时)
✓ → 返回结果
Implementation Phases(实现阶段)
按风险从低到高分阶段实现,每个 Phase 形成独立可测试的闭环。
Phase 1 — 只读闭环(核心基础)
目标:跑通完整链路,AST 校验 + 只读查询可用。
- [ ] 项目初始化(NestJS + TypeScript + 依赖安装)
- [ ] ConfigModule:读取
.env,Zod 校验必填项 - [ ] ConnectionPoolService:mysql2 连接池,健康检查
- [ ]
ast-validation.service.ts:实现 SELECT 规则(Step 3-6) - [ ] QueryService:执行参数化 SELECT,自动追加 LIMIT
- [ ] SchemaService:
mysql_list_databases/mysql_list_tables/mysql_describe_table - [ ] ExplainService:
mysql_explain - [ ] AuditService:写入本地日志文件
- [ ] 单元测试:AST 校验规则全覆盖
验收:可通过 MCP 执行 SELECT 查询,危险 SQL 被正确拒绝。
Phase 2 — 接入 MCP Tools
目标:将 Phase 1 的能力通过 MCP 协议暴露给 Claude Code。
- [ ] McpService:初始化 StdioServerTransport,注册 Level 1 工具
- [ ] ToolsHandler:工具调用分发
- [ ] ToolLevelGuard:Level 门控逻辑
- [ ]
main.ts:启动 MCP Server
验收:在 Claude Code 中配置后,可调用 mysql_query 和 Schema 工具。
Phase 3 — DML 写操作
目标:在安全校验完备的前提下,开放 Level 2 工具。
- [ ]
ast-validation.service.ts:补充 INSERT / UPDATE / DELETE 规则 - [ ] DmlService:执行 DML,返回 affectedRows / insertId
- [ ] PermissionService:PERMISSION_MODE 校验
- [ ] 注册
mysql_execute工具(Level 2) - [ ] 集成测试:WHERE 缺失、恒等条件等场景验证
验收:mysql_execute 可用,无 WHERE 的 UPDATE/DELETE 被正确拒绝。
Phase 4 — DDL 与事务(高危,按需开启)
目标:在显式配置开启后,提供 Level 3 能力。
- [ ]
ast-validation.service.ts:补充 DDL 规则 - [ ] DdlService:执行 DDL
- [ ] TransactionService:事务管理,v1 仅 INSERT
- [ ] 注册
mysql_ddl/mysql_transaction工具(Level 3,默认不注册) - [ ] 集成测试:DROP 保护、系统库保护、事务回滚验证
验收:ENABLE_DDL=false 时工具不可见;开启后 DROP 受 ALLOW_DROP 控制。
一次请求的完整生命周期
以 mysql_execute 执行一条 UPDATE 为例,追踪请求从进入到返回的每一步。
Claude Code
│
│ 调用工具:mysql_execute
│ 参数:{ sql: "UPDATE users SET name=? WHERE id=?", params: ["Alice", 1] }
│
▼
StdioServerTransport.onMessage()
│ 接收 JSON-RPC 消息,解析 tool name + arguments
│
▼
ToolsHandler.handle("mysql_execute", args)
│ 查找工具定义,注入 riskLevel: "medium"
│
▼
ToolLevelGuard.canActivate()
│ PERMISSION_MODE=read_write ✓
│ mysql_execute 是 Level 2,read_write 允许 ✓
│
▼
Zod Schema 校验
│ sql: string ✓,params: array ✓
│
▼
AstValidationService.validate(sql, "UPDATE")
│ parser.astify("UPDATE users SET name=? WHERE id=?")
│ → AST type: "update" ✓
│ → 单语句 ✓
│ → WHERE 存在 ✓
│ → WHERE 非恒等条件(id=? 不是 1=1)✓
│ → 无危险函数 ✓
│ → 目标表 users 非系统库 ✓
│
▼
PermissionService.checkDatabase("users_db")
│ ALLOWED_DATABASES 未配置(不限制)✓
│
▼
ConnectionPoolService.getConnection()
│ 从连接池取出连接
│ 执行 USE users_db(若指定了 database)
│
▼
DmlService.execute(sql, params)
│ connection.execute("UPDATE users SET name=? WHERE id=?", ["Alice", 1])
│ → affectedRows: 1, changedRows: 1
│ connection.release() ← finally 块保证释放
│
▼
AuditService.log()
│ 写入日志:
│ { tool: "mysql_execute", sqlHash: "a3f9...", affectedRows: 1, duration: 12ms }
│ (不记录原始 SQL 参数值,防止敏感数据落盘)
│
▼
返回 Claude Code
{ affectedRows: 1, insertId: 0, changedRows: 1, riskLevel: "medium" }
如果不这样做——典型失败案例
案例 1:关键字检测被绕过
场景:用关键字匹配拦截 SLEEP,AI 发送如下 SQL:
SELECT * FROM users WHERE id = 1 AND (SELECT/**/SLEEP(5))
关键字检测结果:SLEEP 被注释分隔,正则未匹配,放行。数据库挂起 5 秒。
AST 校验结果:解析后函数节点 name: "SLEEP" 清晰可见,拒绝。
案例 2:UPDATE 无 WHERE 全表覆盖
场景:AI 生成了一条错误的 UPDATE,忘记加 WHERE:
UPDATE users SET status = 'disabled'
无校验结果:全表 10 万条记录全部被禁用,不可逆。
AST 校验结果:where === null,REQUIRE_WHERE_CLAUSE=true,拒绝,返回错误。
案例 3:恒等 WHERE 条件绕过
场景:AI 构造了带 WHERE 的语句,但条件恒为真:
DELETE FROM orders WHERE 1=1
仅检查 WHERE 存在:WHERE 存在,放行。全表删除。
AST 校验结果:检测到 left: {value: 1}, right: {value: 1} 恒等条件,拒绝。
案例 4:INSERT SELECT 数据泄露
场景:AI 尝试将敏感表数据复制到可读表:
INSERT INTO logs (content) SELECT password FROM mysql.user
无 INSERT SELECT 限制:密码哈希被写入 logs 表,数据泄露。
AST 校验结果:INSERT 中检测到 select 子节点,v1 禁止 INSERT SELECT,拒绝。
案例 5:DDL 工具未分级,AI 误删表
场景:AI 在清理测试数据时,误将 DROP 发给了生产库:
DROP TABLE users
无分级控制:工具始终可用,表被删除。
分级控制结果:ENABLE_DDL=false(默认),工具在 MCP 中不注册,Claude Code 根本看不到该工具,无法调用。
模块划分
McpModule
| 文件 | 职责 |
|------|------|
| mcp.service.ts | 初始化 MCP Server,按级别注册 Tools |
| tools.handler.ts | 工具调用分发,注入 riskLevel 元数据 |
| tools.service.ts | 工具定义(名称、描述、参数 schema、级别) |
DatabaseModule
| 文件 | 职责 |
|------|------|
| connection-pool.service.ts | mysql2 连接池管理 |
| query.service.ts | SELECT 查询 |
| dml.service.ts | INSERT / UPDATE / DELETE |
| ddl.service.ts | CREATE / ALTER / DROP |
| schema.service.ts | Schema 探索 |
| transaction.service.ts | 事务管理(v1 仅 INSERT) |
| explain.service.ts | EXPLAIN 执行计划分析 |
SecurityModule
| 文件 | 职责 |
|------|------|
| tool-level.guard.ts | Tool 级别门控,检查 ENABLE_* 配置 |
| ast-validation.service.ts | 基于 node-sql-parser 的 AST 校验(核心) |
| permission.service.ts | 权限模式校验、数据库白名单 |
| audit.service.ts | 审计日志写入 |
ConfigModule
| 文件 | 职责 |
|------|------|
| config.service.ts | 统一配置读取 |
| config.schema.ts | Zod 配置校验,启动时检查必填项 |
项目目录结构
mysql-mcp-nest/
├── src/
│ ├── main.ts
│ ├── app.module.ts
│ │
│ ├── config/
│ │ ├── config.module.ts
│ │ ├── config.service.ts
│ │ └── config.schema.ts
│ │
│ ├── mcp/
│ │ ├── mcp.module.ts
│ │ ├── mcp.service.ts
│ │ ├── tools.handler.ts
│ │ └── tools.service.ts
│ │
│ ├── database/
│ │ ├── database.module.ts
│ │ ├── connection-pool.service.ts
│ │ ├── query.service.ts
│ │ ├── dml.service.ts
│ │ ├── ddl.service.ts
│ │ ├── schema.service.ts
│ │ ├── transaction.service.ts
│ │ └── explain.service.ts
│ │
│ └── security/
│ ├── security.module.ts
│ ├── tool-level.guard.ts # Tool 级别门控
│ ├── ast-validation.service.ts # AST 校验(核心)
│ ├── permission.service.ts
│ └── audit.service.ts
│
├── test/
│ ├── ast-validation.service.spec.ts
│ ├── query.service.spec.ts
│ ├── dml.service.spec.ts
│ └── tool-level.guard.spec.ts
│
├── logs/
├── .env.example
├── .env
├── .gitignore
├── package.json
├── tsconfig.json
└── README.md
配置参考
# --- MySQL 连接 ---
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=root
DB_PASSWORD=your_password
DB_DATABASE=app_db
# --- 连接池 ---
DB_POOL_MIN=2
DB_POOL_MAX=10
DB_POOL_ACQUIRE_TIMEOUT=30000
DB_POOL_IDLE_TIMEOUT=60000
# --- 查询限制 ---
MAX_QUERY_LIMIT=100
MAX_QUERY_LIMIT_HARD=1000
QUERY_TIMEOUT_MS=30000
# --- 权限控制 ---
PERMISSION_MODE=read_write # read_only | read_write | full
ALLOWED_DATABASES= # 白名单,逗号分隔,空表示不限制
REQUIRE_WHERE_CLAUSE=true # UPDATE/DELETE 必须带 WHERE
# --- Tool 级别开关(Level 3 默认关闭)---
ENABLE_DDL=false
ENABLE_TRANSACTION=false
ALLOW_DROP=false
ALLOW_TRUNCATE=false
# --- EXPLAIN 配置 ---
EXPLAIN_FULL_SCAN_WARN_ROWS=10000 # 全表扫描超过此行数时输出警告
# --- 审计日志 ---
AUDIT_LOG_ENABLED=true
AUDIT_LOG_DIR=./logs
AUDIT_LOG_PARAMS=false # 是否记录参数值
# --- 应用日志 ---
LOG_LEVEL=info
核心依赖
| 包 | 用途 |
|----|------|
| @nestjs/core | NestJS 框架 |
| @modelcontextprotocol/sdk | MCP 协议实现 |
| mysql2 | MySQL 驱动 + 连接池 |
| node-sql-parser | SQL AST 解析(安全核心) |
| zod | 配置与参数校验 |
快速开始
npm install
cp .env.example .env
# 编辑 .env 填入 MySQL 连接信息
npm run start:dev # 开发模式
npm run build # 构建
npm run start:prod # 生产运行
在 Claude Code 中配置
先构建项目:
npm run build
使用 claude mcp add 命令注册(推荐,写入用户级全局配置):
claude mcp add mysql node /path/to/mysql-mcp-nest/dist/main.js \
--scope user \
-e DB_HOST=127.0.0.1 \
-e DB_PORT=3306 \
-e DB_USER=root \
-e DB_PASSWORD=your_password \
-e DB_DATABASE=your_database \
-e PERMISSION_MODE=read_write \
-e AUDIT_LOG_ENABLED=true \
-e AUDIT_LOG_DIR=/path/to/mysql-mcp-nest/logs
--scope user:写入~/.claude.json,所有项目均可使用--scope project:写入当前项目的.claude.json,仅当前项目可用
注册后重启 claude,执行 /mcp 验证连接状态:
❯ /mcp
mysql connected
连接成功后即可直接使用:
列出 your_database 中的所有表