Skip to main content
Glama
raduis2136

MySQL MCP Server

by raduis2136
README.md
# MySQL MCP Server

MySQL 数据库的 AI 原生交互层,基于 FastMCP 构建。运行时动态连接任意 MySQL 实例,将数据库操作沉淀为 18 个结构化工具,覆盖**元数据搜索**、**性能分析**、**大表洞察**、**阻塞诊断**、**慢查询分析**全场景,让 LLM 智能体像资深工程师一样自主完成复杂任务,无需人工介入。

**核心特性:**

- **上下文感知** — 连接即采集 17 项服务器元数据(版本、隔离级别、sql_mode、buffer_pool),为 AI 提供准确运行环境上下文,避免误判。
- **生产安全** — 只读拦截 + 查询超时 + 参数化防注入 + 误杀防护 + 结果集截断 + 请求鉴权,六层防护保障生产库即接即用
- **工具化约束** — 专用工具替代自由 SQL 执行,约束 AI 行为路径,降低误操作与注入风险
- **数据探索链** — `search_schema → describe_schema → sample_data → count_estimate` 递进式探索,AI 在充分理解数据结构后再生成 SQL,显著提升准确率
- **故障自处理** — `active_connections → lock_waits → kill_query` 闭环,AI 自主完成阻塞诊断与处理
- **并发连多库** — 通过 alias 连接池同时连接多个 MySQL 实例,一个智能体可跨实例查询与诊断

## 工程结构

```
mysql-mcp-server/
├── mysql_mcp/
│   ├── __init__.py           # 包入口
│   ├── server.py             # MCP Server 入口(FastMCP + streamable-http)
│   ├── connection_manager.py  # 连接管理器,线程安全
│   └── config_loader.py      # 配置文件加载(YAML)
├── config.example.yaml       # 配置模板
├── requirements.txt          # 依赖
├── Dockerfile                # 容器构建
├── mysql-mcp.service         # systemd 服务文件
└── README.md
```

## 快速开始

### 1. 安装依赖

```bash
pip install -r requirements.txt
```

### 2. 配置

```bash
cp config.example.yaml config.yaml
```

```yaml
# config.yaml
credentials:
  user: "root"
  password: "你的密码"

auth:
  key: "your-secret-key"   # 鉴权 key,客户端请求需在 X-Auth-Key 头携带

mysql:
  query_timeout_ms: 60000  # 单条查询超时(毫秒),默认 60 秒,防止长查询拖垮数据库
```

### 3. 启动

在项目根目录执行:

```bash
python -m mysql_mcp.server
```

Server 监听 `http://0.0.0.0:8200/mcp`,transport 为 streamable-http。

### 4. Docker 启动

```bash
docker build -t mysql-mcp-server .
docker run -d -p 8200:8200 -v $(pwd)/config.yaml:/app/config.yaml mysql-mcp-server
```

## 对接智能体

客户端配置时需带上 `X-Auth-Key` 头:

```python
from langchain_mcp_adapters.client import MultiServerMCPClient

client = MultiServerMCPClient(
    {
        "mysql": {
            "transport": "streamable-http",
            "url": "http://localhost:8200/mcp",
            "headers": {"X-Auth-Key": "your-secret-key"},
        },
    },
    tool_name_prefix=True,  # 工具名加 server 名前缀,避免多 server 重名碰撞
)
tools = await client.get_tools()
```

跨团队共享时,各团队只需知道 URL 和 `X-Auth-Key` 即可连接。

> 本 server 的工具用裸名注册(如 `connect`、`kill_query`),消费端开启 `tool_name_prefix=True` 后实际调用名为 `mysql_connect`、`mysql_kill_query` 等——由适配器统一负责命名空间。

## 自动加载服务器元数据

`mysql_connect` 连接成功后会自动采集 17 项服务器元数据,作为后续工具调用的上下文,避免 AI 盲猜版本特性:

| 分组 | 字段 | 用途 |
|------|------|------|
| 版本 | `version`、`innodb_version` | 判断特性是否支持(CTE、窗口函数、JSON 等) |
| 身份 | `server_id`、`read_only`、`super_read_only` | 区分主从、判断可执行操作范围 |
| 复制 | `log_bin`、`gtid_mode` | 判断 binlog 是否开启、复制方式 |
| 容量 | `max_connections`、`innodb_buffer_pool_size` | 连接数与内存基线 |
| 事务 | `transaction_isolation` | 默认隔离级别(RR / RC),影响锁行为 |
| 语法 | `sql_mode` | 严格模式、ONLY_FULL_GROUP_BY 等,决定 SQL 写法 |
| 时区 | `time_zone` | 时间函数与存储行为 |
| 慢查询 | `long_query_time` | 慢查询阈值,辅助判断 |
| 字符集 | `character_set_server` | 默认字符集 |
| 双一 | `innodb_flush_log_at_trx_commit`、`sync_binlog` | 持久化与 binlog 同步策略,影响数据安全级别 |

这些信息随连接返回,AI 无需额外调用即可据此选择正确的 SQL 语法与诊断方向。

## 工具列表

> 以下工具名为开启 `tool_name_prefix=True` 后的实际调用名;server 端以裸名注册(如 `connect`、`kill_query`),前缀由 langchain-mcp-adapters 自动添加。

| 工具 | 参数 | 说明 |
|------|------|------|
| `mysql_connect` | `host`(必填), `port`, `user`, `password`, `database`, `alias` | 连接实例,user/password 缺失时从 config.yaml 读取;连接成功自动返回服务器元数据(版本、sql_mode、时区、双一配置等 17 项) |
| `mysql_disconnect` | `alias` | 断开连接 |
| `mysql_list_connections` | — | 列出所有活跃连接 |
| `mysql_search_schema` | `keyword`, `alias` | 按关键词搜表名/列名/表注释,纯 information_schema 查询不扫业务表;表最多 100 条,列最多 200 条 |
| `mysql_describe_schema` | `table`, `alias` | 返回表/视图 DDL(SHOW CREATE TABLE),含列、类型、主键、索引、外键、引擎、字符集、注释;三层定位库名:带前缀直用 → 当前连接库 → 跨库搜同名对象 |
| `mysql_sample_data` | `database`(必填), `table`, `limit`, `alias` | 抽样表数据(SELECT * LIMIT N),供 AI 理解字段语义;database 由 describe_schema 返回;limit 默认 10,上限 50 |
| `mysql_list_large_tables` | `min_size_gb`, `limit`, `alias` | 查 ibd 文件超阈值的表,按大小降序;min_size_gb 默认 10,limit 默认 10,上限 50;返回 total 与 data |
| `mysql_count_estimate` | `database`(必填), `table`, `alias` | 返回表行数估算与最后更新时间(information_schema.TABLES,不扫业务表);database 由 describe_schema 返回 |
| `mysql_query` | `query`, `alias` | 执行任意只读 SQL,超过 2000 行自动截断 |
| `mysql_explain` | `query`, `alias` | 查看 SQL 执行计划,返回 JSON 格式 |
| `mysql_show_status` | `alias` | SHOW GLOBAL STATUS,返回状态变量字典 |
| `mysql_show_variables` | `alias` | SHOW GLOBAL VARIABLES,返回配置变量字典 |
| `mysql_show_engine_status` | `alias` | SHOW ENGINE INNODB STATUS,返回死锁、事务、缓冲池、锁等诊断信息 |
| `mysql_show_statement_digest` | `limit`, `within_hours`, `alias` | 查看 SQL 指纹聚合统计,按平均单次耗时降序定位真正慢的 SQL;默认仅返回近 24 小时近期活跃 SQL |
| `mysql_show_active_connections` | `alias` | 查看活跃连接,按耗时降序,发现长查询与锁等待 |
| `mysql_show_lock_waits` | `alias` | 分析 InnoDB 锁阻塞关系(谁被谁阻塞、等待时长、锁对象、持锁者最后 SQL、kill 建议) |
| `mysql_kill_query` | `process_id`, `alias` | 终止指定连接正在执行的 SQL(KILL QUERY),保留连接本身;用于紧急杀掉慢查询、长事务、阻塞型 DDL |
| `mysql_list_long_running_transactions` | `min_duration_sec`, `alias` | 查长时间未提交的 InnoDB 事务,按持续时长降序;min_duration_sec 默认 60,返回 thread_id 可配合 kill_query 终止 |

## 使用示例

### 示例 1:数据探索

```
用户: 我刚接手 172.10.20.11:3306,帮我摸清订单相关的表结构,写个统计昨日 GMV 的 SQL

智能体自动执行:
1. mysql_connect(host="172.10.20.11", port=3306)
   → 自动获取版本、sql_mode、隔离级别等 17 项元数据
2. mysql_search_schema(keyword="order")
   → 发现 orders、order_detail、order_refund 等相关表
3. mysql_describe_schema(table="orders")
   → 拿到 DDL:字段、类型、主键、索引、注释
4. mysql_sample_data(database="shop", table="orders", limit=5)
   → 抽样真实数据,确认字段语义与金额单位
5. 综合结构与样本 → 生成准确 SQL,无需人工纠正
```

### 示例 2:性能诊断——慢查询定位与优化

```
用户: 172.10.20.11:3306 最近响应变慢,帮我排查

智能体自动执行:
1. mysql_connect(host="172.10.20.11", port=3306)
2. mysql_show_statement_digest(limit=10, within_hours=6)
   → 按平均耗时降序,锁定最慢的 SQL 指纹
3. mysql_explain(query="SELECT * FROM orders WHERE ...")
   → 看执行计划,发现全表扫描、未走索引
4. 综合分析 → 给出加索引建议与优化后的 SQL
```

### 示例 3:故障自处理——锁阻塞诊断与处理

```
用户: 172.10.20.11:3306 上有业务反馈数据库卡住,帮我处理

智能体自动执行:
1. mysql_connect(host="172.10.20.11", port=3306)
2. mysql_show_active_connections()
   → 发现多个连接处于 Locked 状态,等待时间长
3. mysql_show_lock_waits()
   → 锁阻塞关系:连接 12345 持锁不放,阻塞了 30+ 个会话
4. mysql_list_long_running_transactions(min_duration_sec=300)
   → 确认该连接对应一个 8 分钟未提交的长事务
5. mysql_kill_query(process_id=12345)
   → 终止问题 SQL,阻塞解除
6. 回报处置结果 → 无需人工介入,全程自动完成
```

### 示例 4:大表洞察

```
用户: 172.10.20.11:3306 磁盘快满了,帮我找出最大的表

智能体自动执行:
1. mysql_connect(host="172.10.20.11", port=3306)
2. mysql_list_large_tables(min_size_gb=5, limit=20)
   → 返回超 5GB 的表列表,附 total 总数
3. mysql_count_estimate(database="shop", table="order_log_2024")
   → 查看最大表的行数估算与最后更新时间
4. 综合分析 → 给出归档与清理建议
```