Skip to main content
Glama
HaokaiLau

mysql-readonly-mcp

by HaokaiLau
README.md
# mysql-readonly-mcp

本项目是面向个人本机的只读 MySQL MCP Server 首版实现,默认通过 stdio 提供 6 个工具。

## 工具说明

| 工具 | 作用 | 主要参数 | 返回内容 |
| --- | --- | --- | --- |
| `mysql_get_server_info` | 查看当前连接的数据库和 MySQL 服务信息 | 无 | 数据库名、MySQL 版本、字符集、时区及当前安全限制 |
| `mysql_list_tables` | 列出当前数据库中的表和视图 | `keyword`、`offset`、`limit` | 表名、对象类型、注释、存储引擎和估算行数 |
| `mysql_describe_table` | 查看指定表或视图的结构 | `table` | 字段顺序、字段名、类型、可空性、默认值、主键标识、注释和外键关系 |
| `mysql_list_indexes` | 查看指定表的索引 | `table` | 索引名、是否唯一、索引类型、字段顺序和前缀长度 |
| `mysql_query` | 执行一条安全的只读查询 | `sql` | 列信息、二维数据、返回行数、耗时和是否被截断 |
| `mysql_explain` | 查看安全只读查询的 JSON 执行计划 | `sql` | MySQL `EXPLAIN FORMAT=JSON` 执行计划 |

### 查询工具限制

- `mysql_query` 和 `mysql_explain` 的 `sql` 只允许单条 `SELECT` 或只读 CTE。
- 拒绝 `INSERT`、`UPDATE`、`DELETE`、DDL、`CALL`、`SET`、跨库引用、多语句、锁定读取、文件导出、用户变量和危险函数。
- 未指定 `LIMIT` 时,服务端自动追加 `最大返回行数 + 1`,用于判断结果是否截断;实际返回不超过配置的最大行数。
- 已有 `LIMIT` 超过最大返回行数时直接拒绝,不自动改写查询语义。
- 成功和失败结果都包含版本化 JSON 结构;同时通过 MCP `structuredContent` 和精简 JSON 文本返回。

## 连接与调用流程

服务启动和一次工具调用的流程如下:

```text
启动 MCP 进程
    │
    ├─ 读取 .env / 进程环境变量并校验配置
    ├─ 创建 MySQL 连接池(启动时不主动查询业务数据)
    └─ 通过 stdio 等待 MCP 客户端握手
         │
         ├─ 客户端执行 initialize 和 tools/list
         └─ 客户端调用具体工具
              │
              ├─ 校验工具参数
              ├─ mysql_query / mysql_explain:解析并校验只读 SQL
              ├─ 从连接池获取连接
              ├─ START TRANSACTION READ ONLY
              ├─ 设置服务端查询超时并执行 SQL
              ├─ 成功或失败后执行 ROLLBACK
              └─ 返回 structuredContent 和 JSON 文本结果
```

元数据工具使用参数化 SQL 查询 `information_schema`;`mysql_query` 和 `mysql_explain` 使用用户提交的 SQL,但必须先通过 AST 安全策略。查询超时或连接异常时,连接会被销毁而不会放回连接池。服务收到 `SIGINT` 或 `SIGTERM` 后关闭连接池。

从项目目录启动开发模式:

```powershell
Set-Location "C:\Users\77384\WorkProject\mcp\mysql\mysql-readonly-mcp"
npm run dev
```

### 以 Codex 连接为例

本项目采用 MCP `stdio` 传输模式。仍然是“本地运行 MCP,Codex 使用 MCP”,但启动动作由 Codex 完成:Codex 作为父进程启动 `node dist/index.js`,再通过子进程的 stdin/stdout 交换 MCP JSON-RPC 消息。因此,使用 Codex 时不需要提前单独执行 `npm run dev`。

Codex Desktop、Codex CLI 和 IDE 扩展共享 Codex 配置。完成构建后,在 `C:\Users\77384\.codex\config.toml` 中配置 MCP,让 Codex 直接启动编译产物:

1. 在项目目录执行 `npm install` 和 `npm run build`。
2. 打开 `C:\Users\77384\.codex\config.toml`,参考 [docs/codex-mcp-config.example.toml](docs/codex-mcp-config.example.toml) 增加 MCP 配置。
3. 将 `env` 中的 `MYSQL_HOST`、`MYSQL_PORT`、`MYSQL_DATABASE`、`MYSQL_USER` 和 `MYSQL_PASSWORD` 改为本机测试库配置;密码只保存在本机配置中,不要提交到仓库。
4. 重启或重新加载 Codex 的 MCP 配置。Codex 会启动 `node dist/index.js`,通过 stdin/stdout 完成 MCP 握手和工具调用。

两种启动方式的区别:

- `npm run dev`:你手动启动 MCP,适合本地调试、协议测试或使用 MCP Inspector;该服务只监听当前进程的 stdin/stdout,不会开放端口,Codex 不能再通过端口连接到它。
- Codex 配置启动:Codex 自动启动 MCP 子进程,并独占这组 stdin/stdout;这是当前项目接入 Codex 的推荐方式。

如果希望“先手动启动 MCP,再由 Codex 连接”,就需要把服务改造成 Streamable HTTP 等网络传输模式,这不是当前项目的实现方式。

`config.toml` 中的 `env` 内容写在 `[mcp_servers.mysql_readonly.env]` 节点下,示例:

```toml
[mcp_servers.mysql_readonly]
command = "node"
args = ["C:/Users/77384/WorkProject/mcp/mysql/mysql-readonly-mcp/dist/index.js"]

[mcp_servers.mysql_readonly.env]
MYSQL_HOST = "127.0.0.1"
MYSQL_PORT = "3306"
MYSQL_DATABASE = "erp_0808"
MYSQL_USER = "erp_0808_readonly_user"
MYSQL_PASSWORD = "<只保存在本机配置中的密码>"
```

直接执行 `npm run dev` 时,才使用项目根目录 `.env`;Codex 配置中的 `env` 用于 Codex 通过 stdio 启动 MCP 服务。两者同时存在时,进程环境变量优先于 `.env`。

示例配置的连接链路是:

```text
Codex
  └─ 启动 node <项目绝对路径>/dist/index.js
       └─ 通过 config.toml 的 env 传入 MySQL 配置
            └─ MCP Server 等待 initialize / tools/list
                 └─ Codex 调用 mysql_query 等工具
                      └─ MCP Server 使用只读账号连接 erp_0808
```

Codex 调用工具时,MCP Server 才从连接池获取 MySQL 连接;工具执行完成后回滚只读事务并释放或销毁连接。若只修改源码,需要重新执行 `npm run build`,再让 Codex 重新加载 MCP Server。

## 安全边界

服务端只接受单条 `SELECT` 或只读 CTE。SQL 先经过 `node-sql-parser` 的 MySQL AST 校验,再在独立 `START TRANSACTION READ ONLY` 事务中执行。服务端拒绝写操作、管理语句、多语句、跨库引用、锁定读取、文件导出、用户变量赋值和高风险函数。

MySQL 只读账号是最终安全边界。请先参考 [docs/mysql-readonly-account.sql](docs/mysql-readonly-account.sql),再复制 `.env.example` 为 `.env` 填写本机配置。密码不应写入源码、日志或提交记录。

## 开发与验证

```powershell
npm install
npm run check
npm test
npm run build
npm start
```

日志只写入 stderr;stdout 保留给 MCP JSON-RPC。Codex 接入配置见 [docs/codex-mcp-config.example.toml](docs/codex-mcp-config.example.toml);JSON 示例仍保留在 [docs/codex-mcp-config.example.json](docs/codex-mcp-config.example.json),供使用 JSON 格式的其他 MCP 客户端参考。

当前仓库包含不依赖 MySQL 的单元测试。真实 MySQL 8.4 集成测试需要用户提供本机测试库、只读账号和测试数据后执行;本项目默认不会修改数据库。

TDQS

A3.6/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a clearly distinct introspection or query concern: server metadata, table listing, column/FK description, index listing, query execution, and plan explanation. The describe_table vs list_indexes boundary is clear (columns vs indexes), so an agent can reliably select the right tool.

Naming Consistency5/5

All six tools use a consistent mysql_verb_noun snake_case pattern (get_server_info, list_tables, describe_table, list_indexes, query, explain). Predictable and uniform throughout.

Tool Count5/5

Six tools is well-scoped for a read-only database server. Each tool earns its place across discovery (info, tables, describe, indexes) and querying (query, explain) with no redundancy.

Completeness4/5

The read-only surface covers introspection plus querying and plan analysis, which is solid for the stated purpose. Minor gaps like listing databases or schema-level search exist but are workable given the server targets a single configured database.

Maintenance

ActivityMaintained
ResponsivenessNo issues