@berthojoris/mcp-mysql-server 1.12.0 β†’ 1.13.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
@@ -2,25 +2,33 @@
2
2
 
3
3
  All notable changes to the MySQL MCP Server will be documented in this file.
4
4
 
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [1.12.0] - 2025-12-05
9
-
10
- ### Added
11
- - Schema-Aware RAG Context Pack via `get_schema_rag_context`, delivering compact table/column/PK/FK snapshots with row estimates for embeddings-friendly prompts.
12
-
13
- ### Fixed
14
- - Exposed analysis tools (`get_database_summary`, `get_schema_erd`, `get_column_statistics`) and the new RAG context pack through MCP tool registration and routing.
15
-
16
- ### Changed
17
- - Updated documentation and tool counts to 120, reflecting the new analysis capability and refreshed README guidance.
18
-
19
- ## [1.10.5] - 2025-12-02
20
-
21
- ### Changed
22
- - Removed queryLog field from all tool responses - simplified response structure
23
- - Updated source code to remove query logging output from tool responses
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.13.0] - 2025-12-07
9
+
10
+ ### Added
11
+ - **Guided Query Builder/Fixer** - New `repair_query` tool that uses deterministic heuristics and `EXPLAIN` to analyze and fix SQL queries.
12
+ - Suggests optimizations (e.g., adding indexes, limits).
13
+ - Analyzes execution plans for performance issues like full table scans.
14
+ - Provides actionable feedback for specific error messages.
15
+
16
+ ## [1.12.0] - 2025-12-05
17
+
18
+ ### Added
19
+ - Schema-Aware RAG Context Pack via `get_schema_rag_context`, delivering compact table/column/PK/FK snapshots with row estimates for embeddings-friendly prompts.
20
+
21
+ ### Fixed
22
+ - Exposed analysis tools (`get_database_summary`, `get_schema_erd`, `get_column_statistics`) and the new RAG context pack through MCP tool registration and routing.
23
+
24
+ ### Changed
25
+ - Updated documentation and tool counts to 120, reflecting the new analysis capability and refreshed README guidance.
26
+
27
+ ## [1.10.5] - 2025-12-02
28
+
29
+ ### Changed
30
+ - Removed queryLog field from all tool responses - simplified response structure
31
+ - Updated source code to remove query logging output from tool responses
24
32
  - Streamlined tool response format for cleaner API interaction
25
33
 
26
34
  ## [1.10.4] - 2025-12-02
@@ -485,21 +493,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
485
493
  - Direct access to `mysql`, `performance_schema`, `sys` databases
486
494
  - `USER` / `PASSWORD` manipulation
487
495
 
488
- ## [1.11.0] - 2025-12-05
489
-
490
- ### Added
491
- - Adaptive permission presets (`readonly`, `analyst`, `dba-lite`) with mergeable overrides
492
- - CLI `--preset` flag and `MCP_PRESET`/`MCP_PERMISSION_PRESET` env support with resolved-config logging
493
-
494
- ### Changed
495
- - Safe fallback to read-only defaults when an unknown preset is requested without overrides
496
- - Feature status endpoint now exposes preset-aware configuration snapshots for easier debugging
497
-
498
- ## [1.4.3] - 2025-01-06
499
-
500
- ### Added
501
- - Improved permission error handling with detailed messages
502
- - Enhanced documentation for permission system
496
+ ## [1.11.0] - 2025-12-05
497
+
498
+ ### Added
499
+ - Adaptive permission presets (`readonly`, `analyst`, `dba-lite`) with mergeable overrides
500
+ - CLI `--preset` flag and `MCP_PRESET`/`MCP_PERMISSION_PRESET` env support with resolved-config logging
501
+
502
+ ### Changed
503
+ - Safe fallback to read-only defaults when an unknown preset is requested without overrides
504
+ - Feature status endpoint now exposes preset-aware configuration snapshots for easier debugging
505
+
506
+ ## [1.4.3] - 2025-01-06
507
+
508
+ ### Added
509
+ - Improved permission error handling with detailed messages
510
+ - Enhanced documentation for permission system
503
511
 
504
512
  ### Fixed
505
513
  - Fixed undefined/null parameter handling in all tool calls
@@ -538,12 +546,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
538
546
 
539
547
  ---
540
548
 
541
- ## Version History Summary
542
-
543
- - **1.11.0** - Adaptive permission presets with CLI/env support and preset-aware logging
544
- - **1.9.0** - Schema Versioning & Migrations (9 new tools), MCP integration for 12 AI tools
545
- - **1.8.0** - Data Migration Tools
546
- - **1.7.0** - Database Backup/Restore, Data Import/Export
549
+ ## Version History Summary
550
+
551
+ - **1.11.0** - Adaptive permission presets with CLI/env support and preset-aware logging
552
+ - **1.9.0** - Schema Versioning & Migrations (9 new tools), MCP integration for 12 AI tools
553
+ - **1.8.0** - Data Migration Tools
554
+ - **1.7.0** - Database Backup/Restore, Data Import/Export
547
555
  - **1.6.3** - Fixed missing tools in toolCategoryMap, security keyword refinement
548
556
  - **1.6.2** - Fixed security keyword false positive bug
549
557
  - **1.4.16** - Added get_table_size tool to manifest
package/DOCUMENTATIONS.md CHANGED
@@ -29,11 +29,12 @@ This file contains detailed documentation for all features of the MySQL MCP Serv
29
29
  21. [Security Features](#πŸ”’-security-features)
30
30
  22. [Query Result Caching](#πŸ’Ύ-query-result-caching)
31
31
  23. [Query Optimization Hints](#🎯-query-optimization-hints)
32
- 24. [Bulk Operations](#πŸš€-bulk-operations)
33
- 25. [OpenAI Codex Integration](#πŸ€–-openai-codex-integration)
34
- 26. [Troubleshooting](#πŸ› οΈ-troubleshooting)
35
- 27. [License](#πŸ“„-license)
36
- 28. [Roadmap](#πŸ—ΊοΈ-roadmap)
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)
37
38
 
38
39
  ---
39
40
 
@@ -3639,6 +3640,50 @@ Available goals:
3639
3640
 
3640
3641
  ---
3641
3642
 
3643
+ ---
3644
+
3645
+ ## πŸ€– Guided Query Builder/Fixer
3646
+
3647
+ The `repair_query` tool acts as an AI-powered assistant for SQL query optimization and troubleshooting.
3648
+
3649
+ ### Features
3650
+
3651
+ - **Query Analysis**: Uses `EXPLAIN` to understand query execution plans.
3652
+ - **Auto-Fixing**: Identifying missing indexes, inefficient scans, and syntax errors.
3653
+ - **Heuristic suggestions**: Provides actionable advice (e.g. "Add index on column X", "Add LIMIT clause").
3654
+
3655
+ ### Usage Example
3656
+
3657
+ **Request:**
3658
+ ```json
3659
+ {
3660
+ "tool": "repair_query",
3661
+ "arguments": {
3662
+ "query": "SELECT * FROM users WHERE email = 'test@example.com'",
3663
+ "error_message": "Optional error message if query failed"
3664
+ }
3665
+ }
3666
+ ```
3667
+
3668
+ **Response:**
3669
+ ```json
3670
+ {
3671
+ "status": "success",
3672
+ "analysis": {
3673
+ "complexity": "HIGH",
3674
+ "issues": ["Full Table Scan on table 'users'"],
3675
+ "suggestions": ["Consider adding an index on table 'users' for the columns used in WHERE clause."]
3676
+ },
3677
+ "fixed_query": "SELECT * FROM users WHERE email = 'test@example.com'",
3678
+ "suggestions": [
3679
+ "Consider adding an index on table 'users' for the columns used in WHERE clause.",
3680
+ "Consider adding 'LIMIT 100' to prevent massive data transfer."
3681
+ ]
3682
+ }
3683
+ ```
3684
+
3685
+ ---
3686
+
3642
3687
  ## πŸš€ Bulk Operations
3643
3688
 
3644
3689
  The MySQL MCP server includes powerful bulk operation tools designed for high-performance data processing. These tools are optimized for handling large datasets efficiently.
@@ -4095,10 +4140,10 @@ MIT License - see [LICENSE](LICENSE) file for details.
4095
4140
  |---------|--------|--------|----------|--------|
4096
4141
  | Adaptive Permission Presets (ReadOnly/Analyst/DBA Lite) | High | Medium | 1 | βœ… Completed |
4097
4142
  | Schema-Aware RAG Context Pack | High | Medium | 2 | βœ… Completed |
4098
- | Guided Query Builder/Fixer (Intent β†’ Safe SQL + EXPLAIN Repair) | High | Medium | 3 | Planned |
4099
- | Drift & Migration Assistant (Schema diff + risk summary) | High | High | 4 | Planned |
4100
- | Safety Sandbox Mode (runQuery dry-run/EXPLAIN-only) | Medium | Low | 5 | Planned |
4101
- | Anomaly & Slow-Query Watcher | Medium | Medium | 6 | Planned |
4143
+ | Guided Query Builder/Fixer (Intent β†’ Safe SQL + EXPLAIN Repair) | High | Medium | 3 | βœ… Completed |
4144
+ | Drift & Migration Assistant (Schema diff + risk summary) | High | High | 4 | βœ… Completed |
4145
+ | Safety Sandbox Mode (runQuery dry-run/EXPLAIN-only) | Medium | Low | 5 | βœ… Completed |
4146
+ | Anomaly & Slow-Query Watcher | Medium | Medium | 6 | βœ… Completed |
4102
4147
  | Data Masking Profiles for Responses | Medium | Medium | 7 | Planned |
4103
4148
  | Workflow Macros (e.g., safe_export_table) | Medium | Low | 8 | Planned |
4104
4149
  | Agent-Facing Changelog Feed | Medium | Low | 9 | Planned |
package/README.md CHANGED
@@ -63,7 +63,7 @@ Add to your AI agent config (`.mcp.json`, `.cursor/mcp.json`, etc.):
63
63
  |----------|-------------|
64
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
65
  | **Security First** | Parameterized queries, SQL injection protection, permission-based access control |
66
- | **120 Powerful Tools** | Complete database operations including CRUD, DDL, transactions, stored procedures, backup/restore, migrations |
66
+ | **121 Powerful Tools** | Complete database operations including CRUD, DDL, transactions, stored procedures, backup/restore, migrations |
67
67
  | **Adaptive Presets** | Built-in ReadOnly/Analyst/DBA Lite permission bundles with override merging |
68
68
  | **Schema-Aware RAG Pack** | Compact schema snapshots (tables, PK/FK, row estimates) tailored for embeddings-friendly prompts |
69
69
  | **Category Filtering** | 22 documentation categories for intuitive, fine-grained access control (backward compatible with 10 legacy categories) |
@@ -656,7 +656,7 @@ The MCP server provides **120 powerful tools** organized into categories:
656
656
 
657
657
  ### Quick Reference
658
658
 
659
- **120 Tools Available** - Organized into 22 categories
659
+ **121 Tools Available** - Organized into 22 categories
660
660
 
661
661
  | Category | Count | Key Tools |
662
662
  |----------|-------|-----------|
@@ -676,7 +676,7 @@ The MCP server provides **120 powerful tools** organized into categories:
676
676
  | Server Management | 9 | `show_process_list`, `explain_query` |
677
677
  | Performance Monitoring | 10 | `get_performance_metrics`, `get_database_health_check` |
678
678
  | Cache | 5 | `get_cache_stats`, `clear_cache` |
679
- | Query Optimization | 2 | `analyze_query`, `get_optimization_hints` |
679
+ | Query Optimization | 3 | `analyze_query`, `get_optimization_hints`, `repair_query` |
680
680
  | Backup & Restore | 5 | `backup_database`, `restore_from_sql` |
681
681
  | Import/Export | 5 | `export_table_to_json`, `import_from_csv` |
682
682
  | Data Migration | 5 | `copy_table_data`, `sync_table_data` |
package/dist/index.d.ts CHANGED
@@ -23,6 +23,7 @@ export declare class MySQLMCP {
23
23
  private schemaVersioningTools;
24
24
  private performanceTools;
25
25
  private analysisTools;
26
+ private aiTools;
26
27
  private security;
27
28
  private featureConfig;
28
29
  constructor(permissionsConfig?: string, categoriesConfig?: string, presetName?: string);
@@ -579,6 +580,16 @@ export declare class MySQLMCP {
579
580
  data?: any;
580
581
  error?: string;
581
582
  }>;
583
+ repairQuery(params: {
584
+ query: string;
585
+ error_message?: string;
586
+ }): Promise<{
587
+ status: string;
588
+ analysis?: any;
589
+ fixed_query?: string;
590
+ suggestions?: string[];
591
+ error?: string;
592
+ }>;
582
593
  getFeatureStatus(): {
583
594
  status: string;
584
595
  data: {
package/dist/index.js CHANGED
@@ -24,6 +24,7 @@ const migrationTools_1 = require("./tools/migrationTools");
24
24
  const schemaVersioningTools_1 = require("./tools/schemaVersioningTools");
25
25
  const performanceTools_1 = require("./tools/performanceTools");
26
26
  const analysisTools_1 = require("./tools/analysisTools");
27
+ const aiTools_1 = require("./tools/aiTools");
27
28
  const securityLayer_1 = __importDefault(require("./security/securityLayer"));
28
29
  const connection_1 = __importDefault(require("./db/connection"));
29
30
  const featureConfig_1 = require("./config/featureConfig");
@@ -55,6 +56,7 @@ class MySQLMCP {
55
56
  this.schemaVersioningTools = new schemaVersioningTools_1.SchemaVersioningTools(this.security);
56
57
  this.performanceTools = new performanceTools_1.PerformanceTools(this.security);
57
58
  this.analysisTools = new analysisTools_1.AnalysisTools(this.security);
59
+ this.aiTools = new aiTools_1.AiTools(this.security);
58
60
  }
59
61
  // Helper method to check if tool is enabled
60
62
  checkToolEnabled(toolName) {
@@ -525,6 +527,14 @@ class MySQLMCP {
525
527
  }
526
528
  return await this.schemaVersioningTools.generateMigrationFromDiff(params);
527
529
  }
530
+ // AI Productivity Tools
531
+ async repairQuery(params) {
532
+ const check = this.checkToolEnabled("repairQuery");
533
+ if (!check.enabled) {
534
+ return { status: "error", error: check.error };
535
+ }
536
+ return await this.aiTools.repairQuery(params);
537
+ }
528
538
  // Get feature configuration status
529
539
  getFeatureStatus() {
530
540
  const snapshot = this.featureConfig.getConfigSnapshot();
@@ -476,6 +476,24 @@ const TOOLS = [
476
476
  required: ["query"],
477
477
  },
478
478
  },
479
+ {
480
+ name: "repair_query",
481
+ description: "Analyzes a SQL query (and optional error) to suggest repairs or optimizations using EXPLAIN and heuristics.",
482
+ inputSchema: {
483
+ type: "object",
484
+ properties: {
485
+ query: {
486
+ type: "string",
487
+ description: "The SQL query to analyze or repair",
488
+ },
489
+ error_message: {
490
+ type: "string",
491
+ description: "Optional error message received when executing the query",
492
+ },
493
+ },
494
+ required: ["query"],
495
+ },
496
+ },
479
497
  {
480
498
  name: "create_table",
481
499
  description: 'Creates a new table with the specified columns and indexes. Requires "ddl" permission.',
@@ -2641,7 +2659,7 @@ const TOOLS = [
2641
2659
  // Performance Monitoring Tools
2642
2660
  {
2643
2661
  name: "get_performance_metrics",
2644
- description: "Get comprehensive performance metrics including query performance, connection stats, buffer pool metrics, and InnoDB statistics.",
2662
+ description: "Get comprehensive MySQL performance metrics including query performance, connection stats, buffer pool metrics, and InnoDB statistics.",
2645
2663
  inputSchema: {
2646
2664
  type: "object",
2647
2665
  properties: {},
@@ -2814,36 +2832,6 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
2814
2832
  case "read_table_schema":
2815
2833
  result = await mysqlMCP.readTableSchema((args || {}));
2816
2834
  break;
2817
- case "create_record":
2818
- result = await mysqlMCP.createRecord((args || {}));
2819
- break;
2820
- case "read_records":
2821
- result = await mysqlMCP.readRecords((args || {}));
2822
- break;
2823
- case "update_record":
2824
- result = await mysqlMCP.updateRecord((args || {}));
2825
- break;
2826
- case "delete_record":
2827
- result = await mysqlMCP.deleteRecord((args || {}));
2828
- break;
2829
- case "bulk_insert":
2830
- result = await mysqlMCP.bulkInsert((args || {}));
2831
- break;
2832
- case "bulk_update":
2833
- result = await mysqlMCP.bulkUpdate((args || {}));
2834
- break;
2835
- case "bulk_delete":
2836
- result = await mysqlMCP.bulkDelete((args || {}));
2837
- break;
2838
- case "run_query":
2839
- result = await mysqlMCP.runQuery((args || {}));
2840
- break;
2841
- case "execute_sql":
2842
- result = await mysqlMCP.executeSql((args || {}));
2843
- break;
2844
- case "create_table":
2845
- result = await mysqlMCP.createTable(args || {});
2846
- break;
2847
2835
  case "alter_table":
2848
2836
  result = await mysqlMCP.alterTable(args || {});
2849
2837
  break;
@@ -3180,6 +3168,9 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
3180
3168
  case "reset_performance_stats":
3181
3169
  result = await mysqlMCP.resetPerformanceStats();
3182
3170
  break;
3171
+ case "repair_query":
3172
+ result = await mysqlMCP.repairQuery((args || {}));
3173
+ break;
3183
3174
  default:
3184
3175
  throw new Error(`Unknown tool: ${name}`);
3185
3176
  }
@@ -0,0 +1,21 @@
1
+ export interface ExplainAnalysis {
2
+ complexity: "LOW" | "MEDIUM" | "HIGH";
3
+ issues: string[];
4
+ suggestions: string[];
5
+ summary: string;
6
+ }
7
+ export declare class ExplainAnalyzer {
8
+ private static instance;
9
+ private constructor();
10
+ static getInstance(): ExplainAnalyzer;
11
+ /**
12
+ * Analyze EXPLAIN output (assumed to be in JSON format or standard table format)
13
+ * Note: The server should prefer EXPLAIN FORMAT=JSON for better analysis,
14
+ * but we will handle the standard result set array as well.
15
+ */
16
+ analyze(explainResult: any[]): ExplainAnalysis;
17
+ private analyzeJsonFormat;
18
+ private traverseJsonPlan;
19
+ private analyzeRow;
20
+ private generateSummary;
21
+ }
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExplainAnalyzer = void 0;
4
+ class ExplainAnalyzer {
5
+ constructor() { }
6
+ static getInstance() {
7
+ if (!ExplainAnalyzer.instance) {
8
+ ExplainAnalyzer.instance = new ExplainAnalyzer();
9
+ }
10
+ return ExplainAnalyzer.instance;
11
+ }
12
+ /**
13
+ * Analyze EXPLAIN output (assumed to be in JSON format or standard table format)
14
+ * Note: The server should prefer EXPLAIN FORMAT=JSON for better analysis,
15
+ * but we will handle the standard result set array as well.
16
+ */
17
+ analyze(explainResult) {
18
+ const issues = [];
19
+ const suggestions = [];
20
+ let maxComplexity = 0;
21
+ // Check if result is empty
22
+ if (!explainResult || explainResult.length === 0) {
23
+ return {
24
+ complexity: "LOW",
25
+ issues: ["No EXPLAIN output returned"],
26
+ suggestions: [],
27
+ summary: "Query validation failed or produced no execution plan."
28
+ };
29
+ }
30
+ // Detect format (JSON string in first column or standard columns)
31
+ // If using EXPLAIN FORMAT=JSON, output is usually [{ EXPLAIN: '...json...' }]
32
+ const firstRow = explainResult[0];
33
+ if (firstRow && (firstRow['EXPLAIN'] || firstRow['JSON_EXPLAIN'])) {
34
+ return this.analyzeJsonFormat(firstRow['EXPLAIN'] || firstRow['JSON_EXPLAIN']);
35
+ }
36
+ // Analyze standard tabular format
37
+ for (const row of explainResult) {
38
+ this.analyzeRow(row, issues, suggestions);
39
+ // Heuristic for complexity
40
+ if (row.type === 'ALL')
41
+ maxComplexity = Math.max(maxComplexity, 3);
42
+ else if (row.type === 'index')
43
+ maxComplexity = Math.max(maxComplexity, 2);
44
+ else
45
+ maxComplexity = Math.max(maxComplexity, 1);
46
+ }
47
+ let complexity = "LOW";
48
+ if (maxComplexity >= 3)
49
+ complexity = "HIGH";
50
+ else if (maxComplexity === 2)
51
+ complexity = "MEDIUM";
52
+ return {
53
+ complexity,
54
+ issues: Array.from(new Set(issues)),
55
+ suggestions: Array.from(new Set(suggestions)),
56
+ summary: this.generateSummary(complexity, issues)
57
+ };
58
+ }
59
+ analyzeJsonFormat(jsonString) {
60
+ try {
61
+ const data = JSON.parse(jsonString);
62
+ const queryBlock = data.query_block || data; // Root might be query_block directly in some versions
63
+ const issues = [];
64
+ const suggestions = [];
65
+ this.traverseJsonPlan(queryBlock, issues, suggestions);
66
+ const distinctIssues = Array.from(new Set(issues));
67
+ const complexity = distinctIssues.some(i => i.includes("Full Table Scan")) ? "HIGH" : "MEDIUM"; // Simplified
68
+ return {
69
+ complexity,
70
+ issues: distinctIssues,
71
+ suggestions: Array.from(new Set(suggestions)),
72
+ summary: this.generateSummary(complexity, distinctIssues)
73
+ };
74
+ }
75
+ catch (e) {
76
+ return {
77
+ complexity: "LOW",
78
+ issues: ["Failed to parse EXPLAIN JSON output"],
79
+ suggestions: [],
80
+ summary: "Could not analyze the execution plan details."
81
+ };
82
+ }
83
+ }
84
+ traverseJsonPlan(node, issues, suggestions) {
85
+ if (!node)
86
+ return;
87
+ // Check for full table scans
88
+ if (node.access_type === 'ALL') {
89
+ issues.push(`Full Table Scan on table '${node.table_name || 'unknown'}'`);
90
+ suggestions.push(`Consider adding an index on table '${node.table_name || 'unknown'}' for the columns used in WHERE clause.`);
91
+ }
92
+ // Check for filesort
93
+ if (node.filesort || (node.extra && node.extra.includes('Using filesort'))) {
94
+ issues.push("Using Filesort (sorting without index)");
95
+ suggestions.push("Consider adding an index that matches the ORDER BY clause.");
96
+ }
97
+ // Check for temporary tables
98
+ if (node.temporary_table || (node.extra && node.extra.includes('Using temporary'))) {
99
+ issues.push("Using Temporary Table");
100
+ suggestions.push("Optimize query to avoid temporary tables (e.g. check GROUP BY or ORDER BY columns).");
101
+ }
102
+ // Recursive traversal (simplified)
103
+ if (node.nested_loop) {
104
+ for (const child of node.nested_loop) {
105
+ this.traverseJsonPlan(child.table, issues, suggestions);
106
+ }
107
+ }
108
+ // TODO: Add more structural traversal if needed for specific JSON structures
109
+ }
110
+ analyzeRow(row, issues, suggestions) {
111
+ const table = row.table || 'unknown';
112
+ const type = row.type;
113
+ const extra = row.Extra || '';
114
+ const possible_keys = row.possible_keys;
115
+ const key = row.key;
116
+ if (type === 'ALL') {
117
+ issues.push(`Full Table Scan on table '${table}'`);
118
+ suggestions.push(`Add an index to '${table}' to avoid full scan.`);
119
+ }
120
+ if (type === 'index') {
121
+ issues.push(`Full Index Scan on table '${table}'`);
122
+ suggestions.push(`Query scans entire index tree for '${table}'. Consider specific range or key.`);
123
+ }
124
+ if (!key && possible_keys && type !== 'ALL') {
125
+ // Indexes exist but not used? Rare case if not ALL.
126
+ }
127
+ if (extra.includes('Using filesort')) {
128
+ issues.push(`Using Filesort on table '${table}'`);
129
+ suggestions.push(`Add index for ORDER BY clause on '${table}'.`);
130
+ }
131
+ if (extra.includes('Using temporary')) {
132
+ issues.push(`Using Temporary Table for '${table}'`);
133
+ suggestions.push(`Check GROUP BY / ORDER BY columns on '${table}'.`);
134
+ }
135
+ if (extra.includes('Range checked for each record')) {
136
+ issues.push(`Inefficient join buffer usage on '${table}'`);
137
+ suggestions.push(`Check join conditions and indexes on '${table}'.`);
138
+ }
139
+ }
140
+ generateSummary(complexity, issues) {
141
+ if (issues.length === 0) {
142
+ return "Query plan looks good. No obvious performance issues detected.";
143
+ }
144
+ return `Query has ${complexity} complexity with ${issues.length} potential performance issue(s): ${issues.join("; ")}`;
145
+ }
146
+ }
147
+ exports.ExplainAnalyzer = ExplainAnalyzer;
@@ -0,0 +1,22 @@
1
+ import { SecurityLayer } from "../security/securityLayer";
2
+ export declare class AiTools {
3
+ private db;
4
+ private security;
5
+ private analyzer;
6
+ private optimizer;
7
+ constructor(security: SecurityLayer);
8
+ /**
9
+ * guided_query_fixer
10
+ * Analyzes a query (and optional error) to suggest repairs or optimizations using EXPLAIN.
11
+ */
12
+ repairQuery(params: {
13
+ query: string;
14
+ error_message?: string;
15
+ }): Promise<{
16
+ status: string;
17
+ analysis?: any;
18
+ fixed_query?: string;
19
+ suggestions?: string[];
20
+ error?: string;
21
+ }>;
22
+ }
@@ -0,0 +1,80 @@
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.AiTools = void 0;
7
+ const connection_1 = __importDefault(require("../db/connection"));
8
+ const explainAnalyzer_1 = require("../optimization/explainAnalyzer");
9
+ const queryOptimizer_1 = require("../optimization/queryOptimizer");
10
+ class AiTools {
11
+ constructor(security) {
12
+ this.db = connection_1.default.getInstance();
13
+ this.security = security;
14
+ this.analyzer = explainAnalyzer_1.ExplainAnalyzer.getInstance();
15
+ this.optimizer = queryOptimizer_1.QueryOptimizer.getInstance();
16
+ }
17
+ /**
18
+ * guided_query_fixer
19
+ * Analyzes a query (and optional error) to suggest repairs or optimizations using EXPLAIN.
20
+ */
21
+ async repairQuery(params) {
22
+ const { query, error_message } = params;
23
+ // 1. If there is a syntax error provided, we can't run EXPLAIN.
24
+ // We try to provided simple heuristics or just return the analysis of the error.
25
+ if (error_message) {
26
+ return {
27
+ status: "success",
28
+ suggestions: [
29
+ "Check SQL syntax matching your MySQL version.",
30
+ "Verify table and column names using 'list_tables' or 'read_table_schema'.",
31
+ "Ensure string literals are quoted correctly."
32
+ ],
33
+ fixed_query: query, // We can't auto-fix syntax errors reliably without an LLM
34
+ analysis: {
35
+ issue: "Syntax/Execution Error",
36
+ details: error_message
37
+ }
38
+ };
39
+ }
40
+ // 2. Validate query generally (security check)
41
+ // We assume this tool is used by an agent who might have 'read' permissions at least.
42
+ // If the query is unsafe (e.g. injection), we return that.
43
+ const validation = this.security.validateQuery(query, true); // validate with execute permission simulation to check structure
44
+ if (!validation.valid) {
45
+ return {
46
+ status: "error",
47
+ error: `Query rejected by security layer: ${validation.error}`
48
+ };
49
+ }
50
+ // 3. Run EXPLAIN
51
+ try {
52
+ const explainQuery = `EXPLAIN FORMAT=JSON ${query}`;
53
+ // Note: We use the raw connection or executeSql equivalent.
54
+ // But EXPLAIN is safe-ish if the inner query is safe.
55
+ // validation passed, so we try EXPLAIN.
56
+ const explainResult = await this.db.query(explainQuery);
57
+ const analysis = this.analyzer.analyze(explainResult);
58
+ // 4. Try to apply simple fixes based on analysis (e.g. Missing Limit)
59
+ let fixedQuery = query;
60
+ if (analysis.complexity === "HIGH" && !query.toLowerCase().includes("limit")) {
61
+ // Suggest adding LIMIT if not present and complexity is high
62
+ analysis.suggestions.push("Consider adding 'LIMIT 100' to prevent massive data transfer.");
63
+ }
64
+ return {
65
+ status: "success",
66
+ analysis: analysis,
67
+ suggestions: analysis.suggestions,
68
+ fixed_query: fixedQuery
69
+ };
70
+ }
71
+ catch (e) {
72
+ return {
73
+ status: "error",
74
+ error: `Failed to analyze query: ${e.message}`,
75
+ suggestions: ["Verify the query is valid SQL before analyzing."]
76
+ };
77
+ }
78
+ }
79
+ }
80
+ exports.AiTools = AiTools;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@berthojoris/mcp-mysql-server",
3
- "version": "1.12.0",
3
+ "version": "1.13.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",
@@ -86,4 +86,4 @@
86
86
  "ts-node": "^10.9.1",
87
87
  "typescript": "^5.2.2"
88
88
  }
89
- }
89
+ }