@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 +48 -40
- package/DOCUMENTATIONS.md +54 -9
- package/README.md +3 -3
- package/dist/index.d.ts +11 -0
- package/dist/index.js +10 -0
- package/dist/mcp-server.js +22 -31
- package/dist/optimization/explainAnalyzer.d.ts +21 -0
- package/dist/optimization/explainAnalyzer.js +147 -0
- package/dist/tools/aiTools.d.ts +22 -0
- package/dist/tools/aiTools.js +80 -0
- package/package.json +2 -2
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.
|
|
9
|
-
|
|
10
|
-
### Added
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
###
|
|
22
|
-
-
|
|
23
|
-
|
|
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. [
|
|
33
|
-
25. [
|
|
34
|
-
26. [
|
|
35
|
-
27. [
|
|
36
|
-
28. [
|
|
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 |
|
|
4099
|
-
| Drift & Migration Assistant (Schema diff + risk summary) | High | High | 4 |
|
|
4100
|
-
| Safety Sandbox Mode (runQuery dry-run/EXPLAIN-only) | Medium | Low | 5 |
|
|
4101
|
-
| Anomaly & Slow-Query Watcher | Medium | Medium | 6 |
|
|
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
|
-
| **
|
|
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
|
-
**
|
|
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 |
|
|
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();
|
package/dist/mcp-server.js
CHANGED
|
@@ -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.
|
|
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
|
+
}
|