@qdkj/mysql-mcp-server-multi
v1.0.6
Published
多连接版 MySQL MCP 服务端;基于 @qdkj/mysql-mcp-server v1.0.5,单 server 实例承载 N 个 MySQL 连接,工具层显式 conn 参数路由。
Maintainers
Readme
@qdkj/mysql-mcp-server-multi
多连接版 MySQL MCP 服务端 · 单 server 实例承载 N 个 MySQL 连接,工具层显式
conn参数路由
📘 进阶文档(开发者 / 本地调试 / 跑测试 / 贡献指南)请看 DEV.md
🎯 这个库是做什么的
@qdkj/mysql-mcp-server-multi 是 @qdkj/mysql-mcp-server v1.0.1 的多连接升级版。单 server 实例承载 N 个 MySQL 连接,工具层显式 conn 参数路由到指定连接 —— LLM 视角下工具"全名 = list_tables(dev) / exec_sql(prod)"语义自描述,从根源消除同名工具冲突。仅支持 MySQL(本项目不涉及 PostgreSQL / SQL Server / Redis;如需 Redis 多连接请用对应 Redis MCP 包)。
😩 解决了什么问题
- 多 DB 必须启多个 mcp server —— 原
@qdkj/mysql-mcp-serverv1.0.1 只支持单连接;想连 dev + test + prod 三个 MySQL 就要在 mcp.json 配三个 server 实例,但工具名都是list_tables/exec_sql/get_table_structure/ddl_exec,工具名冲突让 LLM 不知道调哪个。 - LLM 选错库的 silent 错误 —— 同名工具在多 server 并行时,LLM 可能"我说要查 dev 但实际拿到 prod 的表",这种 silent 错误是生产事故的温床。显式
conn参数让 LLM 每次调用都必须指明目标连接,错误信息在工具层就暴露。 - per-conn
allowWrite/allowDDL无法跨 server 实施 —— 原包要"全局只读"必须单独部署一份 server;要"dev 库放开 / prod 库强只读"根本做不到。新包 1 个 server 配 N 个 conn,每个 conn 独立 allowWrite/allowDDL,dev 库可写、prod 库强只读,一个 mcp.json 解决所有环境的权限分层。
🧭 什么场景下用
✅ 用本库的场景:
- 多项目 / 多环境 MySQL(dev / test / staging / prod 四套库)用 1 个 mcp.json 配,工具调用时显式
conn: "dev"/conn: "prod"选库 - 多业务 MySQL(同公司不同业务线库 / 不同业务模块库)按业务拆分 conn,LLM 调
exec_sql({ conn: "user-db", ... })/exec_sql({ conn: "order-db", ... })自然路由 - 跨库数据迁移 / 对账(dev → staging 同步 / dev 与 prod 数据对账),1 个 mcp 客户端搞定双 conn,工具层
conn显式选源库和目标库
❌ 不要用本库的场景:
- 你只有 1 个 MySQL 库 → 用更轻的
@qdkj/mysql-mcp-serverv1.0.1 就够了,本包 0 多连接收益 - 你不用 MCP stdio 协议(直接在 Node.js 里 import 用)→ 本包是 MCP server 形态,不是 ORM 库
- 你需要 PostgreSQL / SQL Server / Redis / MongoDB → 本项目不涉及,请用对应数据库的 MCP 包
1. 🚀 MCP 使用方法 + JSON 配置
把这个 JSON 整段粘到你 MCP 客户端(Cursor / Claude Desktop / CodeBuddy 等)的配置里即可使用。npx -y @qdkj/mysql-mcp-server-multi@latest 会在首次启动时自动拉取最新版本。
1.1 多连接版(CONNECTION 单行 JSON,推荐)— 独立编辑 JSON 工作流
Step 1:先把 conn 列表保存为独立可编辑的 JSON 文件(conns/dev.json):
[
{
"id": "<your-mysql-hostname>",
"note": "<Your project MySQL dev>",
"allowWrite": true,
"allowDDL": true,
"conf": {
"host": "127.0.0.1",
"port": 3306,
"user": "<USER>",
"password": "<PASSWORD>",
"database": "<DB>"
}
},
{
"id": "<your-mysql-hostname-prod>",
"note": "<Your project MySQL prod>",
"allowWrite": false,
"allowDDL": false,
"conf": {
"host": "<PROD_HOST>",
"port": 3306,
"user": "<PROD_USER>",
"password": "<PROD_PASSWORD>",
"database": "<PROD_DB>"
}
}
]占位符(需替换为真实值):
<USER>/<PASSWORD>/<DB>/<PROD_HOST>/<PROD_USER>/<PROD_PASSWORD>/<PROD_DB>
Step 2:mcp.json 只保留 server 入口 + 引用 conn.json 路径(推荐)或贴 CONNECTION 单行 JSON:
{
"mcpServers": {
"mysql-multi": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@qdkj/mysql-mcp-server-multi@latest"],
"env": {
"CONNECTION_PATH": "/abs/path/to/conns/dev.json"
}
}
}
}CONNECTION_PATH 工作流优势:conn 列表在独立
.json文件,可读可 diff 可纳入 git;避免在 mcp.json 内嵌单行 JSON 字符串(不易编辑 + 容易转义错)
Step 3(备选):如果必须用单行 JSON 字符串模式(无独立文件),把上面 JSON 用 JSON.stringify() 转成单行后嵌到 mcp.json:
{
"mcpServers": {
"mysql-multi": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@qdkj/mysql-mcp-server-multi@latest"],
"env": {
"CONNECTION": "[{\"id\":\"<your-mysql-hostname>\",\"note\":\"<Your project MySQL dev>\",\"allowWrite\":true,\"allowDDL\":true,\"conf\":{\"host\":\"127.0.0.1\",\"port\":3306,\"user\":\"<USER>\",\"password\":\"<PASSWORD>\",\"database\":\"<DB>\"}},{\"id\":\"<your-mysql-hostname-prod>\",\"note\":\"<Your project MySQL prod>\",\"allowWrite\":false,\"allowDDL\":false,\"conf\":{\"host\":\"<PROD_HOST>\",\"port\":3306,\"user\":\"<PROD_USER>\",\"password\":\"<PROD_PASSWORD>\",\"database\":\"<PROD_DB>\"}}]"
}
}
}
}CONNECTION 单行 JSON 字符串编辑工作流(v2.4.2-dev-2 反馈):
- 在 VSCode / Sublime 打开 conn 列表(上方独立 JSON)
- 编辑 → 保存到
conns/dev.json- 复制文件内容 →
node -e "console.log(JSON.stringify(require('./conns/dev.json')))"转单行- 粘贴到 mcp.json env CONNECTION 字段(用
\"转义内部")- 或更推荐:改用 §1.1 Step 2 的 CONNECTION_PATH 模式避免转义
1.2 老 env 单连接版(向后兼容,无 CONNECTION/CONNECTION_PATH 时自动 fallback)
{
"mcpServers": {
"mysql-multi": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@qdkj/mysql-mcp-server-multi@latest"],
"env": {
"MYSQL_HOST": "你的MySQL地址",
"MYSQL_PORT": "3306",
"MYSQL_USER": "你的用户名",
"MYSQL_PASSWORD": "你的密码",
"MYSQL_DATABASE": "你的数据库名",
"MYSQL_ALLOW_WRITE": "true",
"MYSQL_ALLOW_DDL": "true"
}
}
}
}老 env 走 fallback 路径,自动包装成 {id: "default", ...} 一个 conn,工具调用时 conn: "default"。
1.3 配置优先级(Q04 + v2.4.2-dev-2 升级)
| 优先级 | 触发条件 | 数据来源 | 备注 |
|--------|----------|----------|------|
| 1. CONNECTION env | CONNECTION 任何非空字符串 | 单行 JSON 字符串 | 最高优先级;完全忽略其他配置 |
| 2. CONNECTION_PATH env | 无 CONNECTION + CONNECTION_PATH 任何非空字符串 | 独立 .json 文件(绝对/相对 cwd 路径)| 优先级 2 |
| 3. 老 MYSQL_ env* | CONNECTION/CONNECTION_PATH 都没有 | 老 env 5+2 变量 | 最低优先级(fallback)|
1.4 CONNECTION_PATH 路径说明
| 类型 | 示例 | 解析规则 |
|------|------|----------|
| 绝对路径(Windows)| C:/Users/<USER>/conns/dev.json | 原样使用 |
| 绝对路径(Linux/macOS)| /home/<USER>/conns/dev.json | 原样使用 |
| 相对路径 | ./conns/dev.json 或 conns/dev.json | 相对 cwd(进程当前工作目录;通常 = MCP 客户端启动目录)|
CONNECTION_PATH 错误信息示例(文件不存在):
[2026-09-10T...] [ERROR] 错误:CONNECTION_PATH 指向的文件不存在 (path="/non/existent/conn.json", resolved="D:\work\...\conn.json", cwd="D:\work\...", code=ENOENT) 期望格式:CONNECTION_PATH 指向一个可读 JSON 文件,内容是 conn 数组: [ { "id": "<your-mysql-hostname>", ... } ] 提示: - 绝对路径示例(Windows):C:/Users/<USER>/conns/dev.json - 绝对路径示例(Linux/macOS):/home/<USER>/conns/dev.json - 相对路径示例:./conns/dev.json(相对 cwd) - 相对路径示例:conns/dev.json(相对 cwd,等价) - 当前 cwd: D:\work\... - 检查文件是否存在 + 当前用户是否有读权限1.5 工具与客户端通信
服务通过 stdio 与 MCP 客户端通信,所有日志写到 stderr,不污染 stdout。客户端工具调用 → JSON-RPC over stdin → 服务执行 → JSON-RPC over stdout 返回结果。
2. 🛠️ 工具列表
服务对外暴露 5 个 MCP 工具(4 老工具加 conn + 1 新工具),AI 客户端会看到这些工具并可在对话中调用。
2.1 list_connections(新增第 5 工具)
- 功能:列出所有已注册 conn 的元数据
- 参数:无
- 返回:JSON 数组,每个元素含
id/note/allowWrite/allowDDL - 安全:不返回 host/port/user/password/database 等敏感字段
- 示例返回:
[ { "id": "<your-mysql-hostname>", "note": "开发库", "allowWrite": true, "allowDDL": true }, { "id": "<your-mysql-hostname-prod>", "note": "生产库", "allowWrite": false, "allowDDL": false } ]
2.2 list_tables(+conn 必填)
- 功能:获取指定 conn 数据库中的所有表名和表备注
- 参数:
conn(必填):conn 标识,先用list_connections工具查看可用列表
- 返回:JSON 数组,每个元素含
table_name/table_comment - 示例返回:
[ { "table_name": "users", "table_comment": "用户表" }, { "table_name": "orders", "table_comment": "订单表" } ]
2.3 get_table_structure(+conn 必填)
- 功能:查询指定 conn 一个或多个表的详细结构信息
- 参数:
conn(必填):conn 标识tables(必填):表名,多个表用逗号分隔(如users,orders,products)
- 返回:JSON 数组,每个元素含
table_name与columns列表 - 列信息字段:
column_name/data_type/is_nullable/column_key/column_default/column_comment/extra
2.4 exec_sql(+conn 必填)
- 功能:执行预编译 SQL,支持 SELECT / INSERT / UPDATE / DELETE 等增删改查
- 参数:
conn(必填):conn 标识sql(必填):预编译 SQL,?作为占位符params(可选):参数数组,与?一一对应
- 返回:JSON 数组,每行为字段名到值的映射(
{ "id": 1, "username": "alice" }) - 安全约束(per-conn 独立):
allowWrite: false的 conn → 默认只允许SELECT/SHOW/EXPLAIN/DESCRIBE/DESC- 遇到变更语句(如
INSERT)且未开启写权限 → 不执行,原样返回并提示手动跑 - 命中 DDL 关键字 → 提示改用
ddl_exec工具 allowWrite: true的 conn → 默认允许;切换需重启服务
2.5 ddl_exec(+conn 必填)
- 功能:执行 DDL 语句(表结构修改),仅支持 CREATE / ALTER / DROP / TRUNCATE / RENAME
- 参数:
conn(必填):conn 标识sql(必填):DDL 语句params(可选):参数列表(用于预编译)
- 返回:执行结果,含
affected_rows/message/success - 安全约束(per-conn 独立):
allowDDL: false的 conn → 默认不允许执行 DDLallowDDL: true的 conn → 默认允许;切换需重启服务
2.6 工具签名变更表(vs @qdkj/mysql-mcp-server v1.0.5)
| 工具 | 旧签名 | 新签名 | 变更 |
|------|--------|--------|------|
| list_tables | () | ({ conn: string }) | 加 conn 必填(破坏兼容)|
| get_table_structure | ({ tables }) | ({ conn, tables }) | 加 conn 必填(破坏兼容)|
| exec_sql | ({ sql, params? }) | ({ conn, sql, params? }) | 加 conn 必填(破坏兼容)|
| ddl_exec | ({ sql, params? }) | ({ conn, sql, params? }) | 加 conn 必填(破坏兼容)|
| list_connections | — | ({}) | 新增 |
3. ⚙️ CONNECTION 配置完整说明
3.1 conn 字段
| 字段 | 必填 | 默认 | 说明 |
|------|------|------|------|
| id | ✅ | — | conn 唯一标识,字符集 [a-z0-9_-],长度 1-64,区分大小写,重复 id 启动报错 |
| note | | "" | 描述(仅供人类阅读,list_connections 工具返回)|
| allowWrite | | true | 该 conn 是否允许 INSERT/UPDATE/DELETE |
| allowDDL | | true | 该 conn 是否允许 CREATE/ALTER/DROP/TRUNCATE/RENAME |
| conf.host | ✅ | — | MySQL 主机 |
| conf.port | | 3306 | MySQL 端口 |
| conf.user | ✅ | — | MySQL 用户 |
| conf.password | ✅ | — | MySQL 密码(允许空字符串)|
| conf.database | ✅ | — | MySQL 数据库名 |
3.2 启动期预 ping(Q01 拍板 — 硬退出)
服务启动时遍历所有 conn 调 1 次 ping()(SELECT 1,无副作用):
- ✅ 全部通过 → 启动服务 + 启动 1 min 周期的回收定时器
- ❌ 任一 conn 预 ping 失败 →
process.exit(1)+ stderr 错误(不软警告)
理由:Q01 拍板"配置错误在启动期就暴露"(spec line 18)。用户感知 = mcp 服务启动不了,需修 mcp.json 重启。
3.3 懒加载 + 长期回收
- 懒加载:conn 首次被工具调用时才
createPool + ping,未调用的 conn 不占 MySQL 连接 - 长期回收:闲置 > 10min 的 conn 池子被
pool.end()优雅关闭,避 MySQLmax_connections上限 - 回收周期:1 min 扫一次 Map(dev 决策 Q06;30s 浪费 CPU,5min 延迟到 15min 不可接受)
3.4 ❌ 不支持
- ❌ 跨 conn 事务(明确告知用户):没有 BEGIN/COMMIT/ROLLBACK 跨 conn
- ❌ SSL / TLS 证书配置(v1.0.0 暂不支持,与原包一致)
- ❌ SSH 隧道 / SOCKS 代理(与原包一致)
- ❌ 多语句(
multipleStatements: true,沿用原包false,不放开) - ❌ 链接池大小可配(沿用原包默认 10)
4. 🔧 从 @qdkj/mysql-mcp-server 升级到 @qdkj/mysql-mcp-server-multi(迁移步骤)
⚠️ BREAKING CHANGE:4 老工具全部加必填
conn参数,mcp.json 客户端工具调用代码需更新。
4.1 场景 A:只用一个库(老 env 单连接用户)
之前(用 @qdkj/mysql-mcp-server v1.0.5):
{
"mcpServers": {
"mysql-sql-exec-qdkj": {
"command": "npx",
"args": ["-y", "@qdkj/mysql-mcp-server@latest"],
"env": {
"MYSQL_HOST": "127.0.0.1",
"MYSQL_USER": "root",
"MYSQL_PASSWORD": "<PASSWORD>",
"MYSQL_DATABASE": "my_db"
}
}
}
}之后(切到新包)— mcp.json 完全不动,只改包名 + 加 conn: "default" 到工具调用:
{
"mcpServers": {
"mysql-multi": {
"command": "npx",
"args": ["-y", "@qdkj/mysql-mcp-server-multi@latest"],
"env": {
"MYSQL_HOST": "127.0.0.1",
"MYSQL_USER": "root",
"MYSQL_PASSWORD": "<PASSWORD>",
"MYSQL_DATABASE": "my_db"
}
}
}
}工具调用方需在每次调用时加 conn: "default":
list_tables()→list_tables({ conn: "default" })get_table_structure({ tables: "users" })→get_table_structure({ conn: "default", tables: "users" })exec_sql({ sql: "SELECT 1" })→exec_sql({ conn: "default", sql: "SELECT 1" })ddl_exec({ sql: "ALTER TABLE ..." })→ddl_exec({ conn: "default", sql: "ALTER TABLE ..." })
4.2 场景 B:多库(迁移到 CONNECTION 数组)
之前:mcp.json 配 N 个 server 实例(同工具名冲突),LLM 视角下 list_tables 不知指 dev 还是 prod。
之后:1 个 server 实例 + N 个 conn:
{
"mcpServers": {
"mysql-multi": {
"command": "npx",
"args": ["-y", "@qdkj/mysql-mcp-server-multi@latest"],
"env": {
"CONNECTION": "[{\"id\":\"dev\",\"note\":\"开发库\",\"allowWrite\":true,\"allowDDL\":true,\"conf\":{\"host\":\"127.0.0.1\",\"port\":3306,\"user\":\"root\",\"password\":\"<P>\"}},{\"id\":\"prod\",\"note\":\"生产库\",\"allowWrite\":false,\"allowDDL\":false,\"conf\":{\"host\":\"<PROD_HOST>\",\"user\":\"<P_USER>\",\"password\":\"<P_P>\",\"database\":\"<P_DB>\"}}]"
}
}
}
}工具调用方显式带 conn: "dev" 或 conn: "prod",LLM 视角工具"全名 = list_tables(dev) / exec_sql(prod)"语义自描述。
4.3 逐步迁移路径
- 第一步:老 mcp.json 完全不动,只改包名为
@qdkj/mysql-mcp-server-multi(fallback 路径生效,1 个 conn id="default") - 第二步:工具调用方加
conn: "default"(不改 mcp.json) - 第三步:mcp.json 改成 CONNECTION 数组(多 conn),工具调用方把
conn: "default"改成conn: "xxx"(dev/test/prod 等) - 完成:老 env 从 mcp.json 移除(CONNECTION 优先,老 env 完全忽略)
5. ⚠️ 注意事项
- 确保 MySQL 服务可连且账号有权限访问目标数据库
- CONNECTION 是单行 JSON 字符串(OS 层强制 process.env 必须是 string)
- conn id 字符集严格
[a-z0-9_-]{1,64},区分大小写("Dev" 和 "dev" 算不同 conn) - 重复 conn id 启动报错(不后定义覆盖前定义)
CONNECTION与老MYSQL_*env 同时存在时,CONNECTION 优先,老 env 完全忽略(Q04 拍板)allowWrite/allowDDLper-conn 独立;dev 库可放开、prod 库建议强只读(allowWrite: false, allowDDL: false)- 切换
CONNECTION/allowWrite/allowDDL后必须重启 MCP 客户端才生效 - 不支持跨 conn 事务(明确告知)
- 日志通过 stderr 输出,便于排查,不影响 MCP 协议(stdout)通信
- 本包需要 Node.js >= 22.6.0(engines 硬约束,因
conn-path.test.ts等 .ts 测试用--experimental-strip-types需 v22.6+;老 Node 用户请用 v1.0.0 旧版)
6. 📄 License
本项目采用 MIT License(与 package.json license: "MIT" 一致)。
📘 进阶文档(开发者 / 本地调试 / 跑测试 / 贡献指南)请看 DEV.md
版本 1.0.4 · 最后更新 2026-09-10
