@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.
Files changed (2) hide show
  1. package/README.md +68 -13
  2. 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 this only in the runtime environment. Do not commit it.
17
- export MYSQL_DSN='<runtime-dsn>'
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; do not grant `EXECUTE`, `FILE`,
56
- `LOCK TABLES`, or administrative privileges.
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 -e MYSQL_DSN ghcr.io/futuretea/mysql-mcp-server:dev
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 -e MYSQL_DSN -p 8080:8080 ghcr.io/futuretea/mysql-mcp-server:dev --port 8080 --listen 0.0.0.0
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
- | `MCP_LOG_LEVEL` | Log level | `info` |
159
- | `MCP_PORT` | HTTP port (`0` = stdio) | `0` |
160
- | `MCP_LISTEN` | HTTP listen host | `127.0.0.1` |
161
- | `MCP_SSE_BASE_URL` | Public SSE base URL | `""` |
162
- | `MYSQL_DSN` | Required single MySQL runtime DSN; never logged or returned | none |
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.2",
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.2",
11
- "@futuretea/mysql-mcp-server-darwin-arm64": "0.0.2",
12
- "@futuretea/mysql-mcp-server-linux-amd64": "0.0.2",
13
- "@futuretea/mysql-mcp-server-linux-arm64": "0.0.2",
14
- "@futuretea/mysql-mcp-server-windows-amd64": "0.0.2"
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
  }