mysql-db-mcp 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 +374 -0
- package/dist/config.d.ts +26 -0
- package/dist/config.js +83 -0
- package/dist/config.js.map +1 -0
- package/dist/db/MySqlClient.d.ts +16 -0
- package/dist/db/MySqlClient.js +115 -0
- package/dist/db/MySqlClient.js.map +1 -0
- package/dist/db/MySqlPool.d.ts +3 -0
- package/dist/db/MySqlPool.js +36 -0
- package/dist/db/MySqlPool.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +6 -0
- package/dist/logger.js +53 -0
- package/dist/logger.js.map +1 -0
- package/dist/security.d.ts +17 -0
- package/dist/security.js +165 -0
- package/dist/security.js.map +1 -0
- package/dist/tools/alterTableAddColumn.d.ts +3 -0
- package/dist/tools/alterTableAddColumn.js +49 -0
- package/dist/tools/alterTableAddColumn.js.map +1 -0
- package/dist/tools/alterTableAddIndex.d.ts +3 -0
- package/dist/tools/alterTableAddIndex.js +46 -0
- package/dist/tools/alterTableAddIndex.js.map +1 -0
- package/dist/tools/alterTableDropColumn.d.ts +3 -0
- package/dist/tools/alterTableDropColumn.js +36 -0
- package/dist/tools/alterTableDropColumn.js.map +1 -0
- package/dist/tools/alterTableDropIndex.d.ts +3 -0
- package/dist/tools/alterTableDropIndex.js +33 -0
- package/dist/tools/alterTableDropIndex.js.map +1 -0
- package/dist/tools/alterTableModifyColumn.d.ts +3 -0
- package/dist/tools/alterTableModifyColumn.js +46 -0
- package/dist/tools/alterTableModifyColumn.js.map +1 -0
- package/dist/tools/alterTableRenameColumn.d.ts +3 -0
- package/dist/tools/alterTableRenameColumn.js +38 -0
- package/dist/tools/alterTableRenameColumn.js.map +1 -0
- package/dist/tools/describeTable.d.ts +3 -0
- package/dist/tools/describeTable.js +18 -0
- package/dist/tools/describeTable.js.map +1 -0
- package/dist/tools/explainSelect.d.ts +3 -0
- package/dist/tools/explainSelect.js +18 -0
- package/dist/tools/explainSelect.js.map +1 -0
- package/dist/tools/insertRow.d.ts +3 -0
- package/dist/tools/insertRow.js +30 -0
- package/dist/tools/insertRow.js.map +1 -0
- package/dist/tools/insertRows.d.ts +3 -0
- package/dist/tools/insertRows.js +40 -0
- package/dist/tools/insertRows.js.map +1 -0
- package/dist/tools/listSchemas.d.ts +3 -0
- package/dist/tools/listSchemas.js +7 -0
- package/dist/tools/listSchemas.js.map +1 -0
- package/dist/tools/listTables.d.ts +3 -0
- package/dist/tools/listTables.js +16 -0
- package/dist/tools/listTables.js.map +1 -0
- package/dist/tools/querySelect.d.ts +3 -0
- package/dist/tools/querySelect.js +20 -0
- package/dist/tools/querySelect.js.map +1 -0
- package/dist/tools/shared.d.ts +43 -0
- package/dist/tools/shared.js +113 -0
- package/dist/tools/shared.js.map +1 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
# mysql-db-mcp
|
|
2
|
+
|
|
3
|
+
A secure MySQL database MCP Server for reading schemas, tables, columns, running SELECT queries, running EXPLAIN, and optionally performing structured inserts and controlled table DDL.
|
|
4
|
+
|
|
5
|
+
The default mode is read-only:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
MYSQL_ENABLE_WRITE=false
|
|
9
|
+
MYSQL_ENABLE_DDL=false
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
No arbitrary `execute_sql`, `execute_write`, or `execute_ddl` tool is provided. Write and DDL operations are only available through structured tool parameters, so identifiers can be validated, values can use MySQL parameter binding, and high-risk operations can require explicit confirmation.
|
|
13
|
+
|
|
14
|
+
## Tools
|
|
15
|
+
|
|
16
|
+
Read-only tools enabled by default:
|
|
17
|
+
|
|
18
|
+
- `list_schemas`
|
|
19
|
+
- `list_tables`
|
|
20
|
+
- `describe_table`
|
|
21
|
+
- `query_select`
|
|
22
|
+
- `explain_select`
|
|
23
|
+
|
|
24
|
+
Write tools disabled by default:
|
|
25
|
+
|
|
26
|
+
- `insert_row`
|
|
27
|
+
- `insert_rows`
|
|
28
|
+
|
|
29
|
+
DDL tools disabled by default:
|
|
30
|
+
|
|
31
|
+
- `alter_table_add_column`
|
|
32
|
+
- `alter_table_modify_column`
|
|
33
|
+
- `alter_table_drop_column`
|
|
34
|
+
- `alter_table_rename_column`
|
|
35
|
+
- `alter_table_add_index`
|
|
36
|
+
- `alter_table_drop_index`
|
|
37
|
+
|
|
38
|
+
## Environment Variables
|
|
39
|
+
|
|
40
|
+
| Variable | Default | Description |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| `MYSQL_HOST` | `127.0.0.1` | MySQL host |
|
|
43
|
+
| `MYSQL_PORT` | `3306` | MySQL port |
|
|
44
|
+
| `MYSQL_USER` | `root` | MySQL user |
|
|
45
|
+
| `MYSQL_PASSWORD` | empty | MySQL password |
|
|
46
|
+
| `MYSQL_DATABASE` | unset | Default schema |
|
|
47
|
+
| `MYSQL_SSL` | `false` | Enable mysql2 SSL option |
|
|
48
|
+
| `MYSQL_CONNECTION_LIMIT` | `10` | Pool connection limit |
|
|
49
|
+
| `MYSQL_MAX_ROWS` | `200` | Maximum returned SELECT rows |
|
|
50
|
+
| `MYSQL_ENABLE_WRITE` | `false` | Enables `insert_row` and `insert_rows` |
|
|
51
|
+
| `MYSQL_ENABLE_DDL` | `false` | Enables controlled ALTER TABLE tools |
|
|
52
|
+
| `MYSQL_WRITE_ALLOWED_SCHEMAS` | unset | Comma-separated schemas allowed for writes |
|
|
53
|
+
| `MYSQL_WRITE_ALLOWED_TABLES` | unset | Comma-separated tables allowed for writes |
|
|
54
|
+
| `MYSQL_DDL_ALLOWED_SCHEMAS` | unset | Comma-separated schemas allowed for DDL |
|
|
55
|
+
| `MYSQL_DDL_ALLOWED_TABLES` | unset | Comma-separated tables allowed for DDL |
|
|
56
|
+
| `MYSQL_BLOCKED_TABLES` | unset | Extra comma-separated blocked tables |
|
|
57
|
+
| `MYSQL_MAX_INSERT_ROWS` | `100` | Max rows for `insert_rows` |
|
|
58
|
+
| `MYSQL_REQUIRE_CONFIRMATION` | `true` | Requires `confirm: true` for write and DDL tools |
|
|
59
|
+
|
|
60
|
+
System schemas are always blocked: `mysql`, `information_schema`, `performance_schema`, and `sys`.
|
|
61
|
+
|
|
62
|
+
## Install And Run
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
mkdir mysql-db-mcp
|
|
66
|
+
cd mysql-db-mcp
|
|
67
|
+
npm install
|
|
68
|
+
npm run build
|
|
69
|
+
npm link
|
|
70
|
+
mysql-db-mcp
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
For local development:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm run dev
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
After publishing to npm, users can start it with:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npx mysql-db-mcp
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## MCP Client Config
|
|
86
|
+
|
|
87
|
+
Read-only mode:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"mcpServers": {
|
|
92
|
+
"mysql-db": {
|
|
93
|
+
"command": "npx",
|
|
94
|
+
"args": ["-y", "mysql-db-mcp"],
|
|
95
|
+
"env": {
|
|
96
|
+
"MYSQL_HOST": "127.0.0.1",
|
|
97
|
+
"MYSQL_PORT": "3306",
|
|
98
|
+
"MYSQL_USER": "readonly_user",
|
|
99
|
+
"MYSQL_PASSWORD": "your_password",
|
|
100
|
+
"MYSQL_DATABASE": "your_database",
|
|
101
|
+
"MYSQL_MAX_ROWS": "200"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Allow inserts:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"mcpServers": {
|
|
113
|
+
"mysql-db": {
|
|
114
|
+
"command": "npx",
|
|
115
|
+
"args": ["-y", "mysql-db-mcp"],
|
|
116
|
+
"env": {
|
|
117
|
+
"MYSQL_HOST": "127.0.0.1",
|
|
118
|
+
"MYSQL_PORT": "3306",
|
|
119
|
+
"MYSQL_USER": "writer_user",
|
|
120
|
+
"MYSQL_PASSWORD": "your_password",
|
|
121
|
+
"MYSQL_DATABASE": "your_database",
|
|
122
|
+
"MYSQL_ENABLE_WRITE": "true",
|
|
123
|
+
"MYSQL_WRITE_ALLOWED_SCHEMAS": "your_database",
|
|
124
|
+
"MYSQL_WRITE_ALLOWED_TABLES": "users,orders",
|
|
125
|
+
"MYSQL_REQUIRE_CONFIRMATION": "true",
|
|
126
|
+
"MYSQL_MAX_INSERT_ROWS": "100"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Allow DDL:
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"mcpServers": {
|
|
138
|
+
"mysql-db": {
|
|
139
|
+
"command": "npx",
|
|
140
|
+
"args": ["-y", "mysql-db-mcp"],
|
|
141
|
+
"env": {
|
|
142
|
+
"MYSQL_HOST": "127.0.0.1",
|
|
143
|
+
"MYSQL_PORT": "3306",
|
|
144
|
+
"MYSQL_USER": "ddl_user",
|
|
145
|
+
"MYSQL_PASSWORD": "your_password",
|
|
146
|
+
"MYSQL_DATABASE": "your_database",
|
|
147
|
+
"MYSQL_ENABLE_DDL": "true",
|
|
148
|
+
"MYSQL_DDL_ALLOWED_SCHEMAS": "your_database",
|
|
149
|
+
"MYSQL_DDL_ALLOWED_TABLES": "users,orders",
|
|
150
|
+
"MYSQL_REQUIRE_CONFIRMATION": "true"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Allow inserts and DDL:
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"mcpServers": {
|
|
162
|
+
"mysql-db": {
|
|
163
|
+
"command": "npx",
|
|
164
|
+
"args": ["-y", "mysql-db-mcp"],
|
|
165
|
+
"env": {
|
|
166
|
+
"MYSQL_HOST": "127.0.0.1",
|
|
167
|
+
"MYSQL_PORT": "3306",
|
|
168
|
+
"MYSQL_USER": "admin_limited_user",
|
|
169
|
+
"MYSQL_PASSWORD": "your_password",
|
|
170
|
+
"MYSQL_DATABASE": "your_database",
|
|
171
|
+
"MYSQL_ENABLE_WRITE": "true",
|
|
172
|
+
"MYSQL_ENABLE_DDL": "true",
|
|
173
|
+
"MYSQL_WRITE_ALLOWED_SCHEMAS": "your_database",
|
|
174
|
+
"MYSQL_WRITE_ALLOWED_TABLES": "users,orders",
|
|
175
|
+
"MYSQL_DDL_ALLOWED_SCHEMAS": "your_database",
|
|
176
|
+
"MYSQL_DDL_ALLOWED_TABLES": "users,orders",
|
|
177
|
+
"MYSQL_REQUIRE_CONFIRMATION": "true"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Tool Examples
|
|
185
|
+
|
|
186
|
+
SELECT:
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"sql": "SELECT id, email FROM users WHERE status = ? LIMIT 10",
|
|
191
|
+
"params": ["active"]
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
EXPLAIN:
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"sql": "SELECT id, email FROM users WHERE status = ? LIMIT 10",
|
|
200
|
+
"params": ["active"]
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Insert one row:
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"schema": "your_database",
|
|
209
|
+
"table": "users",
|
|
210
|
+
"data": {
|
|
211
|
+
"email": "a@example.com",
|
|
212
|
+
"status": "active"
|
|
213
|
+
},
|
|
214
|
+
"confirm": true
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Insert multiple rows:
|
|
219
|
+
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"schema": "your_database",
|
|
223
|
+
"table": "users",
|
|
224
|
+
"rows": [
|
|
225
|
+
{ "email": "a@example.com", "status": "active" },
|
|
226
|
+
{ "email": "b@example.com", "status": "pending" }
|
|
227
|
+
],
|
|
228
|
+
"confirm": true
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Add a column:
|
|
233
|
+
|
|
234
|
+
```json
|
|
235
|
+
{
|
|
236
|
+
"schema": "your_database",
|
|
237
|
+
"table": "users",
|
|
238
|
+
"columnName": "nickname",
|
|
239
|
+
"columnType": "VARCHAR(255)",
|
|
240
|
+
"nullable": true,
|
|
241
|
+
"comment": "Display name",
|
|
242
|
+
"afterColumn": "email",
|
|
243
|
+
"confirm": true
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Modify a column:
|
|
248
|
+
|
|
249
|
+
```json
|
|
250
|
+
{
|
|
251
|
+
"schema": "your_database",
|
|
252
|
+
"table": "users",
|
|
253
|
+
"columnName": "nickname",
|
|
254
|
+
"columnType": "VARCHAR(128)",
|
|
255
|
+
"nullable": true,
|
|
256
|
+
"comment": "Short display name",
|
|
257
|
+
"confirm": true
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Drop a column:
|
|
262
|
+
|
|
263
|
+
```json
|
|
264
|
+
{
|
|
265
|
+
"schema": "your_database",
|
|
266
|
+
"table": "users",
|
|
267
|
+
"columnName": "nickname",
|
|
268
|
+
"confirm": true
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Rename a column:
|
|
273
|
+
|
|
274
|
+
```json
|
|
275
|
+
{
|
|
276
|
+
"schema": "your_database",
|
|
277
|
+
"table": "users",
|
|
278
|
+
"oldColumnName": "nickname",
|
|
279
|
+
"newColumnName": "display_name",
|
|
280
|
+
"confirm": true
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Add an index:
|
|
285
|
+
|
|
286
|
+
```json
|
|
287
|
+
{
|
|
288
|
+
"schema": "your_database",
|
|
289
|
+
"table": "users",
|
|
290
|
+
"indexName": "idx_users_status",
|
|
291
|
+
"columns": ["status"],
|
|
292
|
+
"unique": false,
|
|
293
|
+
"confirm": true
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Drop an index:
|
|
298
|
+
|
|
299
|
+
```json
|
|
300
|
+
{
|
|
301
|
+
"schema": "your_database",
|
|
302
|
+
"table": "users",
|
|
303
|
+
"indexName": "idx_users_status",
|
|
304
|
+
"confirm": true
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## MCP Inspector
|
|
309
|
+
|
|
310
|
+
Build first, then run the MCP Inspector:
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
npm run build
|
|
314
|
+
npx @modelcontextprotocol/inspector node dist/index.js
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Set MySQL environment variables in the Inspector process before testing tools.
|
|
318
|
+
|
|
319
|
+
## MySQL Account Recommendations
|
|
320
|
+
|
|
321
|
+
Do not use `root` in production.
|
|
322
|
+
|
|
323
|
+
Read-only user:
|
|
324
|
+
|
|
325
|
+
```sql
|
|
326
|
+
CREATE USER 'mcp_readonly'@'%' IDENTIFIED BY 'your_password';
|
|
327
|
+
GRANT SELECT ON your_database.* TO 'mcp_readonly'@'%';
|
|
328
|
+
FLUSH PRIVILEGES;
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Insert user:
|
|
332
|
+
|
|
333
|
+
```sql
|
|
334
|
+
CREATE USER 'mcp_writer'@'%' IDENTIFIED BY 'your_password';
|
|
335
|
+
GRANT SELECT, INSERT ON your_database.* TO 'mcp_writer'@'%';
|
|
336
|
+
FLUSH PRIVILEGES;
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
DDL user:
|
|
340
|
+
|
|
341
|
+
```sql
|
|
342
|
+
CREATE USER 'mcp_ddl'@'%' IDENTIFIED BY 'your_password';
|
|
343
|
+
GRANT SELECT, ALTER, INDEX ON your_database.* TO 'mcp_ddl'@'%';
|
|
344
|
+
FLUSH PRIVILEGES;
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Development user:
|
|
348
|
+
|
|
349
|
+
```sql
|
|
350
|
+
CREATE USER 'mcp_dev'@'%' IDENTIFIED BY 'your_password';
|
|
351
|
+
GRANT SELECT, INSERT, ALTER, INDEX ON your_database.* TO 'mcp_dev'@'%';
|
|
352
|
+
FLUSH PRIVILEGES;
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
The MCP Server does not execute authorization SQL. A DBA or developer should run those SQL statements manually.
|
|
356
|
+
|
|
357
|
+
## Safety Notes
|
|
358
|
+
|
|
359
|
+
- Keep the default read-only mode for production unless there is a clear operational need.
|
|
360
|
+
- Prefer separate database accounts for read-only, insert, and DDL use cases.
|
|
361
|
+
- Use `MYSQL_WRITE_ALLOWED_SCHEMAS` and `MYSQL_WRITE_ALLOWED_TABLES` to narrow write scope.
|
|
362
|
+
- Use `MYSQL_DDL_ALLOWED_SCHEMAS` and `MYSQL_DDL_ALLOWED_TABLES` to narrow DDL scope.
|
|
363
|
+
- DDL should be enabled only in development or tightly controlled environments.
|
|
364
|
+
- MySQL DDL commonly causes implicit commits and cannot be treated as safely rollbackable.
|
|
365
|
+
- `confirm: true` exists to make write and DDL calls explicit at the tool boundary.
|
|
366
|
+
- Passwords and full connection strings are never written to logs by this server.
|
|
367
|
+
|
|
368
|
+
## Publish To npm
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
npm login
|
|
372
|
+
npm run build
|
|
373
|
+
npm publish --access public
|
|
374
|
+
```
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare const config: {
|
|
2
|
+
readonly mysql: {
|
|
3
|
+
readonly host: string;
|
|
4
|
+
readonly port: number;
|
|
5
|
+
readonly user: string;
|
|
6
|
+
readonly password: string;
|
|
7
|
+
readonly database: string | undefined;
|
|
8
|
+
readonly ssl: boolean;
|
|
9
|
+
readonly connectionLimit: number;
|
|
10
|
+
readonly maxRows: number;
|
|
11
|
+
};
|
|
12
|
+
readonly security: {
|
|
13
|
+
readonly enableWrite: boolean;
|
|
14
|
+
readonly enableDDL: boolean;
|
|
15
|
+
readonly writeAllowedSchemas: string[];
|
|
16
|
+
readonly writeAllowedTables: string[];
|
|
17
|
+
readonly ddlAllowedSchemas: string[];
|
|
18
|
+
readonly ddlAllowedTables: string[];
|
|
19
|
+
readonly blockedSchemas: readonly ["mysql", "information_schema", "performance_schema", "sys"];
|
|
20
|
+
readonly blockedTables: string[];
|
|
21
|
+
readonly maxInsertRows: number;
|
|
22
|
+
readonly requireConfirmation: boolean;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export type AppConfig = typeof config;
|
|
26
|
+
export declare function defaultSchema(): string;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
function parseBoolean(value, defaultValue) {
|
|
3
|
+
if (value === undefined || value === "") {
|
|
4
|
+
return defaultValue;
|
|
5
|
+
}
|
|
6
|
+
if (/^(true|1|yes|on)$/i.test(value)) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
if (/^(false|0|no|off)$/i.test(value)) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
throw new Error(`Invalid boolean value: ${value}`);
|
|
13
|
+
}
|
|
14
|
+
function parseInteger(value, defaultValue, min, max) {
|
|
15
|
+
if (value === undefined || value === "") {
|
|
16
|
+
return defaultValue;
|
|
17
|
+
}
|
|
18
|
+
const parsed = Number(value);
|
|
19
|
+
if (!Number.isInteger(parsed) || parsed < min || parsed > max) {
|
|
20
|
+
throw new Error(`Invalid integer value: ${value}. Expected ${min}-${max}.`);
|
|
21
|
+
}
|
|
22
|
+
return parsed;
|
|
23
|
+
}
|
|
24
|
+
function parseCsv(value) {
|
|
25
|
+
if (!value) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
return value
|
|
29
|
+
.split(",")
|
|
30
|
+
.map((item) => item.trim())
|
|
31
|
+
.filter((item) => item.length > 0);
|
|
32
|
+
}
|
|
33
|
+
const envSchema = z.object({
|
|
34
|
+
MYSQL_HOST: z.string().default("127.0.0.1"),
|
|
35
|
+
MYSQL_PORT: z.string().optional(),
|
|
36
|
+
MYSQL_USER: z.string().default("root"),
|
|
37
|
+
MYSQL_PASSWORD: z.string().optional(),
|
|
38
|
+
MYSQL_DATABASE: z.string().optional(),
|
|
39
|
+
MYSQL_SSL: z.string().optional(),
|
|
40
|
+
MYSQL_CONNECTION_LIMIT: z.string().optional(),
|
|
41
|
+
MYSQL_MAX_ROWS: z.string().optional(),
|
|
42
|
+
MYSQL_ENABLE_WRITE: z.string().optional(),
|
|
43
|
+
MYSQL_ENABLE_DDL: z.string().optional(),
|
|
44
|
+
MYSQL_WRITE_ALLOWED_SCHEMAS: z.string().optional(),
|
|
45
|
+
MYSQL_WRITE_ALLOWED_TABLES: z.string().optional(),
|
|
46
|
+
MYSQL_DDL_ALLOWED_SCHEMAS: z.string().optional(),
|
|
47
|
+
MYSQL_DDL_ALLOWED_TABLES: z.string().optional(),
|
|
48
|
+
MYSQL_BLOCKED_TABLES: z.string().optional(),
|
|
49
|
+
MYSQL_MAX_INSERT_ROWS: z.string().optional(),
|
|
50
|
+
MYSQL_REQUIRE_CONFIRMATION: z.string().optional()
|
|
51
|
+
});
|
|
52
|
+
const env = envSchema.parse(process.env);
|
|
53
|
+
export const config = {
|
|
54
|
+
mysql: {
|
|
55
|
+
host: env.MYSQL_HOST,
|
|
56
|
+
port: parseInteger(env.MYSQL_PORT, 3306, 1, 65535),
|
|
57
|
+
user: env.MYSQL_USER,
|
|
58
|
+
password: env.MYSQL_PASSWORD ?? "",
|
|
59
|
+
database: env.MYSQL_DATABASE,
|
|
60
|
+
ssl: parseBoolean(env.MYSQL_SSL, false),
|
|
61
|
+
connectionLimit: parseInteger(env.MYSQL_CONNECTION_LIMIT, 10, 1, 100),
|
|
62
|
+
maxRows: parseInteger(env.MYSQL_MAX_ROWS, 200, 1, 10000)
|
|
63
|
+
},
|
|
64
|
+
security: {
|
|
65
|
+
enableWrite: parseBoolean(env.MYSQL_ENABLE_WRITE, false),
|
|
66
|
+
enableDDL: parseBoolean(env.MYSQL_ENABLE_DDL, false),
|
|
67
|
+
writeAllowedSchemas: parseCsv(env.MYSQL_WRITE_ALLOWED_SCHEMAS),
|
|
68
|
+
writeAllowedTables: parseCsv(env.MYSQL_WRITE_ALLOWED_TABLES),
|
|
69
|
+
ddlAllowedSchemas: parseCsv(env.MYSQL_DDL_ALLOWED_SCHEMAS),
|
|
70
|
+
ddlAllowedTables: parseCsv(env.MYSQL_DDL_ALLOWED_TABLES),
|
|
71
|
+
blockedSchemas: ["mysql", "information_schema", "performance_schema", "sys"],
|
|
72
|
+
blockedTables: parseCsv(env.MYSQL_BLOCKED_TABLES),
|
|
73
|
+
maxInsertRows: parseInteger(env.MYSQL_MAX_INSERT_ROWS, 100, 1, 10000),
|
|
74
|
+
requireConfirmation: parseBoolean(env.MYSQL_REQUIRE_CONFIRMATION, true)
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
export function defaultSchema() {
|
|
78
|
+
if (!config.mysql.database) {
|
|
79
|
+
throw new Error("schema is required when MYSQL_DATABASE is not configured.");
|
|
80
|
+
}
|
|
81
|
+
return config.mysql.database;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ResultSetHeader } from "mysql2";
|
|
2
|
+
export type QueryValue = string | number | boolean | null | Date;
|
|
3
|
+
export type QueryParams = QueryValue[];
|
|
4
|
+
export type DbRow = Record<string, unknown>;
|
|
5
|
+
export declare class MySqlClient {
|
|
6
|
+
queryRows(sql: string, params?: QueryParams): Promise<DbRow[]>;
|
|
7
|
+
execute(sql: string, params?: QueryParams): Promise<ResultSetHeader>;
|
|
8
|
+
listSchemas(): Promise<DbRow[]>;
|
|
9
|
+
listTables(schema: string): Promise<DbRow[]>;
|
|
10
|
+
describeTable(schema: string, table: string): Promise<DbRow[]>;
|
|
11
|
+
columnExists(schema: string, table: string, column: string): Promise<boolean>;
|
|
12
|
+
columnsExist(schema: string, table: string, columns: readonly string[]): Promise<boolean>;
|
|
13
|
+
isPrimaryKeyColumn(schema: string, table: string, column: string): Promise<boolean>;
|
|
14
|
+
isUniqueIndexColumn(schema: string, table: string, column: string): Promise<boolean>;
|
|
15
|
+
indexExists(schema: string, table: string, indexName: string): Promise<boolean>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { config } from "../config.js";
|
|
2
|
+
import { getPool } from "./MySqlPool.js";
|
|
3
|
+
function convertRows(rows) {
|
|
4
|
+
if (Array.isArray(rows) && rows.every((row) => !Array.isArray(row))) {
|
|
5
|
+
return rows;
|
|
6
|
+
}
|
|
7
|
+
return [];
|
|
8
|
+
}
|
|
9
|
+
export class MySqlClient {
|
|
10
|
+
async queryRows(sql, params = []) {
|
|
11
|
+
const [rows] = await getPool().execute(sql, params);
|
|
12
|
+
return convertRows(rows).slice(0, config.mysql.maxRows);
|
|
13
|
+
}
|
|
14
|
+
async execute(sql, params = []) {
|
|
15
|
+
const [result] = await getPool().execute(sql, params);
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
async listSchemas() {
|
|
19
|
+
return this.queryRows(`
|
|
20
|
+
SELECT SCHEMA_NAME AS schemaName
|
|
21
|
+
FROM INFORMATION_SCHEMA.SCHEMATA
|
|
22
|
+
WHERE SCHEMA_NAME NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
|
|
23
|
+
ORDER BY SCHEMA_NAME
|
|
24
|
+
`);
|
|
25
|
+
}
|
|
26
|
+
async listTables(schema) {
|
|
27
|
+
return this.queryRows(`
|
|
28
|
+
SELECT TABLE_SCHEMA AS schemaName,
|
|
29
|
+
TABLE_NAME AS tableName,
|
|
30
|
+
TABLE_TYPE AS tableType,
|
|
31
|
+
ENGINE AS engine,
|
|
32
|
+
TABLE_ROWS AS estimatedRows,
|
|
33
|
+
CREATE_TIME AS createdAt,
|
|
34
|
+
UPDATE_TIME AS updatedAt,
|
|
35
|
+
TABLE_COMMENT AS tableComment
|
|
36
|
+
FROM INFORMATION_SCHEMA.TABLES
|
|
37
|
+
WHERE TABLE_SCHEMA = ?
|
|
38
|
+
ORDER BY TABLE_NAME
|
|
39
|
+
`, [schema]);
|
|
40
|
+
}
|
|
41
|
+
async describeTable(schema, table) {
|
|
42
|
+
return this.queryRows(`
|
|
43
|
+
SELECT COLUMN_NAME AS columnName,
|
|
44
|
+
ORDINAL_POSITION AS ordinalPosition,
|
|
45
|
+
COLUMN_DEFAULT AS columnDefault,
|
|
46
|
+
IS_NULLABLE AS isNullable,
|
|
47
|
+
DATA_TYPE AS dataType,
|
|
48
|
+
COLUMN_TYPE AS columnType,
|
|
49
|
+
CHARACTER_MAXIMUM_LENGTH AS characterMaximumLength,
|
|
50
|
+
NUMERIC_PRECISION AS numericPrecision,
|
|
51
|
+
NUMERIC_SCALE AS numericScale,
|
|
52
|
+
COLUMN_KEY AS columnKey,
|
|
53
|
+
EXTRA AS extra,
|
|
54
|
+
COLUMN_COMMENT AS columnComment
|
|
55
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
56
|
+
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
|
|
57
|
+
ORDER BY ORDINAL_POSITION
|
|
58
|
+
`, [schema, table]);
|
|
59
|
+
}
|
|
60
|
+
async columnExists(schema, table, column) {
|
|
61
|
+
const rows = await this.queryRows(`
|
|
62
|
+
SELECT 1 AS ok
|
|
63
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
64
|
+
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND COLUMN_NAME = ?
|
|
65
|
+
LIMIT 1
|
|
66
|
+
`, [schema, table, column]);
|
|
67
|
+
return rows.length > 0;
|
|
68
|
+
}
|
|
69
|
+
async columnsExist(schema, table, columns) {
|
|
70
|
+
if (columns.length === 0) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
const placeholders = columns.map(() => "?").join(", ");
|
|
74
|
+
const rows = await this.queryRows(`
|
|
75
|
+
SELECT COLUMN_NAME AS columnName
|
|
76
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
77
|
+
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND COLUMN_NAME IN (${placeholders})
|
|
78
|
+
`, [schema, table, ...columns]);
|
|
79
|
+
return new Set(rows.map((row) => String(row.columnName))).size === new Set(columns).size;
|
|
80
|
+
}
|
|
81
|
+
async isPrimaryKeyColumn(schema, table, column) {
|
|
82
|
+
const rows = await this.queryRows(`
|
|
83
|
+
SELECT 1 AS ok
|
|
84
|
+
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
|
85
|
+
WHERE TABLE_SCHEMA = ?
|
|
86
|
+
AND TABLE_NAME = ?
|
|
87
|
+
AND COLUMN_NAME = ?
|
|
88
|
+
AND CONSTRAINT_NAME = 'PRIMARY'
|
|
89
|
+
LIMIT 1
|
|
90
|
+
`, [schema, table, column]);
|
|
91
|
+
return rows.length > 0;
|
|
92
|
+
}
|
|
93
|
+
async isUniqueIndexColumn(schema, table, column) {
|
|
94
|
+
const rows = await this.queryRows(`
|
|
95
|
+
SELECT 1 AS ok
|
|
96
|
+
FROM INFORMATION_SCHEMA.STATISTICS
|
|
97
|
+
WHERE TABLE_SCHEMA = ?
|
|
98
|
+
AND TABLE_NAME = ?
|
|
99
|
+
AND COLUMN_NAME = ?
|
|
100
|
+
AND NON_UNIQUE = 0
|
|
101
|
+
LIMIT 1
|
|
102
|
+
`, [schema, table, column]);
|
|
103
|
+
return rows.length > 0;
|
|
104
|
+
}
|
|
105
|
+
async indexExists(schema, table, indexName) {
|
|
106
|
+
const rows = await this.queryRows(`
|
|
107
|
+
SELECT 1 AS ok
|
|
108
|
+
FROM INFORMATION_SCHEMA.STATISTICS
|
|
109
|
+
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND INDEX_NAME = ?
|
|
110
|
+
LIMIT 1
|
|
111
|
+
`, [schema, table, indexName]);
|
|
112
|
+
return rows.length > 0;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=MySqlClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MySqlClient.js","sourceRoot":"","sources":["../../src/db/MySqlClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import mysql from "mysql2/promise";
|
|
2
|
+
import { config } from "../config.js";
|
|
3
|
+
import { logger } from "../logger.js";
|
|
4
|
+
let pool;
|
|
5
|
+
export function getPool() {
|
|
6
|
+
if (!pool) {
|
|
7
|
+
pool = mysql.createPool({
|
|
8
|
+
host: config.mysql.host,
|
|
9
|
+
port: config.mysql.port,
|
|
10
|
+
user: config.mysql.user,
|
|
11
|
+
password: config.mysql.password,
|
|
12
|
+
database: config.mysql.database,
|
|
13
|
+
waitForConnections: true,
|
|
14
|
+
connectionLimit: config.mysql.connectionLimit,
|
|
15
|
+
multipleStatements: false,
|
|
16
|
+
ssl: config.mysql.ssl ? {} : undefined,
|
|
17
|
+
namedPlaceholders: false
|
|
18
|
+
});
|
|
19
|
+
logger.info("MySQL pool created", {
|
|
20
|
+
host: config.mysql.host,
|
|
21
|
+
port: config.mysql.port,
|
|
22
|
+
user: config.mysql.user,
|
|
23
|
+
database: config.mysql.database,
|
|
24
|
+
connectionLimit: config.mysql.connectionLimit
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return pool;
|
|
28
|
+
}
|
|
29
|
+
export async function closePool() {
|
|
30
|
+
if (pool) {
|
|
31
|
+
await pool.end();
|
|
32
|
+
pool = undefined;
|
|
33
|
+
logger.info("MySQL pool closed");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=MySqlPool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MySqlPool.js","sourceRoot":"","sources":["../../src/db/MySqlPool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,IAAI,IAAsB,CAAC;AAE3B,MAAM,UAAU,OAAO;IACrB,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC;YACtB,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;YACvB,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;YACvB,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;YACvB,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ;YAC/B,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ;YAC/B,kBAAkB,EAAE,IAAI;YACxB,eAAe,EAAE,MAAM,CAAC,KAAK,CAAC,eAAe;YAC7C,kBAAkB,EAAE,KAAK;YACzB,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;YACtC,iBAAiB,EAAE,KAAK;SACzB,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE;YAChC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;YACvB,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;YACvB,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;YACvB,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ;YAC/B,eAAe,EAAE,MAAM,CAAC,KAAK,CAAC,eAAe;SAC9C,CAAC,CAAC;IACL,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;QACjB,IAAI,GAAG,SAAS,CAAC;QACjB,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACnC,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED