@berthojoris/mcp-mysql-server 1.10.4 → 1.12.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.
@@ -51,7 +51,71 @@ var DocCategory;
51
51
  DocCategory["IMPORT_EXPORT"] = "import_export";
52
52
  DocCategory["DATA_MIGRATION"] = "data_migration";
53
53
  DocCategory["SCHEMA_MIGRATIONS"] = "schema_migrations";
54
+ DocCategory["ANALYSIS"] = "analysis";
54
55
  })(DocCategory || (exports.DocCategory = DocCategory = {}));
56
+ const normalizePresetName = (value) => (value || "").toLowerCase().replace(/[\s_-]/g, "");
57
+ const permissionPresets = {
58
+ readonly: {
59
+ name: "readonly",
60
+ description: "Safe read-only profile with discovery, querying, exports, and diagnostics",
61
+ permissions: [ToolCategory.LIST, ToolCategory.READ, ToolCategory.UTILITY],
62
+ categories: [
63
+ DocCategory.DATABASE_DISCOVERY,
64
+ DocCategory.CRUD_OPERATIONS,
65
+ DocCategory.CUSTOM_QUERIES,
66
+ DocCategory.UTILITIES,
67
+ DocCategory.IMPORT_EXPORT,
68
+ DocCategory.PERFORMANCE_MONITORING,
69
+ DocCategory.ANALYSIS,
70
+ ],
71
+ },
72
+ analyst: {
73
+ name: "analyst",
74
+ description: "Exploratory analytics profile with query insights and safe exports",
75
+ permissions: [ToolCategory.LIST, ToolCategory.READ, ToolCategory.UTILITY],
76
+ categories: [
77
+ DocCategory.DATABASE_DISCOVERY,
78
+ DocCategory.CRUD_OPERATIONS,
79
+ DocCategory.CUSTOM_QUERIES,
80
+ DocCategory.UTILITIES,
81
+ DocCategory.IMPORT_EXPORT,
82
+ DocCategory.PERFORMANCE_MONITORING,
83
+ DocCategory.ANALYSIS,
84
+ DocCategory.QUERY_OPTIMIZATION,
85
+ DocCategory.CACHE_MANAGEMENT,
86
+ DocCategory.SERVER_MANAGEMENT,
87
+ ],
88
+ },
89
+ dbalite: {
90
+ name: "dba-lite",
91
+ description: "Admin-lite profile for schema care, migrations, and maintenance",
92
+ permissions: [
93
+ ToolCategory.LIST,
94
+ ToolCategory.READ,
95
+ ToolCategory.UTILITY,
96
+ ToolCategory.DDL,
97
+ ToolCategory.TRANSACTION,
98
+ ToolCategory.PROCEDURE,
99
+ ],
100
+ categories: [
101
+ DocCategory.DATABASE_DISCOVERY,
102
+ DocCategory.CUSTOM_QUERIES,
103
+ DocCategory.UTILITIES,
104
+ DocCategory.SERVER_MANAGEMENT,
105
+ DocCategory.SCHEMA_MANAGEMENT,
106
+ DocCategory.TABLE_MAINTENANCE,
107
+ DocCategory.INDEX_MANAGEMENT,
108
+ DocCategory.CONSTRAINT_MANAGEMENT,
109
+ DocCategory.BACKUP_RESTORE,
110
+ DocCategory.SCHEMA_MIGRATIONS,
111
+ DocCategory.PERFORMANCE_MONITORING,
112
+ DocCategory.VIEWS_MANAGEMENT,
113
+ DocCategory.TRIGGERS_MANAGEMENT,
114
+ DocCategory.FUNCTIONS_MANAGEMENT,
115
+ DocCategory.STORED_PROCEDURES,
116
+ ],
117
+ },
118
+ };
55
119
  /**
56
120
  * Map of tool names to their legacy categories
57
121
  */
@@ -60,11 +124,17 @@ exports.toolCategoryMap = {
60
124
  listDatabases: ToolCategory.LIST,
61
125
  listTables: ToolCategory.LIST,
62
126
  readTableSchema: ToolCategory.LIST,
127
+ // Analysis tools (added here to group with database tools)
128
+ getDatabaseSummary: ToolCategory.LIST,
129
+ getSchemaERD: ToolCategory.LIST,
130
+ getSchemaRagContext: ToolCategory.LIST,
63
131
  // CRUD tools
64
132
  createRecord: ToolCategory.CREATE,
65
133
  readRecords: ToolCategory.READ,
66
134
  updateRecord: ToolCategory.UPDATE,
67
135
  deleteRecord: ToolCategory.DELETE,
136
+ // Analysis tools (added here to group with read tools)
137
+ getColumnStatistics: ToolCategory.READ,
68
138
  // Bulk operations
69
139
  bulkInsert: ToolCategory.CREATE,
70
140
  bulkUpdate: ToolCategory.UPDATE,
@@ -186,6 +256,8 @@ exports.toolCategoryMap = {
186
256
  validateMigrations: ToolCategory.LIST,
187
257
  resetFailedMigration: ToolCategory.DDL,
188
258
  generateMigrationFromDiff: ToolCategory.DDL,
259
+ // Analysis tools - MOVED here to avoid duplication
260
+ // Note: keys must be unique in the object literal
189
261
  // Performance monitoring tools
190
262
  getPerformanceMetrics: ToolCategory.UTILITY,
191
263
  getTopQueriesByTime: ToolCategory.UTILITY,
@@ -343,6 +415,11 @@ exports.toolDocCategoryMap = {
343
415
  validateMigrations: DocCategory.SCHEMA_MIGRATIONS,
344
416
  resetFailedMigration: DocCategory.SCHEMA_MIGRATIONS,
345
417
  generateMigrationFromDiff: DocCategory.SCHEMA_MIGRATIONS,
418
+ // Analysis
419
+ getDatabaseSummary: DocCategory.ANALYSIS,
420
+ getSchemaERD: DocCategory.ANALYSIS,
421
+ getColumnStatistics: DocCategory.ANALYSIS,
422
+ getSchemaRagContext: DocCategory.ANALYSIS,
346
423
  };
347
424
  /**
348
425
  * Mapping between legacy categories and documentation categories
@@ -360,8 +437,9 @@ const legacyToDocCategoryMap = {
360
437
  DocCategory.TABLE_MAINTENANCE,
361
438
  DocCategory.SERVER_MANAGEMENT,
362
439
  DocCategory.SCHEMA_MIGRATIONS,
440
+ DocCategory.ANALYSIS,
363
441
  ],
364
- read: [DocCategory.CRUD_OPERATIONS, DocCategory.CUSTOM_QUERIES],
442
+ read: [DocCategory.CRUD_OPERATIONS, DocCategory.CUSTOM_QUERIES, DocCategory.ANALYSIS],
365
443
  create: [
366
444
  DocCategory.CRUD_OPERATIONS,
367
445
  DocCategory.BULK_OPERATIONS,
@@ -409,20 +487,66 @@ const legacyToDocCategoryMap = {
409
487
  * - Layer 2 (Categories): Documentation categories (fine-grained control, optional)
410
488
  */
411
489
  class FeatureConfig {
412
- constructor(permissionsStr, categoriesStr) {
490
+ constructor(permissionsStr, categoriesStr, presetName) {
491
+ const presetInput = presetName ||
492
+ process.env.MCP_PERMISSION_PRESET ||
493
+ process.env.MCP_PRESET ||
494
+ "";
495
+ this.activePreset = this.resolvePreset(presetInput);
496
+ this.presetName = this.activePreset?.name;
497
+ const presetRequested = !!presetInput.trim();
413
498
  // Support both old single-parameter and new dual-parameter signatures
414
- const permissions = permissionsStr ||
499
+ const permissionsInput = permissionsStr ||
415
500
  process.env.MCP_PERMISSIONS ||
416
501
  process.env.MCP_CONFIG ||
417
502
  "";
418
- const categories = categoriesStr || process.env.MCP_CATEGORIES || "";
419
- this.originalPermissionsString = permissions;
420
- this.originalCategoriesString = categories;
421
- this.useDualLayer = !!categories.trim();
422
- const parsed = this.parseConfig(permissions, categories);
503
+ const categoriesInput = categoriesStr || process.env.MCP_CATEGORIES || "";
504
+ // Use preset values when available, otherwise fall back to user input
505
+ // If an unknown preset is requested without explicit permissions/categories,
506
+ // default to a safe read-only baseline rather than enabling everything.
507
+ const basePermissions = this.activePreset
508
+ ? this.activePreset.permissions.join(",")
509
+ : presetRequested && !permissionsInput
510
+ ? [ToolCategory.LIST, ToolCategory.READ, ToolCategory.UTILITY].join(",")
511
+ : "";
512
+ const baseCategories = this.activePreset
513
+ ? this.activePreset.categories.join(",")
514
+ : presetRequested && !categoriesInput
515
+ ? [
516
+ DocCategory.DATABASE_DISCOVERY,
517
+ DocCategory.CRUD_OPERATIONS,
518
+ DocCategory.CUSTOM_QUERIES,
519
+ DocCategory.UTILITIES,
520
+ ].join(",")
521
+ : "";
522
+ if (presetRequested && !this.activePreset) {
523
+ console.warn(`Preset '${presetInput}' not recognized. Falling back to safe read-only defaults.`);
524
+ }
525
+ const mergedPermissions = this.mergeConfigStrings(basePermissions, permissionsInput);
526
+ const mergedCategories = this.mergeConfigStrings(baseCategories, categoriesInput);
527
+ this.originalPermissionsString = mergedPermissions;
528
+ this.originalCategoriesString = mergedCategories;
529
+ this.useDualLayer = !!mergedCategories.trim();
530
+ const parsed = this.parseConfig(mergedPermissions, mergedCategories);
423
531
  this.enabledLegacyCategories = parsed.legacy;
424
532
  this.enabledDocCategories = parsed.doc;
425
533
  }
534
+ /**
535
+ * Normalize and merge preset + user-supplied configuration lists
536
+ */
537
+ mergeConfigStrings(base, override) {
538
+ const items = [...(base || "").split(","), ...(override || "").split(",")]
539
+ .map((c) => c.trim().toLowerCase())
540
+ .filter(Boolean);
541
+ return Array.from(new Set(items)).join(",");
542
+ }
543
+ /**
544
+ * Resolve a preset name to its configuration
545
+ */
546
+ resolvePreset(name) {
547
+ const normalized = normalizePresetName(name);
548
+ return normalized ? permissionPresets[normalized] : undefined;
549
+ }
426
550
  /**
427
551
  * Parse permissions and categories for dual-layer filtering
428
552
  * Layer 1 (permissions): Broad control using legacy categories
@@ -472,11 +596,37 @@ class FeatureConfig {
472
596
  /**
473
597
  * Update configuration at runtime
474
598
  */
475
- setConfig(permissionsStr, categoriesStr) {
476
- this.originalPermissionsString = permissionsStr;
477
- this.originalCategoriesString = categoriesStr || "";
478
- this.useDualLayer = !!(categoriesStr && categoriesStr.trim());
479
- const parsed = this.parseConfig(permissionsStr, categoriesStr || "");
599
+ setConfig(permissionsStr, categoriesStr, presetName) {
600
+ const presetRequested = presetName !== undefined ? !!presetName.trim() : !!this.presetName;
601
+ this.activePreset =
602
+ presetName === ""
603
+ ? undefined
604
+ : this.resolvePreset(presetName || this.presetName);
605
+ this.presetName = this.activePreset?.name;
606
+ const basePermissions = this.activePreset
607
+ ? this.activePreset.permissions.join(",")
608
+ : presetRequested && !permissionsStr
609
+ ? [ToolCategory.LIST, ToolCategory.READ, ToolCategory.UTILITY].join(",")
610
+ : "";
611
+ const baseCategories = this.activePreset
612
+ ? this.activePreset.categories.join(",")
613
+ : presetRequested && !categoriesStr
614
+ ? [
615
+ DocCategory.DATABASE_DISCOVERY,
616
+ DocCategory.CRUD_OPERATIONS,
617
+ DocCategory.CUSTOM_QUERIES,
618
+ DocCategory.UTILITIES,
619
+ ].join(",")
620
+ : "";
621
+ if (presetRequested && !this.activePreset) {
622
+ console.warn(`Preset '${presetName}' not recognized. Falling back to safe read-only defaults.`);
623
+ }
624
+ const mergedPermissions = this.mergeConfigStrings(basePermissions, permissionsStr);
625
+ const mergedCategories = this.mergeConfigStrings(baseCategories, categoriesStr || "");
626
+ this.originalPermissionsString = mergedPermissions;
627
+ this.originalCategoriesString = mergedCategories;
628
+ this.useDualLayer = !!(mergedCategories && mergedCategories.trim());
629
+ const parsed = this.parseConfig(mergedPermissions, mergedCategories || "");
480
630
  this.enabledLegacyCategories = parsed.legacy;
481
631
  this.enabledDocCategories = parsed.doc;
482
632
  }
@@ -602,6 +752,31 @@ class FeatureConfig {
602
752
  isUsingDualLayer() {
603
753
  return this.useDualLayer;
604
754
  }
755
+ /**
756
+ * Get the active preset (if any)
757
+ */
758
+ getActivePreset() {
759
+ return this.activePreset;
760
+ }
761
+ /**
762
+ * Snapshot of the resolved configuration for logging/telemetry
763
+ */
764
+ getConfigSnapshot() {
765
+ return {
766
+ preset: this.activePreset
767
+ ? {
768
+ name: this.activePreset.name,
769
+ description: this.activePreset.description,
770
+ }
771
+ : undefined,
772
+ permissions: this.originalPermissionsString || "all",
773
+ categories: this.originalCategoriesString ||
774
+ (this.useDualLayer ? "" : "derived from permissions"),
775
+ filteringMode: this.getFilteringMode(),
776
+ enabledLegacy: this.getEnabledCategories(),
777
+ enabledDoc: this.getEnabledDocCategories(),
778
+ };
779
+ }
605
780
  /**
606
781
  * Get filtering mode description
607
782
  */
package/dist/index.d.ts CHANGED
@@ -22,9 +22,10 @@ export declare class MySQLMCP {
22
22
  private migrationTools;
23
23
  private schemaVersioningTools;
24
24
  private performanceTools;
25
+ private analysisTools;
25
26
  private security;
26
27
  private featureConfig;
27
- constructor(permissionsConfig?: string, categoriesConfig?: string);
28
+ constructor(permissionsConfig?: string, categoriesConfig?: string, presetName?: string);
28
29
  private checkToolEnabled;
29
30
  listDatabases(): Promise<{
30
31
  status: string;
@@ -45,6 +46,20 @@ export declare class MySQLMCP {
45
46
  data?: import("./validation/schemas").ColumnInfo[];
46
47
  error?: string;
47
48
  }>;
49
+ getDatabaseSummary(params: {
50
+ database?: string;
51
+ }): Promise<{
52
+ status: string;
53
+ data?: string;
54
+ error?: string;
55
+ }>;
56
+ getSchemaERD(params: {
57
+ database?: string;
58
+ }): Promise<{
59
+ status: string;
60
+ data?: string;
61
+ error?: string;
62
+ }>;
48
63
  createRecord(params: {
49
64
  table_name: string;
50
65
  data: Record<string, any>;
@@ -94,11 +109,18 @@ export declare class MySQLMCP {
94
109
  runQuery(params: {
95
110
  query: string;
96
111
  params?: any[];
112
+ hints?: any;
113
+ useCache?: boolean;
114
+ dry_run?: boolean;
97
115
  }): Promise<{
98
116
  status: string;
99
117
  data?: any[];
100
118
  error?: string;
101
119
  optimizedQuery?: string;
120
+ dry_run?: boolean;
121
+ execution_plan?: any;
122
+ estimated_cost?: string;
123
+ message?: string;
102
124
  }>;
103
125
  executeSql(params: {
104
126
  query: string;
@@ -108,6 +130,25 @@ export declare class MySQLMCP {
108
130
  data?: any;
109
131
  error?: string;
110
132
  }>;
133
+ getColumnStatistics(params: {
134
+ table_name: string;
135
+ column_name: string;
136
+ database?: string;
137
+ }): Promise<{
138
+ status: string;
139
+ data?: any;
140
+ error?: string;
141
+ }>;
142
+ getSchemaRagContext(params: {
143
+ database?: string;
144
+ max_tables?: number;
145
+ max_columns?: number;
146
+ include_relationships?: boolean;
147
+ }): Promise<{
148
+ status: string;
149
+ data?: any;
150
+ error?: string;
151
+ }>;
111
152
  createTable(params: any): Promise<{
112
153
  status: string;
113
154
  data?: any;
@@ -541,8 +582,22 @@ export declare class MySQLMCP {
541
582
  getFeatureStatus(): {
542
583
  status: string;
543
584
  data: {
585
+ config: {
586
+ preset?: {
587
+ name: string;
588
+ description: string;
589
+ };
590
+ permissions: string;
591
+ categories: string;
592
+ filteringMode: string;
593
+ enabledLegacy: import("./config/featureConfig").ToolCategory[];
594
+ enabledDoc: import("./config/featureConfig").DocCategory[];
595
+ };
596
+ preset: import("./config/featureConfig").PermissionPreset | undefined;
597
+ filteringMode: string;
544
598
  enabledCategories: import("./config/featureConfig").ToolCategory[];
545
599
  categoryStatus: Record<import("./config/featureConfig").ToolCategory, boolean>;
600
+ docCategoryStatus: Record<import("./config/featureConfig").DocCategory, boolean>;
546
601
  };
547
602
  };
548
603
  /**
@@ -551,6 +606,20 @@ export declare class MySQLMCP {
551
606
  * @returns boolean indicating if the tool is enabled
552
607
  */
553
608
  isToolEnabled(toolName: string): boolean;
609
+ /**
610
+ * Expose resolved access profile (preset + merged permissions/categories)
611
+ */
612
+ getAccessProfile(): {
613
+ preset?: {
614
+ name: string;
615
+ description: string;
616
+ };
617
+ permissions: string;
618
+ categories: string;
619
+ filteringMode: string;
620
+ enabledLegacy: import("./config/featureConfig").ToolCategory[];
621
+ enabledDoc: import("./config/featureConfig").DocCategory[];
622
+ };
554
623
  /**
555
624
  * Bulk insert multiple records into the specified table
556
625
  */
package/dist/index.js CHANGED
@@ -23,6 +23,7 @@ const backupRestoreTools_1 = require("./tools/backupRestoreTools");
23
23
  const migrationTools_1 = require("./tools/migrationTools");
24
24
  const schemaVersioningTools_1 = require("./tools/schemaVersioningTools");
25
25
  const performanceTools_1 = require("./tools/performanceTools");
26
+ const analysisTools_1 = require("./tools/analysisTools");
26
27
  const securityLayer_1 = __importDefault(require("./security/securityLayer"));
27
28
  const connection_1 = __importDefault(require("./db/connection"));
28
29
  const featureConfig_1 = require("./config/featureConfig");
@@ -31,8 +32,8 @@ const featureConfig_1 = require("./config/featureConfig");
31
32
  * A secure interface for AI models to interact with MySQL databases
32
33
  */
33
34
  class MySQLMCP {
34
- constructor(permissionsConfig, categoriesConfig) {
35
- this.featureConfig = new featureConfig_1.FeatureConfig(permissionsConfig, categoriesConfig);
35
+ constructor(permissionsConfig, categoriesConfig, presetName) {
36
+ this.featureConfig = new featureConfig_1.FeatureConfig(permissionsConfig, categoriesConfig, presetName);
36
37
  this.security = new securityLayer_1.default(this.featureConfig);
37
38
  this.dbTools = new databaseTools_1.DatabaseTools();
38
39
  this.crudTools = new crudTools_1.CrudTools(this.security);
@@ -53,6 +54,7 @@ class MySQLMCP {
53
54
  this.migrationTools = new migrationTools_1.MigrationTools(this.security);
54
55
  this.schemaVersioningTools = new schemaVersioningTools_1.SchemaVersioningTools(this.security);
55
56
  this.performanceTools = new performanceTools_1.PerformanceTools(this.security);
57
+ this.analysisTools = new analysisTools_1.AnalysisTools(this.security);
56
58
  }
57
59
  // Helper method to check if tool is enabled
58
60
  checkToolEnabled(toolName) {
@@ -86,6 +88,20 @@ class MySQLMCP {
86
88
  }
87
89
  return await this.dbTools.readTableSchema(params);
88
90
  }
91
+ async getDatabaseSummary(params) {
92
+ const check = this.checkToolEnabled("getDatabaseSummary");
93
+ if (!check.enabled) {
94
+ return { status: "error", error: check.error };
95
+ }
96
+ return await this.dbTools.getDatabaseSummary(params);
97
+ }
98
+ async getSchemaERD(params) {
99
+ const check = this.checkToolEnabled("getSchemaERD");
100
+ if (!check.enabled) {
101
+ return { status: "error", error: check.error };
102
+ }
103
+ return await this.dbTools.getSchemaERD(params);
104
+ }
89
105
  // CRUD Tools
90
106
  async createRecord(params) {
91
107
  const check = this.checkToolEnabled("createRecord");
@@ -147,6 +163,21 @@ class MySQLMCP {
147
163
  }
148
164
  return await this.queryTools.executeSql(params);
149
165
  }
166
+ // Analysis Tools
167
+ async getColumnStatistics(params) {
168
+ const check = this.checkToolEnabled("getColumnStatistics");
169
+ if (!check.enabled) {
170
+ return { status: "error", error: check.error };
171
+ }
172
+ return await this.analysisTools.getColumnStatistics(params);
173
+ }
174
+ async getSchemaRagContext(params) {
175
+ const check = this.checkToolEnabled("getSchemaRagContext");
176
+ if (!check.enabled) {
177
+ return { status: "error", error: check.error };
178
+ }
179
+ return await this.analysisTools.getSchemaRagContext(params);
180
+ }
150
181
  // DDL Tools
151
182
  async createTable(params) {
152
183
  const check = this.checkToolEnabled("createTable");
@@ -496,11 +527,16 @@ class MySQLMCP {
496
527
  }
497
528
  // Get feature configuration status
498
529
  getFeatureStatus() {
530
+ const snapshot = this.featureConfig.getConfigSnapshot();
499
531
  return {
500
532
  status: "success",
501
533
  data: {
534
+ config: snapshot,
535
+ preset: this.featureConfig.getActivePreset(),
536
+ filteringMode: this.featureConfig.getFilteringMode(),
502
537
  enabledCategories: this.featureConfig.getEnabledCategories(),
503
538
  categoryStatus: this.featureConfig.getCategoryStatus(),
539
+ docCategoryStatus: this.featureConfig.getDocCategoryStatus(),
504
540
  },
505
541
  };
506
542
  }
@@ -512,6 +548,12 @@ class MySQLMCP {
512
548
  isToolEnabled(toolName) {
513
549
  return this.featureConfig.isToolEnabled(toolName);
514
550
  }
551
+ /**
552
+ * Expose resolved access profile (preset + merged permissions/categories)
553
+ */
554
+ getAccessProfile() {
555
+ return this.featureConfig.getConfigSnapshot();
556
+ }
515
557
  /**
516
558
  * Bulk insert multiple records into the specified table
517
559
  */
@@ -10,6 +10,7 @@ const index_js_2 = require("./index.js");
10
10
  // Layer 2 (Categories): MCP_CATEGORIES (optional, for fine-grained control)
11
11
  const permissions = process.env.MCP_PERMISSIONS || process.env.MCP_CONFIG || "";
12
12
  const categories = process.env.MCP_CATEGORIES || "";
13
+ const preset = process.env.MCP_PRESET || process.env.MCP_PERMISSION_PRESET || "";
13
14
  // Declare the MySQL MCP instance (will be initialized in main())
14
15
  let mysqlMCP;
15
16
  // Define all available tools with their schemas
@@ -35,6 +36,79 @@ const TOOLS = [
35
36
  },
36
37
  },
37
38
  },
39
+ {
40
+ name: "get_database_summary",
41
+ description: "Get a high-level summary of the database (tables, columns, row counts) optimized for AI context.",
42
+ inputSchema: {
43
+ type: "object",
44
+ properties: {
45
+ database: {
46
+ type: "string",
47
+ description: "Optional: specific database name",
48
+ },
49
+ },
50
+ },
51
+ },
52
+ {
53
+ name: "get_schema_erd",
54
+ description: "Get a Mermaid.js ER diagram string representing the database schema and relationships.",
55
+ inputSchema: {
56
+ type: "object",
57
+ properties: {
58
+ database: {
59
+ type: "string",
60
+ description: "Optional: specific database name",
61
+ },
62
+ },
63
+ },
64
+ },
65
+ {
66
+ name: "get_schema_rag_context",
67
+ description: "Return a compact schema-aware context pack (tables, PK/FK, columns, row estimates) optimized for RAG prompts.",
68
+ inputSchema: {
69
+ type: "object",
70
+ properties: {
71
+ database: {
72
+ type: "string",
73
+ description: "Optional: specific database name",
74
+ },
75
+ max_tables: {
76
+ type: "number",
77
+ description: "Optional: maximum number of tables to include (default 50, max 200)",
78
+ },
79
+ max_columns: {
80
+ type: "number",
81
+ description: "Optional: maximum number of columns per table (default 12, max 200)",
82
+ },
83
+ include_relationships: {
84
+ type: "boolean",
85
+ description: "Whether to include FK relationships section (default: true)",
86
+ },
87
+ },
88
+ },
89
+ },
90
+ {
91
+ name: "get_column_statistics",
92
+ description: "Get detailed statistics for a specific column (min, max, avg, distinct counts, nulls).",
93
+ inputSchema: {
94
+ type: "object",
95
+ properties: {
96
+ table_name: {
97
+ type: "string",
98
+ description: "Name of the table",
99
+ },
100
+ column_name: {
101
+ type: "string",
102
+ description: "Name of the column",
103
+ },
104
+ database: {
105
+ type: "string",
106
+ description: "Optional: specific database name",
107
+ },
108
+ },
109
+ required: ["table_name", "column_name"],
110
+ },
111
+ },
38
112
  {
39
113
  name: "read_table_schema",
40
114
  description: "Reads the schema of a specified table, including columns, types, keys, and indexes.",
@@ -375,6 +449,10 @@ const TOOLS = [
375
449
  type: "boolean",
376
450
  description: "Whether to use query result caching (default: true)",
377
451
  },
452
+ dry_run: {
453
+ type: "boolean",
454
+ description: "If true, returns query plan and estimated cost without executing (Safe Mode)",
455
+ },
378
456
  },
379
457
  required: ["query"],
380
458
  },
@@ -2687,7 +2765,7 @@ const TOOLS = [
2687
2765
  // Create the MCP server
2688
2766
  const server = new index_js_1.Server({
2689
2767
  name: "mysql-mcp-server",
2690
- version: "1.4.4",
2768
+ version: "1.12.0",
2691
2769
  }, {
2692
2770
  capabilities: {
2693
2771
  tools: {},
@@ -2721,6 +2799,18 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
2721
2799
  case "list_tables":
2722
2800
  result = await mysqlMCP.listTables((args || {}));
2723
2801
  break;
2802
+ case "get_database_summary":
2803
+ result = await mysqlMCP.getDatabaseSummary((args || {}));
2804
+ break;
2805
+ case "get_schema_erd":
2806
+ result = await mysqlMCP.getSchemaERD((args || {}));
2807
+ break;
2808
+ case "get_schema_rag_context":
2809
+ result = await mysqlMCP.getSchemaRagContext((args || {}));
2810
+ break;
2811
+ case "get_column_statistics":
2812
+ result = await mysqlMCP.getColumnStatistics((args || {}));
2813
+ break;
2724
2814
  case "read_table_schema":
2725
2815
  result = await mysqlMCP.readTableSchema((args || {}));
2726
2816
  break;
@@ -3173,20 +3263,20 @@ async function main() {
3173
3263
  await server.connect(transport);
3174
3264
  // Initialize the MySQL MCP instance AFTER transport is connected
3175
3265
  // This ensures the database connection pool is created when the server is ready
3176
- mysqlMCP = new index_js_2.MySQLMCP(permissions, categories);
3266
+ mysqlMCP = new index_js_2.MySQLMCP(permissions, categories, preset);
3177
3267
  // Log the effective filtering configuration to stderr
3178
- if (permissions && categories) {
3179
- console.error(`Active permissions (Layer 1): ${permissions}`);
3180
- console.error(`Active categories (Layer 2): ${categories}`);
3181
- console.error("Filtering mode: Dual-layer");
3268
+ const accessProfile = mysqlMCP.getAccessProfile();
3269
+ if (accessProfile.preset) {
3270
+ console.error(`Preset: ${accessProfile.preset.name} (${accessProfile.preset.description})`);
3182
3271
  }
3183
- else if (permissions) {
3184
- console.error(`Active permissions: ${permissions}`);
3185
- console.error("Filtering mode: Single-layer");
3272
+ else if (preset) {
3273
+ console.error(`Preset requested but not recognized: ${preset}`);
3186
3274
  }
3187
- else {
3188
- console.error("Active permissions: all (default)");
3275
+ console.error(`Permissions (resolved): ${accessProfile.permissions}`);
3276
+ if (accessProfile.categories) {
3277
+ console.error(`Categories (resolved): ${accessProfile.categories}`);
3189
3278
  }
3279
+ console.error(`Filtering mode: ${accessProfile.filteringMode}`);
3190
3280
  // Log to stderr (not stdout, which is used for MCP protocol)
3191
3281
  console.error("MySQL MCP Server running on stdio");
3192
3282
  }
@@ -0,0 +1,35 @@
1
+ import { SecurityLayer } from "../security/securityLayer";
2
+ export declare class AnalysisTools {
3
+ private db;
4
+ private security;
5
+ constructor(security: SecurityLayer);
6
+ /**
7
+ * Validate database access - ensures only the connected database can be accessed
8
+ */
9
+ private validateDatabaseAccess;
10
+ /**
11
+ * Get statistics for a specific column
12
+ */
13
+ getColumnStatistics(params: {
14
+ table_name: string;
15
+ column_name: string;
16
+ database?: string;
17
+ }): Promise<{
18
+ status: string;
19
+ data?: any;
20
+ error?: string;
21
+ }>;
22
+ /**
23
+ * Build a compact, schema-aware context pack for RAG (tables, PK/FK, columns, row estimates)
24
+ */
25
+ getSchemaRagContext(params?: {
26
+ database?: string;
27
+ max_tables?: number;
28
+ max_columns?: number;
29
+ include_relationships?: boolean;
30
+ }): Promise<{
31
+ status: string;
32
+ data?: any;
33
+ error?: string;
34
+ }>;
35
+ }