@berthojoris/mcp-mysql-server 1.0.1 → 1.1.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/README.md CHANGED
@@ -31,16 +31,7 @@ No installation needed! Use directly with npx:
31
31
  npx @berthojoris/mcp-mysql-server mysql://user:pass@localhost:3306/db "list,read,utility"
32
32
  ```
33
33
 
34
- ### Option 2: Clone and Build
35
-
36
- ```bash
37
- git clone https://github.com/berthojoris/mysql-mcp.git
38
- cd mysql-mcp
39
- npm install
40
- npm run build
41
- ```
42
-
43
- ### Option 3: Global Installation
34
+ ### Option 2: Global Installation
44
35
 
45
36
  ```bash
46
37
  npm install -g @berthojoris/mcp-mysql-server
@@ -934,48 +925,7 @@ curl http://localhost:3000/health
934
925
 
935
926
  ---
936
927
 
937
- ## 🚀 Publishing to npm
938
-
939
- To make your MCP server available to the world:
940
-
941
- ### 1. Update package.json
942
-
943
- ```json
944
- {
945
- "name": "@your-username/mcp-mysql",
946
- "author": "Your Name <your.email@example.com>",
947
- "repository": {
948
- "type": "git",
949
- "url": "https://github.com/berthojoris/mysql-mcp.git"
950
- }
951
- }
952
- ```
953
-
954
- ### 2. Build
955
-
956
- ```bash
957
- npm run build
958
- ```
959
-
960
- ### 3. Publish
961
-
962
- ```bash
963
- # Login to npm
964
- npm login
965
-
966
- # Publish (for scoped packages)
967
- npm publish --access public
968
- ```
969
-
970
- ### 4. Users Can Install
971
-
972
- ```bash
973
- npx @your-username/mcp-mysql mysql://user:pass@localhost:3306/db "list,read,utility"
974
- ```
975
-
976
- ---
977
-
978
- ## 🐛 Troubleshooting
928
+ ## Troubleshooting
979
929
 
980
930
  ### MCP Server Not Connecting
981
931
 
@@ -3,7 +3,8 @@ export declare class DatabaseTools {
3
3
  private db;
4
4
  constructor();
5
5
  /**
6
- * List all available databases
6
+ * List only the connected database (security restriction)
7
+ * This prevents access to other databases on the MySQL server
7
8
  */
8
9
  listDatabases(): Promise<{
9
10
  status: string;
@@ -6,20 +6,37 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.DatabaseTools = void 0;
7
7
  const connection_1 = __importDefault(require("../db/connection"));
8
8
  const schemas_1 = require("../validation/schemas");
9
+ const config_1 = require("../config/config");
9
10
  class DatabaseTools {
10
11
  constructor() {
11
12
  this.db = connection_1.default.getInstance();
12
13
  }
13
14
  /**
14
- * List all available databases
15
+ * List only the connected database (security restriction)
16
+ * This prevents access to other databases on the MySQL server
15
17
  */
16
18
  async listDatabases() {
17
19
  try {
18
- const results = await this.db.query('SHOW DATABASES');
19
- const databases = results.map(row => row.Database);
20
+ // Only return the database specified in the connection string
21
+ // This is a security measure to prevent access to other databases
22
+ if (!config_1.dbConfig.database) {
23
+ return {
24
+ status: 'error',
25
+ error: 'No database specified in connection string. Please specify a database name in your MySQL connection URL.'
26
+ };
27
+ }
28
+ // Verify the database exists and is accessible
29
+ const results = await this.db.query('SELECT DATABASE() as current_database');
30
+ const currentDatabase = results[0]?.current_database;
31
+ if (!currentDatabase) {
32
+ return {
33
+ status: 'error',
34
+ error: 'No database selected. Please ensure your connection string includes a valid database name.'
35
+ };
36
+ }
20
37
  return {
21
38
  status: 'success',
22
- data: databases
39
+ data: [currentDatabase]
23
40
  };
24
41
  }
25
42
  catch (error) {
@@ -41,8 +58,23 @@ class DatabaseTools {
41
58
  };
42
59
  }
43
60
  try {
61
+ // Security validation: if database is specified, ensure it matches the connected database
62
+ if (params.database) {
63
+ if (!config_1.dbConfig.database) {
64
+ return {
65
+ status: 'error',
66
+ error: 'No database specified in connection string. Cannot access other databases.'
67
+ };
68
+ }
69
+ if (params.database !== config_1.dbConfig.database) {
70
+ return {
71
+ status: 'error',
72
+ error: `Access denied. You can only access the connected database '${config_1.dbConfig.database}'. Requested database '${params.database}' is not allowed.`
73
+ };
74
+ }
75
+ }
44
76
  let query = 'SHOW TABLES';
45
- // If database is specified, use it
77
+ // If database is specified and validated, use it
46
78
  if (params.database) {
47
79
  query = `SHOW TABLES FROM \`${params.database}\``;
48
80
  }
@@ -3,6 +3,10 @@ export declare class StoredProcedureTools {
3
3
  private db;
4
4
  private security;
5
5
  constructor(security: SecurityLayer);
6
+ /**
7
+ * Validate database access - ensures only the connected database can be accessed
8
+ */
9
+ private validateDatabaseAccess;
6
10
  /**
7
11
  * List all stored procedures in the current database
8
12
  */
@@ -12,6 +12,38 @@ class StoredProcedureTools {
12
12
  this.db = connection_1.default.getInstance();
13
13
  this.security = security;
14
14
  }
15
+ /**
16
+ * Validate database access - ensures only the connected database can be accessed
17
+ */
18
+ validateDatabaseAccess(requestedDatabase) {
19
+ const connectedDatabase = config_1.dbConfig.database;
20
+ if (!connectedDatabase) {
21
+ return {
22
+ valid: false,
23
+ database: '',
24
+ error: 'No database specified in connection string. Cannot access any database.'
25
+ };
26
+ }
27
+ // If no database is requested, use the connected database
28
+ if (!requestedDatabase) {
29
+ return {
30
+ valid: true,
31
+ database: connectedDatabase
32
+ };
33
+ }
34
+ // If a specific database is requested, ensure it matches the connected database
35
+ if (requestedDatabase !== connectedDatabase) {
36
+ return {
37
+ valid: false,
38
+ database: '',
39
+ error: `Access denied. You can only access the connected database '${connectedDatabase}'. Requested database '${requestedDatabase}' is not allowed.`
40
+ };
41
+ }
42
+ return {
43
+ valid: true,
44
+ database: connectedDatabase
45
+ };
46
+ }
15
47
  /**
16
48
  * List all stored procedures in the current database
17
49
  */
@@ -24,13 +56,15 @@ class StoredProcedureTools {
24
56
  error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateListStoredProcedures.errors)
25
57
  };
26
58
  }
27
- const database = params.database || config_1.dbConfig.database;
28
- if (!database) {
59
+ // Validate database access
60
+ const dbValidation = this.validateDatabaseAccess(params.database);
61
+ if (!dbValidation.valid) {
29
62
  return {
30
63
  status: 'error',
31
- error: 'No database specified and no current database selected'
64
+ error: dbValidation.error
32
65
  };
33
66
  }
67
+ const database = dbValidation.database;
34
68
  const query = `
35
69
  SELECT
36
70
  ROUTINE_NAME as name,
@@ -72,14 +106,16 @@ class StoredProcedureTools {
72
106
  error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateGetStoredProcedureInfo.errors)
73
107
  };
74
108
  }
75
- const { procedure_name } = params;
76
- const database = params.database || config_1.dbConfig.database;
77
- if (!database) {
109
+ // Validate database access
110
+ const dbValidation = this.validateDatabaseAccess(params.database);
111
+ if (!dbValidation.valid) {
78
112
  return {
79
113
  status: 'error',
80
- error: 'No database specified and no current database selected'
114
+ error: dbValidation.error
81
115
  };
82
116
  }
117
+ const { procedure_name } = params;
118
+ const database = dbValidation.database;
83
119
  // Get procedure information
84
120
  const procedureQuery = `
85
121
  SELECT
@@ -148,14 +184,16 @@ class StoredProcedureTools {
148
184
  };
149
185
  }
150
186
  try {
151
- const { procedure_name, parameters = [] } = params;
152
- const database = params.database || config_1.dbConfig.database;
153
- if (!database) {
187
+ // Validate database access
188
+ const dbValidation = this.validateDatabaseAccess(params.database);
189
+ if (!dbValidation.valid) {
154
190
  return {
155
191
  status: 'error',
156
- error: 'No database specified and no current database selected'
192
+ error: dbValidation.error
157
193
  };
158
194
  }
195
+ const { procedure_name, parameters = [] } = params;
196
+ const database = dbValidation.database;
159
197
  // Validate procedure name
160
198
  const identifierValidation = this.security.validateIdentifier(procedure_name);
161
199
  if (!identifierValidation.valid) {
@@ -260,14 +298,16 @@ class StoredProcedureTools {
260
298
  };
261
299
  }
262
300
  try {
263
- const { procedure_name, parameters = [], body, comment } = params;
264
- const database = params.database || config_1.dbConfig.database;
265
- if (!database) {
301
+ // Validate database access
302
+ const dbValidation = this.validateDatabaseAccess(params.database);
303
+ if (!dbValidation.valid) {
266
304
  return {
267
305
  status: 'error',
268
- error: 'No database specified and no current database selected'
306
+ error: dbValidation.error
269
307
  };
270
308
  }
309
+ const { procedure_name, parameters = [], body, comment } = params;
310
+ const database = dbValidation.database;
271
311
  // Validate procedure name
272
312
  const identifierValidation = this.security.validateIdentifier(procedure_name);
273
313
  if (!identifierValidation.valid) {
@@ -327,14 +367,16 @@ class StoredProcedureTools {
327
367
  error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateDropStoredProcedure.errors)
328
368
  };
329
369
  }
330
- const { procedure_name, if_exists = false } = params;
331
- const database = params.database || config_1.dbConfig.database;
332
- if (!database) {
370
+ // Validate database access
371
+ const dbValidation = this.validateDatabaseAccess(params.database);
372
+ if (!dbValidation.valid) {
333
373
  return {
334
374
  status: 'error',
335
- error: 'No database specified and no current database selected'
375
+ error: dbValidation.error
336
376
  };
337
377
  }
378
+ const { procedure_name, if_exists = false } = params;
379
+ const database = dbValidation.database;
338
380
  // Validate procedure name
339
381
  const identifierValidation = this.security.validateIdentifier(procedure_name);
340
382
  if (!identifierValidation.valid) {
@@ -371,14 +413,16 @@ class StoredProcedureTools {
371
413
  error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateShowCreateProcedure.errors)
372
414
  };
373
415
  }
374
- const { procedure_name } = params;
375
- const database = params.database || config_1.dbConfig.database;
376
- if (!database) {
416
+ // Validate database access
417
+ const dbValidation = this.validateDatabaseAccess(params.database);
418
+ if (!dbValidation.valid) {
377
419
  return {
378
420
  status: 'error',
379
- error: 'No database specified and no current database selected'
421
+ error: dbValidation.error
380
422
  };
381
423
  }
424
+ const { procedure_name } = params;
425
+ const database = dbValidation.database;
382
426
  // Validate procedure name
383
427
  const identifierValidation = this.security.validateIdentifier(procedure_name);
384
428
  if (!identifierValidation.valid) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@berthojoris/mcp-mysql-server",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Model Context Protocol server for MySQL database integration with dynamic per-project permissions",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",