SQL MCP Server
by imShire
README.md
# SQL MCP
动态 SQL MCP 服务,支持 **MySQL** 与 **PostgreSQL**。所有数据库连接在运行时通过 MCP tool 参数传入,无需配置文件;同时支持 `stdio`(适合 Claude Desktop 等本地客户端)和 `sse`(适合 Docker 远程部署)两种 transport。
## 特性
- 支持 MySQL 8 与 PostgreSQL 16
- 支持 `stdio` / `sse` 双 transport
- 运行时动态传入数据库连接(`connection` 对象)
- 可选的 `alias` 注册/释放机制,便于复用连接
- 默认只读执行;通过 `allow_write: true` 显式开启写入
- 连接池自动缓存与回收
- 提供 5 个 MCP tools:
- `register_database`
- `unregister_database`
- `list_db_servers`
- `list_database_tables`
- `get_table_schema`
- `query_database`
## 目录
- [快速开始](#快速开始)
- [安装](#安装)
- [运行方式](#运行方式)
- [MCP Tools](#mcp-tools)
- [连接对象](#连接对象-databaseconnection)
- [环境变量](#环境变量)
- [开发与测试](#开发与测试)
- [安全提示](#安全提示)
## 快速开始
### 本地运行(SSE)
```bash
pip install -r requirements.txt
python -m src.server --transport sse --host 127.0.0.1 --port 3000
```
### Docker 运行
```bash
docker build -t sql-mcp .
docker run -p 3000:3000 -e SQL_MCP_HOST=0.0.0.0 -e LOG_LEVEL=INFO sql-mcp
```
### Docker Compose 运行
```bash
docker compose up -d
```
服务默认监听 `http://0.0.0.0:3000`,SSE endpoint 为 `http://localhost:3000/sse`。
## 安装
```bash
# 使用 requirements.txt
pip install -r requirements.txt
# 或作为可编辑包安装
pip install -e .
```
需要 Python >= 3.11。
## 运行方式
### stdio(本地 MCP 客户端,如 Claude Desktop)
```bash
python -m src.server --transport stdio
```
### SSE(远程 / Docker)
```bash
python -m src.server --transport sse --host 0.0.0.0 --port 3000
```
命令行参数也可通过环境变量设置:
| 参数 | 环境变量 | 默认值 | 说明 |
|------|----------|--------|------|
| `--host` | `SQL_MCP_HOST` | `127.0.0.1` | SSE 监听地址 |
| `--port` | `SQL_MCP_PORT` | `3000` | SSE 监听端口 |
| - | `LOG_LEVEL` | `INFO` | 日志级别(DEBUG/INFO/WARNING/ERROR) |
## MCP Tools
### register_database
注册一个数据库连接别名,后续可通过 `alias` 复用该连接。注册同名别名会覆盖旧连接,并自动释放旧连接池。
**参数**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `alias` | `string` | 是 | 别名 |
| `connection` | `DatabaseConnection` | 是 | 数据库连接对象 |
**示例**
```json
{
"alias": "prod-mysql",
"connection": {
"type": "mysql",
"host": "localhost",
"port": 3306,
"user": "root",
"password": "secret",
"database": "mydb"
}
}
```
**返回**
```json
{ "status": "ok", "alias": "prod-mysql", "type": "mysql" }
```
### unregister_database
释放一个已注册的别名,并关闭对应的连接池。
**参数**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `alias` | `string` | 是 | 要释放的别名 |
**示例**
```json
{ "alias": "prod-mysql" }
```
**返回**
```json
{ "status": "ok", "alias": "prod-mysql" }
```
若别名不存在:
```json
{ "status": "not_found", "alias": "prod-mysql" }
```
### list_db_servers
列出所有已注册的连接元信息(**不含密码**)。
**返回**
```json
[
{
"alias": "prod-mysql",
"type": "mysql",
"host": "localhost",
"port": 3306,
"database": "mydb",
"ssl": false
}
]
```
### list_database_tables
列出数据库中的所有表。支持通过 `alias` 或完整 `connection` 对象定位数据库,二者只能选其一。
**参数**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `alias` | `string` | 二选一 | 已注册的别名 |
| `connection` | `DatabaseConnection` | 二选一 | 完整连接对象 |
**示例**
```json
{ "alias": "prod-mysql" }
```
**返回**
```json
{ "tables": ["users", "orders"] }
```
### get_table_schema
获取指定表的结构信息,包括列、主键约束、索引。
**参数**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `table_name` | `string` | 是 | 表名 |
| `alias` | `string` | 二选一 | 已注册的别名 |
| `connection` | `DatabaseConnection` | 二选一 | 完整连接对象 |
**示例**
```json
{
"alias": "prod-mysql",
"table_name": "users"
}
```
**返回**
```json
{
"columns": [
{ "name": "id", "type": "INTEGER", "nullable": false, "default": null },
{ "name": "name", "type": "VARCHAR", "nullable": true, "default": null }
],
"primary_key": { "name": "pk_users", "constrained_columns": ["id"] },
"indexes": [...]
}
```
### query_database
执行 SQL 查询。默认处于**只读模式**,禁止 `INSERT`/`UPDATE`/`DELETE`/`DROP` 等写入操作;传入 `allow_write: true` 可显式开启写入。
**参数**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `sql` | `string` | 是 | SQL 语句 |
| `alias` | `string` | 二选一 | 已注册的别名 |
| `connection` | `DatabaseConnection` | 二选一 | 完整连接对象 |
| `params` | `object` | 否 | SQL 参数(命名参数) |
| `limit` | `integer` | 否 | 只读查询默认最大返回行数,默认 `1000`,最大 `10000` |
| `allow_write` | `boolean` | 否 | 是否允许写入,默认 `false` |
**只读查询示例**
```json
{
"alias": "prod-mysql",
"sql": "SELECT * FROM users WHERE name = :name",
"params": { "name": "Alice" },
"limit": 100
}
```
**写入示例**
```json
{
"alias": "prod-mysql",
"sql": "INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com')",
"allow_write": true
}
```
**返回**
- 查询语句:结果数组
- 写入语句:`{ "rows_affected": 1 }`
## 连接对象 DatabaseConnection
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `type` | `string` | 是 | 数据库类型:`mysql` 或 `postgres` |
| `host` | `string` | 是 | 数据库主机 |
| `port` | `integer` | 否 | 端口;MySQL 默认 `3306`,PostgreSQL 默认 `5432` |
| `user` | `string` | 是 | 用户名 |
| `password` | `string` | 是 | 密码 |
| `database` | `string` | 是 | 数据库名 |
| `ssl` | `boolean` | 否 | 是否启用 SSL,默认 `false` |
## 环境变量
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `SQL_MCP_HOST` | `127.0.0.1` | SSE 监听地址 |
| `SQL_MCP_PORT` | `3000` | SSE 监听端口 |
| `LOG_LEVEL` | `INFO` | 日志级别 |
| `PYTHONUNBUFFERED` | - | 建议设为 `1`,避免日志缓冲 |
## 开发与测试
项目使用 `pytest` 做单元测试,使用 `scripts/agents/` 下的 Agent 脚本做集成测试。
### 启动本地测试数据库与 MCP 服务
```bash
bash scripts/start-test-infra.sh
```
该脚本会启动 PostgreSQL、MySQL 两个 Docker 容器,并在 `localhost:3000` 启动 SSE 模式的 MCP 服务。
### 运行单元测试
```bash
python -m pytest tests/test_basic.py -v
```
### 运行集成测试
```bash
python -m pytest tests/integration/test_mcp_server.py -v
```
### 运行 Agent 测试
```bash
python scripts/agents/agent_postgres.py
python scripts/agents/agent_mysql.py
python scripts/agents/agent_security.py
python scripts/agents/agent_direct_connection.py
python scripts/agents/agent_extensibility.py
```
### 停止测试环境
```bash
bash scripts/stop-test-infra.sh
```
## 安全提示
当前版本通过 MCP tool 参数**明文传入**数据库凭据,请求会经过 MCP 客户端、网络传输(SSE)以及服务端日志。该方案适用于:
- 受控内网环境
- 本地开发/测试
- 快速原型验证
**生产环境建议**:
- 启用 SSE TLS(如通过反向代理提供 HTTPS)
- 限制可访问的源 IP
- 由服务端通过环境变量/密钥管理系统加载凭据模板,客户端 tool 参数只传 `alias`
- 开启审计日志并避免在日志中记录 `password` 与原始 SQL 参数
> 只读守卫基于 SQL 前缀与关键字做最佳努力检测,**不能替代**数据库级权限控制。建议为 MCP 服务单独配置权限受限的数据库账号。
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues