mysql-client-mcp-py 0.2.0__tar.gz
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.
- mysql_client_mcp_py-0.2.0/LICENSE +21 -0
- mysql_client_mcp_py-0.2.0/PKG-INFO +225 -0
- mysql_client_mcp_py-0.2.0/README.md +198 -0
- mysql_client_mcp_py-0.2.0/pyproject.toml +53 -0
- mysql_client_mcp_py-0.2.0/scripts/test_live.py +58 -0
- mysql_client_mcp_py-0.2.0/src/mysql_client_mcp/__init__.py +3 -0
- mysql_client_mcp_py-0.2.0/src/mysql_client_mcp/__main__.py +5 -0
- mysql_client_mcp_py-0.2.0/src/mysql_client_mcp/client.py +151 -0
- mysql_client_mcp_py-0.2.0/src/mysql_client_mcp/config.py +227 -0
- mysql_client_mcp_py-0.2.0/src/mysql_client_mcp/server.py +477 -0
- mysql_client_mcp_py-0.2.0/src/mysql_client_mcp/sql_analysis.py +139 -0
- mysql_client_mcp_py-0.2.0/tests/test_server.py +158 -0
- mysql_client_mcp_py-0.2.0/uv.lock +925 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 dong_tech
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mysql-client-mcp-py
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: MCP Server for MySQL-protocol databases - schema discovery, SQL analysis, safe execution
|
|
5
|
+
Project-URL: Homepage, https://github.com/dong-tech/mysql-client-mcp-py
|
|
6
|
+
Project-URL: Repository, https://github.com/dong-tech/mysql-client-mcp-py
|
|
7
|
+
Author: dong_tech
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: ai,database,llm,mcp,model-context-protocol,mysql
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Database
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: mcp>=1.0.0
|
|
20
|
+
Requires-Dist: pydantic>=2.0.0
|
|
21
|
+
Requires-Dist: pymysql>=1.1.0
|
|
22
|
+
Requires-Dist: sqlparse>=0.5.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# MySQL Client MCP Server (mysql-client-mcp-py)
|
|
29
|
+
|
|
30
|
+
支持 MySQL 协议的 MCP Server:连接与元数据发现、SQL 分析、安全执行(单条,DDL 不执行,写操作需确认)。
|
|
31
|
+
|
|
32
|
+
## 环境变量
|
|
33
|
+
|
|
34
|
+
### 必填(单连接)
|
|
35
|
+
|
|
36
|
+
| 变量 | 说明 |
|
|
37
|
+
|------|------|
|
|
38
|
+
| `DB_HOST` | 主机 |
|
|
39
|
+
| `DB_USER` | 用户名 |
|
|
40
|
+
| `DB_PASSWORD` | 密码 |
|
|
41
|
+
| `DB_PORT` | 端口,默认 3306 |
|
|
42
|
+
| `DB_DATABASE` | 默认库,可选 |
|
|
43
|
+
|
|
44
|
+
### 多环境(仅方式二:TEST_DB_PROFILES / UAT_DB_PROFILES / PROD_DB_PROFILES)
|
|
45
|
+
|
|
46
|
+
- **多环境只配三个变量**:`TEST_DB_PROFILES`、`UAT_DB_PROFILES`、`PROD_DB_PROFILES`,每个为 **JSON 数组** `[{},{}]`,表示该环境下的一条或多条连接。**不需**再配 `DB_HOST`/`DB_USER`/`DB_PASSWORD`。
|
|
47
|
+
- 每个数组项需含 `host`、`port`、`user`、`password`;可选 `database`、`description`、`databases`、`name`(子名)。
|
|
48
|
+
- Profile 名:`test_0`、`test_1`、`test_finance`(若该项含 `"name":"finance"`)、`uat_0`、`prod_0` 等。默认连接取 prod 下第一个(如 `prod_0`)。
|
|
49
|
+
- **单环境**:不设任一 `*_DB_PROFILES` 时,只配 `DB_HOST`、`DB_USER`、`DB_PASSWORD`(及可选 `DB_PORT`、`DB_DATABASE`)。
|
|
50
|
+
|
|
51
|
+
**示例(test / uat / prod 三环境)**:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
TEST_DB_PROFILES='[{"host":"test-db.example.com","port":3306,"user":"t1","password":"xxx","database":"app_test","description":"测试环境","databases":["app_test"]}]'
|
|
55
|
+
UAT_DB_PROFILES='[{"host":"uat-db.example.com","port":3306,"user":"u1","password":"yyy","database":"app_uat","description":"UAT环境","databases":["app_uat"]}]'
|
|
56
|
+
PROD_DB_PROFILES='[{"host":"db.example.com","port":3306,"user":"ro","password":"zzz","database":"app","description":"生产环境","databases":["app","report"]}]'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
测试环境多条连接时,数组里放多项即可,例如:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
TEST_DB_PROFILES='[{"host":"t1","port":3306,"user":"u","password":"p","database":"app"},{"host":"t2","port":3306,"user":"u","password":"p","database":"order","name":"order"}]'
|
|
63
|
+
# → profile 为 test_0、test_order
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
调用时传 `connection="test_0"` 或 `connection="prod_0"` 等指定用哪条。
|
|
67
|
+
|
|
68
|
+
**让智能体根据自然语言选连接**:每项可配 `description`,`list_connections` / `db://config` 会展示,便于将用户说的「测试」「生产」映射到 profile 名。
|
|
69
|
+
|
|
70
|
+
**每个连接聚焦若干数据库**:每项可配 `databases`:**不配置** → 默认所有库;**空数组 `[]`** → 不允许任何库;**非空数组** → 仅允许这些库。
|
|
71
|
+
|
|
72
|
+
### 安全与行为
|
|
73
|
+
|
|
74
|
+
| 变量 | 默认 | 说明 |
|
|
75
|
+
|------|------|------|
|
|
76
|
+
| `DB_READ_ONLY` | false | 为 true 时仅允许 SELECT |
|
|
77
|
+
| `DB_MAX_SELECT_ROWS` | 10000 | SELECT 单次最大行数 |
|
|
78
|
+
| `DB_QUERY_TIMEOUT_SECONDS` | 30 | 执行超时(秒) |
|
|
79
|
+
| `DB_SLOW_QUERY_SECONDS` | 10 | 超过此秒数提示慢查询 |
|
|
80
|
+
|
|
81
|
+
## 安装与运行
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# 开发
|
|
85
|
+
cd mysql-client-mcp-py
|
|
86
|
+
uv sync
|
|
87
|
+
uv run python -m mysql_client_mcp
|
|
88
|
+
|
|
89
|
+
# 或安装后
|
|
90
|
+
pip install -e .
|
|
91
|
+
DB_HOST=localhost DB_USER=root DB_PASSWORD=xxx mysql-client-mcp-py
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Cursor / Claude 配置示例
|
|
95
|
+
|
|
96
|
+
**发布到 PyPI 后**(用户已 `pip install mysql-client-mcp-py` 或使用 `uvx`):
|
|
97
|
+
|
|
98
|
+
**Cursor** 编辑 `~/.cursor/mcp.json`:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"mcpServers": {
|
|
103
|
+
"database": {
|
|
104
|
+
"command": "uvx",
|
|
105
|
+
"args": ["mysql-client-mcp-py"],
|
|
106
|
+
"env": {
|
|
107
|
+
"DB_HOST": "localhost",
|
|
108
|
+
"DB_PORT": "3306",
|
|
109
|
+
"DB_USER": "root",
|
|
110
|
+
"DB_PASSWORD": "your-password",
|
|
111
|
+
"DB_DATABASE": "your_db"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
多环境示例(**只配 TEST_DB_PROFILES / UAT_DB_PROFILES / PROD_DB_PROFILES**,每项需含 `host`、`port`、`user`、`password`):
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"mcpServers": {
|
|
123
|
+
"database": {
|
|
124
|
+
"command": "uvx",
|
|
125
|
+
"args": ["mysql-client-mcp-py"],
|
|
126
|
+
"env": {
|
|
127
|
+
"TEST_DB_PROFILES": "[{\"host\":\"test-db.example.com\",\"port\":3306,\"user\":\"u\",\"password\":\"p\",\"database\":\"app\"}]",
|
|
128
|
+
"UAT_DB_PROFILES": "[{\"host\":\"uat-db.example.com\",\"port\":3306,\"user\":\"u\",\"password\":\"p\",\"database\":\"app\"}]",
|
|
129
|
+
"PROD_DB_PROFILES": "[{\"host\":\"db.example.com\",\"port\":3306,\"user\":\"ro\",\"password\":\"xxx\",\"database\":\"app\"}]"
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Claude Desktop** 编辑 `~/Library/Application Support/Claude/claude_desktop_config.json`(macOS):
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"mcpServers": {
|
|
141
|
+
"database": {
|
|
142
|
+
"command": "uvx",
|
|
143
|
+
"args": ["mysql-client-mcp-py"],
|
|
144
|
+
"env": {
|
|
145
|
+
"DB_HOST": "localhost",
|
|
146
|
+
"DB_USER": "root",
|
|
147
|
+
"DB_PASSWORD": "your-password",
|
|
148
|
+
"DB_DATABASE": "your_db"
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
若已用 pip 安装到当前环境,也可直接指定命令(无需 uvx):
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"mcpServers": {
|
|
160
|
+
"database": {
|
|
161
|
+
"command": "mysql-client-mcp-py",
|
|
162
|
+
"args": [],
|
|
163
|
+
"env": {
|
|
164
|
+
"DB_HOST": "localhost",
|
|
165
|
+
"DB_USER": "root",
|
|
166
|
+
"DB_PASSWORD": "your-password"
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**本地开发**(未发布、从源码运行):
|
|
174
|
+
|
|
175
|
+
```json
|
|
176
|
+
{
|
|
177
|
+
"mcpServers": {
|
|
178
|
+
"database": {
|
|
179
|
+
"command": "uv",
|
|
180
|
+
"args": ["run", "python", "-m", "mysql_client_mcp"],
|
|
181
|
+
"cwd": "/path/to/mysql-client-mcp-py",
|
|
182
|
+
"env": {
|
|
183
|
+
"DB_HOST": "localhost",
|
|
184
|
+
"DB_USER": "root",
|
|
185
|
+
"DB_PASSWORD": "your-password",
|
|
186
|
+
"DB_DATABASE": "your_db"
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## 工具
|
|
194
|
+
|
|
195
|
+
| 工具 | 说明 |
|
|
196
|
+
|------|------|
|
|
197
|
+
| `list_connections` | 列出可用连接(profile + 可选说明),便于按用户自然语言选 connection |
|
|
198
|
+
| `list_databases` | 列出数据库 |
|
|
199
|
+
| `list_tables` | 列出指定库的表 |
|
|
200
|
+
| `describe_table` | 表结构(列、行数、大小) |
|
|
201
|
+
| `analyze_sql` | 分析 SQL(支持多条),不执行 |
|
|
202
|
+
| `execute_sql` | 执行单条 SQL(DDL 不执行,写操作需 confirm=true) |
|
|
203
|
+
|
|
204
|
+
## 资源
|
|
205
|
+
|
|
206
|
+
- `db://config` - 配置与安全策略摘要
|
|
207
|
+
- `db://databases` - 数据库列表
|
|
208
|
+
- `db://tables/{database}` - 表列表
|
|
209
|
+
- `db://table/{database}/{table}` - 单表结构
|
|
210
|
+
|
|
211
|
+
## 提示词
|
|
212
|
+
|
|
213
|
+
- **`ask_user_which_connection_prompt`** - **连接选择规则**:一开始无已选配置,必须先 list_connections 并让用户选择;用户选择后记住该 connection,后续默认使用且不再提示;仅当用户明确要切换环境时,再次列出并让用户选择
|
|
214
|
+
- `query_safely_prompt` - 安全查询习惯
|
|
215
|
+
- `explore_schema_prompt` - 先看 Schema 再写 SQL
|
|
216
|
+
- `switch_connection_prompt` - 切换环境时带 connection 参数
|
|
217
|
+
- `use_connection_from_natural_language_prompt` - 列出配置让用户选择,并根据用户说法映射到 connection
|
|
218
|
+
|
|
219
|
+
## 设计文档
|
|
220
|
+
|
|
221
|
+
参见项目内 `docs/plans/2025-03-14-database-mcp-design.md`。
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
MIT
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# MySQL Client MCP Server (mysql-client-mcp-py)
|
|
2
|
+
|
|
3
|
+
支持 MySQL 协议的 MCP Server:连接与元数据发现、SQL 分析、安全执行(单条,DDL 不执行,写操作需确认)。
|
|
4
|
+
|
|
5
|
+
## 环境变量
|
|
6
|
+
|
|
7
|
+
### 必填(单连接)
|
|
8
|
+
|
|
9
|
+
| 变量 | 说明 |
|
|
10
|
+
|------|------|
|
|
11
|
+
| `DB_HOST` | 主机 |
|
|
12
|
+
| `DB_USER` | 用户名 |
|
|
13
|
+
| `DB_PASSWORD` | 密码 |
|
|
14
|
+
| `DB_PORT` | 端口,默认 3306 |
|
|
15
|
+
| `DB_DATABASE` | 默认库,可选 |
|
|
16
|
+
|
|
17
|
+
### 多环境(仅方式二:TEST_DB_PROFILES / UAT_DB_PROFILES / PROD_DB_PROFILES)
|
|
18
|
+
|
|
19
|
+
- **多环境只配三个变量**:`TEST_DB_PROFILES`、`UAT_DB_PROFILES`、`PROD_DB_PROFILES`,每个为 **JSON 数组** `[{},{}]`,表示该环境下的一条或多条连接。**不需**再配 `DB_HOST`/`DB_USER`/`DB_PASSWORD`。
|
|
20
|
+
- 每个数组项需含 `host`、`port`、`user`、`password`;可选 `database`、`description`、`databases`、`name`(子名)。
|
|
21
|
+
- Profile 名:`test_0`、`test_1`、`test_finance`(若该项含 `"name":"finance"`)、`uat_0`、`prod_0` 等。默认连接取 prod 下第一个(如 `prod_0`)。
|
|
22
|
+
- **单环境**:不设任一 `*_DB_PROFILES` 时,只配 `DB_HOST`、`DB_USER`、`DB_PASSWORD`(及可选 `DB_PORT`、`DB_DATABASE`)。
|
|
23
|
+
|
|
24
|
+
**示例(test / uat / prod 三环境)**:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
TEST_DB_PROFILES='[{"host":"test-db.example.com","port":3306,"user":"t1","password":"xxx","database":"app_test","description":"测试环境","databases":["app_test"]}]'
|
|
28
|
+
UAT_DB_PROFILES='[{"host":"uat-db.example.com","port":3306,"user":"u1","password":"yyy","database":"app_uat","description":"UAT环境","databases":["app_uat"]}]'
|
|
29
|
+
PROD_DB_PROFILES='[{"host":"db.example.com","port":3306,"user":"ro","password":"zzz","database":"app","description":"生产环境","databases":["app","report"]}]'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
测试环境多条连接时,数组里放多项即可,例如:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
TEST_DB_PROFILES='[{"host":"t1","port":3306,"user":"u","password":"p","database":"app"},{"host":"t2","port":3306,"user":"u","password":"p","database":"order","name":"order"}]'
|
|
36
|
+
# → profile 为 test_0、test_order
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
调用时传 `connection="test_0"` 或 `connection="prod_0"` 等指定用哪条。
|
|
40
|
+
|
|
41
|
+
**让智能体根据自然语言选连接**:每项可配 `description`,`list_connections` / `db://config` 会展示,便于将用户说的「测试」「生产」映射到 profile 名。
|
|
42
|
+
|
|
43
|
+
**每个连接聚焦若干数据库**:每项可配 `databases`:**不配置** → 默认所有库;**空数组 `[]`** → 不允许任何库;**非空数组** → 仅允许这些库。
|
|
44
|
+
|
|
45
|
+
### 安全与行为
|
|
46
|
+
|
|
47
|
+
| 变量 | 默认 | 说明 |
|
|
48
|
+
|------|------|------|
|
|
49
|
+
| `DB_READ_ONLY` | false | 为 true 时仅允许 SELECT |
|
|
50
|
+
| `DB_MAX_SELECT_ROWS` | 10000 | SELECT 单次最大行数 |
|
|
51
|
+
| `DB_QUERY_TIMEOUT_SECONDS` | 30 | 执行超时(秒) |
|
|
52
|
+
| `DB_SLOW_QUERY_SECONDS` | 10 | 超过此秒数提示慢查询 |
|
|
53
|
+
|
|
54
|
+
## 安装与运行
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# 开发
|
|
58
|
+
cd mysql-client-mcp-py
|
|
59
|
+
uv sync
|
|
60
|
+
uv run python -m mysql_client_mcp
|
|
61
|
+
|
|
62
|
+
# 或安装后
|
|
63
|
+
pip install -e .
|
|
64
|
+
DB_HOST=localhost DB_USER=root DB_PASSWORD=xxx mysql-client-mcp-py
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Cursor / Claude 配置示例
|
|
68
|
+
|
|
69
|
+
**发布到 PyPI 后**(用户已 `pip install mysql-client-mcp-py` 或使用 `uvx`):
|
|
70
|
+
|
|
71
|
+
**Cursor** 编辑 `~/.cursor/mcp.json`:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"mcpServers": {
|
|
76
|
+
"database": {
|
|
77
|
+
"command": "uvx",
|
|
78
|
+
"args": ["mysql-client-mcp-py"],
|
|
79
|
+
"env": {
|
|
80
|
+
"DB_HOST": "localhost",
|
|
81
|
+
"DB_PORT": "3306",
|
|
82
|
+
"DB_USER": "root",
|
|
83
|
+
"DB_PASSWORD": "your-password",
|
|
84
|
+
"DB_DATABASE": "your_db"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
多环境示例(**只配 TEST_DB_PROFILES / UAT_DB_PROFILES / PROD_DB_PROFILES**,每项需含 `host`、`port`、`user`、`password`):
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"mcpServers": {
|
|
96
|
+
"database": {
|
|
97
|
+
"command": "uvx",
|
|
98
|
+
"args": ["mysql-client-mcp-py"],
|
|
99
|
+
"env": {
|
|
100
|
+
"TEST_DB_PROFILES": "[{\"host\":\"test-db.example.com\",\"port\":3306,\"user\":\"u\",\"password\":\"p\",\"database\":\"app\"}]",
|
|
101
|
+
"UAT_DB_PROFILES": "[{\"host\":\"uat-db.example.com\",\"port\":3306,\"user\":\"u\",\"password\":\"p\",\"database\":\"app\"}]",
|
|
102
|
+
"PROD_DB_PROFILES": "[{\"host\":\"db.example.com\",\"port\":3306,\"user\":\"ro\",\"password\":\"xxx\",\"database\":\"app\"}]"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Claude Desktop** 编辑 `~/Library/Application Support/Claude/claude_desktop_config.json`(macOS):
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"mcpServers": {
|
|
114
|
+
"database": {
|
|
115
|
+
"command": "uvx",
|
|
116
|
+
"args": ["mysql-client-mcp-py"],
|
|
117
|
+
"env": {
|
|
118
|
+
"DB_HOST": "localhost",
|
|
119
|
+
"DB_USER": "root",
|
|
120
|
+
"DB_PASSWORD": "your-password",
|
|
121
|
+
"DB_DATABASE": "your_db"
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
若已用 pip 安装到当前环境,也可直接指定命令(无需 uvx):
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"mcpServers": {
|
|
133
|
+
"database": {
|
|
134
|
+
"command": "mysql-client-mcp-py",
|
|
135
|
+
"args": [],
|
|
136
|
+
"env": {
|
|
137
|
+
"DB_HOST": "localhost",
|
|
138
|
+
"DB_USER": "root",
|
|
139
|
+
"DB_PASSWORD": "your-password"
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**本地开发**(未发布、从源码运行):
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"mcpServers": {
|
|
151
|
+
"database": {
|
|
152
|
+
"command": "uv",
|
|
153
|
+
"args": ["run", "python", "-m", "mysql_client_mcp"],
|
|
154
|
+
"cwd": "/path/to/mysql-client-mcp-py",
|
|
155
|
+
"env": {
|
|
156
|
+
"DB_HOST": "localhost",
|
|
157
|
+
"DB_USER": "root",
|
|
158
|
+
"DB_PASSWORD": "your-password",
|
|
159
|
+
"DB_DATABASE": "your_db"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## 工具
|
|
167
|
+
|
|
168
|
+
| 工具 | 说明 |
|
|
169
|
+
|------|------|
|
|
170
|
+
| `list_connections` | 列出可用连接(profile + 可选说明),便于按用户自然语言选 connection |
|
|
171
|
+
| `list_databases` | 列出数据库 |
|
|
172
|
+
| `list_tables` | 列出指定库的表 |
|
|
173
|
+
| `describe_table` | 表结构(列、行数、大小) |
|
|
174
|
+
| `analyze_sql` | 分析 SQL(支持多条),不执行 |
|
|
175
|
+
| `execute_sql` | 执行单条 SQL(DDL 不执行,写操作需 confirm=true) |
|
|
176
|
+
|
|
177
|
+
## 资源
|
|
178
|
+
|
|
179
|
+
- `db://config` - 配置与安全策略摘要
|
|
180
|
+
- `db://databases` - 数据库列表
|
|
181
|
+
- `db://tables/{database}` - 表列表
|
|
182
|
+
- `db://table/{database}/{table}` - 单表结构
|
|
183
|
+
|
|
184
|
+
## 提示词
|
|
185
|
+
|
|
186
|
+
- **`ask_user_which_connection_prompt`** - **连接选择规则**:一开始无已选配置,必须先 list_connections 并让用户选择;用户选择后记住该 connection,后续默认使用且不再提示;仅当用户明确要切换环境时,再次列出并让用户选择
|
|
187
|
+
- `query_safely_prompt` - 安全查询习惯
|
|
188
|
+
- `explore_schema_prompt` - 先看 Schema 再写 SQL
|
|
189
|
+
- `switch_connection_prompt` - 切换环境时带 connection 参数
|
|
190
|
+
- `use_connection_from_natural_language_prompt` - 列出配置让用户选择,并根据用户说法映射到 connection
|
|
191
|
+
|
|
192
|
+
## 设计文档
|
|
193
|
+
|
|
194
|
+
参见项目内 `docs/plans/2025-03-14-database-mcp-design.md`。
|
|
195
|
+
|
|
196
|
+
## License
|
|
197
|
+
|
|
198
|
+
MIT
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "mysql-client-mcp-py"
|
|
3
|
+
version = "0.2.0"
|
|
4
|
+
description = "MCP Server for MySQL-protocol databases - schema discovery, SQL analysis, safe execution"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = { text = "MIT" }
|
|
7
|
+
requires-python = ">=3.10"
|
|
8
|
+
authors = [{ name = "dong_tech" }]
|
|
9
|
+
keywords = ["mcp", "mysql", "database", "model-context-protocol", "ai", "llm"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"License :: OSI Approved :: MIT License",
|
|
12
|
+
"Programming Language :: Python :: 3",
|
|
13
|
+
"Programming Language :: Python :: 3.10",
|
|
14
|
+
"Programming Language :: Python :: 3.11",
|
|
15
|
+
"Programming Language :: Python :: 3.12",
|
|
16
|
+
"Programming Language :: Python :: 3.13",
|
|
17
|
+
"Topic :: Database",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"mcp>=1.0.0",
|
|
21
|
+
"pymysql>=1.1.0",
|
|
22
|
+
"pydantic>=2.0.0",
|
|
23
|
+
"sqlparse>=0.5.0",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/dong-tech/mysql-client-mcp-py"
|
|
28
|
+
Repository = "https://github.com/dong-tech/mysql-client-mcp-py"
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
dev = [
|
|
32
|
+
"pytest>=8.0.0",
|
|
33
|
+
"pytest-asyncio>=0.23.0",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
mysql-client-mcp-py = "mysql_client_mcp.server:main"
|
|
38
|
+
|
|
39
|
+
[build-system]
|
|
40
|
+
requires = ["hatchling"]
|
|
41
|
+
build-backend = "hatchling.build"
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.targets.wheel]
|
|
44
|
+
packages = ["src/mysql_client_mcp"]
|
|
45
|
+
|
|
46
|
+
[tool.uv]
|
|
47
|
+
dev-dependencies = [
|
|
48
|
+
"pytest>=8.0.0",
|
|
49
|
+
"pytest-asyncio>=0.23.0",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
[tool.pytest.ini_options]
|
|
53
|
+
pythonpath = ["src"]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""用当前环境变量连接数据库,依次调用 list_connections、list_databases、list_tables、analyze_sql、execute_sql(SELECT 1)。"""
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
# 确保能 import 到 mysql_client_mcp
|
|
7
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
|
8
|
+
|
|
9
|
+
from mysql_client_mcp.config import load_connection_map, load_safety_config
|
|
10
|
+
from mysql_client_mcp.client import connect, list_databases, list_tables, get_connection_config, execute_select
|
|
11
|
+
from mysql_client_mcp.sql_analysis import analyze_one
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main():
|
|
15
|
+
default_conn, conn_map, default_name = load_connection_map()
|
|
16
|
+
safety = load_safety_config()
|
|
17
|
+
|
|
18
|
+
print("=== list_connections 等效 ===")
|
|
19
|
+
print(f"默认 profile: {default_name}")
|
|
20
|
+
for k, c in sorted(conn_map.items()):
|
|
21
|
+
print(f" {k}: {c.host}:{c.port} user={c.user} database={c.database or '(未指定)'}")
|
|
22
|
+
|
|
23
|
+
config = get_connection_config(None, default_conn, conn_map)
|
|
24
|
+
print(f"\n使用连接: {config.host}:{config.port} database={config.database}")
|
|
25
|
+
|
|
26
|
+
with connect(config, safety) as conn:
|
|
27
|
+
dbs = list_databases(conn, getattr(config, "databases", None))
|
|
28
|
+
print(f"\n=== list_databases === 共 {len(dbs)} 个库")
|
|
29
|
+
for db in (dbs or [])[:20]:
|
|
30
|
+
print(f" {db}")
|
|
31
|
+
if len(dbs or []) > 20:
|
|
32
|
+
print(f" ... 等共 {len(dbs)} 个")
|
|
33
|
+
|
|
34
|
+
db_name = config.database or (dbs[0] if dbs else None)
|
|
35
|
+
if not db_name:
|
|
36
|
+
print("\n跳过 list_tables(无默认库且未指定)")
|
|
37
|
+
else:
|
|
38
|
+
tables = list_tables(conn, db_name)
|
|
39
|
+
print(f"\n=== list_tables({db_name!r}) === 共 {len(tables)} 张表")
|
|
40
|
+
for t in (tables or [])[:10]:
|
|
41
|
+
print(f" {t.get('name', t)}")
|
|
42
|
+
if len(tables or []) > 10:
|
|
43
|
+
print(f" ... 等共 {len(tables)} 张")
|
|
44
|
+
|
|
45
|
+
a = analyze_one("SELECT 1")
|
|
46
|
+
print(f"\n=== analyze_sql('SELECT 1') === type={a.stype} need_confirm={a.need_confirm} message={a.message}")
|
|
47
|
+
|
|
48
|
+
with connect(config, safety) as conn:
|
|
49
|
+
rows, truncated = execute_select(conn, "SELECT 1 AS n", max_rows=safety.max_select_rows)
|
|
50
|
+
print(f"\n=== execute_sql('SELECT 1') === rows={len(rows)} truncated={truncated}")
|
|
51
|
+
if rows:
|
|
52
|
+
print(f" 结果: {rows[0]}")
|
|
53
|
+
|
|
54
|
+
print("\n测试通过。")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
if __name__ == "__main__":
|
|
58
|
+
main()
|