@futuretea/mysql-mcp-server 0.0.2 → 0.1.0
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/README.md +68 -13
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -13,8 +13,12 @@ support writes, administration, backups, replication, or dynamic targets.
|
|
|
13
13
|
make build
|
|
14
14
|
./bin/mysql-mcp-server version
|
|
15
15
|
|
|
16
|
-
# Set
|
|
17
|
-
export
|
|
16
|
+
# Set these only in the runtime environment. Do not commit the password.
|
|
17
|
+
export MYSQL_MCP_HOST='127.0.0.1'
|
|
18
|
+
export MYSQL_MCP_DB_PORT='3306'
|
|
19
|
+
export MYSQL_MCP_USERNAME='readonly'
|
|
20
|
+
export MYSQL_MCP_PASSWORD='<runtime-secret>'
|
|
21
|
+
export MYSQL_MCP_DATABASE='inventory'
|
|
18
22
|
|
|
19
23
|
# Start MCP server (stdio, default)
|
|
20
24
|
./bin/mysql-mcp-server mcp
|
|
@@ -52,8 +56,10 @@ blocked session/file functions. Accepted queries run in a read-only transaction
|
|
|
52
56
|
that is always rolled back.
|
|
53
57
|
|
|
54
58
|
This is not proof that stored functions, UDFs, views, or plugins have no side
|
|
55
|
-
effects. Use a least-privilege account
|
|
56
|
-
`
|
|
59
|
+
effects. Use a least-privilege account. Startup rejects `EXECUTE`, schema-wide `ALL`, `FILE`,
|
|
60
|
+
`SHOW_ROUTINE`, grants on the `mysql` schema, global `SELECT`, and other
|
|
61
|
+
administrative privileges unless `allow_unsafe_database_role` is set. See
|
|
62
|
+
[Service account](#service-account).
|
|
57
63
|
|
|
58
64
|
## CLI commands
|
|
59
65
|
|
|
@@ -92,7 +98,14 @@ Cursor / Claude Desktop style config:
|
|
|
92
98
|
"mcpServers": {
|
|
93
99
|
"mysql-mcp-server": {
|
|
94
100
|
"command": "/absolute/path/to/bin/mysql-mcp-server",
|
|
95
|
-
"args": ["mcp"]
|
|
101
|
+
"args": ["mcp"],
|
|
102
|
+
"env": {
|
|
103
|
+
"MYSQL_MCP_HOST": "127.0.0.1",
|
|
104
|
+
"MYSQL_MCP_DB_PORT": "3306",
|
|
105
|
+
"MYSQL_MCP_USERNAME": "readonly",
|
|
106
|
+
"MYSQL_MCP_PASSWORD": "<runtime-secret>",
|
|
107
|
+
"MYSQL_MCP_DATABASE": "inventory"
|
|
108
|
+
}
|
|
96
109
|
}
|
|
97
110
|
}
|
|
98
111
|
}
|
|
@@ -139,10 +152,16 @@ Same process as HTTP mode. Endpoints:
|
|
|
139
152
|
make docker
|
|
140
153
|
|
|
141
154
|
# Stdio (default ENTRYPOINT is `mysql-mcp-server mcp`)
|
|
142
|
-
docker run -i --rm
|
|
155
|
+
docker run -i --rm \
|
|
156
|
+
-e MYSQL_MCP_HOST -e MYSQL_MCP_DB_PORT -e MYSQL_MCP_USERNAME \
|
|
157
|
+
-e MYSQL_MCP_PASSWORD -e MYSQL_MCP_DATABASE \
|
|
158
|
+
ghcr.io/futuretea/mysql-mcp-server:dev
|
|
143
159
|
|
|
144
160
|
# HTTP
|
|
145
|
-
docker run --rm
|
|
161
|
+
docker run --rm \
|
|
162
|
+
-e MYSQL_MCP_HOST -e MYSQL_MCP_DB_PORT -e MYSQL_MCP_USERNAME \
|
|
163
|
+
-e MYSQL_MCP_PASSWORD -e MYSQL_MCP_DATABASE \
|
|
164
|
+
-p 8080:8080 ghcr.io/futuretea/mysql-mcp-server:dev --port 8080 --listen 0.0.0.0
|
|
146
165
|
```
|
|
147
166
|
|
|
148
167
|
HTTP / SSE have **no auth and no TLS**. Default `--listen 127.0.0.1`. Use only on trusted networks; put a reverse proxy in front if you expose the port.
|
|
@@ -155,11 +174,39 @@ Priority: **flags > environment variables > config file > defaults**.
|
|
|
155
174
|
|
|
156
175
|
| Variable | Description | Default |
|
|
157
176
|
|----------|-------------|---------|
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
162
|
-
| `
|
|
177
|
+
| `MYSQL_MCP_LOG_LEVEL` | Log level | `info` |
|
|
178
|
+
| `MYSQL_MCP_PORT` | MCP HTTP port (`0` = stdio) | `0` |
|
|
179
|
+
| `MYSQL_MCP_LISTEN` | MCP HTTP listen host | `127.0.0.1` |
|
|
180
|
+
| `MYSQL_MCP_SSE_BASE_URL` | Public SSE base URL | `""` |
|
|
181
|
+
| `MYSQL_MCP_HOST` | MySQL TCP host | `127.0.0.1` |
|
|
182
|
+
| `MYSQL_MCP_DB_PORT` | MySQL TCP port; distinct from `MYSQL_MCP_PORT` | `3306` |
|
|
183
|
+
| `MYSQL_MCP_USERNAME` | Required MySQL username | none |
|
|
184
|
+
| `MYSQL_MCP_PASSWORD` | Optional MySQL password; never logged or returned | none |
|
|
185
|
+
| `MYSQL_MCP_DATABASE` | Optional default MySQL database | none |
|
|
186
|
+
| `MYSQL_MCP_ALLOW_UNSAFE_DATABASE_ROLE` | Skip only the startup unsafe-privilege rejection | `false` |
|
|
187
|
+
|
|
188
|
+
### Service account
|
|
189
|
+
|
|
190
|
+
After the process connects, and before any tool runs SQL, startup reads `SHOW GRANTS` for the current account. Plain `SHOW GRANTS` includes mandatory roles; `SHOW GRANTS FOR CURRENT_USER()` does not. Privileges inherited through those roles and through explicitly granted roles are expanded before any tool runs. The process exits with `[mysql_unsafe_service_role]` when the account has any of:
|
|
191
|
+
|
|
192
|
+
- `SUPER`, `FILE`, `PROCESS`, `SHUTDOWN`, `RELOAD`, `CREATE USER`, `CREATE TABLESPACE`, or `PROXY`
|
|
193
|
+
- `CREATE ROLE`, `DROP ROLE`, or `EXECUTE`
|
|
194
|
+
- `REPLICATION SLAVE` or `REPLICATION CLIENT`
|
|
195
|
+
- `SHOW_ROUTINE` or `RESOURCE_GROUP_USER`
|
|
196
|
+
- global `SELECT`, `ALL`, or `ALL PRIVILEGES` (`ON *.*`)
|
|
197
|
+
- schema-wide `ALL` or `ALL PRIVILEGES` (`ON db.*`). MySQL stores `EXECUTE` on that database privilege row and `SHOW GRANTS` keeps the shorthand, so the word `EXECUTE` never appears. `ALL` on one table (`ON db.table`) does not include `EXECUTE`
|
|
198
|
+
- any privilege on the `mysql` schema, including `SELECT` on `mysql.user`
|
|
199
|
+
- MySQL 8 dynamic privileges that replace `SUPER` or administer the server, including `SYSTEM_VARIABLES_ADMIN`, `SESSION_VARIABLES_ADMIN`, `CONNECTION_ADMIN`, `TP_CONNECTION_ADMIN`, `SYSTEM_USER`, `ROLE_ADMIN`, `BINLOG_ADMIN`, `REPLICATION_SLAVE_ADMIN`, `SET_USER_ID`, `ALLOW_NONEXISTENT_DEFINER`, `BACKUP_ADMIN`, `CLONE_ADMIN`, `FLUSH_PRIVILEGES`, `FLUSH_TABLES`, `FIREWALL_ADMIN`, `OPTIMIZE_LOCAL_TABLE`, and `VERSION_TOKEN_ADMIN`
|
|
200
|
+
|
|
201
|
+
`USAGE` plus `SELECT` on an application schema starts with the default configuration. No opt-out is required. `SELECT` on `*.*` does not start: that grant includes the `mysql` grant tables. An expanded database privilege list that does not include `EXECUTE` also starts. A routine call then fails in MySQL rather than at startup.
|
|
202
|
+
|
|
203
|
+
A view created by a DBA with `SQL SECURITY DEFINER` is published schema. An account that can `SELECT` the view can read its output, including a `mysql.user` count or a function result, without holding `EXECUTE`. Startup does not classify that body. For this account `VIEW_DEFINITION` is empty and `SHOW CREATE VIEW` is denied, so the check cannot tell a normal default-definer application view from one that publishes catalog data. Do not publish a definer view that exposes data the service account should not see. That boundary is not a substitute for rejecting `EXECUTE` or schema-wide `ALL`.
|
|
204
|
+
|
|
205
|
+
Startup allows 5 seconds for the TCP connection and the grant probe. A server that does not answer in that time stops startup. `allow_unsafe_database_role` does not extend the deadline.
|
|
206
|
+
|
|
207
|
+
`allow_unsafe_database_role` defaults to `false`. Set it to `true` in the config file, or export `MYSQL_MCP_ALLOW_UNSAFE_DATABASE_ROLE=true`, only when you cannot provision a least-privilege account. The server logs a warning and skips this privilege rejection. A refused connection, a failed grant probe, a startup timeout, and every other startup check still stop startup. Queries still run in a read-only transaction, but that transaction does not constrain `FILE`, `SHUTDOWN`, `SUPER`, replication privileges, `PROXY`, `EXECUTE`, or the dynamic privileges above. Enable the option only for a MySQL instance you control.
|
|
208
|
+
|
|
209
|
+
Stdio MCP and `tools call` keep logs at error level so protocol output stays intact. The opt-out warning is emitted at warn level and is visible in HTTP mode at the default `info` level.
|
|
163
210
|
|
|
164
211
|
### Config file
|
|
165
212
|
|
|
@@ -174,6 +221,7 @@ enabled_tools: []
|
|
|
174
221
|
disabled_tools: []
|
|
175
222
|
enabled_domains: []
|
|
176
223
|
disabled_domains: []
|
|
224
|
+
allow_unsafe_database_role: false
|
|
177
225
|
```
|
|
178
226
|
|
|
179
227
|
```bash
|
|
@@ -240,7 +288,14 @@ Configure an MCP client that supports stdio with npm:
|
|
|
240
288
|
"mcpServers": {
|
|
241
289
|
"mysql-mcp-server": {
|
|
242
290
|
"command": "npx",
|
|
243
|
-
"args": ["-y", "@futuretea/mysql-mcp-server@<version>"]
|
|
291
|
+
"args": ["-y", "@futuretea/mysql-mcp-server@<version>"],
|
|
292
|
+
"env": {
|
|
293
|
+
"MYSQL_MCP_HOST": "127.0.0.1",
|
|
294
|
+
"MYSQL_MCP_DB_PORT": "3306",
|
|
295
|
+
"MYSQL_MCP_USERNAME": "readonly",
|
|
296
|
+
"MYSQL_MCP_PASSWORD": "<runtime-secret>",
|
|
297
|
+
"MYSQL_MCP_DATABASE": "inventory"
|
|
298
|
+
}
|
|
244
299
|
}
|
|
245
300
|
}
|
|
246
301
|
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@futuretea/mysql-mcp-server",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "MCP server binary launcher",
|
|
5
5
|
"main": "./bin/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"mysql-mcp-server": "bin/index.js"
|
|
8
8
|
},
|
|
9
9
|
"optionalDependencies": {
|
|
10
|
-
"@futuretea/mysql-mcp-server-darwin-amd64": "0.0
|
|
11
|
-
"@futuretea/mysql-mcp-server-darwin-arm64": "0.0
|
|
12
|
-
"@futuretea/mysql-mcp-server-linux-amd64": "0.0
|
|
13
|
-
"@futuretea/mysql-mcp-server-linux-arm64": "0.0
|
|
14
|
-
"@futuretea/mysql-mcp-server-windows-amd64": "0.0
|
|
10
|
+
"@futuretea/mysql-mcp-server-darwin-amd64": "0.1.0",
|
|
11
|
+
"@futuretea/mysql-mcp-server-darwin-arm64": "0.1.0",
|
|
12
|
+
"@futuretea/mysql-mcp-server-linux-amd64": "0.1.0",
|
|
13
|
+
"@futuretea/mysql-mcp-server-linux-arm64": "0.1.0",
|
|
14
|
+
"@futuretea/mysql-mcp-server-windows-amd64": "0.1.0"
|
|
15
15
|
},
|
|
16
16
|
"license": "MIT"
|
|
17
17
|
}
|