Metadata-Version: 2.4
Name: mysql-mcp-server-plus
Version: 1.0.0
Summary: A safe MySQL Model Context Protocol server
Author: CleanCode
License-Expression: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp[cli]<3,>=2.0.0
Requires-Dist: PyMySQL<2,>=1.1
Dynamic: license-file

# MySQL MCP Server

[![Python](https://img.shields.io/badge/Python-3.10%2B-3776AB?logo=python&logoColor=white)](https://www.python.org/)
[![MCP](https://img.shields.io/badge/MCP-Python%20SDK%20v2-6B4EFF)](https://modelcontextprotocol.io/)
[![uv](https://img.shields.io/badge/managed%20by-uv-DE5FE9?logo=uv&logoColor=white)](https://docs.astral.sh/uv/)
[![License](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

一个基于官方 MCP Python SDK v2 的 MySQL Model Context Protocol（MCP）服务。它通过 **database 白名单**、**MySQL SQL 安全审计** 与 **数据库账号最小权限**，向 MCP 客户端提供受控的 MySQL 查询、元数据读取和可选写入能力。

## 功能

- 使用官方 `mcp` Python SDK v2，首期采用 stdio transport。
- 使用 `uv` 管理 Python 版本、依赖和锁文件。
- 通过 `MYSQL_ALLOWED_DATABASES` 限制可访问的 database。
- 支持切换当前 database、执行 SQL、列出表、查看表字段/索引、统计表数量。
- 默认只读；关闭只读后仅允许受控 DML 及表、索引、视图相关 DDL。
- 拒绝多语句、注释、账户/权限管理、文件读写、复制、例程、触发器、事件和事务控制等高风险 SQL。
- 查询默认分页，避免单次返回过大结果集。

## 前置条件

- Python 3.10 或更高版本。
- 已安装 [uv](https://docs.astral.sh/uv/getting-started/installation/)。
- 可访问的 MySQL 服务。建议使用仅具备必要 database 权限的专用账号。

## 安装

克隆仓库后，在项目根目录执行：

```powershell
uv sync --all-groups
```

该命令会根据 `uv.lock` 创建 `.venv` 并安装所有运行、开发依赖。

## 配置

服务通过环境变量读取连接与安全配置。

| 环境变量 | 必填 | 默认值 | 说明 |
|---|:---:|---|---|
| `MYSQL_HOST` | 是 | - | MySQL 主机地址 |
| `MYSQL_PORT` | 否 | `3306` | MySQL 端口，范围为 1-65535 |
| `MYSQL_USER` | 是 | - | MySQL 用户名 |
| `MYSQL_PASSWORD` | 是 | - | MySQL 密码；服务不会写入日志或响应 |
| `MYSQL_DEFAULT_DATABASE` | 是 | - | 启动时使用的 database，必须在白名单中 |
| `MYSQL_ALLOWED_DATABASES` | 是 | - | 允许访问的 database，以英文逗号分隔 |
| `MYSQL_READ_ONLY` | 否 | `true` | `true` 时仅允许安全只读 SQL |
| `MYSQL_CONNECT_TIMEOUT` | 否 | `10` | 连接超时秒数，范围为 1-60 |
| `MYSQL_LOG_LEVEL` | 否 | `INFO` | `DEBUG`、`INFO`、`WARNING`、`ERROR` 或 `CRITICAL` |

PowerShell 示例：

```powershell
$env:MYSQL_HOST = "127.0.0.1"
$env:MYSQL_PORT = "3306"
$env:MYSQL_USER = "mcp_readonly"
$env:MYSQL_PASSWORD = "replace-with-a-secret"
$env:MYSQL_DEFAULT_DATABASE = "appdb"
$env:MYSQL_ALLOWED_DATABASES = "appdb,reportdb"
$env:MYSQL_READ_ONLY = "true"
```

## 启动

```powershell
uv run mysql-mcp-server-plus
```

该服务使用 stdio 协议。直接在终端运行后会等待 MCP 客户端请求，终端没有业务输出是正常现象；请通过 MCP 客户端调用工具，而不是在标准输入中手工输入 SQL。

也可以按模块启动：

```powershell
uv run python -m mysql_mcp_server_plus.server
```

## MCP 客户端配置

本服务支持从本地项目运行，或直接从 PyPI 使用已发布版本。请将 database 与密码替换为实际值，并避免把真实密码提交到仓库。

### 从本地项目运行

Windows 图形化 MCP 客户端必须能够在自身的 `PATH` 中找到 `uv`。若客户端未继承终端环境变量，请将 `command` 改为 `uv.exe` 的绝对路径，例如 `C:/Users/your-user/.local/bin/uv.exe`。

```json
{
  "mcpServers": {
    "mysql": {
      "command": "uv",
      "args": ["run", "mysql-mcp-server-plus"],
      "cwd": "E:/path/to/mysql-mcp-server-plus",
      "env": {
        "MYSQL_HOST": "127.0.0.1",
        "MYSQL_PORT": "3306",
        "MYSQL_USER": "username",
        "MYSQL_PASSWORD": "password",
        "MYSQL_DEFAULT_DATABASE": "appdb",
        "MYSQL_ALLOWED_DATABASES": "appdb,reportdb",
        "MYSQL_READ_ONLY": "false"
      }
    }
  }
}
```

### 使用最新发布版

适用于希望直接使用已发布版本、无需下载或维护本地源码的场景。请先安装 [uv](https://docs.astral.sh/uv/getting-started/installation/)，然后将以下配置添加到 MCP 客户端。`uvx` 会从 PyPI 下载并启动 `mysql-mcp-server-plus`；`--refresh` 会在每次启动时检查更新，优先使用最新的兼容版本。若客户端无法在 `PATH` 中找到 `uvx`，请将 `command` 改为 `uvx.exe` 的绝对路径。

```json
{
  "mcpServers": {
    "mysql-mcp": {
      "command": "uvx",
      "args": ["--refresh", "--from", "mysql-mcp-server-plus", "mysql-mcp-server-plus"],
      "env": {
        "MYSQL_HOST": "127.0.0.1",
        "MYSQL_PORT": "3306",
        "MYSQL_USER": "username",
        "MYSQL_PASSWORD": "password",
        "MYSQL_DEFAULT_DATABASE": "appdb",
        "MYSQL_ALLOWED_DATABASES": "appdb,reportdb",
        "MYSQL_READ_ONLY": "false"
      }
    }
  }
}
```

## 工具

| 工具 | 参数 | 说明 |
|---|---|---|
| `test_connection` | 无 | 测试当前 database 连接，返回 MySQL 版本、当前 database、白名单和只读状态。 |
| `get_current_context` | 无 | 返回当前 database、白名单、主机、端口和只读状态。 |
| `list_databases` | 无 | 返回配置白名单内的 database，不枚举服务器上的其他 database。 |
| `switch_database` | `database` | 切换当前 database；目标必须在白名单中。 |
| `execute_sql` | `sql`、`fetch_results`、`limit`、`offset` | 执行一条经过安全审计的 SQL；查询支持分页。 |
| `list_tables` | `database?`、`include_views?` | 列出指定或当前 database 中的表和视图。 |
| `describe_table` | `table`、`database?` | 返回表属性、字段、主键和索引。 |
| `count_tables` | `database?` | 统计指定或当前 database 中普通表的数量。 |

`database?` 表示可选参数；不传时使用当前 database。

所有工具返回 JSON 对象，成功时包含 `status: "success"`；失败时包含 `status: "error"`、`code`、`message`，部分错误还会提供 `hint`。常见错误码包括：

| 错误码 | 含义 |
|---|---|
| `DATABASE_NOT_ALLOWED` | 请求的 database 不在 `MYSQL_ALLOWED_DATABASES` 中。 |
| `INVALID_ARGUMENT` | 参数格式、分页范围或调用方式不符合要求。 |
| `READ_ONLY` | 只读模式下尝试执行写入或危险 SQL。 |
| `SQL_BLOCKED` | SQL 命中了安全审计限制。 |
| `DATABASE_ERROR` | MySQL 连接或执行发生错误。 |

失败响应示例：

```json
{
  "status": "error",
  "code": "DATABASE_NOT_ALLOWED",
  "message": "不允许访问 database 'otherdb'。",
  "hint": "请使用 list_databases 查看允许范围。"
}
```

### `execute_sql` 示例

查询：

```json
{
  "sql": "SELECT id, name FROM users ORDER BY id",
  "limit": 20,
  "offset": 0
}
```

在明确关闭只读模式后执行写入：

```json
{
  "sql": "UPDATE users SET enabled = 1 WHERE id = 42",
  "fetch_results": false
}
```

写入操作会受到 SQL 审计和数据库账号权限的双重约束。生产环境建议保持 `MYSQL_READ_ONLY=true`。

`execute_sql` 参数规则：

- `fetch_results` 默认为 `true`；执行 `INSERT`、`UPDATE`、`DELETE` 或 DDL 时，必须显式传入 `false`。
- 只有 `SELECT` 与 `WITH` 查询可以传入 `limit`、`offset`。
- `limit` 取值范围为 1-10000，未传时为 1000；`offset` 必须为非负整数，未传时为 0。
- 非查询成功后返回 `affected_rows`；DDL 结果会额外提示 MySQL DDL 可能隐式提交。

## 安全策略

本项目的安全校验用于降低 MCP 自动化场景中的误操作风险，不能替代 MySQL 的用户权限管理。生产环境请始终使用最小权限账号。

例如，为只读服务账号仅授予指定 database 的查询权限：

```sql
CREATE USER 'mcp_readonly'@'%' IDENTIFIED BY 'replace-with-a-strong-secret';
GRANT SELECT ON appdb.* TO 'mcp_readonly'@'%';
```

请将 `appdb`、主机范围和密码替换为生产实际值。若需要开启 `MYSQL_READ_ONLY=false`，应单独创建受限写入账号，并只授予业务所需的 `INSERT`、`UPDATE`、`DELETE` 或特定 DDL 权限；白名单不会替代 MySQL 的权限控制。

服务会执行以下限制：

- 仅允许访问 `MYSQL_ALLOWED_DATABASES` 中的 database。
- 仅允许一条 SQL；禁止 SQL 注释和 `DELIMITER`。
- 默认只读，仅允许 `SELECT`、`WITH`、`SHOW`、`DESCRIBE`、`EXPLAIN` 等安全查询。
- 拒绝锁定读、`SELECT ... INTO`、`EXPLAIN ANALYZE`。
- 永久拒绝账户与权限操作、文件读写、复制管理、例程、触发器、事件、服务器设置和显式事务控制。
- 非只读模式下，只允许 DML 及表、索引、视图的基础 DDL；不会开放 database、用户或服务器级 DDL。
- `information_schema` 查询必须使用受白名单约束的 database 过滤条件。
- 查询的 `limit` 范围为 1-10000，默认值为 1000。

## 开发与测试

```powershell
uv run pytest
uv run ruff check .
uv run mypy src
uv build
```

测试覆盖配置解析、database 白名单、SQL 安全审计、连接事务、元数据工具和 MCP 工具发现。`uv build` 会生成 wheel 与 source distribution。

## PyCharm

将项目解释器设置为 `.venv\Scripts\python.exe`，然后新建 **Python** 运行配置：

- **Run**：`Module name`
- **Module name**：`mysql_mcp_server_plus.server`
- **Working directory**：项目根目录
- **Environment variables**：配置章节中的 `MYSQL_*` 变量

由于服务通过 stdio 与 MCP 客户端通信，调试具体逻辑时更建议运行 pytest 并设置断点。

## 贡献

欢迎提交 Issue 和 Pull Request。提交前请确保：

```powershell
uv run pytest
uv run ruff check .
uv run mypy src
```

请勿提交密码、真实连接信息、`.venv`、构建产物、IDE 私有配置或本地测试数据。

## 许可证

本项目采用 [MIT License](LICENSE)。
