@yanzhang123/readonly-db-mcp 0.7.2 → 0.7.4
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/LICENSE +20 -20
- package/README.md +262 -205
- package/SECURITY.md +122 -122
- package/npm/vendor/mysql_mcp_server-0.7.4-py3-none-any.whl +0 -0
- package/package.json +1 -1
- package/npm/vendor/mysql_mcp_server-0.7.2-py3-none-any.whl +0 -0
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2024 Dana K. Williams
|
|
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 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
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Dana K. Williams
|
|
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 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
21
|
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,18 +1,30 @@
|
|
|
1
1
|
[](https://github.com/12zhangyan/mysql_mcp_server/actions)
|
|
2
|
-
[](https://www.npmjs.com/package/@yanzhang123/readonly-db-mcp)
|
|
3
|
+
[](https://www.npmjs.com/package/@yanzhang123/readonly-db-mcp)
|
|
4
|
+
|
|
5
|
+
# MySQL MCP Server
|
|
6
|
+
|
|
7
|
+
An enterprise-auditable, strictly read-only Model Context Protocol (MCP) server
|
|
8
|
+
for exploring multiple MySQL environments and databases from one process.
|
|
9
|
+
|
|
10
|
+
The supported npm distribution for this fork is
|
|
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.
|
|
14
|
+
|
|
15
|
+
> **Note**: MySQL MCP Server supports both standard input/output (STDIO) and Streamable HTTP (SSE) transport modes. The SSE mode is recommended for remote/self-hosted deployments.
|
|
16
|
+
|
|
17
|
+
> [!IMPORTANT]
|
|
18
|
+
> Read-only enforcement does not trust the MySQL account grants. Even if the
|
|
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.
|
|
23
|
+
|
|
13
24
|
## Features
|
|
14
25
|
- **Named connection profiles** for dev/test/staging/prod and multiple servers
|
|
15
26
|
- Select a `connection` and `database` independently on every tool call
|
|
27
|
+
- Database-to-profile routing hints without implicit cross-environment switching
|
|
16
28
|
- **Strictly read-only SQL** with fail-closed validation, a MySQL read-only transaction, and unconditional rollback
|
|
17
29
|
- Discover connections, databases, tables, schemas, and sample rows
|
|
18
30
|
- Return-size protection (`MYSQL_MAX_ROWS`, hard maximum 1000)
|
|
@@ -20,44 +32,75 @@ A Model Context Protocol (MCP) implementation that enables secure interaction wi
|
|
|
20
32
|
- **SSE/HTTP transport support** (`MCP_TRANSPORT=sse`)
|
|
21
33
|
- Per-profile SSL/TLS and SSH tunneling
|
|
22
34
|
- Passwords can stay in environment variables instead of the profiles file
|
|
23
|
-
|
|
35
|
+
- Compatibility `query` alias for clients migrating from older MySQL MCP servers
|
|
36
|
+
|
|
24
37
|
## Installation
|
|
25
38
|
|
|
26
39
|
### npm / npx
|
|
27
40
|
|
|
28
|
-
|
|
29
|
-
|
|
41
|
+
Requirements: Node.js 18+, npm 9+, and Python 3.11+ available on `PATH`.
|
|
42
|
+
|
|
43
|
+
Run the current release without installing it globally:
|
|
30
44
|
|
|
31
45
|
```bash
|
|
32
46
|
npx -y @yanzhang123/readonly-db-mcp
|
|
33
47
|
```
|
|
34
48
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
For controlled production rollouts, pin the reviewed version:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx -y @yanzhang123/readonly-db-mcp@0.7.3
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
On first use, the launcher creates a versioned virtual environment in the user
|
|
56
|
+
cache and installs the bundled wheel plus exact Python dependencies from a
|
|
57
|
+
version-controlled SHA-256 lock file. Downloads use the configured pip index
|
|
58
|
+
and the completed environment is cached by wheel-and-lock fingerprint. Override
|
|
59
|
+
Python with `MYSQL_MCP_PYTHON` or the cache location with
|
|
60
|
+
`MYSQL_MCP_NPM_CACHE_DIR`.
|
|
41
61
|
|
|
42
62
|
For MCP clients, use `npx` as the command and
|
|
43
63
|
`["-y", "@yanzhang123/readonly-db-mcp"]` as its arguments.
|
|
44
64
|
|
|
45
|
-
###
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
### Minimal MCP client configuration
|
|
66
|
+
|
|
67
|
+
Create `mysql-connections.toml` from
|
|
68
|
+
[`mysql-connections.example.toml`](mysql-connections.example.toml), keep
|
|
69
|
+
passwords in environment variables, and use an absolute path:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"mcpServers": {
|
|
74
|
+
"mysql-readonly": {
|
|
75
|
+
"command": "npx",
|
|
76
|
+
"args": ["-y", "@yanzhang123/readonly-db-mcp@0.7.3"],
|
|
77
|
+
"env": {
|
|
78
|
+
"MYSQL_PROFILES_FILE": "C:/absolute/path/mysql-connections.toml",
|
|
79
|
+
"MYSQL_DEV_PASSWORD": "set-in-the-client-secret-store"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
On Windows clients that do not resolve npm command shims correctly, set
|
|
87
|
+
`"command": "npx.cmd"`. Do not commit the populated profile, passwords, audit
|
|
88
|
+
HMAC keys, connection strings, or client configuration containing secrets.
|
|
89
|
+
|
|
90
|
+
After startup, call `validate_connections`, then `check_connection`, before
|
|
91
|
+
running discovery queries. `check_connection` reports an irreversible account
|
|
92
|
+
fingerprint and privilege classification without returning the username or raw
|
|
93
|
+
grant statements.
|
|
94
|
+
|
|
95
|
+
### Manual Python installation
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install mysql-mcp-server
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The Python package remains available for source-oriented deployments, but the
|
|
102
|
+
scoped npm package is the documented distribution path for this fork.
|
|
103
|
+
|
|
61
104
|
## Configuration
|
|
62
105
|
|
|
63
106
|
### Recommended: named connections
|
|
@@ -163,8 +206,8 @@ MYSQL_PORT=3306 # Optional: Database port (defaults to 3306 if not speci
|
|
|
163
206
|
MYSQL_USER=readonly_user
|
|
164
207
|
MYSQL_PASSWORD=your_password
|
|
165
208
|
MYSQL_DATABASE=your_database # Optional: Omit for multi-database mode
|
|
166
|
-
|
|
167
|
-
# Advanced Configuration
|
|
209
|
+
|
|
210
|
+
# Advanced Configuration
|
|
168
211
|
MYSQL_SSL_MODE=REQUIRED # DISABLED, REQUIRED, VERIFY_CA, VERIFY_IDENTITY
|
|
169
212
|
MYSQL_SSL_CA= # required for VERIFY_CA / VERIFY_IDENTITY
|
|
170
213
|
MYSQL_CONNECT_TIMEOUT=10 # Timeout in seconds
|
|
@@ -183,18 +226,18 @@ MYSQL_AUDIT_REQUIRED_CONTEXT=actor,purpose,ticket_id
|
|
|
183
226
|
MYSQL_AUDIT_FAIL_CLOSED=true
|
|
184
227
|
MYSQL_AUDIT_FSYNC=true
|
|
185
228
|
MYSQL_ALLOWED_DATABASES=your_database
|
|
186
|
-
|
|
187
|
-
# Connection behaviour (Optional)
|
|
188
|
-
MYSQL_SQL_MODE=TRADITIONAL # SQL mode applied to the connection (default: TRADITIONAL)
|
|
189
|
-
|
|
190
|
-
# Compatibility (Optional)
|
|
191
|
-
MYSQL_CHARSET=utf8mb4
|
|
192
|
-
MYSQL_COLLATION=utf8mb4_unicode_ci
|
|
193
|
-
MYSQL_AUTH_PLUGIN= # e.g., mysql_native_password for older MySQL versions
|
|
194
|
-
MYSQL_USE_PURE=false # Force the pure-Python connector (default: false)
|
|
195
|
-
MYSQL_RAISE_ON_WARNINGS=false # Raise on SQL warnings (default: false)
|
|
196
|
-
|
|
197
|
-
# SSE Transport (Optional)
|
|
229
|
+
|
|
230
|
+
# Connection behaviour (Optional)
|
|
231
|
+
MYSQL_SQL_MODE=TRADITIONAL # SQL mode applied to the connection (default: TRADITIONAL)
|
|
232
|
+
|
|
233
|
+
# Compatibility (Optional)
|
|
234
|
+
MYSQL_CHARSET=utf8mb4
|
|
235
|
+
MYSQL_COLLATION=utf8mb4_unicode_ci
|
|
236
|
+
MYSQL_AUTH_PLUGIN= # e.g., mysql_native_password for older MySQL versions
|
|
237
|
+
MYSQL_USE_PURE=false # Force the pure-Python connector (default: false)
|
|
238
|
+
MYSQL_RAISE_ON_WARNINGS=false # Raise on SQL warnings (default: false)
|
|
239
|
+
|
|
240
|
+
# SSE Transport (Optional)
|
|
198
241
|
MCP_TRANSPORT=stdio # stdio or sse
|
|
199
242
|
MCP_SSE_HOST=127.0.0.1 # Safe default: loopback only
|
|
200
243
|
PORT=8000 # HTTP port (fallback for MCP_SSE_PORT)
|
|
@@ -202,30 +245,30 @@ MCP_SSE_ALLOWED_HOSTS= # Comma-separated allowed Host headers (default: localh
|
|
|
202
245
|
MCP_SSE_BEARER_TOKEN= # Optional; at least 32 characters
|
|
203
246
|
# Set only when an authenticated reverse proxy is the sole network entry point:
|
|
204
247
|
MCP_SSE_TRUST_PROXY_AUTH=false
|
|
205
|
-
|
|
206
|
-
# SSH Tunneling (Optional)
|
|
207
|
-
MYSQL_SSH_ENABLE=false # Set to true to enable
|
|
208
|
-
MYSQL_SSH_HOST= # SSH jump host
|
|
209
|
-
MYSQL_SSH_PORT=22 # SSH port
|
|
210
|
-
MYSQL_SSH_USER= # SSH username
|
|
211
|
-
MYSQL_SSH_KEY_PATH= # Path to SSH private key
|
|
212
|
-
MYSQL_SSH_REMOTE_HOST=localhost # Host from the perspective of the jump host
|
|
213
|
-
MYSQL_SSH_REMOTE_PORT=3306
|
|
248
|
+
|
|
249
|
+
# SSH Tunneling (Optional)
|
|
250
|
+
MYSQL_SSH_ENABLE=false # Set to true to enable
|
|
251
|
+
MYSQL_SSH_HOST= # SSH jump host
|
|
252
|
+
MYSQL_SSH_PORT=22 # SSH port
|
|
253
|
+
MYSQL_SSH_USER= # SSH username
|
|
254
|
+
MYSQL_SSH_KEY_PATH= # Path to SSH private key
|
|
255
|
+
MYSQL_SSH_REMOTE_HOST=localhost # Host from the perspective of the jump host
|
|
256
|
+
MYSQL_SSH_REMOTE_PORT=3306
|
|
214
257
|
MYSQL_LOCAL_PORT=0 # 0 selects a free port; the tunnel is reused
|
|
215
258
|
```
|
|
216
|
-
|
|
217
|
-
### `.env` file loading
|
|
218
|
-
|
|
219
|
-
On startup the server automatically loads a `.env` file via `python-dotenv`, so for local use you can simply:
|
|
220
|
-
|
|
221
|
-
```bash
|
|
222
|
-
cp .env.example .env # then edit with your credentials
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
The file is read from the **process working directory** (and parent directories), which works when you run the server yourself from the project folder.
|
|
226
|
-
|
|
227
|
-
> ⚠️ **Claude Code / Claude Desktop:** these hosts launch the server from their own working directory, so the project's `.env` will **not** be found and you'll see `Missing required database configuration`. Put your `MYSQL_*` values in the `env` block of the MCP config (shown in the Usage section below) rather than relying on `.env`.
|
|
228
|
-
|
|
259
|
+
|
|
260
|
+
### `.env` file loading
|
|
261
|
+
|
|
262
|
+
On startup the server automatically loads a `.env` file via `python-dotenv`, so for local use you can simply:
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
cp .env.example .env # then edit with your credentials
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
The file is read from the **process working directory** (and parent directories), which works when you run the server yourself from the project folder.
|
|
269
|
+
|
|
270
|
+
> ⚠️ **Claude Code / Claude Desktop:** these hosts launch the server from their own working directory, so the project's `.env` will **not** be found and you'll see `Missing required database configuration`. Put your `MYSQL_*` values in the `env` block of the MCP config (shown in the Usage section below) rather than relying on `.env`.
|
|
271
|
+
|
|
229
272
|
### Multi-database mode
|
|
230
273
|
|
|
231
274
|
When `MYSQL_DATABASE` is not set, the server operates in multi-database mode:
|
|
@@ -239,6 +282,9 @@ All tools are declared with `readOnlyHint=true` and `destructiveHint=false`.
|
|
|
239
282
|
|
|
240
283
|
### `list_connections`
|
|
241
284
|
Lists named profiles, default database, policy limits and readiness. It never returns hosts, usernames, passwords, or SSH key paths.
|
|
285
|
+
It also returns a `database_routes` index so clients can select the correct
|
|
286
|
+
profile when one environment is split across several database-specific
|
|
287
|
+
connections.
|
|
242
288
|
|
|
243
289
|
### `validate_connections`
|
|
244
290
|
Forces a configuration reload and reports valid/invalid profiles plus missing
|
|
@@ -271,123 +317,134 @@ Executes exactly one read-only statement.
|
|
|
271
317
|
- **Pagination:** JSON output includes `truncated` and `next_offset`; pass that value back as `offset`.
|
|
272
318
|
- **Formats:** `json` preserves structured rows and metadata; `csv` uses RFC-style quoting and explicit `NULL`.
|
|
273
319
|
- **Attribution:** `audit_context` supports `actor`, `purpose`, and `ticket_id`. A profile can require any of these fields before a connection is opened.
|
|
320
|
+
- **Transient connector recovery:** client-side Connector/Python failures with
|
|
321
|
+
`errno=-1` are retried once. Persistent failures report only a safe exception
|
|
322
|
+
type and lifecycle phase; connector messages are not exposed.
|
|
323
|
+
|
|
324
|
+
### `query`
|
|
325
|
+
Compatibility alias for `execute_sql` with the same schema and all the same
|
|
326
|
+
read-only, database allowlist, masking, timeout, pagination, and audit controls.
|
|
327
|
+
Stateful legacy tools such as `use_connection` and `use_database` are
|
|
328
|
+
intentionally not restored because process-global selection is unsafe with
|
|
329
|
+
concurrent MCP clients.
|
|
274
330
|
|
|
275
331
|
### `get_schema_info`
|
|
276
332
|
Provides detailed metadata about database structures.
|
|
277
333
|
- **Arguments:** `table_name`, `connection`, `database` (all optional)
|
|
278
|
-
- **Output:** Column names, types, nullability, default values, and comments.
|
|
279
|
-
- **Cross-database:** Pass `database.table` to query a table outside `MYSQL_DATABASE`; bare names use the configured database.
|
|
280
|
-
- **Identifier rules:** Names must contain only alphanumeric characters, underscores, and `$` (dots are allowed as a separator between database and table names).
|
|
281
|
-
|
|
334
|
+
- **Output:** Column names, types, nullability, default values, and comments.
|
|
335
|
+
- **Cross-database:** Pass `database.table` to query a table outside `MYSQL_DATABASE`; bare names use the configured database.
|
|
336
|
+
- **Identifier rules:** Names must contain only alphanumeric characters, underscores, and `$` (dots are allowed as a separator between database and table names).
|
|
337
|
+
|
|
282
338
|
### `get_table_sample`
|
|
283
339
|
Fetches a representative sample of data.
|
|
284
340
|
- **Arguments:** `table_name` (required), `limit` (optional integer, max 100), `offset`, `connection`, `database`, `timeout_ms`, `result_format`
|
|
285
|
-
- **Use Case:** Quickly understand data formats and content without fetching large result sets.
|
|
286
|
-
- **Cross-database:** Pass `database.table` to sample a table outside `MYSQL_DATABASE`; bare names use the configured database.
|
|
287
|
-
- **Identifier rules:** Names must contain only alphanumeric characters, underscores, and `$` (dots are allowed as a separator between database and table names).
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
341
|
+
- **Use Case:** Quickly understand data formats and content without fetching large result sets.
|
|
342
|
+
- **Cross-database:** Pass `database.table` to sample a table outside `MYSQL_DATABASE`; bare names use the configured database.
|
|
343
|
+
- **Identifier rules:** Names must contain only alphanumeric characters, underscores, and `$` (dots are allowed as a separator between database and table names).
|
|
344
|
+
- **Bounded execution:** Sampling applies `LIMIT limit+1 OFFSET offset` in
|
|
345
|
+
MySQL and fully consumes that small result. It does not open an unbounded
|
|
346
|
+
table scan merely to return a few rows.
|
|
347
|
+
|
|
348
|
+
## Available Prompts
|
|
349
|
+
|
|
350
|
+
In addition to tools, the server exposes **MCP prompts** — guided, multi-step workflows that a client can launch on demand. In Claude Code they appear as slash commands (`/mcp__<server>__<prompt>`); in Claude Desktop they appear in the prompts (`+`) menu.
|
|
351
|
+
|
|
352
|
+
| Prompt | Arguments | Description |
|
|
353
|
+
| --- | --- | --- |
|
|
295
354
|
| `explore_database` | `connection`, `database` *(optional)* | Systematically explore the selected database: discover tables, inspect schemas, sample data, and summarize it. |
|
|
296
355
|
| `analyze_table` | `table_name` *(required)*; `connection`, `database` *(optional)* | Deep-dive into a specific table. Accepts `database.table` notation. |
|
|
297
|
-
|
|
298
|
-
**Example (Claude Code):**
|
|
299
|
-
```
|
|
300
|
-
/mcp__mysql__explore_database
|
|
301
|
-
/mcp__mysql__analyze_table customers
|
|
302
|
-
```
|
|
303
|
-
|
|
356
|
+
|
|
357
|
+
**Example (Claude Code):**
|
|
358
|
+
```
|
|
359
|
+
/mcp__mysql__explore_database
|
|
360
|
+
/mcp__mysql__analyze_table customers
|
|
361
|
+
```
|
|
362
|
+
|
|
304
363
|
Both prompts orchestrate the read-only discovery, schema, and sampling tools.
|
|
305
|
-
|
|
306
|
-
## Usage
|
|
307
|
-
### With Claude Desktop
|
|
308
|
-
Add this to your `claude_desktop_config.json`:
|
|
309
|
-
```json
|
|
310
|
-
{
|
|
311
|
-
"mcpServers": {
|
|
312
|
-
"mysql": {
|
|
313
|
-
"command": "
|
|
314
|
-
"args": [
|
|
315
|
-
"--directory",
|
|
316
|
-
"path/to/mysql_mcp_server",
|
|
317
|
-
"run",
|
|
318
|
-
"mysql_mcp_server"
|
|
319
|
-
],
|
|
364
|
+
|
|
365
|
+
## Usage
|
|
366
|
+
### With Claude Desktop
|
|
367
|
+
Add this to your `claude_desktop_config.json`:
|
|
368
|
+
```json
|
|
369
|
+
{
|
|
370
|
+
"mcpServers": {
|
|
371
|
+
"mysql-readonly": {
|
|
372
|
+
"command": "npx",
|
|
373
|
+
"args": ["-y", "@yanzhang123/readonly-db-mcp@0.7.3"],
|
|
320
374
|
"env": {
|
|
321
375
|
"MYSQL_PROFILES_FILE": "C:/absolute/path/mysql-connections.toml",
|
|
322
376
|
"MYSQL_DEV_PASSWORD": "your_dev_password",
|
|
323
377
|
"MYSQL_PROD_PASSWORD": "your_prod_password"
|
|
324
378
|
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
For more detailed examples and agent-specific guidance, see [MCP_USECASES.md](MCP_USECASES.md).
|
|
331
|
-
|
|
332
|
-
### With Visual Studio Code
|
|
333
|
-
Add this to your `mcp.json`:
|
|
334
|
-
```json
|
|
335
|
-
{
|
|
336
|
-
"mcpServers": {
|
|
337
|
-
"mysql": {
|
|
338
|
-
"type": "stdio",
|
|
339
|
-
"command": "
|
|
340
|
-
"args": [
|
|
341
|
-
"--from",
|
|
342
|
-
"mysql-mcp-server",
|
|
343
|
-
"mysql_mcp_server"
|
|
344
|
-
],
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
For more detailed examples and agent-specific guidance, see [MCP_USECASES.md](MCP_USECASES.md).
|
|
385
|
+
|
|
386
|
+
### With Visual Studio Code
|
|
387
|
+
Add this to your `mcp.json`:
|
|
388
|
+
```json
|
|
389
|
+
{
|
|
390
|
+
"mcpServers": {
|
|
391
|
+
"mysql-readonly": {
|
|
392
|
+
"type": "stdio",
|
|
393
|
+
"command": "npx",
|
|
394
|
+
"args": ["-y", "@yanzhang123/readonly-db-mcp@0.7.3"],
|
|
345
395
|
"env": {
|
|
346
396
|
"MYSQL_PROFILES_FILE": "C:/absolute/path/mysql-connections.toml",
|
|
347
397
|
"MYSQL_DEV_PASSWORD": "your_dev_password",
|
|
348
398
|
"MYSQL_PROD_PASSWORD": "your_prod_password"
|
|
349
399
|
}
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Use `npx.cmd` instead of `npx` if required by your Windows MCP host.
|
|
406
|
+
|
|
407
|
+
### Debugging with MCP Inspector
|
|
408
|
+
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.
|
|
409
|
+
|
|
410
|
+
The MCP Inspector provides a convenient way to test and debug your MCP implementation:
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
# Install dependencies
|
|
414
|
+
pip install -r requirements.txt
|
|
415
|
+
# Use the MCP Inspector for debugging (do not run directly with Python)
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
The MySQL MCP Server is designed to be integrated with AI applications like Claude Desktop and should not be run directly as a standalone Python program.
|
|
419
|
+
|
|
420
|
+
## Development
|
|
421
|
+
```bash
|
|
422
|
+
# Clone the repository
|
|
372
423
|
git clone https://github.com/12zhangyan/mysql_mcp_server.git
|
|
373
|
-
cd mysql_mcp_server
|
|
374
|
-
# Create virtual environment
|
|
375
|
-
python -m venv venv
|
|
376
|
-
source venv/bin/activate
|
|
377
|
-
#
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
#
|
|
382
|
-
#
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
424
|
+
cd mysql_mcp_server
|
|
425
|
+
# Create virtual environment
|
|
426
|
+
python -m venv venv
|
|
427
|
+
# Linux/macOS: source venv/bin/activate
|
|
428
|
+
# Windows PowerShell: .\venv\Scripts\Activate.ps1
|
|
429
|
+
# Install development dependencies
|
|
430
|
+
pip install -r requirements-dev.txt
|
|
431
|
+
# Copy the example config and edit with your credentials
|
|
432
|
+
# Linux/macOS: cp .env.example .env
|
|
433
|
+
# Windows PowerShell: Copy-Item .env.example .env
|
|
434
|
+
# Edit .env with your MySQL connection details
|
|
435
|
+
# Run tests
|
|
436
|
+
pytest
|
|
437
|
+
```
|
|
438
|
+
|
|
386
439
|
## Security Considerations
|
|
387
440
|
- **Read-only SQL gate:** Only result-producing read statements are accepted; write/DDL/transaction/locking constructs are rejected before a connection is opened.
|
|
388
441
|
- **Database enforcement:** Every exposed query runs with `autocommit=false` in a read-only transaction. Normal completion rolls back; cancellation or truncation closes the socket and forces server-side rollback.
|
|
389
442
|
- **Write-capable credentials:** Read-only behavior does not depend on account grants. Unrecognized stored functions/UDFs, side-effecting functions, sequence advancement and locking reads are rejected because they can hide effects inside `SELECT`.
|
|
390
443
|
- **Database allowlist:** `allowed_databases` is enforced with a MySQL AST parser for tools and resource URIs; system schemas are blocked by default.
|
|
444
|
+
- **Controlled metadata:** User SQL cannot query `information_schema` by
|
|
445
|
+
default. Dedicated `list_tables` and `get_schema_info` operations use narrowly
|
|
446
|
+
scoped internal metadata queries, so catalog access does not become a general
|
|
447
|
+
system-schema bypass.
|
|
391
448
|
- **Resource limits:** Calls have full-operation, socket and server statement timeouts; at most 1000 rows are returned and oversized cells are truncated.
|
|
392
449
|
- **Cancellation:** Cancelling the MCP request closes the active connector socket. The worker does not continue silently after the response is abandoned.
|
|
393
450
|
- **Enterprise audit:** Versioned UTC JSONL events include an event ID, MCP request ID, operation, caller-supplied attribution, policy decision, target database, literal-free query fingerprint, duration, result size and outcome. SQL text and result data are never logged. Optional rotation, fsync, HMAC signatures, required context and fail-closed behavior are supported.
|
|
@@ -401,50 +458,50 @@ pytest
|
|
|
401
458
|
- **Diagnostic Privacy:** Connection diagnostics expose an account fingerprint and privilege summary, not raw usernames or `SHOW GRANTS`; configuration paths and database-supplied error text are redacted.
|
|
402
459
|
- **Least Privilege:** A dedicated `SELECT` account is recommended as additional defense, but it is not assumed by the MCP read-only enforcement. `check_connection` warns about broader grants without disabling the profile.
|
|
403
460
|
- **SSE is loopback-only by default.** Configure `MCP_SSE_BEARER_TOKEN` with at least 32 characters to enable built-in bearer authentication. A non-loopback bind is refused unless bearer authentication is enabled or `MCP_SSE_TRUST_PROXY_AUTH=true` explicitly confirms that an authenticated reverse proxy is the only network entry point. Example with nginx and HTTP Basic Auth:
|
|
404
|
-
|
|
405
|
-
```nginx
|
|
406
|
-
location /sse {
|
|
407
|
-
auth_basic "MCP";
|
|
408
|
-
auth_basic_user_file /etc/nginx/.htpasswd;
|
|
409
|
-
proxy_pass http://127.0.0.1:8000;
|
|
410
|
-
proxy_set_header Host $host;
|
|
411
|
-
proxy_buffering off;
|
|
412
|
-
}
|
|
413
|
-
location /messages/ {
|
|
414
|
-
auth_basic "MCP";
|
|
415
|
-
auth_basic_user_file /etc/nginx/.htpasswd;
|
|
416
|
-
proxy_pass http://127.0.0.1:8000;
|
|
417
|
-
proxy_set_header Host $host;
|
|
418
|
-
}
|
|
419
|
-
```
|
|
420
|
-
|
|
461
|
+
|
|
462
|
+
```nginx
|
|
463
|
+
location /sse {
|
|
464
|
+
auth_basic "MCP";
|
|
465
|
+
auth_basic_user_file /etc/nginx/.htpasswd;
|
|
466
|
+
proxy_pass http://127.0.0.1:8000;
|
|
467
|
+
proxy_set_header Host $host;
|
|
468
|
+
proxy_buffering off;
|
|
469
|
+
}
|
|
470
|
+
location /messages/ {
|
|
471
|
+
auth_basic "MCP";
|
|
472
|
+
auth_basic_user_file /etc/nginx/.htpasswd;
|
|
473
|
+
proxy_pass http://127.0.0.1:8000;
|
|
474
|
+
proxy_set_header Host $host;
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
421
478
|
Keep `MCP_SSE_HOST=127.0.0.1` so the proxy is the sole public entry point. If a container requires `0.0.0.0`, set `MCP_SSE_TRUST_PROXY_AUTH=true` only after network policy prevents direct access. Set `MCP_SSE_ALLOWED_HOSTS` to the hostname forwarded by the proxy.
|
|
422
479
|
|
|
423
480
|
See [SECURITY.md](SECURITY.md) and [ENTERPRISE_DEPLOYMENT.md](ENTERPRISE_DEPLOYMENT.md) for deployment and audit guidance.
|
|
424
481
|
Maintainers should follow [RELEASING.md](RELEASING.md) for synchronized Python/npm version releases.
|
|
425
|
-
|
|
426
|
-
## Security Best Practices
|
|
427
|
-
This MCP implementation requires database access to function. For security:
|
|
428
|
-
1. **
|
|
429
|
-
2. **Never use root credentials** or administrative accounts
|
|
430
|
-
3. **Restrict
|
|
431
|
-
4. **
|
|
432
|
-
5. **
|
|
433
|
-
|
|
482
|
+
|
|
483
|
+
## Security Best Practices
|
|
484
|
+
This MCP implementation requires database access to function. For security:
|
|
485
|
+
1. **Prefer a dedicated MySQL user** with `SELECT` only as defense in depth; MCP enforcement remains read-only even when broader credentials are supplied
|
|
486
|
+
2. **Never use root credentials** or administrative accounts
|
|
487
|
+
3. **Restrict `allowed_databases`** to the schemas each profile needs
|
|
488
|
+
4. **Require audit attribution** and protect the optional HMAC key in a secret manager
|
|
489
|
+
5. **Review masking patterns, audit events, dependency updates, and account grants regularly**
|
|
490
|
+
|
|
434
491
|
See [MySQL Security Configuration Guide](https://github.com/12zhangyan/mysql_mcp_server/blob/main/SECURITY.md) for detailed instructions on:
|
|
435
|
-
- Creating a restricted MySQL user
|
|
436
|
-
- Setting appropriate permissions
|
|
437
|
-
- Monitoring database access
|
|
438
|
-
- Security best practices
|
|
439
|
-
|
|
440
|
-
⚠️ IMPORTANT: Always follow the principle of least privilege when configuring database access.
|
|
441
|
-
|
|
442
|
-
## License
|
|
443
|
-
MIT License - see LICENSE file for details.
|
|
444
|
-
|
|
445
|
-
## Contributing
|
|
446
|
-
1. Fork the repository
|
|
447
|
-
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
448
|
-
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
449
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
450
|
-
5. Open a Pull Request
|
|
492
|
+
- Creating a restricted MySQL user
|
|
493
|
+
- Setting appropriate permissions
|
|
494
|
+
- Monitoring database access
|
|
495
|
+
- Security best practices
|
|
496
|
+
|
|
497
|
+
⚠️ IMPORTANT: Always follow the principle of least privilege when configuring database access.
|
|
498
|
+
|
|
499
|
+
## License
|
|
500
|
+
MIT License - see LICENSE file for details.
|
|
501
|
+
|
|
502
|
+
## Contributing
|
|
503
|
+
1. Fork the repository
|
|
504
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
505
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
506
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
507
|
+
5. Open a Pull Request
|
package/SECURITY.md
CHANGED
|
@@ -1,137 +1,137 @@
|
|
|
1
|
-
## MySQL Security Configuration
|
|
2
|
-
|
|
3
|
-
### Creating a Restricted MySQL User
|
|
4
|
-
|
|
5
|
-
It's crucial to create a dedicated MySQL user with minimal permissions for the MCP server. Never use the root account or a user with full administrative privileges.
|
|
6
|
-
|
|
7
|
-
#### 1. Create a new MySQL user
|
|
8
|
-
|
|
9
|
-
```sql
|
|
10
|
-
-- Connect as root or administrator
|
|
11
|
-
CREATE USER 'mcp_user'@'localhost' IDENTIFIED BY 'your_secure_password';
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
#### 2. Grant minimal required permissions
|
|
15
|
-
|
|
16
|
-
Basic read-only access (recommended for exploration and analysis):
|
|
17
|
-
```sql
|
|
18
|
-
-- Grant SELECT permission only
|
|
19
|
-
GRANT SELECT ON your_database.* TO 'mcp_user'@'localhost';
|
|
20
|
-
```
|
|
21
|
-
|
|
1
|
+
## MySQL Security Configuration
|
|
2
|
+
|
|
3
|
+
### Creating a Restricted MySQL User
|
|
4
|
+
|
|
5
|
+
It's crucial to create a dedicated MySQL user with minimal permissions for the MCP server. Never use the root account or a user with full administrative privileges.
|
|
6
|
+
|
|
7
|
+
#### 1. Create a new MySQL user
|
|
8
|
+
|
|
9
|
+
```sql
|
|
10
|
+
-- Connect as root or administrator
|
|
11
|
+
CREATE USER 'mcp_user'@'localhost' IDENTIFIED BY 'your_secure_password';
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
#### 2. Grant minimal required permissions
|
|
15
|
+
|
|
16
|
+
Basic read-only access (recommended for exploration and analysis):
|
|
17
|
+
```sql
|
|
18
|
+
-- Grant SELECT permission only
|
|
19
|
+
GRANT SELECT ON your_database.* TO 'mcp_user'@'localhost';
|
|
20
|
+
```
|
|
21
|
+
|
|
22
22
|
Do not grant `INSERT`, `UPDATE`, `DELETE`, DDL, routine execution, file, lock, or
|
|
23
23
|
temporary-table privileges to the MCP account. The server rejects those operations,
|
|
24
24
|
and MySQL permissions provide the final security boundary.
|
|
25
|
-
|
|
26
|
-
#### 3. Apply the permissions
|
|
27
|
-
```sql
|
|
28
|
-
FLUSH PRIVILEGES;
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### Additional Security Measures
|
|
32
|
-
|
|
33
|
-
1. **Network Access**
|
|
34
|
-
- Restrict the user to connecting only from localhost if the MCP server runs on the same machine
|
|
35
|
-
- If remote access is needed, specify exact IP addresses rather than using wildcards
|
|
36
|
-
|
|
37
|
-
2. **Query Restrictions**
|
|
38
|
-
- Consider using VIEWs to further restrict data access
|
|
25
|
+
|
|
26
|
+
#### 3. Apply the permissions
|
|
27
|
+
```sql
|
|
28
|
+
FLUSH PRIVILEGES;
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Additional Security Measures
|
|
32
|
+
|
|
33
|
+
1. **Network Access**
|
|
34
|
+
- Restrict the user to connecting only from localhost if the MCP server runs on the same machine
|
|
35
|
+
- If remote access is needed, specify exact IP addresses rather than using wildcards
|
|
36
|
+
|
|
37
|
+
2. **Query Restrictions**
|
|
38
|
+
- Consider using VIEWs to further restrict data access
|
|
39
39
|
- Set an appropriate `max_queries_per_hour` limit:
|
|
40
|
-
```sql
|
|
41
|
-
ALTER USER 'mcp_user'@'localhost'
|
|
40
|
+
```sql
|
|
41
|
+
ALTER USER 'mcp_user'@'localhost'
|
|
42
42
|
WITH MAX_QUERIES_PER_HOUR 1000;
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
3. **Data Access Control**
|
|
46
|
-
- Grant access only to specific tables when possible
|
|
47
|
-
- Use column-level permissions for sensitive data:
|
|
48
|
-
```sql
|
|
49
|
-
GRANT SELECT (public_column1, public_column2)
|
|
50
|
-
ON your_database.sensitive_table TO 'mcp_user'@'localhost';
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
4. **Regular Auditing**
|
|
54
|
-
- Enable MySQL audit logging for the MCP user
|
|
55
|
-
- Regularly review logs for unusual patterns
|
|
56
|
-
- Periodically review and adjust permissions
|
|
57
|
-
|
|
58
|
-
### Environment Configuration
|
|
59
|
-
|
|
60
|
-
When setting up the MCP server, use these restricted credentials in your environment:
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
MYSQL_USER=mcp_user
|
|
64
|
-
MYSQL_PASSWORD=your_secure_password
|
|
65
|
-
MYSQL_DATABASE=your_database
|
|
66
|
-
MYSQL_HOST=localhost
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Monitoring Usage
|
|
70
|
-
|
|
71
|
-
To monitor the MCP user's database usage:
|
|
72
|
-
|
|
73
|
-
```sql
|
|
74
|
-
-- Check current connections
|
|
75
|
-
SELECT * FROM information_schema.PROCESSLIST
|
|
76
|
-
WHERE user = 'mcp_user';
|
|
77
|
-
|
|
78
|
-
-- View user privileges
|
|
79
|
-
SHOW GRANTS FOR 'mcp_user'@'localhost';
|
|
80
|
-
|
|
81
|
-
-- Check resource limits
|
|
82
|
-
SELECT * FROM mysql.user
|
|
83
|
-
WHERE user = 'mcp_user' AND host = 'localhost';
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Best Practices
|
|
87
|
-
|
|
88
|
-
1. **Regular Password Rotation**
|
|
89
|
-
- Change the MCP user's password periodically
|
|
90
|
-
- Use strong, randomly generated passwords
|
|
91
|
-
- Update application configurations after password changes
|
|
92
|
-
|
|
93
|
-
2. **Permission Review**
|
|
94
|
-
- Regularly audit granted permissions
|
|
95
|
-
- Remove unnecessary privileges
|
|
96
|
-
- Keep permissions as restrictive as possible
|
|
97
|
-
|
|
98
|
-
3. **Access Patterns**
|
|
99
|
-
- Monitor query patterns for potential issues
|
|
100
|
-
- Set up alerts for unusual activity
|
|
101
|
-
- Maintain detailed logs of database access
|
|
102
|
-
|
|
103
|
-
4. **Data Protection**
|
|
104
|
-
- Consider encrypting sensitive columns
|
|
105
|
-
- Use SSL/TLS for database connections (see **SSL/TLS Support** below)
|
|
106
|
-
- Implement data masking where appropriate
|
|
107
|
-
|
|
108
|
-
### Secure Remote Access (SSH Tunneling)
|
|
109
|
-
|
|
110
|
-
If your MySQL server is not on the same network as the MCP server, **do not expose MySQL directly to the internet.** Instead, use the built-in SSH tunneling support:
|
|
111
|
-
|
|
112
|
-
1. Enable SSH tunneling by setting `MYSQL_SSH_ENABLE=true`.
|
|
113
|
-
2. Configure your SSH jump host credentials and private key path.
|
|
114
|
-
3. The MCP server will establish a secure encrypted tunnel and connect to MySQL over `localhost`, keeping your database port closed to the outside world.
|
|
115
|
-
|
|
116
|
-
### SSL/TLS Support
|
|
117
|
-
|
|
118
|
-
For production environments, always encrypt the connection between the MCP server and MySQL.
|
|
119
|
-
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
3. **Data Access Control**
|
|
46
|
+
- Grant access only to specific tables when possible
|
|
47
|
+
- Use column-level permissions for sensitive data:
|
|
48
|
+
```sql
|
|
49
|
+
GRANT SELECT (public_column1, public_column2)
|
|
50
|
+
ON your_database.sensitive_table TO 'mcp_user'@'localhost';
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
4. **Regular Auditing**
|
|
54
|
+
- Enable MySQL audit logging for the MCP user
|
|
55
|
+
- Regularly review logs for unusual patterns
|
|
56
|
+
- Periodically review and adjust permissions
|
|
57
|
+
|
|
58
|
+
### Environment Configuration
|
|
59
|
+
|
|
60
|
+
When setting up the MCP server, use these restricted credentials in your environment:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
MYSQL_USER=mcp_user
|
|
64
|
+
MYSQL_PASSWORD=your_secure_password
|
|
65
|
+
MYSQL_DATABASE=your_database
|
|
66
|
+
MYSQL_HOST=localhost
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Monitoring Usage
|
|
70
|
+
|
|
71
|
+
To monitor the MCP user's database usage:
|
|
72
|
+
|
|
73
|
+
```sql
|
|
74
|
+
-- Check current connections
|
|
75
|
+
SELECT * FROM information_schema.PROCESSLIST
|
|
76
|
+
WHERE user = 'mcp_user';
|
|
77
|
+
|
|
78
|
+
-- View user privileges
|
|
79
|
+
SHOW GRANTS FOR 'mcp_user'@'localhost';
|
|
80
|
+
|
|
81
|
+
-- Check resource limits
|
|
82
|
+
SELECT * FROM mysql.user
|
|
83
|
+
WHERE user = 'mcp_user' AND host = 'localhost';
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Best Practices
|
|
87
|
+
|
|
88
|
+
1. **Regular Password Rotation**
|
|
89
|
+
- Change the MCP user's password periodically
|
|
90
|
+
- Use strong, randomly generated passwords
|
|
91
|
+
- Update application configurations after password changes
|
|
92
|
+
|
|
93
|
+
2. **Permission Review**
|
|
94
|
+
- Regularly audit granted permissions
|
|
95
|
+
- Remove unnecessary privileges
|
|
96
|
+
- Keep permissions as restrictive as possible
|
|
97
|
+
|
|
98
|
+
3. **Access Patterns**
|
|
99
|
+
- Monitor query patterns for potential issues
|
|
100
|
+
- Set up alerts for unusual activity
|
|
101
|
+
- Maintain detailed logs of database access
|
|
102
|
+
|
|
103
|
+
4. **Data Protection**
|
|
104
|
+
- Consider encrypting sensitive columns
|
|
105
|
+
- Use SSL/TLS for database connections (see **SSL/TLS Support** below)
|
|
106
|
+
- Implement data masking where appropriate
|
|
107
|
+
|
|
108
|
+
### Secure Remote Access (SSH Tunneling)
|
|
109
|
+
|
|
110
|
+
If your MySQL server is not on the same network as the MCP server, **do not expose MySQL directly to the internet.** Instead, use the built-in SSH tunneling support:
|
|
111
|
+
|
|
112
|
+
1. Enable SSH tunneling by setting `MYSQL_SSH_ENABLE=true`.
|
|
113
|
+
2. Configure your SSH jump host credentials and private key path.
|
|
114
|
+
3. The MCP server will establish a secure encrypted tunnel and connect to MySQL over `localhost`, keeping your database port closed to the outside world.
|
|
115
|
+
|
|
116
|
+
### SSL/TLS Support
|
|
117
|
+
|
|
118
|
+
For production environments, always encrypt the connection between the MCP server and MySQL.
|
|
119
|
+
|
|
120
120
|
Use the `MYSQL_SSL_MODE` environment variable to control encryption:
|
|
121
121
|
- `DISABLED`: Allows plaintext only when explicitly selected; do not use in production.
|
|
122
122
|
- `REQUIRED`: Ensures the connection is encrypted.
|
|
123
|
-
- `VERIFY_CA`: Encrypts and verifies the server's certificate against a CA.
|
|
124
|
-
- `VERIFY_IDENTITY`: Encrypts and verifies that the server's hostname matches the certificate.
|
|
125
|
-
|
|
123
|
+
- `VERIFY_CA`: Encrypts and verifies the server's certificate against a CA.
|
|
124
|
+
- `VERIFY_IDENTITY`: Encrypts and verifies that the server's hostname matches the certificate.
|
|
125
|
+
|
|
126
126
|
`REQUIRED` is the default, and the MCP verifies after connection that the
|
|
127
127
|
connector reports an encrypted session. Specify the CA certificate path using
|
|
128
128
|
`MYSQL_SSL_CA` when using either verification mode.
|
|
129
|
-
|
|
129
|
+
|
|
130
130
|
### SQL Injection Protection
|
|
131
|
-
|
|
132
|
-
The MCP server includes built-in protection against SQL injection for administrative operations:
|
|
133
|
-
- All database and table identifiers provided via resources or tool arguments are strictly validated against a regex whitelist (`^[a-zA-Z0-9_$]+$`).
|
|
134
|
-
- Identifiers are automatically quoted with backticks in internal queries.
|
|
131
|
+
|
|
132
|
+
The MCP server includes built-in protection against SQL injection for administrative operations:
|
|
133
|
+
- All database and table identifiers provided via resources or tool arguments are strictly validated against a regex whitelist (`^[a-zA-Z0-9_$]+$`).
|
|
134
|
+
- Identifiers are automatically quoted with backticks in internal queries.
|
|
135
135
|
- `execute_sql` uses a lexer-style guard that ignores ordinary strings and comments but rejects MySQL `/*!...*/` and MariaDB `/*M!...*/` executable comments, multiple statements, DML, DDL, locks, transactions, `SELECT INTO`, and session assignment.
|
|
136
136
|
- Stored functions and UDFs are fail-closed unless sqlglot recognizes them as a
|
|
137
137
|
built-in or their reviewed name is explicitly listed in `allowed_functions`.
|
|
Binary file
|
package/package.json
CHANGED
|
Binary file
|