@yanzhang123/readonly-db-mcp 0.7.6 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/ENTERPRISE_DEPLOYMENT.md
CHANGED
|
@@ -59,7 +59,7 @@ allowed_databases = ["application_database"]
|
|
|
59
59
|
# Unrecognized stored functions/UDFs are blocked. This list should normally
|
|
60
60
|
# remain empty. Add only reviewed deterministic functions with no side effects.
|
|
61
61
|
allowed_functions = []
|
|
62
|
-
mask_columns = ["password", "passwd", "*secret*", "*token*", "*api_key*", "*private_key*", "ssn", "id_card", "phone", "email"]
|
|
62
|
+
mask_columns = ["password", "*password*", "*passwd*", "*pwd*", "*secret*", "token", "*token", "*_token", "token_*", "*tokenvalue*", "*accesstoken*", "*refreshtoken*", "*idtoken*", "*appsec*", "*api_key*", "*private_key*", "*ssn*", "*id_card*", "*phone*", "*mobile*", "*email*"]
|
|
63
63
|
|
|
64
64
|
ssl_mode = "VERIFY_IDENTITY"
|
|
65
65
|
ssl_ca = "/etc/mysql-mcp/company-ca.pem"
|
|
@@ -79,6 +79,26 @@ audit_fail_closed = true
|
|
|
79
79
|
audit_fsync = true
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
+
For desktop deployments, replace `password_env` with an OS keyring reference so
|
|
83
|
+
user-level MCP configuration contains no database password:
|
|
84
|
+
|
|
85
|
+
```toml
|
|
86
|
+
credential_provider = "keyring"
|
|
87
|
+
credential_ref = "prod"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Provision it interactively with `readonly-db-mcp credentials --profiles-file
|
|
91
|
+
C:/absolute/path/mysql-connections.toml set prod`. The tool never prints the
|
|
92
|
+
credential. For non-interactive services, the `command` provider accepts a
|
|
93
|
+
reviewed argv array for a secret-manager CLI and executes it without a shell.
|
|
94
|
+
Restrict the profiles file because command names and non-secret arguments can
|
|
95
|
+
still reveal infrastructure topology.
|
|
96
|
+
|
|
97
|
+
If an environment spans physical profiles, use `[routes.ENVIRONMENT]` with
|
|
98
|
+
exact database aliases. Each audit event records `requested_connection`,
|
|
99
|
+
`requested_database`, the resolved physical `connection`/`database`, and
|
|
100
|
+
`route_applied`; unknown aliases fail rather than being guessed.
|
|
101
|
+
|
|
82
102
|
All database tools accept:
|
|
83
103
|
|
|
84
104
|
```json
|
|
@@ -196,6 +216,10 @@ read-only operations were sent:
|
|
|
196
216
|
- configuration validation, connection health and grants inspection
|
|
197
217
|
- allowed-database discovery and system-schema filtering
|
|
198
218
|
- table/schema metadata reads
|
|
219
|
+
- controlled catalog projections for tables, columns, indexes, constraints,
|
|
220
|
+
foreign keys and views while arbitrary system-schema SQL remains denied
|
|
221
|
+
- deterministic keyring, command-provider and explicit-route tests with no
|
|
222
|
+
production credential material
|
|
199
223
|
- normal query execution and pagination
|
|
200
224
|
- pre-connection rejection of DML, DDL, multiple statements, locking reads and
|
|
201
225
|
system-schema access
|
package/README.md
CHANGED
|
@@ -4,117 +4,92 @@
|
|
|
4
4
|
|
|
5
5
|
# MySQL MCP Server
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
for exploring multiple MySQL environments and databases from one process.
|
|
7
|
+
一个可审计、严格只读的 MySQL Model Context Protocol(MCP)服务。单个进程即可安全访问多个 MySQL 环境和数据库。
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
[`@yanzhang123/readonly-db-mcp`](https://www.npmjs.com/package/@yanzhang123/readonly-db-mcp).
|
|
12
|
-
It includes the matching Python wheel and a cross-platform launcher, so MCP
|
|
13
|
-
clients do not need a repository checkout or a separate package installation.
|
|
9
|
+
本分支推荐通过 npm 包 [`@yanzhang123/readonly-db-mcp`](https://www.npmjs.com/package/@yanzhang123/readonly-db-mcp) 使用。npm 包内置匹配版本的 Python wheel 和跨平台启动器,MCP 客户端无需检出仓库或单独安装 Python 包。
|
|
14
10
|
|
|
15
|
-
>
|
|
11
|
+
> [!NOTE]
|
|
12
|
+
> 服务同时支持标准输入输出(STDIO)和 Streamable HTTP(SSE)传输。远程或自托管场景可使用 SSE,并应按本文配置认证和网络边界。
|
|
16
13
|
|
|
17
14
|
> [!IMPORTANT]
|
|
18
|
-
>
|
|
19
|
-
> supplied account has `INSERT`, `UPDATE`, `DELETE`, or DDL privileges, the MCP
|
|
20
|
-
> SQL gate only accepts reviewed read statement families, runs them in a
|
|
21
|
-
> read-only transaction, and always rolls back. A database-level `SELECT`-only
|
|
22
|
-
> account is still strongly recommended as independent defense in depth.
|
|
15
|
+
> 只读约束不依赖 MySQL 账号权限。即使账号拥有 `INSERT`、`UPDATE`、`DELETE` 或 DDL 权限,SQL 闸门也只接受经过审查的只读语句,并在只读事务中执行后统一回滚。生产环境仍强烈建议使用仅授予 `SELECT` 的数据库账号,形成独立的纵深防御。
|
|
23
16
|
|
|
24
|
-
##
|
|
25
|
-
- **Named connection profiles** for dev/test/staging/prod and multiple servers
|
|
26
|
-
- Select a `connection` and `database` independently on every tool call
|
|
27
|
-
- Database-to-profile routing hints without implicit cross-environment switching
|
|
28
|
-
- **Strictly read-only SQL** with fail-closed validation, a MySQL read-only transaction, and unconditional rollback
|
|
29
|
-
- Discover connections, databases, tables, schemas, and sample rows
|
|
30
|
-
- Return-size protection (`MYSQL_MAX_ROWS`, hard maximum 1000)
|
|
31
|
-
- Legacy single-connection `MYSQL_*` configuration remains supported
|
|
32
|
-
- **SSE/HTTP transport support** (`MCP_TRANSPORT=sse`)
|
|
33
|
-
- Per-profile SSL/TLS and SSH tunneling
|
|
34
|
-
- Passwords can stay in environment variables instead of the profiles file
|
|
35
|
-
- Compatibility `query` alias for clients migrating from older MySQL MCP servers
|
|
17
|
+
## 功能特性
|
|
36
18
|
|
|
37
|
-
|
|
19
|
+
- 使用命名连接配置管理开发、测试、预发、生产等多个环境
|
|
20
|
+
- 每次工具调用都显式选择 `connection` 和 `database`,避免并发客户端相互污染状态
|
|
21
|
+
- 支持逻辑数据库到物理连接的精确路由,不会隐式跨环境切换
|
|
22
|
+
- 严格只读 SQL:失败即拒绝的语法校验、MySQL 只读事务、无条件回滚
|
|
23
|
+
- 可发现连接、数据库、表、字段、索引、约束和样例数据
|
|
24
|
+
- 查询分页下推到 MySQL,避免客户端截断结果引发 Connector/Python `errno=-1`
|
|
25
|
+
- 内置结果行数和单元格长度限制,最大返回 1000 行
|
|
26
|
+
- 按源字段精确脱敏,支持别名、CTE 以及 JSON 内敏感键
|
|
27
|
+
- 支持 SSL/TLS、SSH 隧道和 SSE/HTTP 传输
|
|
28
|
+
- 密码可保存在环境变量、操作系统凭据库或受控的密钥命令中
|
|
29
|
+
- 保留旧版单连接 `MYSQL_*` 环境变量和 `query` 工具别名
|
|
38
30
|
|
|
39
|
-
|
|
31
|
+
## 安装
|
|
40
32
|
|
|
41
|
-
|
|
33
|
+
### npm / npx(推荐)
|
|
42
34
|
|
|
43
|
-
|
|
35
|
+
环境要求:Node.js 18+、npm 9+,并确保 Python 3.11+ 可从 `PATH` 找到。
|
|
36
|
+
|
|
37
|
+
直接运行最新版本:
|
|
44
38
|
|
|
45
39
|
```bash
|
|
46
40
|
npx -y @yanzhang123/readonly-db-mcp
|
|
47
41
|
```
|
|
48
42
|
|
|
49
|
-
|
|
43
|
+
生产环境建议固定经过审核的版本:
|
|
50
44
|
|
|
51
45
|
```bash
|
|
52
|
-
npx -y @yanzhang123/readonly-db-mcp@
|
|
46
|
+
npx -y @yanzhang123/readonly-db-mcp@0.8.1
|
|
53
47
|
```
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
examples below intentionally resolve the npm `latest` tag.
|
|
57
|
-
|
|
58
|
-
On first use, the launcher creates a versioned virtual environment in the user
|
|
59
|
-
cache and installs the bundled wheel plus exact Python dependencies from a
|
|
60
|
-
version-controlled SHA-256 lock file. Downloads use the configured pip index
|
|
61
|
-
and the completed environment is cached by wheel-and-lock fingerprint. Override
|
|
62
|
-
Python with `MYSQL_MCP_PYTHON` or the cache location with
|
|
63
|
-
`MYSQL_MCP_NPM_CACHE_DIR`.
|
|
64
|
-
|
|
65
|
-
For MCP clients, use `npx` as the command and
|
|
66
|
-
`["-y", "@yanzhang123/readonly-db-mcp"]` as its arguments.
|
|
49
|
+
首次运行时,启动器会在用户缓存目录创建版本化虚拟环境,并安装包内 wheel 与带 SHA-256 锁定的 Python 依赖。完成后的环境按 wheel 和依赖锁指纹复用。可通过 `MYSQL_MCP_PYTHON` 指定 Python,通过 `MYSQL_MCP_NPM_CACHE_DIR` 修改缓存位置。
|
|
67
50
|
|
|
68
|
-
###
|
|
51
|
+
### 最小 MCP 配置
|
|
69
52
|
|
|
70
|
-
|
|
71
|
-
[`mysql-connections.example.toml`](mysql-connections.example.toml), keep
|
|
72
|
-
passwords in environment variables, and use an absolute path:
|
|
53
|
+
复制 [`mysql-connections.example.toml`](mysql-connections.example.toml) 为本地配置文件,把密码放入环境变量,并在 MCP 配置中使用绝对路径:
|
|
73
54
|
|
|
74
55
|
```json
|
|
75
56
|
{
|
|
76
57
|
"mcpServers": {
|
|
77
58
|
"mysql-readonly": {
|
|
78
59
|
"command": "npx",
|
|
79
|
-
"args": ["-y", "@yanzhang123/readonly-db-mcp"],
|
|
60
|
+
"args": ["-y", "@yanzhang123/readonly-db-mcp@0.8.1"],
|
|
80
61
|
"env": {
|
|
81
62
|
"MYSQL_PROFILES_FILE": "C:/absolute/path/mysql-connections.toml",
|
|
82
|
-
"MYSQL_DEV_PASSWORD": "
|
|
63
|
+
"MYSQL_DEV_PASSWORD": "由客户端密钥存储提供"
|
|
83
64
|
}
|
|
84
65
|
}
|
|
85
66
|
}
|
|
86
67
|
}
|
|
87
68
|
```
|
|
88
69
|
|
|
89
|
-
|
|
90
|
-
`"command": "npx.cmd"`. Do not commit the populated profile, passwords, audit
|
|
91
|
-
HMAC keys, connection strings, or client configuration containing secrets.
|
|
70
|
+
部分 Windows MCP 客户端无法正确解析 npm 命令垫片,此时将 `command` 改为 `npx.cmd`。不要提交真实连接配置、密码、审计 HMAC 密钥、连接串或含有敏感信息的 MCP 客户端配置。
|
|
92
71
|
|
|
93
|
-
|
|
94
|
-
running discovery queries. `check_connection` reports an irreversible account
|
|
95
|
-
fingerprint and privilege classification without returning the username or raw
|
|
96
|
-
grant statements.
|
|
72
|
+
服务启动后,建议依次调用 `validate_connections` 和 `check_connection`,确认配置有效、网络可达、账号权限符合预期。`check_connection` 只返回不可逆账号指纹和权限分类,不会暴露用户名或原始授权语句。
|
|
97
73
|
|
|
98
|
-
###
|
|
74
|
+
### 手动安装 Python 包
|
|
99
75
|
|
|
100
76
|
```bash
|
|
101
77
|
pip install mysql-mcp-server
|
|
102
78
|
```
|
|
103
79
|
|
|
104
|
-
|
|
105
|
-
scoped npm package is the documented distribution path for this fork.
|
|
80
|
+
Python 包仍适用于源码部署,但本分支的主要分发方式是上述 npm 包。
|
|
106
81
|
|
|
107
|
-
##
|
|
82
|
+
## 配置
|
|
108
83
|
|
|
109
|
-
###
|
|
84
|
+
### 推荐:命名连接
|
|
110
85
|
|
|
111
|
-
|
|
86
|
+
将 [`mysql-connections.example.toml`](mysql-connections.example.toml) 复制为已被 Git 忽略的 `mysql-connections.toml`,然后集中声明各环境:
|
|
112
87
|
|
|
113
88
|
```toml
|
|
114
89
|
default = "dev"
|
|
115
90
|
|
|
116
91
|
[connections.dev]
|
|
117
|
-
description = "
|
|
92
|
+
description = "本地开发环境"
|
|
118
93
|
host = "127.0.0.1"
|
|
119
94
|
port = 3306
|
|
120
95
|
user = "readonly_user"
|
|
@@ -125,27 +100,26 @@ query_timeout_ms = 30000
|
|
|
125
100
|
max_rows = 500
|
|
126
101
|
max_cell_length = 20000
|
|
127
102
|
result_format = "json"
|
|
128
|
-
mask_columns = ["password", "passwd", "*secret*", "*token*", "*api_key*", "*private_key*", "ssn", "id_card", "phone", "email"]
|
|
103
|
+
mask_columns = ["password", "*password*", "*passwd*", "*pwd*", "*secret*", "token", "*token", "*_token", "token_*", "*tokenvalue*", "*accesstoken*", "*refreshtoken*", "*idtoken*", "*appsec*", "*api_key*", "*private_key*", "*ssn*", "*id_card*", "*phone*", "*mobile*", "*email*"]
|
|
129
104
|
pool_size = 3
|
|
130
105
|
audit_enabled = true
|
|
131
106
|
|
|
132
107
|
[connections.prod]
|
|
133
|
-
description = "
|
|
108
|
+
description = "生产只读副本"
|
|
134
109
|
host = "prod-read.example.internal"
|
|
135
110
|
user = "readonly_user"
|
|
136
111
|
password_env = "MYSQL_PROD_PASSWORD"
|
|
137
112
|
database = "app"
|
|
138
113
|
allowed_databases = ["app", "reporting"]
|
|
139
|
-
allowed_functions = [] #
|
|
114
|
+
allowed_functions = [] # 仅填写已经审核、确定无副作用的 UDF/存储函数
|
|
140
115
|
query_timeout_ms = 15000
|
|
141
116
|
max_rows = 200
|
|
142
117
|
result_format = "json"
|
|
143
|
-
mask_columns = ["password", "passwd", "*secret*", "*token*", "*api_key*", "*private_key*", "ssn", "id_card", "phone", "email"]
|
|
144
118
|
pool_size = 5
|
|
145
119
|
ssl_mode = "VERIFY_CA"
|
|
146
120
|
ssl_ca = "C:/certs/company-ca.pem"
|
|
147
121
|
|
|
148
|
-
#
|
|
122
|
+
# 企业审计配置
|
|
149
123
|
audit_enabled = true
|
|
150
124
|
audit_log_file = "C:/var/log/mysql-mcp/audit.jsonl"
|
|
151
125
|
audit_log_max_bytes = 10000000
|
|
@@ -156,27 +130,63 @@ audit_fail_closed = true
|
|
|
156
130
|
audit_fsync = true
|
|
157
131
|
```
|
|
158
132
|
|
|
159
|
-
|
|
133
|
+
通过环境变量提供配置路径和密钥:
|
|
160
134
|
|
|
161
135
|
```bash
|
|
162
136
|
MYSQL_PROFILES_FILE=C:/absolute/path/mysql-connections.toml
|
|
163
137
|
MYSQL_DEV_PASSWORD=...
|
|
164
138
|
MYSQL_PROD_PASSWORD=...
|
|
165
|
-
MYSQL_MCP_AUDIT_SIGNING_KEY=... #
|
|
166
|
-
MYSQL_DEFAULT_CONNECTION=dev
|
|
167
|
-
MYSQL_MAX_ROWS=500
|
|
168
|
-
MYSQL_QUERY_TIMEOUT_MS=30000
|
|
169
|
-
MYSQL_MAX_CELL_LENGTH=20000
|
|
170
|
-
MYSQL_RESULT_FORMAT=json
|
|
171
|
-
|
|
172
|
-
MYSQL_POOL_SIZE=0 # legacy mode; named profiles default to 5
|
|
139
|
+
MYSQL_MCP_AUDIT_SIGNING_KEY=... # 由密钥管理系统提供,禁止提交
|
|
140
|
+
MYSQL_DEFAULT_CONNECTION=dev # 可选,覆盖 TOML 中的 default
|
|
141
|
+
MYSQL_MAX_ROWS=500 # 可选,1-1000,默认 500
|
|
142
|
+
MYSQL_QUERY_TIMEOUT_MS=30000 # 整次调用超时,100-300000 毫秒
|
|
143
|
+
MYSQL_MAX_CELL_LENGTH=20000 # 超长单元格截断长度
|
|
144
|
+
MYSQL_RESULT_FORMAT=json # json 或 csv
|
|
145
|
+
MYSQL_POOL_SIZE=0 # 旧单连接模式;命名配置默认 5
|
|
173
146
|
MYSQL_ALLOWED_DATABASES=app,reporting
|
|
174
|
-
MYSQL_ALLOWED_FUNCTIONS=
|
|
147
|
+
MYSQL_ALLOWED_FUNCTIONS= # 可选,经过审核的函数名
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
推荐使用 `password_env`。本地环境也支持 `password` 字段,但 `mysql-connections.toml` 已加入 `.gitignore`,因为它可能包含敏感信息。桌面 MCP 客户端的工作目录不固定,因此 `MYSQL_PROFILES_FILE` 必须使用绝对路径。
|
|
151
|
+
|
|
152
|
+
### 使用操作系统凭据库
|
|
153
|
+
|
|
154
|
+
用户级 MCP 配置可使用系统凭据库,让密码不出现在 MCP JSON 或 TOML 中:
|
|
155
|
+
|
|
156
|
+
```toml
|
|
157
|
+
[connections.dev]
|
|
158
|
+
host = "127.0.0.1"
|
|
159
|
+
user = "readonly_user"
|
|
160
|
+
credential_provider = "keyring"
|
|
161
|
+
credential_ref = "dev"
|
|
162
|
+
database = "app_dev"
|
|
163
|
+
allowed_databases = ["app_dev"]
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
使用遮罩输入在本机管理凭据:
|
|
167
|
+
|
|
168
|
+
```powershell
|
|
169
|
+
readonly-db-mcp credentials --profiles-file C:/absolute/path/mysql-connections.toml set dev
|
|
170
|
+
readonly-db-mcp credentials --profiles-file C:/absolute/path/mysql-connections.toml status dev
|
|
171
|
+
readonly-db-mcp credentials --profiles-file C:/absolute/path/mysql-connections.toml delete dev
|
|
175
172
|
```
|
|
176
173
|
|
|
177
|
-
|
|
174
|
+
Windows 下 `keyring` 使用 Windows 凭据管理器。无桌面的服务环境可设置 `credential_provider = "command"`,并通过 `credential_command = ["executable", "arg1"]` 调用经过批准的密钥管理 CLI。程序不会通过 shell 执行命令;stderr 会被丢弃,输出长度受限,且只接受一行非空 UTF-8 文本。失败信息不会包含密钥、命令参数或凭据引用。
|
|
175
|
+
|
|
176
|
+
### 逻辑环境路由
|
|
177
|
+
|
|
178
|
+
一个逻辑环境分布在多个物理实例时,可声明精确别名:
|
|
178
179
|
|
|
179
|
-
|
|
180
|
+
```toml
|
|
181
|
+
[routes.shared-test]
|
|
182
|
+
ubp = { connection = "test-ubp", database = "ubp" }
|
|
183
|
+
gts = { connection = "test-gts", database = "gts" }
|
|
184
|
+
eam = { connection = "test-eam", database = "eam" }
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
调用 `connection="shared-test", database="eam"` 时,只会解析到声明的目标。未知别名会明确失败,服务不会搜索或猜测其他环境。JSON 结果和审计记录会同时保留请求目标与实际目标。
|
|
188
|
+
|
|
189
|
+
每次调用都可以选择环境,无需重启:
|
|
180
190
|
|
|
181
191
|
```json
|
|
182
192
|
{
|
|
@@ -185,326 +195,274 @@ Each tool call can now target an environment without restarting the server:
|
|
|
185
195
|
"query": "SELECT COUNT(*) FROM orders",
|
|
186
196
|
"audit_context": {
|
|
187
197
|
"actor": "reporting-service",
|
|
188
|
-
"purpose": "
|
|
198
|
+
"purpose": "月末对账",
|
|
189
199
|
"ticket_id": "FIN-2026-042"
|
|
190
200
|
}
|
|
191
201
|
}
|
|
192
202
|
```
|
|
193
203
|
|
|
194
|
-
|
|
204
|
+
服务刻意不提供进程级“切换连接/数据库”工具。显式逐次选择可防止一个并发客户端悄悄改变另一个客户端的活动环境。
|
|
195
205
|
|
|
196
|
-
|
|
197
|
-
One invalid profile is reported by `validate_connections` without disabling other
|
|
198
|
-
valid profiles. Password environment variables are resolved only when their
|
|
199
|
-
profile is used, so an unavailable production credential does not break local
|
|
200
|
-
development.
|
|
206
|
+
配置文件的大小或修改时间变化后会自动热加载。单个配置无效时,`validate_connections` 会报告该配置,但不会停用其他有效配置。密码环境变量只在使用对应连接时解析,因此生产凭据暂时不可用不会影响本地开发环境。
|
|
201
207
|
|
|
202
|
-
###
|
|
208
|
+
### 旧版单连接环境变量
|
|
203
209
|
|
|
204
|
-
|
|
210
|
+
未设置 `MYSQL_PROFILES_FILE` 时,仍可使用原有环境变量:
|
|
205
211
|
|
|
206
212
|
```bash
|
|
207
|
-
MYSQL_HOST=localhost
|
|
208
|
-
MYSQL_PORT=3306
|
|
213
|
+
MYSQL_HOST=localhost
|
|
214
|
+
MYSQL_PORT=3306
|
|
209
215
|
MYSQL_USER=readonly_user
|
|
210
216
|
MYSQL_PASSWORD=your_password
|
|
211
|
-
MYSQL_DATABASE=your_database
|
|
217
|
+
MYSQL_DATABASE=your_database
|
|
218
|
+
MYSQL_ALLOWED_DATABASES=your_database
|
|
212
219
|
|
|
213
|
-
#
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
MYSQL_CONNECT_TIMEOUT=10 # Timeout in seconds
|
|
220
|
+
MYSQL_SSL_MODE=REQUIRED # DISABLED、REQUIRED、VERIFY_CA、VERIFY_IDENTITY
|
|
221
|
+
MYSQL_SSL_CA= # VERIFY_CA / VERIFY_IDENTITY 必填
|
|
222
|
+
MYSQL_CONNECT_TIMEOUT=10
|
|
217
223
|
MYSQL_QUERY_TIMEOUT_MS=30000
|
|
218
224
|
MYSQL_MAX_ROWS=500
|
|
219
225
|
MYSQL_MAX_CELL_LENGTH=20000
|
|
220
226
|
MYSQL_RESULT_FORMAT=json
|
|
221
227
|
MYSQL_POOL_SIZE=0
|
|
222
|
-
|
|
223
|
-
MYSQL_AUDIT_LOG_FILE=C:/var/log/mysql-mcp/audit.jsonl
|
|
224
|
-
MYSQL_AUDIT_LOG_MAX_BYTES=10000000
|
|
225
|
-
MYSQL_AUDIT_LOG_BACKUP_COUNT=10
|
|
226
|
-
MYSQL_AUDIT_HMAC_KEY_ENV=MYSQL_MCP_AUDIT_SIGNING_KEY
|
|
227
|
-
MYSQL_MCP_AUDIT_SIGNING_KEY=replace-with-secret-manager-value
|
|
228
|
-
MYSQL_AUDIT_REQUIRED_CONTEXT=actor,purpose,ticket_id
|
|
229
|
-
MYSQL_AUDIT_FAIL_CLOSED=true
|
|
230
|
-
MYSQL_AUDIT_FSYNC=true
|
|
231
|
-
MYSQL_ALLOWED_DATABASES=your_database
|
|
232
|
-
|
|
233
|
-
# Connection behaviour (Optional)
|
|
234
|
-
MYSQL_SQL_MODE=TRADITIONAL # SQL mode applied to the connection (default: TRADITIONAL)
|
|
235
|
-
|
|
236
|
-
# Compatibility (Optional)
|
|
228
|
+
MYSQL_SQL_MODE=TRADITIONAL
|
|
237
229
|
MYSQL_CHARSET=utf8mb4
|
|
238
230
|
MYSQL_COLLATION=utf8mb4_unicode_ci
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
#
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
231
|
+
MYSQL_USE_PURE=false
|
|
232
|
+
MYSQL_RAISE_ON_WARNINGS=false
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### SSE 传输
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
MCP_TRANSPORT=stdio # stdio 或 sse
|
|
239
|
+
MCP_SSE_HOST=127.0.0.1 # 默认仅监听回环地址
|
|
240
|
+
PORT=8000 # MCP_SSE_PORT 的后备值
|
|
241
|
+
MCP_SSE_ALLOWED_HOSTS= # 允许的 Host,逗号分隔
|
|
242
|
+
MCP_SSE_BEARER_TOKEN= # 可选,至少 32 个字符
|
|
243
|
+
MCP_SSE_TRUST_PROXY_AUTH=false # 仅在认证反向代理是唯一入口时启用
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
非回环地址只有在启用 Bearer 认证,或显式确认由认证反向代理保护时才允许启动。部署细节见 [`ENTERPRISE_DEPLOYMENT.md`](ENTERPRISE_DEPLOYMENT.md)。
|
|
247
|
+
|
|
248
|
+
### SSH 隧道
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
MYSQL_SSH_ENABLE=false
|
|
252
|
+
MYSQL_SSH_HOST=
|
|
253
|
+
MYSQL_SSH_PORT=22
|
|
254
|
+
MYSQL_SSH_USER=
|
|
255
|
+
MYSQL_SSH_KEY_PATH=
|
|
256
|
+
MYSQL_SSH_REMOTE_HOST=localhost
|
|
259
257
|
MYSQL_SSH_REMOTE_PORT=3306
|
|
260
|
-
MYSQL_LOCAL_PORT=0
|
|
258
|
+
MYSQL_LOCAL_PORT=0 # 0 表示自动选择端口,隧道会复用
|
|
261
259
|
```
|
|
262
260
|
|
|
263
|
-
### `.env`
|
|
261
|
+
### `.env` 文件
|
|
264
262
|
|
|
265
|
-
|
|
263
|
+
服务启动时会通过 `python-dotenv` 从进程工作目录及父目录加载 `.env`:
|
|
266
264
|
|
|
267
265
|
```bash
|
|
268
|
-
cp .env.example .env
|
|
266
|
+
cp .env.example .env
|
|
269
267
|
```
|
|
270
268
|
|
|
271
|
-
|
|
269
|
+
Claude Desktop、Codex 等宿主通常从自己的目录启动 MCP 服务,未必能找到项目内 `.env`。这类场景应将 `MYSQL_*` 配置放入 MCP 配置的 `env` 节点,或使用命名配置文件和凭据库。
|
|
272
270
|
|
|
273
|
-
|
|
271
|
+
### 多数据库模式
|
|
274
272
|
|
|
275
|
-
|
|
273
|
+
未设置 `MYSQL_DATABASE` 时,服务进入多数据库模式:
|
|
276
274
|
|
|
277
|
-
|
|
278
|
-
- `
|
|
279
|
-
-
|
|
280
|
-
- `USE` and multiple statements are intentionally blocked
|
|
275
|
+
- `list_resources` 返回过滤系统库后的可访问数据库
|
|
276
|
+
- 数据工具通过 `database` 参数或 `database.table` 全限定名选择数据库
|
|
277
|
+
- `USE` 和多语句始终被拦截
|
|
281
278
|
|
|
282
|
-
##
|
|
279
|
+
## 可用工具
|
|
283
280
|
|
|
284
|
-
|
|
281
|
+
所有工具都声明 `readOnlyHint=true` 和 `destructiveHint=false`。
|
|
285
282
|
|
|
286
283
|
### `list_connections`
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
profile when one environment is split across several database-specific
|
|
290
|
-
connections.
|
|
284
|
+
|
|
285
|
+
列出命名配置、默认数据库、策略限制和就绪状态,不返回主机、用户名、密码或 SSH 私钥路径。还会返回数据库路由索引和逻辑环境别名。
|
|
291
286
|
|
|
292
287
|
### `validate_connections`
|
|
293
|
-
|
|
294
|
-
|
|
288
|
+
|
|
289
|
+
强制重新加载配置,报告有效/无效配置及缺少的密码环境变量,不建立数据库连接。
|
|
295
290
|
|
|
296
291
|
### `check_connection`
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
count, latency and active profile policy. Raw usernames and grant statements are
|
|
300
|
-
not returned. It classifies non-read privileges and warns when the account does
|
|
301
|
-
not provide read-only defense in depth.
|
|
292
|
+
|
|
293
|
+
通过只读健康检查返回 MySQL 版本、当前数据库、不可逆账号指纹、全局只读状态、授权数量、延迟和当前策略。原始用户名和 `SHOW GRANTS` 内容不会返回。
|
|
302
294
|
|
|
303
295
|
### `list_databases`
|
|
304
|
-
|
|
305
|
-
|
|
296
|
+
|
|
297
|
+
列出可访问的非系统数据库。
|
|
298
|
+
|
|
299
|
+
- 参数:`connection`(可选)
|
|
300
|
+
- 对逻辑连接返回声明的数据库别名,不建立数据库连接
|
|
306
301
|
|
|
307
302
|
### `list_tables`
|
|
308
|
-
|
|
309
|
-
|
|
303
|
+
|
|
304
|
+
列出指定数据库中的表和视图。
|
|
305
|
+
|
|
306
|
+
- 参数:`connection`、`database`、`table_name`/`table`(精确匹配)、`table_pattern`(支持 `*`/`?`)、`max_rows`、`offset`、`timeout_ms`、`result_format`,均可选
|
|
307
|
+
- 大库使用与 `execute_sql` 相同的 `truncated`/`next_offset` 分页契约
|
|
310
308
|
|
|
311
309
|
### `execute_sql`
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
-
|
|
316
|
-
-
|
|
317
|
-
-
|
|
318
|
-
-
|
|
319
|
-
-
|
|
320
|
-
-
|
|
321
|
-
-
|
|
322
|
-
-
|
|
323
|
-
-
|
|
324
|
-
|
|
325
|
-
|
|
310
|
+
|
|
311
|
+
执行且只执行一条只读语句。
|
|
312
|
+
|
|
313
|
+
- 必填参数:`query`
|
|
314
|
+
- 可选参数:`connection`、`database`、`max_rows`、`offset`、`timeout_ms`、`result_format`、`audit_context`
|
|
315
|
+
- 允许:`SELECT`、`WITH`、受数据库范围约束的 `SHOW`(包括 `SHOW CREATE TABLE/VIEW`)、`DESCRIBE`、`DESC`、`EXPLAIN`、`TABLE`
|
|
316
|
+
- 始终拦截:DML、DDL、`USE`、事务控制、锁、`SELECT ... INTO`、会话变量赋值、MySQL 可执行注释和多语句
|
|
317
|
+
- 函数策略:默认拦截无法识别的存储函数/UDF;只有 `allowed_functions` 中经过审核的确定性函数可放行
|
|
318
|
+
- 纵深防御:连接前先校验;随后在 `START TRANSACTION READ ONLY` 中执行并回滚
|
|
319
|
+
- 分页:对适用的 `SELECT`/CTE/UNION 下推 `LIMIT max_rows+1 OFFSET offset`,完整消费该有界结果后再回滚;JSON 结果返回 `truncated` 和 `next_offset`
|
|
320
|
+
- 跨库:使用 `database` 参数或 `database.table` 全限定名
|
|
321
|
+
- 超时/取消:统一限制完整操作、Connector socket 和 MySQL/MariaDB 语句时间;取消请求会关闭活动连接,无需 `KILL` 权限
|
|
322
|
+
- 格式:`json` 保留结构化数据和元信息;`csv` 使用标准引号规则,并明确表示 `NULL`
|
|
323
|
+
- 审计归因:`audit_context` 支持 `actor`、`purpose`、`ticket_id`,配置可要求调用前必须提供指定字段
|
|
324
|
+
- 临时故障恢复:Connector/Python 客户端侧 `errno=-1` 会重试一次;持续失败只返回安全的异常类型和生命周期阶段
|
|
326
325
|
|
|
327
326
|
### `query`
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
Stateful legacy tools such as `use_connection` and `use_database` are
|
|
331
|
-
intentionally not restored because process-global selection is unsafe with
|
|
332
|
-
concurrent MCP clients.
|
|
327
|
+
|
|
328
|
+
`execute_sql` 的兼容别名,使用相同的只读、白名单、脱敏、超时、分页和审计策略。不会恢复不安全的进程级 `use_connection` 或 `use_database`。
|
|
333
329
|
|
|
334
330
|
### `get_schema_info`
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
-
|
|
339
|
-
-
|
|
331
|
+
|
|
332
|
+
返回数据库结构详情,包括字段名、类型、可空性、默认值和注释。
|
|
333
|
+
|
|
334
|
+
- 参数:`table_name` 或兼容别名 `table`,以及 `connection`、`database`
|
|
335
|
+
- 可用 `database.table` 访问允许列表中的其他数据库
|
|
336
|
+
- 标识符只允许字母、数字、下划线、`$`,数据库与表之间允许一个点
|
|
340
337
|
|
|
341
338
|
### `get_table_sample`
|
|
342
|
-
Fetches a representative sample of data.
|
|
343
|
-
- **Arguments:** `table_name` (required), `limit` (optional integer, max 100), `offset`, `connection`, `database`, `timeout_ms`, `result_format`
|
|
344
|
-
- **Use Case:** Quickly understand data formats and content without fetching large result sets.
|
|
345
|
-
- **Cross-database:** Pass `database.table` to sample a table outside `MYSQL_DATABASE`; bare names use the configured database.
|
|
346
|
-
- **Identifier rules:** Names must contain only alphanumeric characters, underscores, and `$` (dots are allowed as a separator between database and table names).
|
|
347
|
-
- **Bounded execution:** Sampling applies `LIMIT limit+1 OFFSET offset` in
|
|
348
|
-
MySQL and fully consumes that small result. It does not open an unbounded
|
|
349
|
-
table scan merely to return a few rows.
|
|
350
339
|
|
|
351
|
-
|
|
340
|
+
返回具有代表性的少量样例数据。
|
|
341
|
+
|
|
342
|
+
- `table_name` 或兼容别名 `table` 必须提供一个
|
|
343
|
+
- 可选参数:`limit`(最大 100)、`offset`、`connection`、`database`、`timeout_ms`、`result_format`
|
|
344
|
+
- 采样会在 MySQL 中应用 `LIMIT limit+1 OFFSET offset` 并完整消费小结果集,不会为了返回几行数据而开启无界扫描结果
|
|
345
|
+
|
|
346
|
+
### `inspect_catalog`
|
|
347
|
+
|
|
348
|
+
返回 `tables`、`columns`、`indexes`、`constraints`、`foreign_keys` 或 `views` 的固定元数据投影。可通过 `table_name` 或 `table` 精确过滤。该工具不会开放任意 `information_schema` SQL。
|
|
352
349
|
|
|
353
|
-
|
|
350
|
+
## 可用提示词
|
|
354
351
|
|
|
355
|
-
|
|
|
352
|
+
| 提示词 | 参数 | 说明 |
|
|
356
353
|
| --- | --- | --- |
|
|
357
|
-
| `explore_database` | `connection
|
|
358
|
-
| `analyze_table` | `table_name
|
|
354
|
+
| `explore_database` | `connection`、`database`(可选) | 依次发现表、检查结构、采样并总结数据库 |
|
|
355
|
+
| `analyze_table` | `table_name`(必填)、`connection`、`database`(可选) | 深入分析指定表,支持 `database.table` |
|
|
359
356
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
/mcp__mysql__analyze_table customers
|
|
364
|
-
```
|
|
357
|
+
这些提示词只编排只读的发现、结构检查和采样工具。
|
|
358
|
+
|
|
359
|
+
## MCP 客户端配置
|
|
365
360
|
|
|
366
|
-
|
|
361
|
+
### Claude Desktop
|
|
362
|
+
|
|
363
|
+
在 `claude_desktop_config.json` 中加入:
|
|
367
364
|
|
|
368
|
-
## Usage
|
|
369
|
-
### With Claude Desktop
|
|
370
|
-
Add this to your `claude_desktop_config.json`:
|
|
371
365
|
```json
|
|
372
366
|
{
|
|
373
367
|
"mcpServers": {
|
|
374
368
|
"mysql-readonly": {
|
|
375
369
|
"command": "npx",
|
|
376
|
-
"args": ["-y", "@yanzhang123/readonly-db-mcp"],
|
|
370
|
+
"args": ["-y", "@yanzhang123/readonly-db-mcp@0.8.1"],
|
|
377
371
|
"env": {
|
|
378
372
|
"MYSQL_PROFILES_FILE": "C:/absolute/path/mysql-connections.toml",
|
|
379
|
-
"MYSQL_DEV_PASSWORD": "your_dev_password"
|
|
380
|
-
"MYSQL_PROD_PASSWORD": "your_prod_password"
|
|
373
|
+
"MYSQL_DEV_PASSWORD": "your_dev_password"
|
|
381
374
|
}
|
|
382
375
|
}
|
|
383
376
|
}
|
|
384
377
|
}
|
|
385
378
|
```
|
|
386
379
|
|
|
387
|
-
|
|
380
|
+
### Visual Studio Code / Codex
|
|
381
|
+
|
|
382
|
+
在 `mcp.json` 或对应 MCP 配置中加入:
|
|
388
383
|
|
|
389
|
-
### With Visual Studio Code
|
|
390
|
-
Add this to your `mcp.json`:
|
|
391
384
|
```json
|
|
392
385
|
{
|
|
393
386
|
"mcpServers": {
|
|
394
387
|
"mysql-readonly": {
|
|
395
388
|
"type": "stdio",
|
|
396
389
|
"command": "npx",
|
|
397
|
-
"args": ["-y", "@yanzhang123/readonly-db-mcp"],
|
|
390
|
+
"args": ["-y", "@yanzhang123/readonly-db-mcp@0.8.1"],
|
|
398
391
|
"env": {
|
|
399
392
|
"MYSQL_PROFILES_FILE": "C:/absolute/path/mysql-connections.toml",
|
|
400
|
-
"MYSQL_DEV_PASSWORD": "your_dev_password"
|
|
401
|
-
"MYSQL_PROD_PASSWORD": "your_prod_password"
|
|
393
|
+
"MYSQL_DEV_PASSWORD": "your_dev_password"
|
|
402
394
|
}
|
|
403
395
|
}
|
|
404
396
|
}
|
|
405
397
|
}
|
|
406
398
|
```
|
|
407
399
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
### Debugging with MCP Inspector
|
|
411
|
-
While MySQL MCP Server isn't intended to be run standalone or directly from the command line with Python, you can use the MCP Inspector to debug it.
|
|
412
|
-
|
|
413
|
-
The MCP Inspector provides a convenient way to test and debug your MCP implementation:
|
|
414
|
-
|
|
415
|
-
```bash
|
|
416
|
-
# Install dependencies
|
|
417
|
-
pip install -r requirements.txt
|
|
418
|
-
# Use the MCP Inspector for debugging (do not run directly with Python)
|
|
419
|
-
```
|
|
400
|
+
Windows 宿主如无法解析 `npx`,改用 `npx.cmd`。更多调用场景见 [`MCP_USECASES.md`](MCP_USECASES.md)。
|
|
420
401
|
|
|
421
|
-
|
|
402
|
+
## 开发与测试
|
|
422
403
|
|
|
423
|
-
## Development
|
|
424
404
|
```bash
|
|
425
|
-
# Clone the repository
|
|
426
405
|
git clone https://github.com/12zhangyan/mysql_mcp_server.git
|
|
427
406
|
cd mysql_mcp_server
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
# Linux/macOS
|
|
431
|
-
|
|
432
|
-
|
|
407
|
+
python -m venv .venv
|
|
408
|
+
|
|
409
|
+
# Linux/macOS
|
|
410
|
+
source .venv/bin/activate
|
|
411
|
+
|
|
412
|
+
# Windows PowerShell
|
|
413
|
+
.\.venv\Scripts\Activate.ps1
|
|
414
|
+
|
|
433
415
|
pip install -r requirements-dev.txt
|
|
434
|
-
# Copy the example config and edit with your credentials
|
|
435
|
-
# Linux/macOS: cp .env.example .env
|
|
436
|
-
# Windows PowerShell: Copy-Item .env.example .env
|
|
437
|
-
# Edit .env with your MySQL connection details
|
|
438
|
-
# Run tests
|
|
439
416
|
pytest
|
|
417
|
+
npm test
|
|
440
418
|
```
|
|
441
419
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
-
|
|
447
|
-
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
-
|
|
452
|
-
-
|
|
453
|
-
-
|
|
454
|
-
-
|
|
455
|
-
-
|
|
456
|
-
-
|
|
457
|
-
-
|
|
458
|
-
-
|
|
459
|
-
-
|
|
460
|
-
- **
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
4. **Require audit attribution** and protect the optional HMAC key in a secret manager
|
|
492
|
-
5. **Review masking patterns, audit events, dependency updates, and account grants regularly**
|
|
493
|
-
|
|
494
|
-
See [MySQL Security Configuration Guide](https://github.com/12zhangyan/mysql_mcp_server/blob/main/SECURITY.md) for detailed instructions on:
|
|
495
|
-
- Creating a restricted MySQL user
|
|
496
|
-
- Setting appropriate permissions
|
|
497
|
-
- Monitoring database access
|
|
498
|
-
- Security best practices
|
|
499
|
-
|
|
500
|
-
⚠️ IMPORTANT: Always follow the principle of least privilege when configuring database access.
|
|
501
|
-
|
|
502
|
-
## License
|
|
503
|
-
MIT License - see LICENSE file for details.
|
|
504
|
-
|
|
505
|
-
## Contributing
|
|
506
|
-
1. Fork the repository
|
|
507
|
-
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
508
|
-
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
509
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
510
|
-
5. Open a Pull Request
|
|
420
|
+
调试 MCP 协议交互时可使用 MCP Inspector,不建议直接把 Python 进程当作普通命令行程序交互。
|
|
421
|
+
|
|
422
|
+
## 安全设计
|
|
423
|
+
|
|
424
|
+
- **只读 SQL 闸门**:仅允许产生结果的只读语句;写入、DDL、事务、锁和有副作用的结构在连接前被拒绝
|
|
425
|
+
- **数据库侧约束**:所有查询以 `autocommit=false` 运行在只读事务中,正常结束统一回滚,取消时关闭连接触发服务端回滚
|
|
426
|
+
- **可写账号防护**:MCP 的只读行为不依赖账号授权;仍建议用专用 `SELECT` 账号作为独立防线
|
|
427
|
+
- **数据库白名单**:工具和资源 URI 均通过 MySQL AST 解析执行 `allowed_databases`,系统库默认禁止
|
|
428
|
+
- **受控元数据**:用户 SQL 默认不能直接查询 `information_schema`;使用 `list_tables`、`get_schema_info`、`inspect_catalog` 获取限定范围的元数据
|
|
429
|
+
- **凭据隔离**:密码可来自环境变量、操作系统凭据库或无 shell 的受控命令;发现接口、日志和错误均不返回凭据值或引用
|
|
430
|
+
- **资源限制**:整次调用、socket 和服务端语句均有超时;最多返回 1000 行,超长单元格会截断
|
|
431
|
+
- **精确脱敏**:依据表达式源字段脱敏,别名不能绕过规则,也不会连带遮罩无关列;JSON 中 `clientSecret`、`AppSec` 等敏感键递归脱敏
|
|
432
|
+
- **安全默认规则**:覆盖常见 password/PWD、mobile/phone、secret、凭据 token、API key、private key 命名;不会用宽泛的 `*token*` 误伤通道代码或 token 有效时长
|
|
433
|
+
- **企业审计**:UTC JSONL 事件包含事件 ID、MCP 请求 ID、操作、调用方归因、策略决定、目标库、无字面量查询指纹、耗时、结果大小和结果状态;不记录 SQL 原文和结果数据
|
|
434
|
+
- **两阶段审计**:失败关闭模式下,建立连接前先 fsync 写入 `started` 事件,随后记录终态事件
|
|
435
|
+
- **默认加密**:数据库 TLS 默认 `REQUIRED`;生产配置建议使用 `VERIFY_CA` 或 `VERIFY_IDENTITY`
|
|
436
|
+
- **解析器加固**:拒绝 MySQL `/*!...*/` 和 MariaDB `/*M!...*/` 可执行注释;未限定到允许数据库的全局 `SHOW` 被拦截
|
|
437
|
+
- **诊断隐私**:连接诊断只公开不可逆账号指纹和权限摘要,不返回用户名、授权原文、配置路径或数据库错误原文
|
|
438
|
+
- **SSE 安全边界**:默认仅绑定回环地址;非回环部署必须配置 Bearer 认证或由唯一入口的认证反向代理保护
|
|
439
|
+
|
|
440
|
+
详细安全和企业部署说明:
|
|
441
|
+
|
|
442
|
+
- [`SECURITY.md`](SECURITY.md)
|
|
443
|
+
- [`ENTERPRISE_DEPLOYMENT.md`](ENTERPRISE_DEPLOYMENT.md)
|
|
444
|
+
|
|
445
|
+
## 安全最佳实践
|
|
446
|
+
|
|
447
|
+
1. 使用仅授予 `SELECT` 的专用 MySQL 用户,不使用 root 或管理员账号
|
|
448
|
+
2. 通过 `allowed_databases` 将每个连接限制到实际需要的数据库
|
|
449
|
+
3. 对生产连接启用证书校验,并限制网络访问来源
|
|
450
|
+
4. 对重要环境要求完整的 `audit_context`,审计 HMAC 密钥由密钥管理系统提供
|
|
451
|
+
5. 定期复核脱敏规则、审计事件、依赖版本和账号授权
|
|
452
|
+
|
|
453
|
+
## 发布
|
|
454
|
+
|
|
455
|
+
Python 与 npm 使用同一版本号。维护者应按 [`RELEASING.md`](RELEASING.md) 完成同步版本、测试、打包和发布。
|
|
456
|
+
|
|
457
|
+
## 参与贡献
|
|
458
|
+
|
|
459
|
+
1. Fork 仓库
|
|
460
|
+
2. 创建功能分支
|
|
461
|
+
3. 提交修改并运行相关测试
|
|
462
|
+
4. 推送分支并创建 Pull Request
|
|
463
|
+
|
|
464
|
+
提交安全问题前请先阅读 [`SECURITY.md`](SECURITY.md)。
|
|
465
|
+
|
|
466
|
+
## 许可证
|
|
467
|
+
|
|
468
|
+
本项目使用 MIT License,详见 [`LICENSE`](LICENSE)。
|
package/SECURITY.md
CHANGED
|
@@ -59,6 +59,13 @@ FLUSH PRIVILEGES;
|
|
|
59
59
|
|
|
60
60
|
When setting up the MCP server, use these restricted credentials in your environment:
|
|
61
61
|
|
|
62
|
+
Prefer `credential_provider = "keyring"` for desktop MCP clients so passwords
|
|
63
|
+
do not appear in user-level MCP JSON or TOML. The local credentials command uses
|
|
64
|
+
a masked prompt and never returns stored values. Enterprise secret-manager
|
|
65
|
+
commands must be configured as an argv array; they run with `shell=false`, no
|
|
66
|
+
stdin, discarded stderr, a bounded timeout/output size, and a one-line output
|
|
67
|
+
contract. Do not embed secrets in command arguments.
|
|
68
|
+
|
|
62
69
|
```bash
|
|
63
70
|
MYSQL_USER=mcp_user
|
|
64
71
|
MYSQL_PASSWORD=your_secure_password
|
package/npm/requirements.lock
CHANGED
|
@@ -18,6 +18,10 @@ attrs==26.1.0 \
|
|
|
18
18
|
# via
|
|
19
19
|
# jsonschema
|
|
20
20
|
# referencing
|
|
21
|
+
backports-tarfile==1.2.0 ; python_full_version < '3.12' \
|
|
22
|
+
--hash=sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34 \
|
|
23
|
+
--hash=sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991
|
|
24
|
+
# via jaraco-context
|
|
21
25
|
certifi==2026.5.20 \
|
|
22
26
|
--hash=sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897 \
|
|
23
27
|
--hash=sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d
|
|
@@ -144,7 +148,9 @@ cryptography==48.0.0 \
|
|
|
144
148
|
--hash=sha256:ecde28a596bead48b0cfd2a1b4416c3d43074c2d785e3a398d7ec1fc4d0f7fbb \
|
|
145
149
|
--hash=sha256:f5333311663ea94f75dd408665686aaf426563556bb5283554a3539177e03b8c \
|
|
146
150
|
--hash=sha256:fdfef35d751d510fcef5252703621574364fec16418c4a1e5e1055248401054b
|
|
147
|
-
# via
|
|
151
|
+
# via
|
|
152
|
+
# pyjwt
|
|
153
|
+
# secretstorage
|
|
148
154
|
h11==0.16.0 \
|
|
149
155
|
--hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \
|
|
150
156
|
--hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86
|
|
@@ -169,6 +175,28 @@ idna==3.18 \
|
|
|
169
175
|
# via
|
|
170
176
|
# anyio
|
|
171
177
|
# httpx
|
|
178
|
+
importlib-metadata==9.0.0 ; python_full_version < '3.12' \
|
|
179
|
+
--hash=sha256:2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7 \
|
|
180
|
+
--hash=sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc
|
|
181
|
+
# via keyring
|
|
182
|
+
jaraco-classes==3.4.0 \
|
|
183
|
+
--hash=sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd \
|
|
184
|
+
--hash=sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790
|
|
185
|
+
# via keyring
|
|
186
|
+
jaraco-context==6.1.2 \
|
|
187
|
+
--hash=sha256:bf8150b79a2d5d91ae48629d8b427a8f7ba0e1097dd6202a9059f29a36379535 \
|
|
188
|
+
--hash=sha256:f1a6c9d391e661cc5b8d39861ff077a7dc24dc23833ccee564b234b81c82dfe3
|
|
189
|
+
# via keyring
|
|
190
|
+
jaraco-functools==4.6.0 \
|
|
191
|
+
--hash=sha256:880c577ec9720b3a052d5bc611fb9f2269b3d87902ef42440df443b88e443280 \
|
|
192
|
+
--hash=sha256:99e3dc0060c5cbe8fcd1cdb36258e2a65ca40f1566b2033b12abb1bb44dd3c30
|
|
193
|
+
# via keyring
|
|
194
|
+
jeepney==0.9.0 ; sys_platform == 'linux' \
|
|
195
|
+
--hash=sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683 \
|
|
196
|
+
--hash=sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732
|
|
197
|
+
# via
|
|
198
|
+
# keyring
|
|
199
|
+
# secretstorage
|
|
172
200
|
jsonschema==4.26.0 \
|
|
173
201
|
--hash=sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326 \
|
|
174
202
|
--hash=sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce
|
|
@@ -177,10 +205,20 @@ jsonschema-specifications==2025.9.1 \
|
|
|
177
205
|
--hash=sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe \
|
|
178
206
|
--hash=sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d
|
|
179
207
|
# via jsonschema
|
|
208
|
+
keyring==25.7.0 \
|
|
209
|
+
--hash=sha256:be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f \
|
|
210
|
+
--hash=sha256:fe01bd85eb3f8fb3dd0405defdeac9a5b4f6f0439edbb3149577f244a2e8245b
|
|
211
|
+
# via mysql-mcp-server
|
|
180
212
|
mcp==1.27.2 \
|
|
181
213
|
--hash=sha256:8e02db104096d1c25b28e64bde29a5c32b31bc241710213e12fd4d84985bdfef \
|
|
182
214
|
--hash=sha256:d6ff5160c6ca65d93013626efb3fc249de683c30b2d8570755ceddd490344de5
|
|
183
215
|
# via mysql-mcp-server
|
|
216
|
+
more-itertools==11.1.0 \
|
|
217
|
+
--hash=sha256:48e8f4d9e7e5878571ecf6f2b4e57634f93cd474cc8cfbd2376f2d11b396e30d \
|
|
218
|
+
--hash=sha256:4b65538ae22f6fed0ce4874efd317463a7489796a0939fa66824dd542125a192
|
|
219
|
+
# via
|
|
220
|
+
# jaraco-classes
|
|
221
|
+
# jaraco-functools
|
|
184
222
|
mysql-connector-python==9.7.0 \
|
|
185
223
|
--hash=sha256:079ce68d617250ef5cefffd5243056dc9f87c6034c804235fd6f45a0daf5a6ae \
|
|
186
224
|
--hash=sha256:15106ed73d74487f86de6b1859ff7f362efca7c7f9c494497ccb7439d3139fe6 \
|
|
@@ -343,6 +381,10 @@ pywin32==312 ; sys_platform == 'win32' \
|
|
|
343
381
|
--hash=sha256:d11417d84412f859b722fad0841b3614459ed0047f7542d8362e77884f6b6e8a \
|
|
344
382
|
--hash=sha256:dab4f65ac9c4e48400a2a0530c46c3c579cd5905ecd11b80692373915269208b
|
|
345
383
|
# via mcp
|
|
384
|
+
pywin32-ctypes==0.2.3 ; sys_platform == 'win32' \
|
|
385
|
+
--hash=sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8 \
|
|
386
|
+
--hash=sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755
|
|
387
|
+
# via keyring
|
|
346
388
|
referencing==0.37.0 \
|
|
347
389
|
--hash=sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231 \
|
|
348
390
|
--hash=sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8
|
|
@@ -483,6 +525,10 @@ rpds-py==2026.5.1 \
|
|
|
483
525
|
# via
|
|
484
526
|
# jsonschema
|
|
485
527
|
# referencing
|
|
528
|
+
secretstorage==3.5.0 ; sys_platform == 'linux' \
|
|
529
|
+
--hash=sha256:0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137 \
|
|
530
|
+
--hash=sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be
|
|
531
|
+
# via keyring
|
|
486
532
|
sqlglot==30.14.0 \
|
|
487
533
|
--hash=sha256:df2ef5d2b8ca814313781f4ff35bf63e58f821ef517eeddbd523c19a61fa9bb9 \
|
|
488
534
|
--hash=sha256:fc768e24889d63a5e1237dea7ad305e5ffb4356a98b0bed828f89591ebcd3636
|
|
@@ -519,3 +565,7 @@ uvicorn==0.49.0 ; sys_platform != 'emscripten' \
|
|
|
519
565
|
--hash=sha256:ba3d14c3ee7e41c6c654c46c9eb489d33213cdd30aa1696eab1374337c13f68f \
|
|
520
566
|
--hash=sha256:ebf4271aa580d9de97f93192d4595176df6e91f9aae919ca73e4fc07df1e66a3
|
|
521
567
|
# via mcp
|
|
568
|
+
zipp==4.1.0 ; python_full_version < '3.12' \
|
|
569
|
+
--hash=sha256:25ad4e16390cd314347dd8f1de67a2ac538ae658ed4ab9db16029c07c188e97f \
|
|
570
|
+
--hash=sha256:4cb57381f544315db7688e976e922a2b18cdb513d21cc194eb42232ba2a3e602
|
|
571
|
+
# via importlib-metadata
|
|
Binary file
|
package/package.json
CHANGED
|
Binary file
|