@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.
@@ -15,72 +15,4 @@ export declare class BackupRestoreTools {
15
15
  * Escape string value for SQL
16
16
  */
17
17
  private escapeValue;
18
- /**
19
- * Get CREATE TABLE statement for a table
20
- */
21
- getCreateTableStatement(params: {
22
- table_name: string;
23
- database?: string;
24
- }): Promise<{
25
- status: string;
26
- data?: any;
27
- error?: string;
28
- }>;
29
- /**
30
- * Backup a single table to SQL dump format
31
- */
32
- backupTable(params: {
33
- table_name: string;
34
- include_data?: boolean;
35
- include_drop?: boolean;
36
- database?: string;
37
- }): Promise<{
38
- status: string;
39
- data?: any;
40
- error?: string;
41
- }>;
42
- /**
43
- * Backup entire database schema and optionally data
44
- */
45
- backupDatabase(params: {
46
- include_data?: boolean;
47
- include_drop?: boolean;
48
- tables?: string[];
49
- database?: string;
50
- }): Promise<{
51
- status: string;
52
- data?: any;
53
- error?: string;
54
- }>;
55
- /**
56
- * Restore database from SQL dump
57
- * Executes SQL statements from the provided SQL dump string
58
- */
59
- restoreFromSql(params: {
60
- sql_dump: string;
61
- stop_on_error?: boolean;
62
- database?: string;
63
- }): Promise<{
64
- status: string;
65
- data?: any;
66
- error?: string;
67
- }>;
68
- /**
69
- * Parse SQL dump into individual statements
70
- */
71
- private parseSqlStatements;
72
- /**
73
- * Get database schema overview (all CREATE statements)
74
- */
75
- getDatabaseSchema(params: {
76
- database?: string;
77
- include_views?: boolean;
78
- include_procedures?: boolean;
79
- include_functions?: boolean;
80
- include_triggers?: boolean;
81
- }): Promise<{
82
- status: string;
83
- data?: any;
84
- error?: string;
85
- }>;
86
18
  }
@@ -66,521 +66,5 @@ class BackupRestoreTools {
66
66
  .replace(/\0/g, "\\0");
67
67
  return `'${escaped}'`;
68
68
  }
69
- /**
70
- * Get CREATE TABLE statement for a table
71
- */
72
- async getCreateTableStatement(params) {
73
- try {
74
- const { table_name, database } = params;
75
- // Validate database access
76
- const dbValidation = this.validateDatabaseAccess(database);
77
- if (!dbValidation.valid) {
78
- return { status: "error", error: dbValidation.error };
79
- }
80
- // Validate table name
81
- const tableValidation = this.security.validateIdentifier(table_name);
82
- if (!tableValidation.valid) {
83
- return { status: "error", error: tableValidation.error };
84
- }
85
- const escapedTable = this.security.escapeIdentifier(table_name);
86
- const query = `SHOW CREATE TABLE ${escapedTable}`;
87
- const results = await this.db.query(query);
88
- if (results.length === 0) {
89
- return {
90
- status: "error",
91
- error: `Table '${table_name}' not found`,
92
- };
93
- }
94
- return {
95
- status: "success",
96
- data: {
97
- table_name: table_name,
98
- create_statement: results[0]["Create Table"],
99
- },
100
- };
101
- }
102
- catch (error) {
103
- return {
104
- status: "error",
105
- error: error.message,
106
- };
107
- }
108
- }
109
- /**
110
- * Backup a single table to SQL dump format
111
- */
112
- async backupTable(params) {
113
- try {
114
- const { table_name, include_data = true, include_drop = true, database, } = params;
115
- // Validate database access
116
- const dbValidation = this.validateDatabaseAccess(database);
117
- if (!dbValidation.valid) {
118
- return { status: "error", error: dbValidation.error };
119
- }
120
- // Validate table name
121
- const tableValidation = this.security.validateIdentifier(table_name);
122
- if (!tableValidation.valid) {
123
- return { status: "error", error: tableValidation.error };
124
- }
125
- const escapedTable = this.security.escapeIdentifier(table_name);
126
- let sqlDump = "";
127
- let queryCount = 0;
128
- // Add header comment
129
- sqlDump += `-- MySQL Dump generated by MySQL MCP Server\n`;
130
- sqlDump += `-- Table: ${table_name}\n`;
131
- sqlDump += `-- Generated at: ${new Date().toISOString()}\n`;
132
- sqlDump += `-- --------------------------------------------------------\n\n`;
133
- // Add DROP TABLE IF EXISTS
134
- if (include_drop) {
135
- sqlDump += `DROP TABLE IF EXISTS ${escapedTable};\n\n`;
136
- }
137
- // Get CREATE TABLE statement
138
- const createQuery = `SHOW CREATE TABLE ${escapedTable}`;
139
- const createResults = await this.db.query(createQuery);
140
- queryCount++;
141
- if (createResults.length === 0) {
142
- return {
143
- status: "error",
144
- error: `Table '${table_name}' not found`,
145
- };
146
- }
147
- sqlDump += `${createResults[0]["Create Table"]};\n\n`;
148
- // Get table data if requested
149
- let rowCount = 0;
150
- if (include_data) {
151
- const dataQuery = `SELECT * FROM ${escapedTable}`;
152
- const dataResults = await this.db.query(dataQuery);
153
- queryCount++;
154
- if (dataResults.length > 0) {
155
- rowCount = dataResults.length;
156
- const columns = Object.keys(dataResults[0]);
157
- const escapedColumns = columns
158
- .map((c) => this.security.escapeIdentifier(c))
159
- .join(", ");
160
- sqlDump += `-- Data for table ${table_name}\n`;
161
- sqlDump += `LOCK TABLES ${escapedTable} WRITE;\n`;
162
- sqlDump += `/*!40000 ALTER TABLE ${escapedTable} DISABLE KEYS */;\n\n`;
163
- // Generate INSERT statements in batches
164
- const batchSize = 100;
165
- for (let i = 0; i < dataResults.length; i += batchSize) {
166
- const batch = dataResults.slice(i, i + batchSize);
167
- const values = batch
168
- .map((row) => {
169
- const rowValues = columns.map((col) => this.escapeValue(row[col]));
170
- return `(${rowValues.join(", ")})`;
171
- })
172
- .join(",\n");
173
- sqlDump += `INSERT INTO ${escapedTable} (${escapedColumns}) VALUES\n${values};\n\n`;
174
- }
175
- sqlDump += `/*!40000 ALTER TABLE ${escapedTable} ENABLE KEYS */;\n`;
176
- sqlDump += `UNLOCK TABLES;\n`;
177
- }
178
- }
179
- return {
180
- status: "success",
181
- data: {
182
- table_name: table_name,
183
- sql_dump: sqlDump,
184
- row_count: rowCount,
185
- include_data: include_data,
186
- include_drop: include_drop,
187
- },
188
- };
189
- }
190
- catch (error) {
191
- return {
192
- status: "error",
193
- error: error.message,
194
- };
195
- }
196
- }
197
- /**
198
- * Backup entire database schema and optionally data
199
- */
200
- async backupDatabase(params) {
201
- try {
202
- const { include_data = true, include_drop = true, tables, database, } = params;
203
- // Validate database access
204
- const dbValidation = this.validateDatabaseAccess(database);
205
- if (!dbValidation.valid) {
206
- return { status: "error", error: dbValidation.error };
207
- }
208
- let sqlDump = "";
209
- let queryCount = 0;
210
- let totalRows = 0;
211
- const backedUpTables = [];
212
- // Add header
213
- sqlDump += `-- MySQL Database Dump generated by MySQL MCP Server\n`;
214
- sqlDump += `-- Database: ${dbValidation.database}\n`;
215
- sqlDump += `-- Generated at: ${new Date().toISOString()}\n`;
216
- sqlDump += `-- --------------------------------------------------------\n\n`;
217
- sqlDump += `SET FOREIGN_KEY_CHECKS=0;\n`;
218
- sqlDump += `SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO';\n`;
219
- sqlDump += `SET AUTOCOMMIT=0;\n`;
220
- sqlDump += `START TRANSACTION;\n\n`;
221
- // Get list of tables
222
- let tableList;
223
- if (tables && tables.length > 0) {
224
- // Validate each table name
225
- for (const tableName of tables) {
226
- const validation = this.security.validateIdentifier(tableName);
227
- if (!validation.valid) {
228
- return {
229
- status: "error",
230
- error: `Invalid table name: ${tableName}`,
231
- };
232
- }
233
- }
234
- tableList = tables;
235
- }
236
- else {
237
- const tablesQuery = `SHOW TABLES`;
238
- const tablesResult = await this.db.query(tablesQuery);
239
- queryCount++;
240
- tableList = tablesResult.map((row) => Object.values(row)[0]);
241
- }
242
- // Backup each table
243
- for (const tableName of tableList) {
244
- const escapedTable = this.security.escapeIdentifier(tableName);
245
- sqlDump += `-- --------------------------------------------------------\n`;
246
- sqlDump += `-- Table structure for ${tableName}\n`;
247
- sqlDump += `-- --------------------------------------------------------\n\n`;
248
- // Add DROP TABLE IF EXISTS
249
- if (include_drop) {
250
- sqlDump += `DROP TABLE IF EXISTS ${escapedTable};\n\n`;
251
- }
252
- // Get CREATE TABLE statement
253
- const createQuery = `SHOW CREATE TABLE ${escapedTable}`;
254
- const createResults = await this.db.query(createQuery);
255
- queryCount++;
256
- if (createResults.length > 0) {
257
- sqlDump += `${createResults[0]["Create Table"]};\n\n`;
258
- backedUpTables.push(tableName);
259
- }
260
- // Get table data if requested
261
- if (include_data) {
262
- const dataQuery = `SELECT * FROM ${escapedTable}`;
263
- const dataResults = await this.db.query(dataQuery);
264
- queryCount++;
265
- if (dataResults.length > 0) {
266
- totalRows += dataResults.length;
267
- const columns = Object.keys(dataResults[0]);
268
- const escapedColumns = columns
269
- .map((c) => this.security.escapeIdentifier(c))
270
- .join(", ");
271
- sqlDump += `-- Data for table ${tableName}\n`;
272
- sqlDump += `LOCK TABLES ${escapedTable} WRITE;\n`;
273
- sqlDump += `/*!40000 ALTER TABLE ${escapedTable} DISABLE KEYS */;\n\n`;
274
- // Generate INSERT statements in batches
275
- const batchSize = 100;
276
- for (let i = 0; i < dataResults.length; i += batchSize) {
277
- const batch = dataResults.slice(i, i + batchSize);
278
- const values = batch
279
- .map((row) => {
280
- const rowValues = columns.map((col) => this.escapeValue(row[col]));
281
- return `(${rowValues.join(", ")})`;
282
- })
283
- .join(",\n");
284
- sqlDump += `INSERT INTO ${escapedTable} (${escapedColumns}) VALUES\n${values};\n\n`;
285
- }
286
- sqlDump += `/*!40000 ALTER TABLE ${escapedTable} ENABLE KEYS */;\n`;
287
- sqlDump += `UNLOCK TABLES;\n\n`;
288
- }
289
- }
290
- }
291
- // Add footer
292
- sqlDump += `COMMIT;\n`;
293
- sqlDump += `SET FOREIGN_KEY_CHECKS=1;\n`;
294
- sqlDump += `\n-- Dump completed successfully\n`;
295
- return {
296
- status: "success",
297
- data: {
298
- database: dbValidation.database,
299
- sql_dump: sqlDump,
300
- tables_backed_up: backedUpTables,
301
- table_count: backedUpTables.length,
302
- total_rows: totalRows,
303
- include_data: include_data,
304
- include_drop: include_drop,
305
- },
306
- };
307
- }
308
- catch (error) {
309
- return {
310
- status: "error",
311
- error: error.message,
312
- };
313
- }
314
- }
315
- /**
316
- * Restore database from SQL dump
317
- * Executes SQL statements from the provided SQL dump string
318
- */
319
- async restoreFromSql(params) {
320
- try {
321
- const { sql_dump, stop_on_error = true, database } = params;
322
- // Validate database access
323
- const dbValidation = this.validateDatabaseAccess(database);
324
- if (!dbValidation.valid) {
325
- return { status: "error", error: dbValidation.error };
326
- }
327
- if (!sql_dump || sql_dump.trim().length === 0) {
328
- return { status: "error", error: "SQL dump content is empty" };
329
- }
330
- // Parse SQL statements (split by semicolon, handling edge cases)
331
- const statements = this.parseSqlStatements(sql_dump);
332
- let successCount = 0;
333
- let errorCount = 0;
334
- const errors = [];
335
- let queryCount = 0;
336
- for (const statement of statements) {
337
- const trimmed = statement.trim();
338
- if (!trimmed || trimmed.startsWith("--") || trimmed.startsWith("/*")) {
339
- continue; // Skip comments and empty statements
340
- }
341
- try {
342
- await this.db.query(trimmed);
343
- queryCount++;
344
- successCount++;
345
- }
346
- catch (error) {
347
- errorCount++;
348
- errors.push({
349
- statement: trimmed.substring(0, 200) + (trimmed.length > 200 ? "..." : ""),
350
- error: error.message,
351
- });
352
- if (stop_on_error) {
353
- return {
354
- status: "error",
355
- error: `Restore stopped at error: ${error.message}`,
356
- data: {
357
- statements_executed: successCount,
358
- statements_failed: errorCount,
359
- errors: errors,
360
- },
361
- };
362
- }
363
- }
364
- }
365
- return {
366
- status: errorCount > 0 ? "partial" : "success",
367
- data: {
368
- message: errorCount > 0
369
- ? `Restore completed with ${errorCount} errors`
370
- : "Restore completed successfully",
371
- statements_executed: successCount,
372
- statements_failed: errorCount,
373
- errors: errors.length > 0 ? errors : undefined,
374
- },
375
- };
376
- }
377
- catch (error) {
378
- return {
379
- status: "error",
380
- error: error.message,
381
- };
382
- }
383
- }
384
- /**
385
- * Parse SQL dump into individual statements
386
- */
387
- parseSqlStatements(sqlDump) {
388
- const statements = [];
389
- let currentStatement = "";
390
- let inString = false;
391
- let stringChar = "";
392
- let inComment = false;
393
- let inBlockComment = false;
394
- for (let i = 0; i < sqlDump.length; i++) {
395
- const char = sqlDump[i];
396
- const nextChar = sqlDump[i + 1];
397
- const prevChar = sqlDump[i - 1];
398
- // Handle block comments /* */
399
- if (!inString && !inComment && char === "/" && nextChar === "*") {
400
- inBlockComment = true;
401
- currentStatement += char;
402
- continue;
403
- }
404
- if (inBlockComment && char === "*" && nextChar === "/") {
405
- inBlockComment = false;
406
- currentStatement += char;
407
- continue;
408
- }
409
- // Handle line comments --
410
- if (!inString && !inBlockComment && char === "-" && nextChar === "-") {
411
- inComment = true;
412
- currentStatement += char;
413
- continue;
414
- }
415
- if (inComment && char === "\n") {
416
- inComment = false;
417
- currentStatement += char;
418
- continue;
419
- }
420
- // Handle strings
421
- if (!inComment && !inBlockComment && (char === "'" || char === '"')) {
422
- if (!inString) {
423
- inString = true;
424
- stringChar = char;
425
- }
426
- else if (char === stringChar && prevChar !== "\\") {
427
- inString = false;
428
- }
429
- }
430
- // Handle statement terminator
431
- if (!inString && !inComment && !inBlockComment && char === ";") {
432
- currentStatement += char;
433
- const trimmed = currentStatement.trim();
434
- if (trimmed && !trimmed.startsWith("--")) {
435
- statements.push(trimmed);
436
- }
437
- currentStatement = "";
438
- continue;
439
- }
440
- currentStatement += char;
441
- }
442
- // Add any remaining statement
443
- const trimmed = currentStatement.trim();
444
- if (trimmed && !trimmed.startsWith("--") && trimmed !== "") {
445
- statements.push(trimmed);
446
- }
447
- return statements;
448
- }
449
- /**
450
- * Get database schema overview (all CREATE statements)
451
- */
452
- async getDatabaseSchema(params) {
453
- try {
454
- const { database, include_views = true, include_procedures = true, include_functions = true, include_triggers = true, } = params;
455
- // Validate database access
456
- const dbValidation = this.validateDatabaseAccess(database);
457
- if (!dbValidation.valid) {
458
- return { status: "error", error: dbValidation.error };
459
- }
460
- const schema = {
461
- database: dbValidation.database,
462
- tables: [],
463
- views: [],
464
- procedures: [],
465
- functions: [],
466
- triggers: [],
467
- };
468
- let queryCount = 0;
469
- // Get tables
470
- const tablesQuery = `SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'`;
471
- const tablesResult = await this.db.query(tablesQuery);
472
- queryCount++;
473
- for (const row of tablesResult) {
474
- const tableName = Object.values(row)[0];
475
- const createQuery = `SHOW CREATE TABLE ${this.security.escapeIdentifier(tableName)}`;
476
- const createResult = await this.db.query(createQuery);
477
- queryCount++;
478
- if (createResult.length > 0) {
479
- schema.tables.push({
480
- name: tableName,
481
- create_statement: createResult[0]["Create Table"],
482
- });
483
- }
484
- }
485
- // Get views
486
- if (include_views) {
487
- const viewsQuery = `SHOW FULL TABLES WHERE Table_type = 'VIEW'`;
488
- const viewsResult = await this.db.query(viewsQuery);
489
- queryCount++;
490
- for (const row of viewsResult) {
491
- const viewName = Object.values(row)[0];
492
- const createQuery = `SHOW CREATE VIEW ${this.security.escapeIdentifier(viewName)}`;
493
- const createResult = await this.db.query(createQuery);
494
- queryCount++;
495
- if (createResult.length > 0) {
496
- schema.views.push({
497
- name: viewName,
498
- create_statement: createResult[0]["Create View"],
499
- });
500
- }
501
- }
502
- }
503
- // Get procedures
504
- if (include_procedures) {
505
- const procsQuery = `SHOW PROCEDURE STATUS WHERE Db = ?`;
506
- const procsResult = await this.db.query(procsQuery, [
507
- dbValidation.database,
508
- ]);
509
- queryCount++;
510
- for (const proc of procsResult) {
511
- try {
512
- const createQuery = `SHOW CREATE PROCEDURE ${this.security.escapeIdentifier(proc.Name)}`;
513
- const createResult = await this.db.query(createQuery);
514
- queryCount++;
515
- if (createResult.length > 0) {
516
- schema.procedures.push({
517
- name: proc.Name,
518
- create_statement: createResult[0]["Create Procedure"],
519
- });
520
- }
521
- }
522
- catch (e) {
523
- // Skip if we can't get the procedure definition
524
- }
525
- }
526
- }
527
- // Get functions
528
- if (include_functions) {
529
- const funcsQuery = `SHOW FUNCTION STATUS WHERE Db = ?`;
530
- const funcsResult = await this.db.query(funcsQuery, [
531
- dbValidation.database,
532
- ]);
533
- queryCount++;
534
- for (const func of funcsResult) {
535
- try {
536
- const createQuery = `SHOW CREATE FUNCTION ${this.security.escapeIdentifier(func.Name)}`;
537
- const createResult = await this.db.query(createQuery);
538
- queryCount++;
539
- if (createResult.length > 0) {
540
- schema.functions.push({
541
- name: func.Name,
542
- create_statement: createResult[0]["Create Function"],
543
- });
544
- }
545
- }
546
- catch (e) {
547
- // Skip if we can't get the function definition
548
- }
549
- }
550
- }
551
- // Get triggers
552
- if (include_triggers) {
553
- const triggersQuery = `SHOW TRIGGERS`;
554
- const triggersResult = await this.db.query(triggersQuery);
555
- queryCount++;
556
- for (const trigger of triggersResult) {
557
- try {
558
- const createQuery = `SHOW CREATE TRIGGER ${this.security.escapeIdentifier(trigger.Trigger)}`;
559
- const createResult = await this.db.query(createQuery);
560
- queryCount++;
561
- if (createResult.length > 0) {
562
- schema.triggers.push({
563
- name: trigger.Trigger,
564
- create_statement: createResult[0]["SQL Original Statement"],
565
- });
566
- }
567
- }
568
- catch (e) {
569
- // Skip if we can't get the trigger definition
570
- }
571
- }
572
- }
573
- return {
574
- status: "success",
575
- data: schema,
576
- };
577
- }
578
- catch (error) {
579
- return {
580
- status: "error",
581
- error: error.message,
582
- };
583
- }
584
- }
585
69
  }
586
70
  exports.BackupRestoreTools = BackupRestoreTools;
@@ -26,18 +26,6 @@ export declare class DataExportTools {
26
26
  data?: any;
27
27
  error?: string;
28
28
  }>;
29
- /**
30
- * Export query results to CSV format
31
- */
32
- exportQueryToCSV(params: {
33
- query: string;
34
- params?: any[];
35
- include_headers?: boolean;
36
- }): Promise<{
37
- status: string;
38
- data?: any;
39
- error?: string;
40
- }>;
41
29
  /**
42
30
  * Export table data to JSON format
43
31
  */
@@ -53,32 +41,6 @@ export declare class DataExportTools {
53
41
  data?: any;
54
42
  error?: string;
55
43
  }>;
56
- /**
57
- * Export query results to JSON format
58
- */
59
- exportQueryToJSON(params: {
60
- query: string;
61
- params?: any[];
62
- pretty?: boolean;
63
- }): Promise<{
64
- status: string;
65
- data?: any;
66
- error?: string;
67
- }>;
68
- /**
69
- * Export table data to SQL INSERT statements
70
- */
71
- exportTableToSql(params: {
72
- table_name: string;
73
- filters?: FilterCondition[];
74
- include_create_table?: boolean;
75
- batch_size?: number;
76
- database?: string;
77
- }): Promise<{
78
- status: string;
79
- data?: any;
80
- error?: string;
81
- }>;
82
44
  /**
83
45
  * Import data from CSV string
84
46
  */