@berthojoris/mcp-mysql-server 1.4.15 → 1.5.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/DOCUMENTATIONS.md +200 -18
- package/dist/cache/queryCache.d.ts +126 -0
- package/dist/cache/queryCache.js +337 -0
- package/dist/config/featureConfig.js +82 -71
- package/dist/db/connection.d.ts +21 -2
- package/dist/db/connection.js +73 -7
- package/dist/db/queryLogger.d.ts +3 -2
- package/dist/db/queryLogger.js +64 -43
- package/dist/index.d.ts +76 -3
- package/dist/index.js +161 -70
- package/dist/mcp-server.js +166 -5
- package/dist/optimization/queryOptimizer.d.ts +125 -0
- package/dist/optimization/queryOptimizer.js +509 -0
- package/dist/tools/queryTools.d.ts +14 -1
- package/dist/tools/queryTools.js +27 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -37,89 +37,89 @@ class MySQLMCP {
|
|
|
37
37
|
if (!this.featureConfig.isToolEnabled(toolName)) {
|
|
38
38
|
return {
|
|
39
39
|
enabled: false,
|
|
40
|
-
error: this.featureConfig.getPermissionError(toolName)
|
|
40
|
+
error: this.featureConfig.getPermissionError(toolName),
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
return { enabled: true };
|
|
44
44
|
}
|
|
45
45
|
// Database Tools
|
|
46
46
|
async listDatabases() {
|
|
47
|
-
const check = this.checkToolEnabled(
|
|
47
|
+
const check = this.checkToolEnabled("listDatabases");
|
|
48
48
|
if (!check.enabled) {
|
|
49
|
-
return { status:
|
|
49
|
+
return { status: "error", error: check.error };
|
|
50
50
|
}
|
|
51
51
|
return await this.dbTools.listDatabases();
|
|
52
52
|
}
|
|
53
53
|
async listTables(params) {
|
|
54
|
-
const check = this.checkToolEnabled(
|
|
54
|
+
const check = this.checkToolEnabled("listTables");
|
|
55
55
|
if (!check.enabled) {
|
|
56
|
-
return { status:
|
|
56
|
+
return { status: "error", error: check.error };
|
|
57
57
|
}
|
|
58
58
|
return await this.dbTools.listTables(params);
|
|
59
59
|
}
|
|
60
60
|
async readTableSchema(params) {
|
|
61
|
-
const check = this.checkToolEnabled(
|
|
61
|
+
const check = this.checkToolEnabled("readTableSchema");
|
|
62
62
|
if (!check.enabled) {
|
|
63
|
-
return { status:
|
|
63
|
+
return { status: "error", error: check.error };
|
|
64
64
|
}
|
|
65
65
|
return await this.dbTools.readTableSchema(params);
|
|
66
66
|
}
|
|
67
67
|
// CRUD Tools
|
|
68
68
|
async createRecord(params) {
|
|
69
|
-
const check = this.checkToolEnabled(
|
|
69
|
+
const check = this.checkToolEnabled("createRecord");
|
|
70
70
|
if (!check.enabled) {
|
|
71
|
-
return { status:
|
|
71
|
+
return { status: "error", error: check.error };
|
|
72
72
|
}
|
|
73
73
|
return await this.crudTools.createRecord(params);
|
|
74
74
|
}
|
|
75
75
|
async readRecords(params) {
|
|
76
|
-
const check = this.checkToolEnabled(
|
|
76
|
+
const check = this.checkToolEnabled("readRecords");
|
|
77
77
|
if (!check.enabled) {
|
|
78
|
-
return { status:
|
|
78
|
+
return { status: "error", error: check.error };
|
|
79
79
|
}
|
|
80
80
|
return await this.crudTools.readRecords(params);
|
|
81
81
|
}
|
|
82
82
|
async updateRecord(params) {
|
|
83
|
-
const check = this.checkToolEnabled(
|
|
83
|
+
const check = this.checkToolEnabled("updateRecord");
|
|
84
84
|
if (!check.enabled) {
|
|
85
|
-
return { status:
|
|
85
|
+
return { status: "error", error: check.error };
|
|
86
86
|
}
|
|
87
87
|
return await this.crudTools.updateRecord(params);
|
|
88
88
|
}
|
|
89
89
|
async deleteRecord(params) {
|
|
90
|
-
const check = this.checkToolEnabled(
|
|
90
|
+
const check = this.checkToolEnabled("deleteRecord");
|
|
91
91
|
if (!check.enabled) {
|
|
92
|
-
return { status:
|
|
92
|
+
return { status: "error", error: check.error };
|
|
93
93
|
}
|
|
94
94
|
return await this.crudTools.deleteRecord(params);
|
|
95
95
|
}
|
|
96
96
|
// Query Tools
|
|
97
97
|
async runQuery(params) {
|
|
98
|
-
const check = this.checkToolEnabled(
|
|
98
|
+
const check = this.checkToolEnabled("runQuery");
|
|
99
99
|
if (!check.enabled) {
|
|
100
|
-
return { status:
|
|
100
|
+
return { status: "error", error: check.error };
|
|
101
101
|
}
|
|
102
102
|
// Additional security check
|
|
103
103
|
if (!this.security.isReadOnlyQuery(params.query)) {
|
|
104
104
|
return {
|
|
105
|
-
status:
|
|
106
|
-
error:
|
|
105
|
+
status: "error",
|
|
106
|
+
error: "Only SELECT queries are allowed with runQuery. Use executeSql for other operations.",
|
|
107
107
|
};
|
|
108
108
|
}
|
|
109
109
|
return await this.queryTools.runQuery(params);
|
|
110
110
|
}
|
|
111
111
|
async executeSql(params) {
|
|
112
|
-
const check = this.checkToolEnabled(
|
|
112
|
+
const check = this.checkToolEnabled("executeSql");
|
|
113
113
|
if (!check.enabled) {
|
|
114
|
-
return { status:
|
|
114
|
+
return { status: "error", error: check.error };
|
|
115
115
|
}
|
|
116
116
|
// Additional security check - block DDL unless DDL permission is enabled
|
|
117
117
|
if (this.security.hasDangerousOperations(params.query)) {
|
|
118
118
|
// Check if DDL permission is enabled
|
|
119
|
-
if (!this.featureConfig.isCategoryEnabled(
|
|
119
|
+
if (!this.featureConfig.isCategoryEnabled("ddl")) {
|
|
120
120
|
return {
|
|
121
|
-
status:
|
|
122
|
-
error: 'DDL operations (DROP, TRUNCATE, ALTER, CREATE) require the "ddl" permission. Use executeDdl tool or add "ddl" to permissions.'
|
|
121
|
+
status: "error",
|
|
122
|
+
error: 'DDL operations (DROP, TRUNCATE, ALTER, CREATE) require the "ddl" permission. Use executeDdl tool or add "ddl" to permissions.',
|
|
123
123
|
};
|
|
124
124
|
}
|
|
125
125
|
}
|
|
@@ -127,178 +127,178 @@ class MySQLMCP {
|
|
|
127
127
|
}
|
|
128
128
|
// DDL Tools
|
|
129
129
|
async createTable(params) {
|
|
130
|
-
const check = this.checkToolEnabled(
|
|
130
|
+
const check = this.checkToolEnabled("createTable");
|
|
131
131
|
if (!check.enabled) {
|
|
132
|
-
return { status:
|
|
132
|
+
return { status: "error", error: check.error };
|
|
133
133
|
}
|
|
134
134
|
return await this.ddlTools.createTable(params);
|
|
135
135
|
}
|
|
136
136
|
async alterTable(params) {
|
|
137
|
-
const check = this.checkToolEnabled(
|
|
137
|
+
const check = this.checkToolEnabled("alterTable");
|
|
138
138
|
if (!check.enabled) {
|
|
139
|
-
return { status:
|
|
139
|
+
return { status: "error", error: check.error };
|
|
140
140
|
}
|
|
141
141
|
return await this.ddlTools.alterTable(params);
|
|
142
142
|
}
|
|
143
143
|
async dropTable(params) {
|
|
144
|
-
const check = this.checkToolEnabled(
|
|
144
|
+
const check = this.checkToolEnabled("dropTable");
|
|
145
145
|
if (!check.enabled) {
|
|
146
|
-
return { status:
|
|
146
|
+
return { status: "error", error: check.error };
|
|
147
147
|
}
|
|
148
148
|
return await this.ddlTools.dropTable(params);
|
|
149
149
|
}
|
|
150
150
|
async executeDdl(params) {
|
|
151
|
-
const check = this.checkToolEnabled(
|
|
151
|
+
const check = this.checkToolEnabled("executeDdl");
|
|
152
152
|
if (!check.enabled) {
|
|
153
|
-
return { status:
|
|
153
|
+
return { status: "error", error: check.error };
|
|
154
154
|
}
|
|
155
155
|
return await this.ddlTools.executeDdl(params);
|
|
156
156
|
}
|
|
157
157
|
// Utility Tools
|
|
158
158
|
async describeConnection() {
|
|
159
|
-
const check = this.checkToolEnabled(
|
|
159
|
+
const check = this.checkToolEnabled("describeConnection");
|
|
160
160
|
if (!check.enabled) {
|
|
161
|
-
return { status:
|
|
161
|
+
return { status: "error", error: check.error };
|
|
162
162
|
}
|
|
163
163
|
return await this.utilityTools.describeConnection();
|
|
164
164
|
}
|
|
165
165
|
async testConnection() {
|
|
166
|
-
const check = this.checkToolEnabled(
|
|
166
|
+
const check = this.checkToolEnabled("testConnection");
|
|
167
167
|
if (!check.enabled) {
|
|
168
|
-
return { status:
|
|
168
|
+
return { status: "error", error: check.error };
|
|
169
169
|
}
|
|
170
170
|
return await this.utilityTools.testConnection();
|
|
171
171
|
}
|
|
172
172
|
async getTableRelationships(params) {
|
|
173
|
-
const check = this.checkToolEnabled(
|
|
173
|
+
const check = this.checkToolEnabled("getTableRelationships");
|
|
174
174
|
if (!check.enabled) {
|
|
175
|
-
return { status:
|
|
175
|
+
return { status: "error", error: check.error };
|
|
176
176
|
}
|
|
177
177
|
return await this.utilityTools.getTableRelationships(params);
|
|
178
178
|
}
|
|
179
179
|
// Transaction Tools
|
|
180
180
|
async beginTransaction(params) {
|
|
181
|
-
const check = this.checkToolEnabled(
|
|
181
|
+
const check = this.checkToolEnabled("beginTransaction");
|
|
182
182
|
if (!check.enabled) {
|
|
183
|
-
return { status:
|
|
183
|
+
return { status: "error", error: check.error };
|
|
184
184
|
}
|
|
185
185
|
return await this.transactionTools.beginTransaction(params);
|
|
186
186
|
}
|
|
187
187
|
async commitTransaction(params) {
|
|
188
|
-
const check = this.checkToolEnabled(
|
|
188
|
+
const check = this.checkToolEnabled("commitTransaction");
|
|
189
189
|
if (!check.enabled) {
|
|
190
|
-
return { status:
|
|
190
|
+
return { status: "error", error: check.error };
|
|
191
191
|
}
|
|
192
192
|
return await this.transactionTools.commitTransaction(params);
|
|
193
193
|
}
|
|
194
194
|
async rollbackTransaction(params) {
|
|
195
|
-
const check = this.checkToolEnabled(
|
|
195
|
+
const check = this.checkToolEnabled("rollbackTransaction");
|
|
196
196
|
if (!check.enabled) {
|
|
197
|
-
return { status:
|
|
197
|
+
return { status: "error", error: check.error };
|
|
198
198
|
}
|
|
199
199
|
return await this.transactionTools.rollbackTransaction(params);
|
|
200
200
|
}
|
|
201
201
|
async getTransactionStatus() {
|
|
202
|
-
const check = this.checkToolEnabled(
|
|
202
|
+
const check = this.checkToolEnabled("getTransactionStatus");
|
|
203
203
|
if (!check.enabled) {
|
|
204
|
-
return { status:
|
|
204
|
+
return { status: "error", error: check.error };
|
|
205
205
|
}
|
|
206
206
|
return await this.transactionTools.getTransactionStatus();
|
|
207
207
|
}
|
|
208
208
|
async executeInTransaction(params) {
|
|
209
|
-
const check = this.checkToolEnabled(
|
|
209
|
+
const check = this.checkToolEnabled("executeSql"); // Use executeSql permission for transaction queries
|
|
210
210
|
if (!check.enabled) {
|
|
211
|
-
return { status:
|
|
211
|
+
return { status: "error", error: check.error };
|
|
212
212
|
}
|
|
213
213
|
return await this.transactionTools.executeInTransaction(params);
|
|
214
214
|
}
|
|
215
215
|
// Stored Procedure Tools
|
|
216
216
|
async listStoredProcedures(params) {
|
|
217
|
-
const check = this.checkToolEnabled(
|
|
217
|
+
const check = this.checkToolEnabled("listStoredProcedures");
|
|
218
218
|
if (!check.enabled) {
|
|
219
|
-
return { status:
|
|
219
|
+
return { status: "error", error: check.error };
|
|
220
220
|
}
|
|
221
221
|
return await this.storedProcedureTools.listStoredProcedures(params);
|
|
222
222
|
}
|
|
223
223
|
async getStoredProcedureInfo(params) {
|
|
224
|
-
const check = this.checkToolEnabled(
|
|
224
|
+
const check = this.checkToolEnabled("getStoredProcedureInfo");
|
|
225
225
|
if (!check.enabled) {
|
|
226
|
-
return { status:
|
|
226
|
+
return { status: "error", error: check.error };
|
|
227
227
|
}
|
|
228
228
|
return await this.storedProcedureTools.getStoredProcedureInfo(params);
|
|
229
229
|
}
|
|
230
230
|
async executeStoredProcedure(params) {
|
|
231
|
-
const check = this.checkToolEnabled(
|
|
231
|
+
const check = this.checkToolEnabled("executeStoredProcedure");
|
|
232
232
|
if (!check.enabled) {
|
|
233
|
-
return { status:
|
|
233
|
+
return { status: "error", error: check.error };
|
|
234
234
|
}
|
|
235
235
|
return await this.storedProcedureTools.executeStoredProcedure(params);
|
|
236
236
|
}
|
|
237
237
|
async createStoredProcedure(params) {
|
|
238
|
-
const check = this.checkToolEnabled(
|
|
238
|
+
const check = this.checkToolEnabled("createStoredProcedure");
|
|
239
239
|
if (!check.enabled) {
|
|
240
|
-
return { status:
|
|
240
|
+
return { status: "error", error: check.error };
|
|
241
241
|
}
|
|
242
242
|
return await this.storedProcedureTools.createStoredProcedure(params);
|
|
243
243
|
}
|
|
244
244
|
async dropStoredProcedure(params) {
|
|
245
|
-
const check = this.checkToolEnabled(
|
|
245
|
+
const check = this.checkToolEnabled("dropStoredProcedure");
|
|
246
246
|
if (!check.enabled) {
|
|
247
|
-
return { status:
|
|
247
|
+
return { status: "error", error: check.error };
|
|
248
248
|
}
|
|
249
249
|
return await this.storedProcedureTools.dropStoredProcedure(params);
|
|
250
250
|
}
|
|
251
251
|
async showCreateProcedure(params) {
|
|
252
|
-
const check = this.checkToolEnabled(
|
|
252
|
+
const check = this.checkToolEnabled("showCreateProcedure");
|
|
253
253
|
if (!check.enabled) {
|
|
254
|
-
return { status:
|
|
254
|
+
return { status: "error", error: check.error };
|
|
255
255
|
}
|
|
256
256
|
return await this.storedProcedureTools.showCreateProcedure(params);
|
|
257
257
|
}
|
|
258
258
|
// Data Export Tools
|
|
259
259
|
async exportTableToCSV(params) {
|
|
260
|
-
const check = this.checkToolEnabled(
|
|
260
|
+
const check = this.checkToolEnabled("exportTableToCSV");
|
|
261
261
|
if (!check.enabled) {
|
|
262
|
-
return { status:
|
|
262
|
+
return { status: "error", error: check.error };
|
|
263
263
|
}
|
|
264
264
|
return await this.dataExportTools.exportTableToCSV(params);
|
|
265
265
|
}
|
|
266
266
|
async exportQueryToCSV(params) {
|
|
267
|
-
const check = this.checkToolEnabled(
|
|
267
|
+
const check = this.checkToolEnabled("exportQueryToCSV");
|
|
268
268
|
if (!check.enabled) {
|
|
269
|
-
return { status:
|
|
269
|
+
return { status: "error", error: check.error };
|
|
270
270
|
}
|
|
271
271
|
return await this.dataExportTools.exportQueryToCSV(params);
|
|
272
272
|
}
|
|
273
273
|
// Get feature configuration status
|
|
274
274
|
getFeatureStatus() {
|
|
275
275
|
return {
|
|
276
|
-
status:
|
|
276
|
+
status: "success",
|
|
277
277
|
data: {
|
|
278
278
|
enabledCategories: this.featureConfig.getEnabledCategories(),
|
|
279
|
-
categoryStatus: this.featureConfig.getCategoryStatus()
|
|
280
|
-
}
|
|
279
|
+
categoryStatus: this.featureConfig.getCategoryStatus(),
|
|
280
|
+
},
|
|
281
281
|
};
|
|
282
282
|
}
|
|
283
283
|
/**
|
|
284
284
|
* Bulk insert multiple records into the specified table
|
|
285
285
|
*/
|
|
286
286
|
async bulkInsert(params) {
|
|
287
|
-
this.checkToolEnabled(
|
|
287
|
+
this.checkToolEnabled("bulk_insert");
|
|
288
288
|
return this.crudTools.bulkInsert(params);
|
|
289
289
|
}
|
|
290
290
|
/**
|
|
291
291
|
* Bulk update multiple records with different conditions and data
|
|
292
292
|
*/
|
|
293
293
|
async bulkUpdate(params) {
|
|
294
|
-
this.checkToolEnabled(
|
|
294
|
+
this.checkToolEnabled("bulk_update");
|
|
295
295
|
return this.crudTools.bulkUpdate(params);
|
|
296
296
|
}
|
|
297
297
|
/**
|
|
298
298
|
* Bulk delete records based on multiple condition sets
|
|
299
299
|
*/
|
|
300
300
|
async bulkDelete(params) {
|
|
301
|
-
this.checkToolEnabled(
|
|
301
|
+
this.checkToolEnabled("bulk_delete");
|
|
302
302
|
return this.crudTools.bulkDelete(params);
|
|
303
303
|
}
|
|
304
304
|
// Close database connection
|
|
@@ -306,6 +306,97 @@ class MySQLMCP {
|
|
|
306
306
|
const db = connection_1.default.getInstance();
|
|
307
307
|
await db.closePool();
|
|
308
308
|
}
|
|
309
|
+
// ==========================================
|
|
310
|
+
// Cache Management Methods
|
|
311
|
+
// ==========================================
|
|
312
|
+
/**
|
|
313
|
+
* Get cache statistics
|
|
314
|
+
*/
|
|
315
|
+
getCacheStats() {
|
|
316
|
+
const db = connection_1.default.getInstance();
|
|
317
|
+
return {
|
|
318
|
+
status: "success",
|
|
319
|
+
data: db.getCacheStats(),
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Get cache configuration
|
|
324
|
+
*/
|
|
325
|
+
getCacheConfig() {
|
|
326
|
+
const db = connection_1.default.getInstance();
|
|
327
|
+
return {
|
|
328
|
+
status: "success",
|
|
329
|
+
data: db.getCacheConfig(),
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Configure cache settings
|
|
334
|
+
*/
|
|
335
|
+
configureCacheSettings(params) {
|
|
336
|
+
const db = connection_1.default.getInstance();
|
|
337
|
+
db.setCacheConfig(params);
|
|
338
|
+
return {
|
|
339
|
+
status: "success",
|
|
340
|
+
data: {
|
|
341
|
+
message: "Cache configuration updated successfully",
|
|
342
|
+
config: db.getCacheConfig(),
|
|
343
|
+
},
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Clear the query cache
|
|
348
|
+
*/
|
|
349
|
+
clearCache() {
|
|
350
|
+
const db = connection_1.default.getInstance();
|
|
351
|
+
const clearedCount = db.clearCache();
|
|
352
|
+
return {
|
|
353
|
+
status: "success",
|
|
354
|
+
data: {
|
|
355
|
+
message: `Cache cleared successfully`,
|
|
356
|
+
entriesCleared: clearedCount,
|
|
357
|
+
},
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Invalidate cache for a specific table
|
|
362
|
+
*/
|
|
363
|
+
invalidateCacheForTable(params) {
|
|
364
|
+
const db = connection_1.default.getInstance();
|
|
365
|
+
const invalidatedCount = db.invalidateCacheForTable(params.table_name);
|
|
366
|
+
return {
|
|
367
|
+
status: "success",
|
|
368
|
+
data: {
|
|
369
|
+
message: `Cache invalidated for table '${params.table_name}'`,
|
|
370
|
+
entriesInvalidated: invalidatedCount,
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
// ==========================================
|
|
375
|
+
// Query Optimization Methods
|
|
376
|
+
// ==========================================
|
|
377
|
+
/**
|
|
378
|
+
* Analyze a query and get optimization suggestions
|
|
379
|
+
*/
|
|
380
|
+
analyzeQuery(params) {
|
|
381
|
+
const analysis = this.queryTools.analyzeQuery(params.query);
|
|
382
|
+
return {
|
|
383
|
+
status: "success",
|
|
384
|
+
data: analysis,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Get suggested optimizer hints for a specific optimization goal
|
|
389
|
+
*/
|
|
390
|
+
getOptimizationHints(params) {
|
|
391
|
+
const hints = this.queryTools.getSuggestedHints(params.goal);
|
|
392
|
+
return {
|
|
393
|
+
status: "success",
|
|
394
|
+
data: {
|
|
395
|
+
goal: params.goal,
|
|
396
|
+
hints,
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
}
|
|
309
400
|
}
|
|
310
401
|
exports.MySQLMCP = MySQLMCP;
|
|
311
402
|
exports.default = MySQLMCP;
|
package/dist/mcp-server.js
CHANGED
|
@@ -316,7 +316,7 @@ const TOOLS = [
|
|
|
316
316
|
},
|
|
317
317
|
{
|
|
318
318
|
name: "run_query",
|
|
319
|
-
description: "Runs a read-only SQL SELECT query with optional parameters. Only SELECT statements are allowed.",
|
|
319
|
+
description: "Runs a read-only SQL SELECT query with optional parameters, optimizer hints, and caching support. Only SELECT statements are allowed.",
|
|
320
320
|
inputSchema: {
|
|
321
321
|
type: "object",
|
|
322
322
|
properties: {
|
|
@@ -329,6 +329,50 @@ const TOOLS = [
|
|
|
329
329
|
description: "Optional array of parameters for parameterized queries",
|
|
330
330
|
items: {},
|
|
331
331
|
},
|
|
332
|
+
hints: {
|
|
333
|
+
type: "object",
|
|
334
|
+
description: "Optional MySQL optimizer hints to apply to the query",
|
|
335
|
+
properties: {
|
|
336
|
+
maxExecutionTime: {
|
|
337
|
+
type: "number",
|
|
338
|
+
description: "Maximum execution time in milliseconds",
|
|
339
|
+
},
|
|
340
|
+
forceIndex: {
|
|
341
|
+
oneOf: [
|
|
342
|
+
{ type: "string" },
|
|
343
|
+
{ type: "array", items: { type: "string" } },
|
|
344
|
+
],
|
|
345
|
+
description: "Force usage of specific index(es)",
|
|
346
|
+
},
|
|
347
|
+
ignoreIndex: {
|
|
348
|
+
oneOf: [
|
|
349
|
+
{ type: "string" },
|
|
350
|
+
{ type: "array", items: { type: "string" } },
|
|
351
|
+
],
|
|
352
|
+
description: "Ignore specific index(es)",
|
|
353
|
+
},
|
|
354
|
+
straightJoin: {
|
|
355
|
+
type: "boolean",
|
|
356
|
+
description: "Use STRAIGHT_JOIN to force join order",
|
|
357
|
+
},
|
|
358
|
+
noCache: {
|
|
359
|
+
type: "boolean",
|
|
360
|
+
description: "Disable query cache for this query",
|
|
361
|
+
},
|
|
362
|
+
sqlBigResult: {
|
|
363
|
+
type: "boolean",
|
|
364
|
+
description: "Optimize for large result sets",
|
|
365
|
+
},
|
|
366
|
+
sqlSmallResult: {
|
|
367
|
+
type: "boolean",
|
|
368
|
+
description: "Optimize for small result sets",
|
|
369
|
+
},
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
useCache: {
|
|
373
|
+
type: "boolean",
|
|
374
|
+
description: "Whether to use query result caching (default: true)",
|
|
375
|
+
},
|
|
332
376
|
},
|
|
333
377
|
required: ["query"],
|
|
334
378
|
},
|
|
@@ -806,6 +850,100 @@ const TOOLS = [
|
|
|
806
850
|
required: ["query"],
|
|
807
851
|
},
|
|
808
852
|
},
|
|
853
|
+
// Cache Management Tools
|
|
854
|
+
{
|
|
855
|
+
name: "get_cache_stats",
|
|
856
|
+
description: "Get query cache statistics including hit rate, size, and configuration.",
|
|
857
|
+
inputSchema: {
|
|
858
|
+
type: "object",
|
|
859
|
+
properties: {},
|
|
860
|
+
},
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
name: "get_cache_config",
|
|
864
|
+
description: "Get current cache configuration settings.",
|
|
865
|
+
inputSchema: {
|
|
866
|
+
type: "object",
|
|
867
|
+
properties: {},
|
|
868
|
+
},
|
|
869
|
+
},
|
|
870
|
+
{
|
|
871
|
+
name: "configure_cache",
|
|
872
|
+
description: "Configure cache settings including TTL, max size, and enable/disable.",
|
|
873
|
+
inputSchema: {
|
|
874
|
+
type: "object",
|
|
875
|
+
properties: {
|
|
876
|
+
enabled: {
|
|
877
|
+
type: "boolean",
|
|
878
|
+
description: "Enable or disable the query cache",
|
|
879
|
+
},
|
|
880
|
+
ttlMs: {
|
|
881
|
+
type: "number",
|
|
882
|
+
description: "Cache time-to-live in milliseconds (default: 60000)",
|
|
883
|
+
},
|
|
884
|
+
maxSize: {
|
|
885
|
+
type: "number",
|
|
886
|
+
description: "Maximum number of cached entries (default: 100)",
|
|
887
|
+
},
|
|
888
|
+
maxMemoryMB: {
|
|
889
|
+
type: "number",
|
|
890
|
+
description: "Maximum memory usage in MB (default: 50)",
|
|
891
|
+
},
|
|
892
|
+
},
|
|
893
|
+
},
|
|
894
|
+
},
|
|
895
|
+
{
|
|
896
|
+
name: "clear_cache",
|
|
897
|
+
description: "Clear all entries from the query cache.",
|
|
898
|
+
inputSchema: {
|
|
899
|
+
type: "object",
|
|
900
|
+
properties: {},
|
|
901
|
+
},
|
|
902
|
+
},
|
|
903
|
+
{
|
|
904
|
+
name: "invalidate_table_cache",
|
|
905
|
+
description: "Invalidate all cached queries related to a specific table.",
|
|
906
|
+
inputSchema: {
|
|
907
|
+
type: "object",
|
|
908
|
+
properties: {
|
|
909
|
+
table_name: {
|
|
910
|
+
type: "string",
|
|
911
|
+
description: "Name of the table to invalidate cache for",
|
|
912
|
+
},
|
|
913
|
+
},
|
|
914
|
+
required: ["table_name"],
|
|
915
|
+
},
|
|
916
|
+
},
|
|
917
|
+
// Query Optimization Tools
|
|
918
|
+
{
|
|
919
|
+
name: "analyze_query",
|
|
920
|
+
description: "Analyze a SQL query and get optimization suggestions including recommended indexes and hints.",
|
|
921
|
+
inputSchema: {
|
|
922
|
+
type: "object",
|
|
923
|
+
properties: {
|
|
924
|
+
query: {
|
|
925
|
+
type: "string",
|
|
926
|
+
description: "SQL query to analyze",
|
|
927
|
+
},
|
|
928
|
+
},
|
|
929
|
+
required: ["query"],
|
|
930
|
+
},
|
|
931
|
+
},
|
|
932
|
+
{
|
|
933
|
+
name: "get_optimization_hints",
|
|
934
|
+
description: "Get suggested MySQL optimizer hints for a specific optimization goal (SPEED, MEMORY, or STABILITY).",
|
|
935
|
+
inputSchema: {
|
|
936
|
+
type: "object",
|
|
937
|
+
properties: {
|
|
938
|
+
goal: {
|
|
939
|
+
type: "string",
|
|
940
|
+
enum: ["SPEED", "MEMORY", "STABILITY"],
|
|
941
|
+
description: "Optimization goal: SPEED for faster queries, MEMORY for lower memory usage, STABILITY for consistent performance",
|
|
942
|
+
},
|
|
943
|
+
},
|
|
944
|
+
required: ["goal"],
|
|
945
|
+
},
|
|
946
|
+
},
|
|
809
947
|
];
|
|
810
948
|
// Create the MCP server
|
|
811
949
|
const server = new index_js_1.Server({
|
|
@@ -927,14 +1065,37 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
927
1065
|
case "export_query_to_csv":
|
|
928
1066
|
result = await mysqlMCP.exportQueryToCSV((args || {}));
|
|
929
1067
|
break;
|
|
1068
|
+
// Cache Management Tools
|
|
1069
|
+
case "get_cache_stats":
|
|
1070
|
+
result = mysqlMCP.getCacheStats();
|
|
1071
|
+
break;
|
|
1072
|
+
case "get_cache_config":
|
|
1073
|
+
result = mysqlMCP.getCacheConfig();
|
|
1074
|
+
break;
|
|
1075
|
+
case "configure_cache":
|
|
1076
|
+
result = mysqlMCP.configureCacheSettings((args || {}));
|
|
1077
|
+
break;
|
|
1078
|
+
case "clear_cache":
|
|
1079
|
+
result = mysqlMCP.clearCache();
|
|
1080
|
+
break;
|
|
1081
|
+
case "invalidate_table_cache":
|
|
1082
|
+
result = mysqlMCP.invalidateCacheForTable((args || {}));
|
|
1083
|
+
break;
|
|
1084
|
+
// Query Optimization Tools
|
|
1085
|
+
case "analyze_query":
|
|
1086
|
+
result = mysqlMCP.analyzeQuery((args || {}));
|
|
1087
|
+
break;
|
|
1088
|
+
case "get_optimization_hints":
|
|
1089
|
+
result = mysqlMCP.getOptimizationHints((args || {}));
|
|
1090
|
+
break;
|
|
930
1091
|
default:
|
|
931
1092
|
throw new Error(`Unknown tool: ${name}`);
|
|
932
1093
|
}
|
|
933
1094
|
// Handle the result based on status
|
|
934
1095
|
if (result.status === "error") {
|
|
935
1096
|
// Include query log in error response if available
|
|
936
|
-
let errorText = `Error: ${result.error}`;
|
|
937
|
-
if (
|
|
1097
|
+
let errorText = `Error: ${"error" in result ? result.error : "Unknown error"}`;
|
|
1098
|
+
if ("queryLog" in result && result.queryLog) {
|
|
938
1099
|
errorText += `\n\n${result.queryLog}`;
|
|
939
1100
|
}
|
|
940
1101
|
return {
|
|
@@ -975,11 +1136,11 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
975
1136
|
}
|
|
976
1137
|
// NEW APPROACH: Wrap the data with SQL query as part of the response structure
|
|
977
1138
|
// This forces the LLM to see and describe the SQL query as part of the data
|
|
978
|
-
if (
|
|
1139
|
+
if ("queryLog" in result && result.queryLog) {
|
|
979
1140
|
const wrappedResponse = {
|
|
980
1141
|
"⚠️ IMPORTANT_INSTRUCTION_TO_ASSISTANT": "ALWAYS display the SQL query execution details below to the user in your response. This is critical information that users need to see.",
|
|
981
1142
|
"⚠️ SQL_QUERY_EXECUTED": result.queryLog,
|
|
982
|
-
"📊 RESULTS": responseData
|
|
1143
|
+
"📊 RESULTS": responseData,
|
|
983
1144
|
};
|
|
984
1145
|
return {
|
|
985
1146
|
content: [
|