@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.
@@ -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
  }