@berthojoris/mcp-mysql-server 1.14.0 β†’ 1.14.1

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 CHANGED
@@ -5,6 +5,13 @@ All notable changes to the MySQL MCP Server will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.14.1] - 2025-12-08
9
+
10
+ ### Added
11
+ - **Workflow Macros** - New `safe_export_table` tool that combines data export with mandatory masking.
12
+ - Allows safe export of sensitive data by enforcing masking before the data leaves the database.
13
+ - Supports configurable masking profiles (strict (default), partial, soft).
14
+
8
15
  ## [1.14.0] - 2025-12-08
9
16
 
10
17
  ### Added
package/DOCUMENTATIONS.md CHANGED
@@ -26,19 +26,6 @@ This file contains detailed documentation for all features of the MySQL MCP Serv
26
26
  18. [Performance Monitoring](#πŸ“ˆ-performance-monitoring)
27
27
  19. [Usage Examples](#πŸ“‹-usage-examples)
28
28
  20. [Query Logging & Automatic SQL Display](#πŸ“-query-logging--automatic-sql-display)
29
- 21. [Security Features](#πŸ”’-security-features)
30
- 22. [Query Result Caching](#πŸ’Ύ-query-result-caching)
31
- 23. [Query Optimization Hints](#🎯-query-optimization-hints)
32
- 24. [Guided Query Builder/Fixer](#πŸ€–-guided-query-builderfixer)
33
- 25. [Bulk Operations](#πŸš€-bulk-operations)
34
- 26. [OpenAI Codex Integration](#πŸ€–-openai-codex-integration)
35
- 27. [Troubleshooting](#πŸ› οΈ-troubleshooting)
36
- 28. [License](#πŸ“„-license)
37
- 29. [Roadmap](#πŸ—ΊοΈ-roadmap)
38
-
39
- ---
40
-
41
- ## Dual-Layer Filtering System
42
29
 
43
30
  Control which database operations are available to AI using a **dual-layer filtering system**:
44
31
 
@@ -754,6 +741,47 @@ Both tools support:
754
741
 
755
742
  ---
756
743
 
744
+ ## πŸ”„ Workflow Macros
745
+
746
+ Workflow Macros are composite tools designed to execute complex, multi-step operations safely and efficiently. They encapsulate best practices and security policies (like data masking) into single, atomic tool calls.
747
+
748
+ ### Available Macros
749
+
750
+ | Tool | Description |
751
+ |------|-------------|
752
+ | `safe_export_table` | Exports table data to CSV with mandated data masking (redaction/hashing) |
753
+
754
+ ### safe_export_table
755
+
756
+ Exports table data to CSV format *with enforced data masking*. This is safer than standard export tools because it ensures sensitive data is masked before leaving the database layer, regardless of the global masking configuration.
757
+
758
+ **Parameters:**
759
+ - `table_name` (required): Name of the table to export.
760
+ - `masking_profile` (optional): "strict" (default), "partial", or "soft".
761
+ - `limit` (optional): Maximum rows to export (default 1000, max 10000).
762
+ - `include_headers` (optional): Whether to include CSV headers (default true).
763
+
764
+ **Example:**
765
+ *User prompt: "Safely export the users table to a CSV file"*
766
+
767
+ ```json
768
+ {
769
+ "tool": "safe_export_table",
770
+ "arguments": {
771
+ "table_name": "users",
772
+ "masking_profile": "strict"
773
+ }
774
+ }
775
+ ```
776
+
777
+ **Result:**
778
+ CSV content where:
779
+ - Emails are masked (e.g., `j***@domain.com`)
780
+ - Passwords/secrets are `[REDACTED]`
781
+ - Phone numbers are partially hidden
782
+
783
+ ---
784
+
757
785
  ## πŸ“₯ Data Import Tools
758
786
 
759
787
  The MySQL MCP Server provides tools to import data from various formats into your database tables.
package/README.md CHANGED
@@ -56,20 +56,6 @@ Add to your AI agent config (`.mcp.json`, `.cursor/mcp.json`, etc.):
56
56
  - [License](#-license)
57
57
 
58
58
  ---
59
-
60
- ## Features
61
-
62
- | Category | Description |
63
- |----------|-------------|
64
- | **Full MCP Support** | Works with Claude Code, Cursor, Windsurf, Zed, Cline, Kilo Code, Roo Code, Gemini CLI, OpenAI Codex, and any MCP-compatible AI agent |
65
- | **Security First** | Parameterized queries, SQL injection protection, permission-based access control |
66
- | **124 Powerful Tools** | Complete database operations including CRUD, DDL, transactions, stored procedures, backup/restore, migrations |
67
- | **Adaptive Presets** | Built-in ReadOnly/Analyst/DBA Lite permission bundles with override merging |
68
- | **Schema-Aware RAG Pack** | Compact schema snapshots (tables, PK/FK, row estimates) tailored for embeddings-friendly prompts |
69
- | **Category Filtering** | 22 documentation categories for intuitive, fine-grained access control (backward compatible with 10 legacy categories) |
70
- | **Transaction Support** | Full ACID transaction management (BEGIN, COMMIT, ROLLBACK) |
71
- | **Schema Migrations** | Version control for database schema with up/down migrations |
72
- | **Dual Mode** | Run as MCP server OR as REST API |
73
59
  | **Data Masking** | Protect PII/Secrets in responses with configurable profiles (soft/partial/strict) |
74
60
  | **TypeScript** | Fully typed with TypeScript definitions |
75
61
 
@@ -230,19 +230,6 @@ exports.toolCategoryMap = {
230
230
  showReplicationStatus: ToolCategory.LIST,
231
231
  // Backup and restore tools
232
232
  backupTable: ToolCategory.UTILITY,
233
- backupDatabase: ToolCategory.UTILITY,
234
- restoreFromSql: ToolCategory.DDL,
235
- getCreateTableStatement: ToolCategory.LIST,
236
- getDatabaseSchema: ToolCategory.LIST,
237
- // Extended data export/import tools
238
- exportTableToJSON: ToolCategory.UTILITY,
239
- exportQueryToJSON: ToolCategory.UTILITY,
240
- exportTableToSql: ToolCategory.UTILITY,
241
- importFromCSV: ToolCategory.CREATE,
242
- importFromJSON: ToolCategory.CREATE,
243
- // Data migration tools
244
- copyTableData: ToolCategory.CREATE,
245
- moveTableData: ToolCategory.DELETE,
246
233
  cloneTable: ToolCategory.DDL,
247
234
  compareTableStructure: ToolCategory.LIST,
248
235
  syncTableData: ToolCategory.UPDATE,
@@ -397,6 +384,7 @@ exports.toolDocCategoryMap = {
397
384
  exportTableToJSON: DocCategory.IMPORT_EXPORT,
398
385
  exportQueryToJSON: DocCategory.IMPORT_EXPORT,
399
386
  exportTableToSql: DocCategory.IMPORT_EXPORT,
387
+ safe_export_table: DocCategory.IMPORT_EXPORT,
400
388
  importFromCSV: DocCategory.IMPORT_EXPORT,
401
389
  importFromJSON: DocCategory.IMPORT_EXPORT,
402
390
  // Data Migration
package/dist/index.d.ts CHANGED
@@ -24,6 +24,7 @@ export declare class MySQLMCP {
24
24
  private performanceTools;
25
25
  private analysisTools;
26
26
  private aiTools;
27
+ private macroTools;
27
28
  private security;
28
29
  private featureConfig;
29
30
  constructor(permissionsConfig?: string, categoriesConfig?: string, presetName?: string);
@@ -590,6 +591,16 @@ export declare class MySQLMCP {
590
591
  suggestions?: string[];
591
592
  error?: string;
592
593
  }>;
594
+ safeExportTable(params: {
595
+ table_name: string;
596
+ masking_profile?: string;
597
+ limit?: number;
598
+ include_headers?: boolean;
599
+ }): Promise<{
600
+ status: string;
601
+ data?: any;
602
+ error?: string;
603
+ }>;
593
604
  getFeatureStatus(): {
594
605
  status: string;
595
606
  data: {
package/dist/index.js CHANGED
@@ -25,6 +25,7 @@ const schemaVersioningTools_1 = require("./tools/schemaVersioningTools");
25
25
  const performanceTools_1 = require("./tools/performanceTools");
26
26
  const analysisTools_1 = require("./tools/analysisTools");
27
27
  const aiTools_1 = require("./tools/aiTools");
28
+ const macroTools_1 = require("./tools/macroTools");
28
29
  const securityLayer_1 = __importDefault(require("./security/securityLayer"));
29
30
  const connection_1 = __importDefault(require("./db/connection"));
30
31
  const featureConfig_1 = require("./config/featureConfig");
@@ -56,7 +57,9 @@ class MySQLMCP {
56
57
  this.schemaVersioningTools = new schemaVersioningTools_1.SchemaVersioningTools(this.security);
57
58
  this.performanceTools = new performanceTools_1.PerformanceTools(this.security);
58
59
  this.analysisTools = new analysisTools_1.AnalysisTools(this.security);
60
+ this.analysisTools = new analysisTools_1.AnalysisTools(this.security);
59
61
  this.aiTools = new aiTools_1.AiTools(this.security);
62
+ this.macroTools = new macroTools_1.MacroTools(this.security);
60
63
  }
61
64
  // Helper method to check if tool is enabled
62
65
  checkToolEnabled(toolName) {
@@ -535,6 +538,14 @@ class MySQLMCP {
535
538
  }
536
539
  return await this.aiTools.repairQuery(params);
537
540
  }
541
+ // Workflow Macros
542
+ async safeExportTable(params) {
543
+ const check = this.checkToolEnabled("safe_export_table");
544
+ if (!check.enabled) {
545
+ return { status: "error", error: check.error };
546
+ }
547
+ return await this.macroTools.safeExportTable(params);
548
+ }
538
549
  // Get feature configuration status
539
550
  getFeatureStatus() {
540
551
  const snapshot = this.featureConfig.getConfigSnapshot();
@@ -476,6 +476,33 @@ const TOOLS = [
476
476
  required: ["query"],
477
477
  },
478
478
  },
479
+ {
480
+ name: "safe_export_table",
481
+ description: "Exports table data to CSV with enforced data masking rules to protect sensitive information.",
482
+ inputSchema: {
483
+ type: "object",
484
+ properties: {
485
+ table_name: {
486
+ type: "string",
487
+ description: "Name of the table to export",
488
+ },
489
+ masking_profile: {
490
+ type: "string",
491
+ enum: ["soft", "partial", "strict"],
492
+ description: "Masking profile to apply (default: strict). strict=redact all PII/secrets, partial=partial mask PII, soft=mask secrets only.",
493
+ },
494
+ limit: {
495
+ type: "number",
496
+ description: "Maximum number of rows to export (default: 1000, max: 10000)",
497
+ },
498
+ include_headers: {
499
+ type: "boolean",
500
+ description: "Whether to include CSV headers (default: true)",
501
+ },
502
+ },
503
+ required: ["table_name"],
504
+ },
505
+ },
479
506
  {
480
507
  name: "repair_query",
481
508
  description: "Analyzes a SQL query (and optional error) to suggest repairs or optimizations using EXPLAIN and heuristics.",
@@ -3083,6 +3110,12 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
3083
3110
  case "export_query_to_json":
3084
3111
  result = await mysqlMCP.exportQueryToJSON((args || {}));
3085
3112
  break;
3113
+ case "export_query_to_csv":
3114
+ result = await mysqlMCP.exportQueryToCSV((args || {}));
3115
+ break;
3116
+ case "safe_export_table":
3117
+ result = await mysqlMCP.safeExportTable((args || {}));
3118
+ break;
3086
3119
  case "export_table_to_sql":
3087
3120
  result = await mysqlMCP.exportTableToSql((args || {}));
3088
3121
  break;
@@ -0,0 +1,20 @@
1
+ import SecurityLayer from "../security/securityLayer";
2
+ export declare class MacroTools {
3
+ private db;
4
+ private security;
5
+ constructor(security: SecurityLayer);
6
+ /**
7
+ * Safe Export Table: Exports table data to CSV with enforced data masking
8
+ * This macro prioritizes data safety by applying masking rules before export.
9
+ */
10
+ safeExportTable(params: {
11
+ table_name: string;
12
+ masking_profile?: string;
13
+ limit?: number;
14
+ include_headers?: boolean;
15
+ }): Promise<{
16
+ status: string;
17
+ data?: any;
18
+ error?: string;
19
+ }>;
20
+ }
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MacroTools = void 0;
7
+ const connection_1 = __importDefault(require("../db/connection"));
8
+ const maskingLayer_1 = require("../security/maskingLayer");
9
+ class MacroTools {
10
+ constructor(security) {
11
+ this.db = connection_1.default.getInstance();
12
+ this.security = security;
13
+ }
14
+ /**
15
+ * Safe Export Table: Exports table data to CSV with enforced data masking
16
+ * This macro prioritizes data safety by applying masking rules before export.
17
+ */
18
+ async safeExportTable(params) {
19
+ try {
20
+ const { table_name, masking_profile = "strict", limit = 1000, include_headers = true, } = params;
21
+ // 1. Validate table name
22
+ const tableValidation = this.security.validateIdentifier(table_name);
23
+ if (!tableValidation.valid) {
24
+ return {
25
+ status: "error",
26
+ error: tableValidation.error,
27
+ };
28
+ }
29
+ // 2. Fetch data (with hard limit to prevent OOM on large safe exports)
30
+ const maxLimit = 10000;
31
+ const actualLimit = Math.min(limit, maxLimit);
32
+ const escapedTableName = this.security.escapeIdentifier(table_name);
33
+ const query = `SELECT * FROM ${escapedTableName} LIMIT ?`;
34
+ const results = (await this.db.query(query, [actualLimit]));
35
+ if (results.length === 0) {
36
+ return {
37
+ status: "success",
38
+ data: {
39
+ csv: include_headers ? "" : "",
40
+ row_count: 0,
41
+ applied_profile: masking_profile,
42
+ },
43
+ };
44
+ }
45
+ // 3. Apply masking explicitly using a new temporary layer to ensure strictness
46
+ // We don't rely on the global masking profile here; we use the one requested (default strict)
47
+ const tempMaskingLayer = new maskingLayer_1.MaskingLayer(masking_profile);
48
+ const maskedResults = tempMaskingLayer.processResults(results);
49
+ // 4. Convert to CSV
50
+ let csv = "";
51
+ if (include_headers) {
52
+ const headers = Object.keys(maskedResults[0]).join(",");
53
+ csv += headers + "\n";
54
+ }
55
+ for (const row of maskedResults) {
56
+ const values = Object.values(row)
57
+ .map((value) => {
58
+ if (value === null)
59
+ return "";
60
+ if (value === undefined)
61
+ return "";
62
+ let str = String(value);
63
+ // Escape quotes and wrap in quotes if contains comma, newline or quotes
64
+ if (str.includes(",") ||
65
+ str.includes("\n") ||
66
+ str.includes('"')) {
67
+ return `"${str.replace(/"/g, '""')}"`;
68
+ }
69
+ return str;
70
+ })
71
+ .join(",");
72
+ csv += values + "\n";
73
+ }
74
+ return {
75
+ status: "success",
76
+ data: {
77
+ csv: csv,
78
+ row_count: maskedResults.length,
79
+ applied_profile: tempMaskingLayer.getProfile(),
80
+ },
81
+ };
82
+ }
83
+ catch (error) {
84
+ return {
85
+ status: "error",
86
+ error: error.message,
87
+ };
88
+ }
89
+ }
90
+ }
91
+ exports.MacroTools = MacroTools;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@berthojoris/mcp-mysql-server",
3
- "version": "1.14.0",
3
+ "version": "1.14.1",
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",
@@ -86,4 +86,4 @@
86
86
  "ts-node": "^10.9.1",
87
87
  "typescript": "^5.2.2"
88
88
  }
89
- }
89
+ }