@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 +7 -0
- package/DOCUMENTATIONS.md +41 -13
- package/README.md +0 -14
- package/dist/config/featureConfig.js +1 -13
- package/dist/index.d.ts +11 -0
- package/dist/index.js +11 -0
- package/dist/mcp-server.js +33 -0
- package/dist/tools/macroTools.d.ts +20 -0
- package/dist/tools/macroTools.js +91 -0
- package/package.json +2 -2
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();
|
package/dist/mcp-server.js
CHANGED
|
@@ -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.
|
|
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
|
+
}
|