@berthojoris/mcp-mysql-server 1.14.0 β†’ 1.15.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 CHANGED
@@ -5,6 +5,24 @@ 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.15.0] - 2025-12-08
9
+
10
+ ### Added
11
+ - **Connection Profiles** - New `dev`, `stage`, and `prod` presets.
12
+ - `dev`: Full access to all tools.
13
+ - `stage`: Allows CRUD but blocks destructive DDL (drop, truncate).
14
+ - `prod`: Strict read-only with explicit denials for modification tools.
15
+ - Implements allowed/denied tools logic for robust security enforcement.
16
+ - **Agent-Facing Changelog Feed** - New `read_changelog` tool.
17
+ - Allows AI agents to read the CHANGELOG.md directly to understand new features and changes.
18
+
19
+ ## [1.14.1] - 2025-12-08
20
+
21
+ ### Added
22
+ - **Workflow Macros** - New `safe_export_table` tool that combines data export with mandatory masking.
23
+ - Allows safe export of sensitive data by enforcing masking before the data leaves the database.
24
+ - Supports configurable masking profiles (strict (default), partial, soft).
25
+
8
26
  ## [1.14.0] - 2025-12-08
9
27
 
10
28
  ### 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
 
@@ -205,6 +192,16 @@ Preset bundles provide safe starting points and **merge** with any explicit perm
205
192
  | `readonly` | `list,read,utility` | `database_discovery,crud_operations,custom_queries,utilities,import_export,performance_monitoring,analysis` | Safe read-only access, exports, and diagnostics |
206
193
  | `analyst` | `list,read,utility` | `database_discovery,crud_operations,custom_queries,utilities,import_export,performance_monitoring,analysis,query_optimization,cache_management,server_management` | Exploration with EXPLAIN, cache, and performance visibility |
207
194
  | `dba-lite` | `list,read,utility,ddl,transaction,procedure` | `database_discovery,custom_queries,utilities,server_management,schema_management,table_maintenance,index_management,constraint_management,backup_restore,schema_migrations,performance_monitoring,views_management,triggers_management,functions_management,stored_procedures` | Admin-lite schema care, maintenance, and migrations |
195
+ | `dev` | ALL | ALL | Full access to all tools (Development environment) |
196
+ | `stage` | `list,read,create,update,delete,utility,transaction` | Most categories (except schema_management) | Data modification allowed, but destructive DDL (drop_table, truncate_table) is **explicitly denied** |
197
+ | `prod` | `list,read,utility` | `database_discovery,crud_operations,custom_queries,utilities,performance_monitoring,analysis` | Strict read-only. Data modification and DDL are **strictly denied** (even if permissions suggest otherwise) |
198
+
199
+ ### Connection Profiles (Allow/Deny Lists)
200
+
201
+ The new mechanism introduces "Connection Profiles" which can enforce strict `allow` and `deny` lists for tools, providing security beyond standard permissions.
202
+
203
+ - **Explicit Deny**: Tools in the `deniedTools` list are blocked *regardless* of their permissions. E.g., `prod` profile denies `create_record` even if `create` permission is somehow granted.
204
+ - **Explicit Allow**: Tools in the `allowedTools` list are enabled even if their category is not listed (unless denied).
208
205
 
209
206
  **Usage**
210
207
 
@@ -337,6 +334,7 @@ This section provides a comprehensive reference of all 120 available tools organ
337
334
  |------|-------------|
338
335
  | `test_connection` | Test database connectivity and measure latency |
339
336
  | `describe_connection` | Get current connection information |
337
+ | `read_changelog` | Read the changelog to see new features/changes |
340
338
  | `export_table_to_csv` | Export table data to CSV format |
341
339
  | `export_query_to_csv` | Export query results to CSV format |
342
340
 
@@ -533,6 +531,11 @@ This section provides a comprehensive reference of all 120 available tools organ
533
531
  - Safety: respects the connected database onlyβ€”cannot introspect other schemasβ€”and notes when tables/columns are truncated.
534
532
  - Output includes per-table PKs, FK targets, nullable flags, and approximate row counts from `INFORMATION_SCHEMA.TABLES` (InnoDB estimates).
535
533
 
534
+ #### Agent-Facing Changelog Feed
535
+ - **`read_changelog`**: Allows AI agents to read the project's CHANGELOG.md directly.
536
+ - **Purpose**: Enables the agent to understand new features, changes, and deprecations in the version it is running.
537
+ - **Usage**: Call `read_changelog()` to get the latest changes, or `read_changelog(version='1.15.0')` for specific version details.
538
+
536
539
  ---
537
540
 
538
541
  ## πŸ—οΈ DDL Operations
@@ -754,6 +757,47 @@ Both tools support:
754
757
 
755
758
  ---
756
759
 
760
+ ## πŸ”„ Workflow Macros
761
+
762
+ 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.
763
+
764
+ ### Available Macros
765
+
766
+ | Tool | Description |
767
+ |------|-------------|
768
+ | `safe_export_table` | Exports table data to CSV with mandated data masking (redaction/hashing) |
769
+
770
+ ### safe_export_table
771
+
772
+ 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.
773
+
774
+ **Parameters:**
775
+ - `table_name` (required): Name of the table to export.
776
+ - `masking_profile` (optional): "strict" (default), "partial", or "soft".
777
+ - `limit` (optional): Maximum rows to export (default 1000, max 10000).
778
+ - `include_headers` (optional): Whether to include CSV headers (default true).
779
+
780
+ **Example:**
781
+ *User prompt: "Safely export the users table to a CSV file"*
782
+
783
+ ```json
784
+ {
785
+ "tool": "safe_export_table",
786
+ "arguments": {
787
+ "table_name": "users",
788
+ "masking_profile": "strict"
789
+ }
790
+ }
791
+ ```
792
+
793
+ **Result:**
794
+ CSV content where:
795
+ - Emails are masked (e.g., `j***@domain.com`)
796
+ - Passwords/secrets are `[REDACTED]`
797
+ - Phone numbers are partially hidden
798
+
799
+ ---
800
+
757
801
  ## πŸ“₯ Data Import Tools
758
802
 
759
803
  The MySQL MCP Server provides tools to import data from various formats into your database tables.
@@ -3796,6 +3840,61 @@ Each bulk operation returns performance metrics:
3796
3840
 
3797
3841
  ---
3798
3842
 
3843
+
3844
+ ---
3845
+
3846
+ ## ⚑ Workflow Macros
3847
+
3848
+ Workflow macros are high-level tools that combine multiple operations into a single, safe, and efficient workflow. They are designed to simplify complex tasks and ensure best practices (like data masking) are automatically applied.
3849
+
3850
+ ### Safe Export Table
3851
+
3852
+ The `safe_export_table` tool allows you to export table data to CSV while strictly enforcing data masking rules. This ensures that sensitive information (PII) is never leaked during exports, even if the agent forgets to apply masking manually.
3853
+
3854
+ #### Features
3855
+
3856
+ - **Forced Masking**: Applies a masking profile (default: `strict`) to all exported data.
3857
+ - **Hard Limit**: Enforces a maximum row limit (10,000) to prevent Out-Of-Memory errors during large exports.
3858
+ - **CSV Formatting**: Automatically handles special characters, quotes, and newlines.
3859
+ - **Header Control**: Option to include or exclude CSV headers.
3860
+
3861
+ #### Usage
3862
+
3863
+ ```json
3864
+ {
3865
+ "tool": "safe_export_table",
3866
+ "arguments": {
3867
+ "table_name": "users",
3868
+ "masking_profile": "partial",
3869
+ "limit": 1000
3870
+ }
3871
+ }
3872
+ ```
3873
+
3874
+ #### Parameters
3875
+
3876
+ | Parameter | Type | Required | Description | Default |
3877
+ |-----------|------|----------|-------------|---------|
3878
+ | `table_name` | string | Yes | Name of the table to export | - |
3879
+ | `masking_profile` | string | No | Masking profile to apply (`strict`, `partial`, `soft`) | `strict` |
3880
+ | `limit` | number | No | Number of rows to export (max 10,000) | 1000 |
3881
+ | `include_headers` | boolean | No | Whether to include CSV headers | `true` |
3882
+
3883
+ #### Response
3884
+
3885
+ ```json
3886
+ {
3887
+ "status": "success",
3888
+ "data": {
3889
+ "csv": "id,name,email\n1,John Doe,j***@example.com...",
3890
+ "row_count": 50,
3891
+ "applied_profile": "partial"
3892
+ }
3893
+ }
3894
+ ```
3895
+
3896
+ ---
3897
+
3799
3898
  ## πŸ€– OpenAI Codex Integration
3800
3899
 
3801
3900
  OpenAI Codex CLI and VS Code Extension support MCP servers through a shared TOML configuration file. This section provides detailed setup instructions for integrating the MySQL MCP Server with Codex.
@@ -4182,9 +4281,9 @@ MIT License - see [LICENSE](LICENSE) file for details.
4182
4281
  | Safety Sandbox Mode (runQuery dry-run/EXPLAIN-only) | Medium | Low | 5 | βœ… Completed |
4183
4282
  | Anomaly & Slow-Query Watcher | Medium | Medium | 6 | βœ… Completed |
4184
4283
  | Data Masking Profiles for Responses | Medium | Medium | 7 | βœ… Completed |
4185
- | Workflow Macros (e.g., safe_export_table) | Medium | Low | 8 | Planned |
4186
- | Agent-Facing Changelog Feed | Medium | Low | 9 | Planned |
4187
- | Connection Profiles (dev/stage/prod with allow/deny) | High | Low | 10 | Planned |
4284
+ | Workflow Macros (e.g., safe_export_table) | Medium | Low | 8 | βœ… Completed |
4285
+ | Agent-Facing Changelog Feed | Medium | Low | 9 | βœ… Completed |
4286
+ | Connection Profiles (dev/stage/prod with allow/deny) | High | Low | 10 | βœ… Completed |
4188
4287
 
4189
4288
  ---
4190
4289
 
package/README.md CHANGED
@@ -50,26 +50,12 @@ Add to your AI agent config (`.mcp.json`, `.cursor/mcp.json`, etc.):
50
50
  - [Environment Variables](#environment-variables-configuration)
51
51
  - [Local Development](#local-path-configuration)
52
52
  - [Permission System](#-permission-system)
53
- - [Available Tools (124 total)](#-available-tools)
53
+ - [Available Tools (126 total)](#-available-tools)
54
54
  - [Documentation](#-detailed-documentation)
55
55
  - [Comparison: MCP vs Manual Access](#-mysql-mcp-vs-manual-database-access)
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
 
@@ -402,6 +388,12 @@ Alternative approach using environment variables instead of connection string:
402
388
 
403
389
  Add `MCP_PRESET` for the base bundle and optionally layer on `MCP_PERMISSIONS` / `MCP_CATEGORIES` for project-specific overrides.
404
390
 
391
+ #### Connection Profiles (dev/stage/prod)
392
+ New presets are available for environment-specific control:
393
+ - `dev`: Full access to all tools (explicitly allows everything).
394
+ - `stage`: Allows data modification but blocks destructive DDL (drop/truncate).
395
+ - `prod`: Strict read-only mode, explicitly denying keys modification keys.
396
+
405
397
  ---
406
398
 
407
399
  ### Local Path Configuration
@@ -655,11 +647,11 @@ Use both 2nd argument (permissions) and 3rd argument (categories):
655
647
 
656
648
  ## Available Tools
657
649
 
658
- The MCP server provides **124 powerful tools** organized into categories:
650
+ The MCP server provides **126 powerful tools** organized into 22 categories:
659
651
 
660
652
  ### Quick Reference
661
653
 
662
- **124 Tools Available** - Organized into 22 categories
654
+ **126 Tools Available** - Organized into 22 categories
663
655
 
664
656
  | Category | Count | Key Tools |
665
657
  |----------|-------|-----------|
@@ -681,7 +673,7 @@ The MCP server provides **124 powerful tools** organized into categories:
681
673
  | Cache | 5 | `get_cache_stats`, `clear_cache` |
682
674
  | Query Optimization | 3 | `analyze_query`, `get_optimization_hints`, `repair_query` |
683
675
  | Backup & Restore | 5 | `backup_database`, `restore_from_sql` |
684
- | Import/Export | 5 | `export_table_to_json`, `import_from_csv` |
676
+ | Import/Export | 6 | `safe_export_table`, `export_table_to_json`, `import_from_csv` |
685
677
  | Data Migration | 5 | `copy_table_data`, `sync_table_data` |
686
678
  | Schema Migrations | 9 | `create_migration`, `apply_migrations` |
687
679
  | Utilities | 4 | `test_connection`, `export_table_to_csv` |
@@ -50,6 +50,8 @@ export interface PermissionPreset {
50
50
  description: string;
51
51
  permissions: ToolCategory[];
52
52
  categories: DocCategory[];
53
+ allowedTools?: string[];
54
+ deniedTools?: string[];
53
55
  }
54
56
  /**
55
57
  * Map of tool names to their legacy categories
@@ -68,6 +70,8 @@ export declare const toolDocCategoryMap: Record<string, DocCategory>;
68
70
  export declare class FeatureConfig {
69
71
  private enabledLegacyCategories;
70
72
  private enabledDocCategories;
73
+ private allowedTools;
74
+ private deniedTools;
71
75
  private originalPermissionsString;
72
76
  private originalCategoriesString;
73
77
  private useDualLayer;
@@ -115,6 +115,58 @@ const permissionPresets = {
115
115
  DocCategory.STORED_PROCEDURES,
116
116
  ],
117
117
  },
118
+ dev: {
119
+ name: "dev",
120
+ description: "Development profile with full access to all tools",
121
+ permissions: Object.values(ToolCategory),
122
+ categories: Object.values(DocCategory),
123
+ deniedTools: [], // Explicitly allow everything
124
+ },
125
+ stage: {
126
+ name: "stage",
127
+ description: "Staging profile with data modification but no destructive DDL",
128
+ permissions: [
129
+ ToolCategory.LIST,
130
+ ToolCategory.READ,
131
+ ToolCategory.CREATE,
132
+ ToolCategory.UPDATE,
133
+ ToolCategory.DELETE,
134
+ ToolCategory.UTILITY,
135
+ ToolCategory.TRANSACTION,
136
+ ],
137
+ categories: [
138
+ DocCategory.DATABASE_DISCOVERY,
139
+ DocCategory.CRUD_OPERATIONS,
140
+ DocCategory.BULK_OPERATIONS,
141
+ DocCategory.CUSTOM_QUERIES,
142
+ DocCategory.UTILITIES,
143
+ DocCategory.TRANSACTION_MANAGEMENT,
144
+ DocCategory.IMPORT_EXPORT,
145
+ DocCategory.DATA_MIGRATION,
146
+ DocCategory.PERFORMANCE_MONITORING,
147
+ DocCategory.ANALYSIS,
148
+ ],
149
+ deniedTools: ["drop_table", "truncate_table", "drop_database"],
150
+ },
151
+ prod: {
152
+ name: "prod",
153
+ description: "Production profile with strict read-only access and safety checks",
154
+ permissions: [ToolCategory.LIST, ToolCategory.READ, ToolCategory.UTILITY],
155
+ categories: [
156
+ DocCategory.DATABASE_DISCOVERY,
157
+ DocCategory.CRUD_OPERATIONS, // Read only via permissions
158
+ DocCategory.CUSTOM_QUERIES,
159
+ DocCategory.UTILITIES,
160
+ DocCategory.PERFORMANCE_MONITORING,
161
+ DocCategory.ANALYSIS,
162
+ ],
163
+ deniedTools: [
164
+ "create_table", "alter_table", "drop_table", "truncate_table",
165
+ "create_record", "update_record", "delete_record",
166
+ "bulk_insert", "bulk_update", "bulk_delete",
167
+ "execute_sql", "execute_ddl"
168
+ ],
169
+ },
118
170
  };
119
171
  /**
120
172
  * Map of tool names to their legacy categories
@@ -153,6 +205,8 @@ exports.toolCategoryMap = {
153
205
  getTableRelationships: ToolCategory.UTILITY,
154
206
  exportTableToCSV: ToolCategory.UTILITY,
155
207
  exportQueryToCSV: ToolCategory.UTILITY,
208
+ safe_export_table: ToolCategory.UTILITY,
209
+ read_changelog: ToolCategory.UTILITY,
156
210
  // Transaction tools
157
211
  beginTransaction: ToolCategory.TRANSACTION,
158
212
  commitTransaction: ToolCategory.TRANSACTION,
@@ -230,19 +284,6 @@ exports.toolCategoryMap = {
230
284
  showReplicationStatus: ToolCategory.LIST,
231
285
  // Backup and restore tools
232
286
  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
287
  cloneTable: ToolCategory.DDL,
247
288
  compareTableStructure: ToolCategory.LIST,
248
289
  syncTableData: ToolCategory.UPDATE,
@@ -301,6 +342,7 @@ exports.toolDocCategoryMap = {
301
342
  describeConnection: DocCategory.UTILITIES,
302
343
  exportTableToCSV: DocCategory.UTILITIES,
303
344
  exportQueryToCSV: DocCategory.UTILITIES,
345
+ read_changelog: DocCategory.UTILITIES,
304
346
  // Transaction Management
305
347
  beginTransaction: DocCategory.TRANSACTION_MANAGEMENT,
306
348
  commitTransaction: DocCategory.TRANSACTION_MANAGEMENT,
@@ -397,6 +439,7 @@ exports.toolDocCategoryMap = {
397
439
  exportTableToJSON: DocCategory.IMPORT_EXPORT,
398
440
  exportQueryToJSON: DocCategory.IMPORT_EXPORT,
399
441
  exportTableToSql: DocCategory.IMPORT_EXPORT,
442
+ safe_export_table: DocCategory.IMPORT_EXPORT,
400
443
  importFromCSV: DocCategory.IMPORT_EXPORT,
401
444
  importFromJSON: DocCategory.IMPORT_EXPORT,
402
445
  // Data Migration
@@ -530,6 +573,9 @@ class FeatureConfig {
530
573
  const parsed = this.parseConfig(mergedPermissions, mergedCategories);
531
574
  this.enabledLegacyCategories = parsed.legacy;
532
575
  this.enabledDocCategories = parsed.doc;
576
+ // Initialize Allow/Deny Lists
577
+ this.allowedTools = new Set(this.activePreset?.allowedTools || []);
578
+ this.deniedTools = new Set(this.activePreset?.deniedTools || []);
533
579
  }
534
580
  /**
535
581
  * Normalize and merge preset + user-supplied configuration lists
@@ -588,6 +634,9 @@ class FeatureConfig {
588
634
  docCats.forEach((dc) => docSet.add(dc));
589
635
  });
590
636
  }
637
+ // Re-initialize Allow/Deny Lists if preset changed
638
+ this.allowedTools = new Set(this.activePreset?.allowedTools || []);
639
+ this.deniedTools = new Set(this.activePreset?.deniedTools || []);
591
640
  return {
592
641
  legacy: legacySet,
593
642
  doc: docSet,
@@ -644,6 +693,15 @@ class FeatureConfig {
644
693
  console.warn(`Unknown tool: ${toolName}`);
645
694
  return false;
646
695
  }
696
+ // Layer 0: Check explicit Deny/Allow lists
697
+ // Deny takes precedence
698
+ if (this.deniedTools.has(toolName)) {
699
+ return false;
700
+ }
701
+ // Allow overrides other checks
702
+ if (this.allowedTools.has(toolName)) {
703
+ return true;
704
+ }
647
705
  // Layer 1: Check permission (legacy category)
648
706
  const hasPermission = legacyCategory
649
707
  ? this.enabledLegacyCategories.has(legacyCategory)
@@ -670,6 +728,9 @@ class FeatureConfig {
670
728
  if (!docCategory && !legacyCategory) {
671
729
  return `Unknown tool '${toolName}'. This tool is not recognized by the MCP server.`;
672
730
  }
731
+ if (this.deniedTools.has(toolName)) {
732
+ return `Permission denied: Tool '${toolName}' is explicitly denied by the current profile ('${this.presetName}').`;
733
+ }
673
734
  const isAllEnabled = !this.originalPermissionsString.trim() &&
674
735
  !this.originalCategoriesString.trim();
675
736
  if (isAllEnabled) {
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);
@@ -189,6 +190,14 @@ export declare class MySQLMCP {
189
190
  data?: any;
190
191
  error?: string;
191
192
  }>;
193
+ readChangelog(params?: {
194
+ version?: string;
195
+ limit?: number;
196
+ }): Promise<{
197
+ status: string;
198
+ data?: any;
199
+ error?: string;
200
+ }>;
192
201
  beginTransaction(params?: {
193
202
  transactionId?: string;
194
203
  }): Promise<import("./tools/transactionTools").TransactionResult | {
@@ -590,6 +599,16 @@ export declare class MySQLMCP {
590
599
  suggestions?: string[];
591
600
  error?: string;
592
601
  }>;
602
+ safeExportTable(params: {
603
+ table_name: string;
604
+ masking_profile?: string;
605
+ limit?: number;
606
+ include_headers?: boolean;
607
+ }): Promise<{
608
+ status: string;
609
+ data?: any;
610
+ error?: string;
611
+ }>;
593
612
  getFeatureStatus(): {
594
613
  status: string;
595
614
  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) {
@@ -231,6 +234,13 @@ class MySQLMCP {
231
234
  }
232
235
  return await this.utilityTools.getTableRelationships(params);
233
236
  }
237
+ async readChangelog(params) {
238
+ const check = this.checkToolEnabled("read_changelog");
239
+ if (!check.enabled) {
240
+ return { status: "error", error: check.error };
241
+ }
242
+ return await this.utilityTools.readChangelog(params);
243
+ }
234
244
  // Transaction Tools
235
245
  async beginTransaction(params) {
236
246
  const check = this.checkToolEnabled("beginTransaction");
@@ -535,6 +545,14 @@ class MySQLMCP {
535
545
  }
536
546
  return await this.aiTools.repairQuery(params);
537
547
  }
548
+ // Workflow Macros
549
+ async safeExportTable(params) {
550
+ const check = this.checkToolEnabled("safe_export_table");
551
+ if (!check.enabled) {
552
+ return { status: "error", error: check.error };
553
+ }
554
+ return await this.macroTools.safeExportTable(params);
555
+ }
538
556
  // Get feature configuration status
539
557
  getFeatureStatus() {
540
558
  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.",
@@ -632,6 +659,23 @@ const TOOLS = [
632
659
  properties: {},
633
660
  },
634
661
  },
662
+ {
663
+ name: "read_changelog",
664
+ description: "Reads the changelog to see what features are new or changed.",
665
+ inputSchema: {
666
+ type: "object",
667
+ properties: {
668
+ version: {
669
+ type: "string",
670
+ description: "Optional: specific version to read (e.g., '1.0.0')",
671
+ },
672
+ limit: {
673
+ type: "number",
674
+ description: "Optional: limit character count (default: 5000)",
675
+ },
676
+ },
677
+ },
678
+ },
635
679
  {
636
680
  name: "test_connection",
637
681
  description: "Tests the database connection and returns latency information.",
@@ -2847,6 +2891,9 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
2847
2891
  case "test_connection":
2848
2892
  result = await mysqlMCP.testConnection();
2849
2893
  break;
2894
+ case "read_changelog":
2895
+ result = await mysqlMCP.readChangelog((args || {}));
2896
+ break;
2850
2897
  case "get_table_relationships":
2851
2898
  result = await mysqlMCP.getTableRelationships((args || {}));
2852
2899
  break;
@@ -3083,6 +3130,12 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
3083
3130
  case "export_query_to_json":
3084
3131
  result = await mysqlMCP.exportQueryToJSON((args || {}));
3085
3132
  break;
3133
+ case "export_query_to_csv":
3134
+ result = await mysqlMCP.exportQueryToCSV((args || {}));
3135
+ break;
3136
+ case "safe_export_table":
3137
+ result = await mysqlMCP.safeExportTable((args || {}));
3138
+ break;
3086
3139
  case "export_table_to_sql":
3087
3140
  result = await mysqlMCP.exportTableToSql((args || {}));
3088
3141
  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;
@@ -27,4 +27,15 @@ export declare class UtilityTools {
27
27
  data?: any;
28
28
  error?: string;
29
29
  }>;
30
+ /**
31
+ * Reads the CHANGELOG.md file from the project root
32
+ */
33
+ readChangelog(params?: {
34
+ version?: string;
35
+ limit?: number;
36
+ }): Promise<{
37
+ status: string;
38
+ data?: any;
39
+ error?: string;
40
+ }>;
30
41
  }
@@ -7,6 +7,8 @@ exports.UtilityTools = void 0;
7
7
  const connection_1 = __importDefault(require("../db/connection"));
8
8
  const config_1 = require("../config/config");
9
9
  const schemas_1 = require("../validation/schemas");
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const path_1 = __importDefault(require("path"));
10
12
  class UtilityTools {
11
13
  constructor() {
12
14
  this.db = connection_1.default.getInstance();
@@ -208,5 +210,74 @@ class UtilityTools {
208
210
  };
209
211
  }
210
212
  }
213
+ /**
214
+ * Reads the CHANGELOG.md file from the project root
215
+ */
216
+ async readChangelog(params) {
217
+ try {
218
+ // Resolve path relative to the built file (dist/tools/utilityTools.js -> ../../CHANGELOG.md)
219
+ // or source file (src/tools/utilityTools.ts -> ../../CHANGELOG.md)
220
+ const changelogPath = path_1.default.resolve(__dirname, "..", "..", "CHANGELOG.md");
221
+ if (!fs_1.default.existsSync(changelogPath)) {
222
+ return {
223
+ status: "error",
224
+ error: "CHANGELOG.md not found in the project root.",
225
+ };
226
+ }
227
+ const content = fs_1.default.readFileSync(changelogPath, "utf-8");
228
+ // If version specified, try to parse and find it
229
+ if (params?.version) {
230
+ // Simple parsing - look for headers like "## [1.2.3]"
231
+ const versionHeader = `## [${params.version}]`;
232
+ const lines = content.split("\n");
233
+ let found = false;
234
+ let versionContent = "";
235
+ for (const line of lines) {
236
+ if (line.startsWith(versionHeader)) {
237
+ found = true;
238
+ versionContent += line + "\n";
239
+ continue;
240
+ }
241
+ if (found) {
242
+ if (line.startsWith("## ["))
243
+ break; // Next version starts
244
+ versionContent += line + "\n";
245
+ }
246
+ }
247
+ if (!found) {
248
+ return {
249
+ status: "error",
250
+ error: `Version ${params.version} not found in CHANGELOG.md`,
251
+ };
252
+ }
253
+ return {
254
+ status: "success",
255
+ data: {
256
+ version: params.version,
257
+ content: versionContent.trim(),
258
+ },
259
+ };
260
+ }
261
+ // If no version, return the whole file or top N characters/lines?
262
+ // For now, let's return the most recent versions.
263
+ // Limit default to 3000 chars to avoid overflowing context
264
+ const maxLength = params?.limit || 5000;
265
+ const truncated = content.length > maxLength
266
+ ? content.substring(0, maxLength) + "\n... (truncated)"
267
+ : content;
268
+ return {
269
+ status: "success",
270
+ data: {
271
+ content: truncated,
272
+ },
273
+ };
274
+ }
275
+ catch (error) {
276
+ return {
277
+ status: "error",
278
+ error: `Failed to read changelog: ${error.message}`,
279
+ };
280
+ }
281
+ }
211
282
  }
212
283
  exports.UtilityTools = UtilityTools;
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.15.0",
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",