@berthojoris/mcp-mysql-server 1.10.2 → 1.10.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/CHANGELOG.md +25 -7
- package/DOCUMENTATIONS.md +2 -2
- package/README.md +1 -1
- package/dist/index.d.ts +0 -99
- package/dist/mcp-server.js +0 -21
- package/dist/tools/backupRestoreTools.d.ts +1 -6
- package/dist/tools/backupRestoreTools.js +99 -97
- package/dist/tools/constraintTools.d.ts +4 -11
- package/dist/tools/constraintTools.js +114 -115
- package/dist/tools/crudTools.d.ts +2 -6
- package/dist/tools/crudTools.js +186 -189
- package/dist/tools/dataExportTools.d.ts +0 -7
- package/dist/tools/dataExportTools.js +0 -15
- package/dist/tools/databaseTools.d.ts +1 -4
- package/dist/tools/databaseTools.js +29 -33
- package/dist/tools/ddlTools.d.ts +1 -5
- package/dist/tools/ddlTools.js +68 -53
- package/dist/tools/functionTools.d.ts +3 -9
- package/dist/tools/functionTools.js +111 -104
- package/dist/tools/indexTools.d.ts +3 -8
- package/dist/tools/indexTools.js +99 -95
- package/dist/tools/maintenanceTools.d.ts +2 -10
- package/dist/tools/maintenanceTools.js +66 -80
- package/dist/tools/migrationTools.d.ts +0 -5
- package/dist/tools/migrationTools.js +56 -24
- package/dist/tools/performanceTools.d.ts +1 -11
- package/dist/tools/performanceTools.js +278 -267
- package/dist/tools/processTools.d.ts +4 -13
- package/dist/tools/processTools.js +78 -80
- package/dist/tools/queryTools.d.ts +0 -2
- package/dist/tools/queryTools.js +0 -4
- package/dist/tools/schemaVersioningTools.d.ts +0 -9
- package/dist/tools/schemaVersioningTools.js +167 -166
- package/dist/tools/storedProcedureTools.d.ts +2 -4
- package/dist/tools/storedProcedureTools.js +143 -134
- package/dist/tools/transactionTools.d.ts +2 -3
- package/dist/tools/transactionTools.js +28 -29
- package/dist/tools/triggerTools.d.ts +3 -8
- package/dist/tools/triggerTools.js +98 -85
- package/dist/tools/utilityTools.d.ts +0 -1
- package/dist/tools/utilityTools.js +0 -2
- package/dist/tools/viewTools.d.ts +7 -13
- package/dist/tools/viewTools.js +100 -93
- package/package.json +1 -1
package/dist/tools/viewTools.js
CHANGED
|
@@ -19,26 +19,26 @@ class ViewTools {
|
|
|
19
19
|
if (!connectedDatabase) {
|
|
20
20
|
return {
|
|
21
21
|
valid: false,
|
|
22
|
-
database:
|
|
23
|
-
error:
|
|
22
|
+
database: "",
|
|
23
|
+
error: "No database specified in connection string. Cannot access any database.",
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
if (!requestedDatabase) {
|
|
27
27
|
return {
|
|
28
28
|
valid: true,
|
|
29
|
-
database: connectedDatabase
|
|
29
|
+
database: connectedDatabase,
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
if (requestedDatabase !== connectedDatabase) {
|
|
33
33
|
return {
|
|
34
34
|
valid: false,
|
|
35
|
-
database:
|
|
36
|
-
error: `Access denied. You can only access the connected database '${connectedDatabase}'. Requested database '${requestedDatabase}' is not allowed
|
|
35
|
+
database: "",
|
|
36
|
+
error: `Access denied. You can only access the connected database '${connectedDatabase}'. Requested database '${requestedDatabase}' is not allowed.`,
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
return {
|
|
40
40
|
valid: true,
|
|
41
|
-
database: connectedDatabase
|
|
41
|
+
database: connectedDatabase,
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
@@ -48,35 +48,33 @@ class ViewTools {
|
|
|
48
48
|
try {
|
|
49
49
|
const dbValidation = this.validateDatabaseAccess(params?.database);
|
|
50
50
|
if (!dbValidation.valid) {
|
|
51
|
-
return { status:
|
|
51
|
+
return { status: "error", error: dbValidation.error };
|
|
52
52
|
}
|
|
53
53
|
const database = dbValidation.database;
|
|
54
|
-
const query = `
|
|
55
|
-
SELECT
|
|
56
|
-
TABLE_NAME as view_name,
|
|
57
|
-
VIEW_DEFINITION as definition,
|
|
58
|
-
CHECK_OPTION as check_option,
|
|
59
|
-
IS_UPDATABLE as is_updatable,
|
|
60
|
-
DEFINER as definer,
|
|
61
|
-
SECURITY_TYPE as security_type,
|
|
62
|
-
CHARACTER_SET_CLIENT as charset,
|
|
63
|
-
COLLATION_CONNECTION as collation
|
|
64
|
-
FROM INFORMATION_SCHEMA.VIEWS
|
|
65
|
-
WHERE TABLE_SCHEMA = ?
|
|
66
|
-
ORDER BY TABLE_NAME
|
|
54
|
+
const query = `
|
|
55
|
+
SELECT
|
|
56
|
+
TABLE_NAME as view_name,
|
|
57
|
+
VIEW_DEFINITION as definition,
|
|
58
|
+
CHECK_OPTION as check_option,
|
|
59
|
+
IS_UPDATABLE as is_updatable,
|
|
60
|
+
DEFINER as definer,
|
|
61
|
+
SECURITY_TYPE as security_type,
|
|
62
|
+
CHARACTER_SET_CLIENT as charset,
|
|
63
|
+
COLLATION_CONNECTION as collation
|
|
64
|
+
FROM INFORMATION_SCHEMA.VIEWS
|
|
65
|
+
WHERE TABLE_SCHEMA = ?
|
|
66
|
+
ORDER BY TABLE_NAME
|
|
67
67
|
`;
|
|
68
68
|
const results = await this.db.query(query, [database]);
|
|
69
69
|
return {
|
|
70
|
-
status:
|
|
70
|
+
status: "success",
|
|
71
71
|
data: results,
|
|
72
|
-
queryLog: this.db.getFormattedQueryLogs(1)
|
|
73
72
|
};
|
|
74
73
|
}
|
|
75
74
|
catch (error) {
|
|
76
75
|
return {
|
|
77
|
-
status:
|
|
76
|
+
status: "error",
|
|
78
77
|
error: error.message,
|
|
79
|
-
queryLog: this.db.getFormattedQueryLogs(1)
|
|
80
78
|
};
|
|
81
79
|
}
|
|
82
80
|
}
|
|
@@ -87,67 +85,67 @@ class ViewTools {
|
|
|
87
85
|
try {
|
|
88
86
|
const dbValidation = this.validateDatabaseAccess(params?.database);
|
|
89
87
|
if (!dbValidation.valid) {
|
|
90
|
-
return { status:
|
|
88
|
+
return { status: "error", error: dbValidation.error };
|
|
91
89
|
}
|
|
92
90
|
const { view_name } = params;
|
|
93
91
|
const database = dbValidation.database;
|
|
94
92
|
// Validate view name
|
|
95
93
|
const identifierValidation = this.security.validateIdentifier(view_name);
|
|
96
94
|
if (!identifierValidation.valid) {
|
|
97
|
-
return {
|
|
95
|
+
return {
|
|
96
|
+
status: "error",
|
|
97
|
+
error: identifierValidation.error || "Invalid view name",
|
|
98
|
+
};
|
|
98
99
|
}
|
|
99
100
|
// Get view information
|
|
100
|
-
const viewQuery = `
|
|
101
|
-
SELECT
|
|
102
|
-
TABLE_NAME as view_name,
|
|
103
|
-
VIEW_DEFINITION as definition,
|
|
104
|
-
CHECK_OPTION as check_option,
|
|
105
|
-
IS_UPDATABLE as is_updatable,
|
|
106
|
-
DEFINER as definer,
|
|
107
|
-
SECURITY_TYPE as security_type,
|
|
108
|
-
CHARACTER_SET_CLIENT as charset,
|
|
109
|
-
COLLATION_CONNECTION as collation
|
|
110
|
-
FROM INFORMATION_SCHEMA.VIEWS
|
|
111
|
-
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
|
|
101
|
+
const viewQuery = `
|
|
102
|
+
SELECT
|
|
103
|
+
TABLE_NAME as view_name,
|
|
104
|
+
VIEW_DEFINITION as definition,
|
|
105
|
+
CHECK_OPTION as check_option,
|
|
106
|
+
IS_UPDATABLE as is_updatable,
|
|
107
|
+
DEFINER as definer,
|
|
108
|
+
SECURITY_TYPE as security_type,
|
|
109
|
+
CHARACTER_SET_CLIENT as charset,
|
|
110
|
+
COLLATION_CONNECTION as collation
|
|
111
|
+
FROM INFORMATION_SCHEMA.VIEWS
|
|
112
|
+
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
|
|
112
113
|
`;
|
|
113
114
|
// Get view columns
|
|
114
|
-
const columnsQuery = `
|
|
115
|
-
SELECT
|
|
116
|
-
COLUMN_NAME as column_name,
|
|
117
|
-
DATA_TYPE as data_type,
|
|
118
|
-
COLUMN_TYPE as column_type,
|
|
119
|
-
IS_NULLABLE as is_nullable,
|
|
120
|
-
COLUMN_DEFAULT as column_default,
|
|
121
|
-
ORDINAL_POSITION as position
|
|
122
|
-
FROM INFORMATION_SCHEMA.COLUMNS
|
|
123
|
-
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
|
|
124
|
-
ORDER BY ORDINAL_POSITION
|
|
115
|
+
const columnsQuery = `
|
|
116
|
+
SELECT
|
|
117
|
+
COLUMN_NAME as column_name,
|
|
118
|
+
DATA_TYPE as data_type,
|
|
119
|
+
COLUMN_TYPE as column_type,
|
|
120
|
+
IS_NULLABLE as is_nullable,
|
|
121
|
+
COLUMN_DEFAULT as column_default,
|
|
122
|
+
ORDINAL_POSITION as position
|
|
123
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
124
|
+
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
|
|
125
|
+
ORDER BY ORDINAL_POSITION
|
|
125
126
|
`;
|
|
126
127
|
const [viewInfo, columns] = await Promise.all([
|
|
127
128
|
this.db.query(viewQuery, [database, view_name]),
|
|
128
|
-
this.db.query(columnsQuery, [database, view_name])
|
|
129
|
+
this.db.query(columnsQuery, [database, view_name]),
|
|
129
130
|
]);
|
|
130
131
|
if (viewInfo.length === 0) {
|
|
131
132
|
return {
|
|
132
|
-
status:
|
|
133
|
+
status: "error",
|
|
133
134
|
error: `View '${view_name}' not found in database '${database}'`,
|
|
134
|
-
queryLog: this.db.getFormattedQueryLogs(2)
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
137
|
return {
|
|
138
|
-
status:
|
|
138
|
+
status: "success",
|
|
139
139
|
data: {
|
|
140
140
|
...viewInfo[0],
|
|
141
|
-
columns: columns
|
|
141
|
+
columns: columns,
|
|
142
142
|
},
|
|
143
|
-
queryLog: this.db.getFormattedQueryLogs(2)
|
|
144
143
|
};
|
|
145
144
|
}
|
|
146
145
|
catch (error) {
|
|
147
146
|
return {
|
|
148
|
-
status:
|
|
147
|
+
status: "error",
|
|
149
148
|
error: error.message,
|
|
150
|
-
queryLog: this.db.getFormattedQueryLogs(2)
|
|
151
149
|
};
|
|
152
150
|
}
|
|
153
151
|
}
|
|
@@ -158,22 +156,28 @@ class ViewTools {
|
|
|
158
156
|
try {
|
|
159
157
|
const dbValidation = this.validateDatabaseAccess(params?.database);
|
|
160
158
|
if (!dbValidation.valid) {
|
|
161
|
-
return { status:
|
|
159
|
+
return { status: "error", error: dbValidation.error };
|
|
162
160
|
}
|
|
163
|
-
const { view_name, definition, or_replace = false, algorithm, security, check_option } = params;
|
|
161
|
+
const { view_name, definition, or_replace = false, algorithm, security, check_option, } = params;
|
|
164
162
|
const database = dbValidation.database;
|
|
165
163
|
// Validate view name
|
|
166
164
|
const identifierValidation = this.security.validateIdentifier(view_name);
|
|
167
165
|
if (!identifierValidation.valid) {
|
|
168
|
-
return {
|
|
166
|
+
return {
|
|
167
|
+
status: "error",
|
|
168
|
+
error: identifierValidation.error || "Invalid view name",
|
|
169
|
+
};
|
|
169
170
|
}
|
|
170
171
|
// Validate that definition is a SELECT statement
|
|
171
172
|
const trimmedDef = definition.trim().toUpperCase();
|
|
172
|
-
if (!trimmedDef.startsWith(
|
|
173
|
-
return {
|
|
173
|
+
if (!trimmedDef.startsWith("SELECT")) {
|
|
174
|
+
return {
|
|
175
|
+
status: "error",
|
|
176
|
+
error: "View definition must be a SELECT statement",
|
|
177
|
+
};
|
|
174
178
|
}
|
|
175
179
|
// Build CREATE VIEW statement
|
|
176
|
-
let createQuery = or_replace ?
|
|
180
|
+
let createQuery = or_replace ? "CREATE OR REPLACE " : "CREATE ";
|
|
177
181
|
if (algorithm) {
|
|
178
182
|
createQuery += `ALGORITHM = ${algorithm} `;
|
|
179
183
|
}
|
|
@@ -186,20 +190,18 @@ class ViewTools {
|
|
|
186
190
|
}
|
|
187
191
|
await this.db.query(createQuery);
|
|
188
192
|
return {
|
|
189
|
-
status:
|
|
193
|
+
status: "success",
|
|
190
194
|
data: {
|
|
191
195
|
message: `View '${view_name}' created successfully`,
|
|
192
196
|
view_name,
|
|
193
|
-
database
|
|
197
|
+
database,
|
|
194
198
|
},
|
|
195
|
-
queryLog: this.db.getFormattedQueryLogs(1)
|
|
196
199
|
};
|
|
197
200
|
}
|
|
198
201
|
catch (error) {
|
|
199
202
|
return {
|
|
200
|
-
status:
|
|
203
|
+
status: "error",
|
|
201
204
|
error: error.message,
|
|
202
|
-
queryLog: this.db.getFormattedQueryLogs(1)
|
|
203
205
|
};
|
|
204
206
|
}
|
|
205
207
|
}
|
|
@@ -210,22 +212,28 @@ class ViewTools {
|
|
|
210
212
|
try {
|
|
211
213
|
const dbValidation = this.validateDatabaseAccess(params?.database);
|
|
212
214
|
if (!dbValidation.valid) {
|
|
213
|
-
return { status:
|
|
215
|
+
return { status: "error", error: dbValidation.error };
|
|
214
216
|
}
|
|
215
217
|
const { view_name, definition, algorithm, security, check_option } = params;
|
|
216
218
|
const database = dbValidation.database;
|
|
217
219
|
// Validate view name
|
|
218
220
|
const identifierValidation = this.security.validateIdentifier(view_name);
|
|
219
221
|
if (!identifierValidation.valid) {
|
|
220
|
-
return {
|
|
222
|
+
return {
|
|
223
|
+
status: "error",
|
|
224
|
+
error: identifierValidation.error || "Invalid view name",
|
|
225
|
+
};
|
|
221
226
|
}
|
|
222
227
|
// Validate that definition is a SELECT statement
|
|
223
228
|
const trimmedDef = definition.trim().toUpperCase();
|
|
224
|
-
if (!trimmedDef.startsWith(
|
|
225
|
-
return {
|
|
229
|
+
if (!trimmedDef.startsWith("SELECT")) {
|
|
230
|
+
return {
|
|
231
|
+
status: "error",
|
|
232
|
+
error: "View definition must be a SELECT statement",
|
|
233
|
+
};
|
|
226
234
|
}
|
|
227
235
|
// Build ALTER VIEW statement
|
|
228
|
-
let alterQuery =
|
|
236
|
+
let alterQuery = "ALTER ";
|
|
229
237
|
if (algorithm) {
|
|
230
238
|
alterQuery += `ALGORITHM = ${algorithm} `;
|
|
231
239
|
}
|
|
@@ -238,20 +246,18 @@ class ViewTools {
|
|
|
238
246
|
}
|
|
239
247
|
await this.db.query(alterQuery);
|
|
240
248
|
return {
|
|
241
|
-
status:
|
|
249
|
+
status: "success",
|
|
242
250
|
data: {
|
|
243
251
|
message: `View '${view_name}' altered successfully`,
|
|
244
252
|
view_name,
|
|
245
|
-
database
|
|
253
|
+
database,
|
|
246
254
|
},
|
|
247
|
-
queryLog: this.db.getFormattedQueryLogs(1)
|
|
248
255
|
};
|
|
249
256
|
}
|
|
250
257
|
catch (error) {
|
|
251
258
|
return {
|
|
252
|
-
status:
|
|
259
|
+
status: "error",
|
|
253
260
|
error: error.message,
|
|
254
|
-
queryLog: this.db.getFormattedQueryLogs(1)
|
|
255
261
|
};
|
|
256
262
|
}
|
|
257
263
|
}
|
|
@@ -262,28 +268,29 @@ class ViewTools {
|
|
|
262
268
|
try {
|
|
263
269
|
const dbValidation = this.validateDatabaseAccess(params?.database);
|
|
264
270
|
if (!dbValidation.valid) {
|
|
265
|
-
return { status:
|
|
271
|
+
return { status: "error", error: dbValidation.error };
|
|
266
272
|
}
|
|
267
273
|
const { view_name, if_exists = false } = params;
|
|
268
274
|
const database = dbValidation.database;
|
|
269
275
|
// Validate view name
|
|
270
276
|
const identifierValidation = this.security.validateIdentifier(view_name);
|
|
271
277
|
if (!identifierValidation.valid) {
|
|
272
|
-
return {
|
|
278
|
+
return {
|
|
279
|
+
status: "error",
|
|
280
|
+
error: identifierValidation.error || "Invalid view name",
|
|
281
|
+
};
|
|
273
282
|
}
|
|
274
|
-
const dropQuery = `DROP VIEW ${if_exists ?
|
|
283
|
+
const dropQuery = `DROP VIEW ${if_exists ? "IF EXISTS" : ""} \`${database}\`.\`${view_name}\``;
|
|
275
284
|
await this.db.query(dropQuery);
|
|
276
285
|
return {
|
|
277
|
-
status:
|
|
286
|
+
status: "success",
|
|
278
287
|
message: `View '${view_name}' dropped successfully`,
|
|
279
|
-
queryLog: this.db.getFormattedQueryLogs(1)
|
|
280
288
|
};
|
|
281
289
|
}
|
|
282
290
|
catch (error) {
|
|
283
291
|
return {
|
|
284
|
-
status:
|
|
292
|
+
status: "error",
|
|
285
293
|
error: error.message,
|
|
286
|
-
queryLog: this.db.getFormattedQueryLogs(1)
|
|
287
294
|
};
|
|
288
295
|
}
|
|
289
296
|
}
|
|
@@ -294,35 +301,35 @@ class ViewTools {
|
|
|
294
301
|
try {
|
|
295
302
|
const dbValidation = this.validateDatabaseAccess(params?.database);
|
|
296
303
|
if (!dbValidation.valid) {
|
|
297
|
-
return { status:
|
|
304
|
+
return { status: "error", error: dbValidation.error };
|
|
298
305
|
}
|
|
299
306
|
const { view_name } = params;
|
|
300
307
|
const database = dbValidation.database;
|
|
301
308
|
// Validate view name
|
|
302
309
|
const identifierValidation = this.security.validateIdentifier(view_name);
|
|
303
310
|
if (!identifierValidation.valid) {
|
|
304
|
-
return {
|
|
311
|
+
return {
|
|
312
|
+
status: "error",
|
|
313
|
+
error: identifierValidation.error || "Invalid view name",
|
|
314
|
+
};
|
|
305
315
|
}
|
|
306
316
|
const query = `SHOW CREATE VIEW \`${database}\`.\`${view_name}\``;
|
|
307
317
|
const results = await this.db.query(query);
|
|
308
318
|
if (results.length === 0) {
|
|
309
319
|
return {
|
|
310
|
-
status:
|
|
320
|
+
status: "error",
|
|
311
321
|
error: `View '${view_name}' not found`,
|
|
312
|
-
queryLog: this.db.getFormattedQueryLogs(1)
|
|
313
322
|
};
|
|
314
323
|
}
|
|
315
324
|
return {
|
|
316
|
-
status:
|
|
325
|
+
status: "success",
|
|
317
326
|
data: results[0],
|
|
318
|
-
queryLog: this.db.getFormattedQueryLogs(1)
|
|
319
327
|
};
|
|
320
328
|
}
|
|
321
329
|
catch (error) {
|
|
322
330
|
return {
|
|
323
|
-
status:
|
|
331
|
+
status: "error",
|
|
324
332
|
error: error.message,
|
|
325
|
-
queryLog: this.db.getFormattedQueryLogs(1)
|
|
326
333
|
};
|
|
327
334
|
}
|
|
328
335
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@berthojoris/mcp-mysql-server",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.4",
|
|
4
4
|
"description": "Model Context Protocol server for MySQL database integration with dynamic per-project permissions, backup/restore, data import/export, and data migration capabilities",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|