@berthojoris/mcp-mysql-server 1.10.0 → 1.10.2

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/bin/mcp-mysql.js CHANGED
@@ -6,25 +6,70 @@
6
6
  * It implements the Model Context Protocol using stdio transport
7
7
  */
8
8
 
9
- const path = require('path');
10
- const { spawn } = require('child_process');
11
- require('dotenv').config();
9
+ const path = require("path");
10
+ const { spawn } = require("child_process");
11
+ require("dotenv").config();
12
12
 
13
- // Get MySQL connection string and optional permissions from command line arguments
13
+ // Get MySQL connection string, permissions, and optional categories from command line arguments
14
14
  const mysqlUrl = process.argv[2];
15
- const permissions = process.argv[3]; // Optional: comma-separated list of permissions
15
+ const permissions = process.argv[3]; // Optional: comma-separated list of permissions (legacy categories)
16
+ const categories = process.argv[4]; // Optional: comma-separated list of documentation categories
16
17
 
17
18
  if (!mysqlUrl) {
18
- console.error('Error: MySQL connection URL is required');
19
- console.error('Usage: mcp-mysql mysql://user:password@host:port/dbname [permissions]');
20
- console.error('');
21
- console.error('Examples:');
22
- console.error(' mcp-mysql mysql://root:pass@localhost:3306/mydb');
23
- console.error(' mcp-mysql mysql://root:pass@localhost:3306/mydb "list,read,utility"');
24
- console.error(' mcp-mysql mysql://root:pass@localhost:3306/mydb "list,read,create,update,delete,utility"');
25
- console.error('');
26
- console.error('Available permissions: list, read, create, update, delete, execute, utility');
27
- console.error('If not specified, all permissions are enabled.');
19
+ console.error("Error: MySQL connection URL is required");
20
+ console.error(
21
+ "Usage: mcp-mysql mysql://user:password@host:port/dbname [permissions] [categories]",
22
+ );
23
+ console.error("");
24
+ console.error("Examples:");
25
+ console.error(" # All tools enabled (no filtering)");
26
+ console.error(" mcp-mysql mysql://root:pass@localhost:3306/mydb");
27
+ console.error("");
28
+ console.error(" # Permission-based filtering only (Layer 1)");
29
+ console.error(
30
+ ' mcp-mysql mysql://root:pass@localhost:3306/mydb "list,read,utility"',
31
+ );
32
+ console.error("");
33
+ console.error(
34
+ " # Dual-layer: Permissions + Categories (fine-grained control)",
35
+ );
36
+ console.error(
37
+ ' mcp-mysql mysql://root:pass@localhost:3306/mydb "list,read,utility" "database_discovery,performance_monitoring"',
38
+ );
39
+ console.error("");
40
+ console.error("Permissions (Layer 1 - Broad Control):");
41
+ console.error(
42
+ " list, read, create, update, delete, execute, ddl, utility, transaction, procedure",
43
+ );
44
+ console.error("");
45
+ console.error("Categories (Layer 2 - Fine-Grained Control, Optional):");
46
+ console.error(
47
+ " database_discovery, crud_operations, bulk_operations, custom_queries,",
48
+ );
49
+ console.error(
50
+ " schema_management, utilities, transaction_management, stored_procedures,",
51
+ );
52
+ console.error(
53
+ " views_management, triggers_management, functions_management, index_management,",
54
+ );
55
+ console.error(
56
+ " constraint_management, table_maintenance, server_management,",
57
+ );
58
+ console.error(
59
+ " performance_monitoring, cache_management, query_optimization,",
60
+ );
61
+ console.error(
62
+ " backup_restore, import_export, data_migration, schema_migrations",
63
+ );
64
+ console.error("");
65
+ console.error("Filtering Logic:");
66
+ console.error(
67
+ " - If only permissions: All tools within those permissions enabled",
68
+ );
69
+ console.error(
70
+ " - If permissions + categories: Only tools matching BOTH layers enabled",
71
+ );
72
+ console.error(" - If nothing specified: All 119 tools enabled");
28
73
  process.exit(1);
29
74
  }
30
75
 
@@ -33,22 +78,23 @@ let connectionConfig;
33
78
  let database;
34
79
  try {
35
80
  const url = new URL(mysqlUrl);
36
-
81
+
37
82
  // Remove leading slash from pathname and make database optional
38
- database = url.pathname.replace(/^\//, '') || null;
39
-
83
+ database = url.pathname.replace(/^\//, "") || null;
84
+
40
85
  // Extract username and password from auth
41
- const auth = url.username && url.password
42
- ? { user: url.username, password: url.password }
43
- : { user: url.username || 'root', password: url.password || '' };
44
-
86
+ const auth =
87
+ url.username && url.password
88
+ ? { user: url.username, password: url.password }
89
+ : { user: url.username || "root", password: url.password || "" };
90
+
45
91
  connectionConfig = {
46
92
  host: url.hostname,
47
93
  port: url.port || 3306,
48
94
  ...auth,
49
- ...(database ? { database } : {})
95
+ ...(database ? { database } : {}),
50
96
  };
51
-
97
+
52
98
  // Set environment variables for the server
53
99
  process.env.DB_HOST = connectionConfig.host;
54
100
  process.env.DB_PORT = connectionConfig.port;
@@ -57,23 +103,35 @@ try {
57
103
  if (database) {
58
104
  process.env.DB_NAME = database;
59
105
  }
60
-
61
106
  } catch (error) {
62
- console.error('Error parsing MySQL URL:', error.message);
63
- console.error('Usage: npx @berthojoris/mcp-mysql-server mysql://user:password@host:port/dbname');
107
+ console.error("Error parsing MySQL URL:", error.message);
108
+ console.error(
109
+ "Usage: npx @berthojoris/mcp-mysql-server mysql://user:password@host:port/dbname",
110
+ );
64
111
  process.exit(1);
65
112
  }
66
113
 
67
- const dbMessage = database
114
+ const dbMessage = database
68
115
  ? `${connectionConfig.host}:${connectionConfig.port}/${database}`
69
116
  : `${connectionConfig.host}:${connectionConfig.port} (no specific database selected)`;
70
117
 
71
- // Set permissions as environment variable if provided
118
+ // Set permissions/categories as environment variables if provided
72
119
  if (permissions) {
73
120
  process.env.MCP_PERMISSIONS = permissions;
74
- console.error(`Permissions: ${permissions}`);
75
- } else {
76
- console.error('Permissions: all (default)');
121
+ console.error(`Permissions (Layer 1): ${permissions}`);
122
+ }
123
+
124
+ if (categories) {
125
+ process.env.MCP_CATEGORIES = categories;
126
+ console.error(`Categories (Layer 2): ${categories}`);
127
+ }
128
+
129
+ if (!permissions && !categories) {
130
+ console.error("Access Control: All tools enabled (no filtering)");
131
+ } else if (permissions && !categories) {
132
+ console.error("Filtering Mode: Permission-based only");
133
+ } else if (permissions && categories) {
134
+ console.error("Filtering Mode: Dual-layer (Permissions + Categories)");
77
135
  }
78
136
 
79
137
  // Log to stderr (not stdout, which is used for MCP protocol)
@@ -82,41 +140,40 @@ console.error(`Starting MySQL MCP server with connection to ${dbMessage}`);
82
140
  // Run the MCP server
83
141
  try {
84
142
  // Determine the path to the compiled MCP server file
85
- const serverPath = path.resolve(__dirname, '../dist/mcp-server.js');
86
-
143
+ const serverPath = path.resolve(__dirname, "../dist/mcp-server.js");
144
+
87
145
  // Spawn the MCP server process with stdio transport
88
146
  // stdin/stdout are used for MCP protocol communication
89
147
  // stderr is used for logging
90
- const server = spawn('node', [serverPath], {
91
- stdio: ['inherit', 'inherit', 'inherit'],
92
- env: process.env
148
+ const server = spawn("node", [serverPath], {
149
+ stdio: ["inherit", "inherit", "inherit"],
150
+ env: process.env,
93
151
  });
94
-
152
+
95
153
  // Handle server process events
96
- server.on('error', (err) => {
97
- console.error('Failed to start MCP server:', err);
154
+ server.on("error", (err) => {
155
+ console.error("Failed to start MCP server:", err);
98
156
  process.exit(1);
99
157
  });
100
-
101
- server.on('exit', (code) => {
158
+
159
+ server.on("exit", (code) => {
102
160
  if (code !== 0 && code !== null) {
103
161
  console.error(`MCP server exited with code ${code}`);
104
162
  process.exit(code);
105
163
  }
106
164
  });
107
-
165
+
108
166
  // Handle termination signals
109
- process.on('SIGINT', () => {
110
- console.error('Shutting down MySQL MCP server...');
111
- server.kill('SIGINT');
167
+ process.on("SIGINT", () => {
168
+ console.error("Shutting down MySQL MCP server...");
169
+ server.kill("SIGINT");
112
170
  });
113
-
114
- process.on('SIGTERM', () => {
115
- console.error('Shutting down MySQL MCP server...');
116
- server.kill('SIGTERM');
171
+
172
+ process.on("SIGTERM", () => {
173
+ console.error("Shutting down MySQL MCP server...");
174
+ server.kill("SIGTERM");
117
175
  });
118
-
119
176
  } catch (error) {
120
- console.error('Error starting MCP server:', error.message);
177
+ console.error("Error starting MCP server:", error.message);
121
178
  process.exit(1);
122
- }
179
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Available MCP tool categories
2
+ * Available MCP tool categories (Legacy - for backward compatibility)
3
3
  */
4
4
  export declare enum ToolCategory {
5
5
  LIST = "list",// List databases, tables, etc.
@@ -14,26 +14,69 @@ export declare enum ToolCategory {
14
14
  PROCEDURE = "procedure"
15
15
  }
16
16
  /**
17
- * Map of tool names to their categories
17
+ * Documentation categories from README (21 categories)
18
+ * More intuitive and matches user mental model
19
+ */
20
+ export declare enum DocCategory {
21
+ DATABASE_DISCOVERY = "database_discovery",
22
+ CRUD_OPERATIONS = "crud_operations",
23
+ BULK_OPERATIONS = "bulk_operations",
24
+ CUSTOM_QUERIES = "custom_queries",
25
+ SCHEMA_MANAGEMENT = "schema_management",
26
+ UTILITIES = "utilities",
27
+ TRANSACTION_MANAGEMENT = "transaction_management",
28
+ STORED_PROCEDURES = "stored_procedures",
29
+ VIEWS_MANAGEMENT = "views_management",
30
+ TRIGGERS_MANAGEMENT = "triggers_management",
31
+ FUNCTIONS_MANAGEMENT = "functions_management",
32
+ INDEX_MANAGEMENT = "index_management",
33
+ CONSTRAINT_MANAGEMENT = "constraint_management",
34
+ TABLE_MAINTENANCE = "table_maintenance",
35
+ SERVER_MANAGEMENT = "server_management",
36
+ PERFORMANCE_MONITORING = "performance_monitoring",
37
+ CACHE_MANAGEMENT = "cache_management",
38
+ QUERY_OPTIMIZATION = "query_optimization",
39
+ BACKUP_RESTORE = "backup_restore",
40
+ IMPORT_EXPORT = "import_export",
41
+ DATA_MIGRATION = "data_migration",
42
+ SCHEMA_MIGRATIONS = "schema_migrations"
43
+ }
44
+ /**
45
+ * Map of tool names to their legacy categories
18
46
  */
19
47
  export declare const toolCategoryMap: Record<string, ToolCategory>;
48
+ /**
49
+ * Map of tool names to their documentation categories (New Enhanced System)
50
+ */
51
+ export declare const toolDocCategoryMap: Record<string, DocCategory>;
20
52
  /**
21
53
  * Class to manage feature configuration based on runtime or environment variables
54
+ * Supports dual-layer filtering:
55
+ * - Layer 1 (Permissions): Legacy categories (broad control)
56
+ * - Layer 2 (Categories): Documentation categories (fine-grained control, optional)
22
57
  */
23
58
  export declare class FeatureConfig {
24
- private enabledCategories;
25
- private originalConfigString;
26
- constructor(configStr?: string);
59
+ private enabledLegacyCategories;
60
+ private enabledDocCategories;
61
+ private originalPermissionsString;
62
+ private originalCategoriesString;
63
+ private useDualLayer;
64
+ constructor(permissionsStr?: string, categoriesStr?: string);
27
65
  /**
28
- * Parse MCP_CONFIG from provided string or environment variables
66
+ * Parse permissions and categories for dual-layer filtering
67
+ * Layer 1 (permissions): Broad control using legacy categories
68
+ * Layer 2 (categories): Fine-grained control using documentation categories (optional)
29
69
  */
30
70
  private parseConfig;
31
71
  /**
32
72
  * Update configuration at runtime
33
73
  */
34
- setConfig(configStr: string): void;
74
+ setConfig(permissionsStr: string, categoriesStr?: string): void;
35
75
  /**
36
76
  * Check if a specific tool is enabled
77
+ * Dual-layer logic:
78
+ * - Layer 1 (Permission): Tool must be allowed by its legacy category
79
+ * - Layer 2 (Category): If categories specified, tool must also be in allowed doc category
37
80
  */
38
81
  isToolEnabled(toolName: string): boolean;
39
82
  /**
@@ -41,16 +84,36 @@ export declare class FeatureConfig {
41
84
  */
42
85
  getPermissionError(toolName: string): string;
43
86
  /**
44
- * Check if a category is enabled
87
+ * Check if a legacy category is enabled
45
88
  */
46
89
  isCategoryEnabled(category: ToolCategory): boolean;
47
90
  /**
48
- * Get all enabled categories
91
+ * Check if a documentation category is enabled
92
+ */
93
+ isDocCategoryEnabled(category: DocCategory): boolean;
94
+ /**
95
+ * Get all enabled legacy categories
49
96
  */
50
97
  getEnabledCategories(): ToolCategory[];
98
+ /**
99
+ * Get all enabled documentation categories
100
+ */
101
+ getEnabledDocCategories(): DocCategory[];
51
102
  /**
52
103
  * Get all available categories with their status
53
104
  */
54
105
  getCategoryStatus(): Record<ToolCategory, boolean>;
106
+ /**
107
+ * Get all available documentation categories with their status
108
+ */
109
+ getDocCategoryStatus(): Record<DocCategory, boolean>;
110
+ /**
111
+ * Check if using dual-layer filtering mode
112
+ */
113
+ isUsingDualLayer(): boolean;
114
+ /**
115
+ * Get filtering mode description
116
+ */
117
+ getFilteringMode(): string;
55
118
  }
56
119
  export declare const featureConfig: FeatureConfig;