@berthojoris/mcp-mysql-server 1.35.0 → 1.36.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/CHANGELOG.md +16 -0
- package/DOCUMENTATIONS.md +13 -38
- package/README.md +2 -2
- package/dist/index.d.ts +0 -180
- package/dist/index.js +0 -135
- package/dist/mcp-server.js +0 -65
- package/dist/tools/backupRestoreTools.d.ts +0 -68
- package/dist/tools/backupRestoreTools.js +0 -516
- package/dist/tools/dataExportTools.d.ts +0 -38
- package/dist/tools/dataExportTools.js +0 -248
- package/dist/tools/migrationTools.d.ts +0 -73
- package/dist/tools/migrationTools.js +0 -508
- package/dist/tools/performanceTools.d.ts +0 -25
- package/dist/tools/performanceTools.js +0 -129
- package/dist/tools/processTools.d.ts +0 -36
- package/dist/tools/processTools.js +0 -122
- package/package.json +1 -1
|
@@ -222,81 +222,6 @@ class DataExportTools {
|
|
|
222
222
|
};
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
|
-
/**
|
|
226
|
-
* Export query results to CSV format
|
|
227
|
-
*/
|
|
228
|
-
async exportQueryToCSV(params) {
|
|
229
|
-
try {
|
|
230
|
-
const { query, params: queryParams = [], include_headers = true, } = params;
|
|
231
|
-
// Validate query is a SELECT statement
|
|
232
|
-
if (!this.security.isReadOnlyQuery(query)) {
|
|
233
|
-
return {
|
|
234
|
-
status: "error",
|
|
235
|
-
error: "Only SELECT queries can be exported to CSV",
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
// Validate parameters
|
|
239
|
-
const paramValidation = this.security.validateParameters(queryParams);
|
|
240
|
-
if (!paramValidation.valid) {
|
|
241
|
-
return {
|
|
242
|
-
status: "error",
|
|
243
|
-
error: paramValidation.error,
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
// Execute query
|
|
247
|
-
const results = await this.db.query(query, queryParams);
|
|
248
|
-
// If no results, return empty CSV
|
|
249
|
-
if (results.length === 0) {
|
|
250
|
-
return {
|
|
251
|
-
status: "success",
|
|
252
|
-
data: {
|
|
253
|
-
csv: include_headers ? "" : "",
|
|
254
|
-
row_count: 0,
|
|
255
|
-
},
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
// Generate CSV
|
|
259
|
-
let csv = "";
|
|
260
|
-
// Add headers if requested
|
|
261
|
-
if (include_headers) {
|
|
262
|
-
const headers = Object.keys(results[0]).join(",");
|
|
263
|
-
csv += headers + "\n";
|
|
264
|
-
}
|
|
265
|
-
// Add data rows
|
|
266
|
-
for (const row of results) {
|
|
267
|
-
const values = Object.values(row)
|
|
268
|
-
.map((value) => {
|
|
269
|
-
if (value === null)
|
|
270
|
-
return "";
|
|
271
|
-
if (typeof value === "string") {
|
|
272
|
-
// Escape quotes and wrap in quotes if contains comma or newline
|
|
273
|
-
if (value.includes(",") ||
|
|
274
|
-
value.includes("\n") ||
|
|
275
|
-
value.includes('"')) {
|
|
276
|
-
return `"${value.replace(/"/g, '""')}"`;
|
|
277
|
-
}
|
|
278
|
-
return value;
|
|
279
|
-
}
|
|
280
|
-
return String(value);
|
|
281
|
-
})
|
|
282
|
-
.join(",");
|
|
283
|
-
csv += values + "\n";
|
|
284
|
-
}
|
|
285
|
-
return {
|
|
286
|
-
status: "success",
|
|
287
|
-
data: {
|
|
288
|
-
csv: csv,
|
|
289
|
-
row_count: results.length,
|
|
290
|
-
},
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
catch (error) {
|
|
294
|
-
return {
|
|
295
|
-
status: "error",
|
|
296
|
-
error: error.message,
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
225
|
/**
|
|
301
226
|
* Export table data to JSON format
|
|
302
227
|
*/
|
|
@@ -424,179 +349,6 @@ class DataExportTools {
|
|
|
424
349
|
};
|
|
425
350
|
}
|
|
426
351
|
}
|
|
427
|
-
/**
|
|
428
|
-
* Export query results to JSON format
|
|
429
|
-
*/
|
|
430
|
-
async exportQueryToJSON(params) {
|
|
431
|
-
try {
|
|
432
|
-
const { query, params: queryParams = [], pretty = true } = params;
|
|
433
|
-
// Validate query is a SELECT statement
|
|
434
|
-
if (!this.security.isReadOnlyQuery(query)) {
|
|
435
|
-
return {
|
|
436
|
-
status: "error",
|
|
437
|
-
error: "Only SELECT queries can be exported to JSON",
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
// Validate parameters
|
|
441
|
-
const paramValidation = this.security.validateParameters(queryParams);
|
|
442
|
-
if (!paramValidation.valid) {
|
|
443
|
-
return { status: "error", error: paramValidation.error };
|
|
444
|
-
}
|
|
445
|
-
// Execute query
|
|
446
|
-
const results = await this.db.query(query, queryParams);
|
|
447
|
-
// Generate JSON
|
|
448
|
-
const json = pretty
|
|
449
|
-
? JSON.stringify(results, null, 2)
|
|
450
|
-
: JSON.stringify(results);
|
|
451
|
-
return {
|
|
452
|
-
status: "success",
|
|
453
|
-
data: {
|
|
454
|
-
json: json,
|
|
455
|
-
row_count: results.length,
|
|
456
|
-
},
|
|
457
|
-
};
|
|
458
|
-
}
|
|
459
|
-
catch (error) {
|
|
460
|
-
return {
|
|
461
|
-
status: "error",
|
|
462
|
-
error: error.message,
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
/**
|
|
467
|
-
* Export table data to SQL INSERT statements
|
|
468
|
-
*/
|
|
469
|
-
async exportTableToSql(params) {
|
|
470
|
-
try {
|
|
471
|
-
const { table_name, filters = [], include_create_table = false, batch_size = 100, database, } = params;
|
|
472
|
-
// Validate database access
|
|
473
|
-
const dbValidation = this.validateDatabaseAccess(database);
|
|
474
|
-
if (!dbValidation.valid) {
|
|
475
|
-
return { status: "error", error: dbValidation.error };
|
|
476
|
-
}
|
|
477
|
-
// Validate table name
|
|
478
|
-
const tableValidation = this.security.validateIdentifier(table_name);
|
|
479
|
-
if (!tableValidation.valid) {
|
|
480
|
-
return { status: "error", error: tableValidation.error };
|
|
481
|
-
}
|
|
482
|
-
const escapedTableName = this.security.escapeIdentifier(table_name);
|
|
483
|
-
let sql = "";
|
|
484
|
-
let queryCount = 0;
|
|
485
|
-
// Add CREATE TABLE if requested
|
|
486
|
-
if (include_create_table) {
|
|
487
|
-
const createQuery = `SHOW CREATE TABLE ${escapedTableName}`;
|
|
488
|
-
const createResults = await this.db.query(createQuery);
|
|
489
|
-
queryCount++;
|
|
490
|
-
if (createResults.length > 0) {
|
|
491
|
-
sql += `-- Table structure for ${table_name}\n`;
|
|
492
|
-
sql += `${createResults[0]["Create Table"]};\n\n`;
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
// Build WHERE clause
|
|
496
|
-
let whereClause = "";
|
|
497
|
-
const whereParams = [];
|
|
498
|
-
if (filters && filters.length > 0) {
|
|
499
|
-
const whereConditions = [];
|
|
500
|
-
for (const filter of filters) {
|
|
501
|
-
const fieldValidation = this.security.validateIdentifier(filter.field);
|
|
502
|
-
if (!fieldValidation.valid) {
|
|
503
|
-
return {
|
|
504
|
-
status: "error",
|
|
505
|
-
error: `Invalid field name: ${filter.field}`,
|
|
506
|
-
};
|
|
507
|
-
}
|
|
508
|
-
const fieldName = this.security.escapeIdentifier(filter.field);
|
|
509
|
-
switch (filter.operator) {
|
|
510
|
-
case "eq":
|
|
511
|
-
whereConditions.push(`${fieldName} = ?`);
|
|
512
|
-
whereParams.push(filter.value);
|
|
513
|
-
break;
|
|
514
|
-
case "neq":
|
|
515
|
-
whereConditions.push(`${fieldName} != ?`);
|
|
516
|
-
whereParams.push(filter.value);
|
|
517
|
-
break;
|
|
518
|
-
case "gt":
|
|
519
|
-
whereConditions.push(`${fieldName} > ?`);
|
|
520
|
-
whereParams.push(filter.value);
|
|
521
|
-
break;
|
|
522
|
-
case "gte":
|
|
523
|
-
whereConditions.push(`${fieldName} >= ?`);
|
|
524
|
-
whereParams.push(filter.value);
|
|
525
|
-
break;
|
|
526
|
-
case "lt":
|
|
527
|
-
whereConditions.push(`${fieldName} < ?`);
|
|
528
|
-
whereParams.push(filter.value);
|
|
529
|
-
break;
|
|
530
|
-
case "lte":
|
|
531
|
-
whereConditions.push(`${fieldName} <= ?`);
|
|
532
|
-
whereParams.push(filter.value);
|
|
533
|
-
break;
|
|
534
|
-
case "like":
|
|
535
|
-
whereConditions.push(`${fieldName} LIKE ?`);
|
|
536
|
-
whereParams.push(filter.value);
|
|
537
|
-
break;
|
|
538
|
-
case "in":
|
|
539
|
-
if (Array.isArray(filter.value)) {
|
|
540
|
-
const placeholders = filter.value.map(() => "?").join(", ");
|
|
541
|
-
whereConditions.push(`${fieldName} IN (${placeholders})`);
|
|
542
|
-
whereParams.push(...filter.value);
|
|
543
|
-
}
|
|
544
|
-
else {
|
|
545
|
-
return {
|
|
546
|
-
status: "error",
|
|
547
|
-
error: "IN operator requires an array of values",
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
break;
|
|
551
|
-
default:
|
|
552
|
-
return {
|
|
553
|
-
status: "error",
|
|
554
|
-
error: `Unsupported operator: ${filter.operator}`,
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
if (whereConditions.length > 0) {
|
|
559
|
-
whereClause = "WHERE " + whereConditions.join(" AND ");
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
// Get data
|
|
563
|
-
const dataQuery = `SELECT * FROM ${escapedTableName} ${whereClause}`;
|
|
564
|
-
const results = await this.db.query(dataQuery, whereParams);
|
|
565
|
-
queryCount++;
|
|
566
|
-
if (results.length > 0) {
|
|
567
|
-
const columns = Object.keys(results[0]);
|
|
568
|
-
const escapedColumns = columns
|
|
569
|
-
.map((c) => this.security.escapeIdentifier(c))
|
|
570
|
-
.join(", ");
|
|
571
|
-
sql += `-- Data for table ${table_name} (${results.length} rows)\n`;
|
|
572
|
-
// Generate INSERT statements in batches
|
|
573
|
-
for (let i = 0; i < results.length; i += batch_size) {
|
|
574
|
-
const batch = results.slice(i, i + batch_size);
|
|
575
|
-
const values = batch
|
|
576
|
-
.map((row) => {
|
|
577
|
-
const rowValues = columns.map((col) => this.escapeValue(row[col]));
|
|
578
|
-
return `(${rowValues.join(", ")})`;
|
|
579
|
-
})
|
|
580
|
-
.join(",\n");
|
|
581
|
-
sql += `INSERT INTO ${escapedTableName} (${escapedColumns}) VALUES\n${values};\n\n`;
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
return {
|
|
585
|
-
status: "success",
|
|
586
|
-
data: {
|
|
587
|
-
sql: sql,
|
|
588
|
-
row_count: results.length,
|
|
589
|
-
table_name: table_name,
|
|
590
|
-
},
|
|
591
|
-
};
|
|
592
|
-
}
|
|
593
|
-
catch (error) {
|
|
594
|
-
return {
|
|
595
|
-
status: "error",
|
|
596
|
-
error: error.message,
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
352
|
/**
|
|
601
353
|
* Import data from CSV string
|
|
602
354
|
*/
|
|
@@ -15,77 +15,4 @@ export declare class MigrationTools {
|
|
|
15
15
|
* Escape string value for SQL
|
|
16
16
|
*/
|
|
17
17
|
private escapeValue;
|
|
18
|
-
/**
|
|
19
|
-
* Copy data from one table to another within the same database
|
|
20
|
-
*/
|
|
21
|
-
copyTableData(params: {
|
|
22
|
-
source_table: string;
|
|
23
|
-
target_table: string;
|
|
24
|
-
column_mapping?: Record<string, string>;
|
|
25
|
-
where_clause?: string;
|
|
26
|
-
truncate_target?: boolean;
|
|
27
|
-
batch_size?: number;
|
|
28
|
-
database?: string;
|
|
29
|
-
}): Promise<{
|
|
30
|
-
status: string;
|
|
31
|
-
data?: any;
|
|
32
|
-
error?: string;
|
|
33
|
-
}>;
|
|
34
|
-
/**
|
|
35
|
-
* Move data from one table to another (copy + delete from source)
|
|
36
|
-
*/
|
|
37
|
-
moveTableData(params: {
|
|
38
|
-
source_table: string;
|
|
39
|
-
target_table: string;
|
|
40
|
-
column_mapping?: Record<string, string>;
|
|
41
|
-
where_clause?: string;
|
|
42
|
-
batch_size?: number;
|
|
43
|
-
database?: string;
|
|
44
|
-
}): Promise<{
|
|
45
|
-
status: string;
|
|
46
|
-
data?: any;
|
|
47
|
-
error?: string;
|
|
48
|
-
}>;
|
|
49
|
-
/**
|
|
50
|
-
* Clone a table structure (with or without data)
|
|
51
|
-
*/
|
|
52
|
-
cloneTable(params: {
|
|
53
|
-
source_table: string;
|
|
54
|
-
new_table_name: string;
|
|
55
|
-
include_data?: boolean;
|
|
56
|
-
include_indexes?: boolean;
|
|
57
|
-
database?: string;
|
|
58
|
-
}): Promise<{
|
|
59
|
-
status: string;
|
|
60
|
-
data?: any;
|
|
61
|
-
error?: string;
|
|
62
|
-
}>;
|
|
63
|
-
/**
|
|
64
|
-
* Compare structure of two tables
|
|
65
|
-
*/
|
|
66
|
-
compareTableStructure(params: {
|
|
67
|
-
table1: string;
|
|
68
|
-
table2: string;
|
|
69
|
-
database?: string;
|
|
70
|
-
}): Promise<{
|
|
71
|
-
status: string;
|
|
72
|
-
data?: any;
|
|
73
|
-
error?: string;
|
|
74
|
-
}>;
|
|
75
|
-
/**
|
|
76
|
-
* Sync data between two tables based on a key column
|
|
77
|
-
*/
|
|
78
|
-
syncTableData(params: {
|
|
79
|
-
source_table: string;
|
|
80
|
-
target_table: string;
|
|
81
|
-
key_column: string;
|
|
82
|
-
columns_to_sync?: string[];
|
|
83
|
-
sync_mode?: "insert_only" | "update_only" | "upsert";
|
|
84
|
-
batch_size?: number;
|
|
85
|
-
database?: string;
|
|
86
|
-
}): Promise<{
|
|
87
|
-
status: string;
|
|
88
|
-
data?: any;
|
|
89
|
-
error?: string;
|
|
90
|
-
}>;
|
|
91
18
|
}
|