@berthojoris/mcp-mysql-server 1.18.0 → 1.20.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 +33 -0
- package/DOCUMENTATIONS.md +2 -0
- package/README.md +3 -11
- package/dist/db/connection.d.ts +37 -0
- package/dist/db/connection.js +198 -15
- package/dist/index.d.ts +1 -3
- package/dist/index.js +2 -2
- package/dist/security/securityLayer.d.ts +25 -1
- package/dist/security/securityLayer.js +162 -54
- package/dist/server.js +105 -43
- package/dist/tools/ddlTools.d.ts +7 -1
- package/dist/tools/ddlTools.js +57 -6
- package/dist/tools/storedProcedureTools.d.ts +4 -0
- package/dist/tools/storedProcedureTools.js +59 -3
- package/dist/tools/transactionTools.d.ts +3 -1
- package/dist/tools/transactionTools.js +21 -2
- package/dist/validation/inputValidation.d.ts +36 -0
- package/dist/validation/inputValidation.js +351 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,12 +5,45 @@ All notable changes to the MySQL MCP Server will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.20.0] - 2025-12-17
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Version increment for implemented features and improvements
|
|
12
|
+
|
|
8
13
|
## [Unreleased]
|
|
9
14
|
|
|
15
|
+
### Security
|
|
16
|
+
- Fixed critical SQL execution bypass in transactions by adding comprehensive security validation
|
|
17
|
+
- Enhanced stored procedure creation with body content validation and injection prevention
|
|
18
|
+
- Improved DDL operations with proper default value sanitization to prevent SQL injection
|
|
19
|
+
- Added transaction timeout mechanism (30 minutes) with automatic cleanup to prevent resource exhaustion
|
|
20
|
+
- Integrated security layer across all transaction operations for complete coverage
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- Updated TransactionTools to require SecurityLayer for proper validation
|
|
24
|
+
- Enhanced DdlTools with comprehensive input sanitization
|
|
25
|
+
- Improved database connection management with timeout and cleanup features
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- Resolved TypeScript compilation error in SecurityLayer access patterns
|
|
29
|
+
- Eliminated all security bypass paths through the system
|
|
30
|
+
|
|
10
31
|
### Removed
|
|
11
32
|
- Preset-based access control configuration: CLI `--preset` flag and `MCP_PRESET` / `MCP_PERMISSION_PRESET` environment variables. Use `MCP_PERMISSIONS` and optionally `MCP_CATEGORIES`.
|
|
12
33
|
- Global masking configuration via `MCP_MASKING_PROFILE`. If you need enforced masking for exports, use the `safe_export_table` macro's `masking_profile` argument.
|
|
13
34
|
|
|
35
|
+
|
|
36
|
+
## [1.18.2] - 2025-12-13
|
|
37
|
+
|
|
38
|
+
### Removed
|
|
39
|
+
- Removed outdated comparison docs under `docs/comparison` (and the related README section). The canonical documentation is `DOCUMENTATIONS.md`.
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
## [1.18.1] - 2025-12-13
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
- Updated documentation files with current datetime stamps
|
|
46
|
+
|
|
14
47
|
## [1.17.0] - 2025-12-12
|
|
15
48
|
|
|
16
49
|
### Added
|
package/DOCUMENTATIONS.md
CHANGED
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
**A production-ready Model Context Protocol (MCP) server for MySQL database integration with AI agents**
|
|
6
6
|
|
|
7
|
+
**Last Updated:** 2025-12-17 00:00:00
|
|
8
|
+
|
|
7
9
|
[](https://www.npmjs.com/package/@berthojoris/mysql-mcp)
|
|
8
10
|
[](https://www.npmjs.com/package/@berthojoris/mysql-mcp)
|
|
9
11
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -333,17 +335,7 @@ For comprehensive documentation, see **[DOCUMENTATIONS.md](DOCUMENTATIONS.md)**:
|
|
|
333
335
|
|
|
334
336
|
This MySQL MCP is a **powerful intermediary layer** between AI assistants and MySQL databases.
|
|
335
337
|
|
|
336
|
-
|
|
337
|
-
|------------------|---------------|
|
|
338
|
-
| Data Access & Querying | [docs/comparison/data-access-querying.md](docs/comparison/data-access-querying.md) |
|
|
339
|
-
| Data Analysis | [docs/comparison/data-analysis.md](docs/comparison/data-analysis.md) |
|
|
340
|
-
| Data Validation | [docs/comparison/data-validation.md](docs/comparison/data-validation.md) |
|
|
341
|
-
| Schema Inspection | [docs/comparison/schema-inspection.md](docs/comparison/schema-inspection.md) |
|
|
342
|
-
| Debugging & Diagnostics | [docs/comparison/debugging-diagnostics.md](docs/comparison/debugging-diagnostics.md) |
|
|
343
|
-
| Advanced Operations | [docs/comparison/advanced-operations.md](docs/comparison/advanced-operations.md) |
|
|
344
|
-
| Key Benefits | [docs/comparison/key-benefits.md](docs/comparison/key-benefits.md) |
|
|
345
|
-
| Example Workflows | [docs/comparison/example-workflows.md](docs/comparison/example-workflows.md) |
|
|
346
|
-
| When to Use | [docs/comparison/when-to-use.md](docs/comparison/when-to-use.md) |
|
|
338
|
+
For full feature coverage and usage examples, see **[DOCUMENTATIONS.md](DOCUMENTATIONS.md)**.
|
|
347
339
|
|
|
348
340
|
---
|
|
349
341
|
|
package/dist/db/connection.d.ts
CHANGED
|
@@ -4,6 +4,10 @@ declare class DatabaseConnection {
|
|
|
4
4
|
private pool;
|
|
5
5
|
private activeTransactions;
|
|
6
6
|
private queryCache;
|
|
7
|
+
private readonly TRANSACTION_TIMEOUT_MS;
|
|
8
|
+
private readonly TRANSACTION_MONITOR_INTERVAL_MS;
|
|
9
|
+
private readonly MAX_TRANSACTION_DURATION_MS;
|
|
10
|
+
private transactionMonitorInterval?;
|
|
7
11
|
private constructor();
|
|
8
12
|
static getInstance(): DatabaseConnection;
|
|
9
13
|
getConnection(): Promise<mysql.PoolConnection>;
|
|
@@ -19,11 +23,44 @@ declare class DatabaseConnection {
|
|
|
19
23
|
errorCode?: string;
|
|
20
24
|
}>;
|
|
21
25
|
closePool(): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Start transaction monitoring system
|
|
28
|
+
*/
|
|
29
|
+
private startTransactionMonitor;
|
|
30
|
+
/**
|
|
31
|
+
* Monitor all active transactions for timeout and security violations
|
|
32
|
+
*/
|
|
33
|
+
private monitorTransactions;
|
|
34
|
+
/**
|
|
35
|
+
* Detect suspicious transaction activity patterns
|
|
36
|
+
*/
|
|
37
|
+
private detectSuspiciousActivity;
|
|
38
|
+
/**
|
|
39
|
+
* Enhanced cleanup of expired transactions with security checks
|
|
40
|
+
*/
|
|
41
|
+
private cleanupExpiredTransactions;
|
|
42
|
+
/**
|
|
43
|
+
* Force rollback a transaction (used for timeout handling)
|
|
44
|
+
*/
|
|
45
|
+
private forceRollbackTransaction;
|
|
46
|
+
/**
|
|
47
|
+
* Reset transaction timeout (call this when there's activity)
|
|
48
|
+
*/
|
|
49
|
+
private resetTransactionTimeout;
|
|
22
50
|
beginTransaction(transactionId: string): Promise<void>;
|
|
23
51
|
commitTransaction(transactionId: string): Promise<void>;
|
|
24
52
|
rollbackTransaction(transactionId: string): Promise<void>;
|
|
25
53
|
getActiveTransactionIds(): string[];
|
|
26
54
|
hasActiveTransaction(transactionId: string): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Get transaction information for debugging/monitoring
|
|
57
|
+
*/
|
|
58
|
+
getTransactionInfo(transactionId: string): {
|
|
59
|
+
exists: boolean;
|
|
60
|
+
createdAt?: Date;
|
|
61
|
+
lastActivity?: Date;
|
|
62
|
+
ageMs?: number;
|
|
63
|
+
};
|
|
27
64
|
getQueryLogs(): import("./queryLogger").QueryLog[];
|
|
28
65
|
getLastQueryLog(): import("./queryLogger").QueryLog | undefined;
|
|
29
66
|
getFormattedQueryLogs(count?: number): string;
|
package/dist/db/connection.js
CHANGED
|
@@ -9,6 +9,9 @@ const queryLogger_1 = require("./queryLogger");
|
|
|
9
9
|
const queryCache_1 = require("../cache/queryCache");
|
|
10
10
|
class DatabaseConnection {
|
|
11
11
|
constructor() {
|
|
12
|
+
this.TRANSACTION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes default timeout
|
|
13
|
+
this.TRANSACTION_MONITOR_INTERVAL_MS = 60 * 1000; // 1 minute monitoring interval
|
|
14
|
+
this.MAX_TRANSACTION_DURATION_MS = 60 * 60 * 1000; // 1 hour maximum duration
|
|
12
15
|
this.pool = promise_1.default.createPool({
|
|
13
16
|
host: config_1.dbConfig.host,
|
|
14
17
|
port: config_1.dbConfig.port,
|
|
@@ -21,6 +24,12 @@ class DatabaseConnection {
|
|
|
21
24
|
});
|
|
22
25
|
this.activeTransactions = new Map();
|
|
23
26
|
this.queryCache = queryCache_1.QueryCache.getInstance();
|
|
27
|
+
// Start transaction monitoring
|
|
28
|
+
this.startTransactionMonitor();
|
|
29
|
+
// Set up periodic cleanup of expired transactions
|
|
30
|
+
setInterval(() => {
|
|
31
|
+
this.cleanupExpiredTransactions();
|
|
32
|
+
}, 5 * 60 * 1000); // Check every 5 minutes
|
|
24
33
|
}
|
|
25
34
|
static getInstance() {
|
|
26
35
|
if (!DatabaseConnection.instance) {
|
|
@@ -110,32 +119,179 @@ class DatabaseConnection {
|
|
|
110
119
|
throw new Error(`Failed to close connection pool: ${error}`);
|
|
111
120
|
}
|
|
112
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Start transaction monitoring system
|
|
124
|
+
*/
|
|
125
|
+
startTransactionMonitor() {
|
|
126
|
+
this.transactionMonitorInterval = setInterval(() => {
|
|
127
|
+
this.monitorTransactions();
|
|
128
|
+
}, this.TRANSACTION_MONITOR_INTERVAL_MS);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Monitor all active transactions for timeout and security violations
|
|
132
|
+
*/
|
|
133
|
+
monitorTransactions() {
|
|
134
|
+
const now = Date.now();
|
|
135
|
+
const transactionsToCleanup = [];
|
|
136
|
+
for (const [transactionId, transaction] of this.activeTransactions) {
|
|
137
|
+
const age = now - transaction.createdAt.getTime();
|
|
138
|
+
const inactivity = now - transaction.lastActivity.getTime();
|
|
139
|
+
// Check for maximum duration violation
|
|
140
|
+
if (age > this.MAX_TRANSACTION_DURATION_MS) {
|
|
141
|
+
console.warn(`Transaction ${transactionId} exceeded maximum duration, forcing rollback`);
|
|
142
|
+
transactionsToCleanup.push(transactionId);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
// Check for inactivity timeout (server-side verification)
|
|
146
|
+
if (inactivity > this.TRANSACTION_TIMEOUT_MS) {
|
|
147
|
+
console.warn(`Transaction ${transactionId} timed out due to inactivity, forcing rollback`);
|
|
148
|
+
transactionsToCleanup.push(transactionId);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
// Check for suspicious activity patterns
|
|
152
|
+
if (this.detectSuspiciousActivity(transaction)) {
|
|
153
|
+
console.warn(`Transaction ${transactionId} shows suspicious activity patterns, forcing rollback`);
|
|
154
|
+
transactionsToCleanup.push(transactionId);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Clean up flagged transactions
|
|
159
|
+
for (const transactionId of transactionsToCleanup) {
|
|
160
|
+
this.forceRollbackTransaction(transactionId, "Security violation or timeout");
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Detect suspicious transaction activity patterns
|
|
165
|
+
*/
|
|
166
|
+
detectSuspiciousActivity(transaction) {
|
|
167
|
+
const now = Date.now();
|
|
168
|
+
const age = now - transaction.createdAt.getTime();
|
|
169
|
+
// Very new transactions with excessive activity could indicate automated attacks
|
|
170
|
+
if (age < 60000 && transaction.queryCount > 100) { // More than 100 queries in first minute
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
// Transactions with extremely high query count could indicate resource exhaustion attacks
|
|
174
|
+
if (transaction.queryCount > 10000) {
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
// Check for rapid-fire queries (potential DoS)
|
|
178
|
+
if (transaction.lastQueryTime && (now - transaction.lastQueryTime.getTime()) < 10) { // Less than 10ms between queries
|
|
179
|
+
transaction.rapidQueryCount = (transaction.rapidQueryCount || 0) + 1;
|
|
180
|
+
if (transaction.rapidQueryCount > 50) { // More than 50 rapid queries
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Enhanced cleanup of expired transactions with security checks
|
|
188
|
+
*/
|
|
189
|
+
cleanupExpiredTransactions() {
|
|
190
|
+
const now = Date.now();
|
|
191
|
+
const transactionsToCleanup = [];
|
|
192
|
+
for (const [transactionId, transaction] of this.activeTransactions) {
|
|
193
|
+
const age = now - transaction.createdAt.getTime();
|
|
194
|
+
const inactivity = now - transaction.lastActivity.getTime();
|
|
195
|
+
// Multiple cleanup criteria for security
|
|
196
|
+
if (inactivity > this.TRANSACTION_TIMEOUT_MS ||
|
|
197
|
+
age > this.MAX_TRANSACTION_DURATION_MS ||
|
|
198
|
+
this.detectSuspiciousActivity(transaction)) {
|
|
199
|
+
transactionsToCleanup.push(transactionId);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
for (const transactionId of transactionsToCleanup) {
|
|
203
|
+
this.forceRollbackTransaction(transactionId, "Automatic cleanup");
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Force rollback a transaction (used for timeout handling)
|
|
208
|
+
*/
|
|
209
|
+
forceRollbackTransaction(transactionId, reason) {
|
|
210
|
+
const transaction = this.activeTransactions.get(transactionId);
|
|
211
|
+
if (!transaction)
|
|
212
|
+
return;
|
|
213
|
+
try {
|
|
214
|
+
// Clear timeout if exists
|
|
215
|
+
if (transaction.timeout) {
|
|
216
|
+
clearTimeout(transaction.timeout);
|
|
217
|
+
}
|
|
218
|
+
// Attempt to rollback
|
|
219
|
+
transaction.connection.rollback();
|
|
220
|
+
transaction.connection.release();
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
console.error(`Failed to rollback expired transaction ${transactionId}:`, error);
|
|
224
|
+
try {
|
|
225
|
+
// Force release connection even if rollback fails
|
|
226
|
+
transaction.connection.release();
|
|
227
|
+
}
|
|
228
|
+
catch (releaseError) {
|
|
229
|
+
console.error(`Failed to release connection for expired transaction ${transactionId}:`, releaseError);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
this.activeTransactions.delete(transactionId);
|
|
233
|
+
console.warn(`Transaction ${transactionId} force rolled back: ${reason}`);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Reset transaction timeout (call this when there's activity)
|
|
237
|
+
*/
|
|
238
|
+
resetTransactionTimeout(transactionId) {
|
|
239
|
+
const transaction = this.activeTransactions.get(transactionId);
|
|
240
|
+
if (!transaction)
|
|
241
|
+
return;
|
|
242
|
+
// Clear existing timeout
|
|
243
|
+
if (transaction.timeout) {
|
|
244
|
+
clearTimeout(transaction.timeout);
|
|
245
|
+
}
|
|
246
|
+
// Update last activity
|
|
247
|
+
transaction.lastActivity = new Date();
|
|
248
|
+
// Set new timeout
|
|
249
|
+
transaction.timeout = setTimeout(() => {
|
|
250
|
+
this.forceRollbackTransaction(transactionId, "Transaction timeout");
|
|
251
|
+
}, this.TRANSACTION_TIMEOUT_MS);
|
|
252
|
+
}
|
|
113
253
|
// Transaction Management Methods
|
|
114
254
|
async beginTransaction(transactionId) {
|
|
115
255
|
try {
|
|
116
256
|
const connection = await this.getConnection();
|
|
117
257
|
await connection.beginTransaction();
|
|
118
|
-
|
|
258
|
+
const now = new Date();
|
|
259
|
+
const timeout = setTimeout(() => {
|
|
260
|
+
this.forceRollbackTransaction(transactionId, "Transaction timeout");
|
|
261
|
+
}, this.TRANSACTION_TIMEOUT_MS);
|
|
262
|
+
this.activeTransactions.set(transactionId, {
|
|
263
|
+
connection,
|
|
264
|
+
createdAt: now,
|
|
265
|
+
lastActivity: now,
|
|
266
|
+
lastQueryTime: now,
|
|
267
|
+
timeout,
|
|
268
|
+
queryCount: 0,
|
|
269
|
+
rapidQueryCount: 0,
|
|
270
|
+
});
|
|
119
271
|
}
|
|
120
272
|
catch (error) {
|
|
121
273
|
throw new Error(`Failed to begin transaction: ${error}`);
|
|
122
274
|
}
|
|
123
275
|
}
|
|
124
276
|
async commitTransaction(transactionId) {
|
|
125
|
-
const
|
|
126
|
-
if (!
|
|
277
|
+
const transaction = this.activeTransactions.get(transactionId);
|
|
278
|
+
if (!transaction) {
|
|
127
279
|
throw new Error(`No active transaction found with ID: ${transactionId}`);
|
|
128
280
|
}
|
|
129
281
|
try {
|
|
130
|
-
|
|
131
|
-
|
|
282
|
+
// Clear timeout
|
|
283
|
+
if (transaction.timeout) {
|
|
284
|
+
clearTimeout(transaction.timeout);
|
|
285
|
+
}
|
|
286
|
+
await transaction.connection.commit();
|
|
287
|
+
transaction.connection.release();
|
|
132
288
|
this.activeTransactions.delete(transactionId);
|
|
133
289
|
}
|
|
134
290
|
catch (error) {
|
|
135
291
|
// If commit fails, rollback and release connection
|
|
136
292
|
try {
|
|
137
|
-
await connection.rollback();
|
|
138
|
-
connection.release();
|
|
293
|
+
await transaction.connection.rollback();
|
|
294
|
+
transaction.connection.release();
|
|
139
295
|
}
|
|
140
296
|
catch (rollbackError) {
|
|
141
297
|
console.error("Failed to rollback after commit error:", rollbackError);
|
|
@@ -145,17 +301,21 @@ class DatabaseConnection {
|
|
|
145
301
|
}
|
|
146
302
|
}
|
|
147
303
|
async rollbackTransaction(transactionId) {
|
|
148
|
-
const
|
|
149
|
-
if (!
|
|
304
|
+
const transaction = this.activeTransactions.get(transactionId);
|
|
305
|
+
if (!transaction) {
|
|
150
306
|
throw new Error(`No active transaction found with ID: ${transactionId}`);
|
|
151
307
|
}
|
|
152
308
|
try {
|
|
153
|
-
|
|
154
|
-
|
|
309
|
+
// Clear timeout
|
|
310
|
+
if (transaction.timeout) {
|
|
311
|
+
clearTimeout(transaction.timeout);
|
|
312
|
+
}
|
|
313
|
+
await transaction.connection.rollback();
|
|
314
|
+
transaction.connection.release();
|
|
155
315
|
this.activeTransactions.delete(transactionId);
|
|
156
316
|
}
|
|
157
317
|
catch (error) {
|
|
158
|
-
connection.release();
|
|
318
|
+
transaction.connection.release();
|
|
159
319
|
this.activeTransactions.delete(transactionId);
|
|
160
320
|
throw new Error(`Failed to rollback transaction: ${error}`);
|
|
161
321
|
}
|
|
@@ -166,6 +326,22 @@ class DatabaseConnection {
|
|
|
166
326
|
hasActiveTransaction(transactionId) {
|
|
167
327
|
return this.activeTransactions.has(transactionId);
|
|
168
328
|
}
|
|
329
|
+
/**
|
|
330
|
+
* Get transaction information for debugging/monitoring
|
|
331
|
+
*/
|
|
332
|
+
getTransactionInfo(transactionId) {
|
|
333
|
+
const transaction = this.activeTransactions.get(transactionId);
|
|
334
|
+
if (!transaction) {
|
|
335
|
+
return { exists: false };
|
|
336
|
+
}
|
|
337
|
+
const now = new Date();
|
|
338
|
+
return {
|
|
339
|
+
exists: true,
|
|
340
|
+
createdAt: transaction.createdAt,
|
|
341
|
+
lastActivity: transaction.lastActivity,
|
|
342
|
+
ageMs: now.getTime() - transaction.createdAt.getTime(),
|
|
343
|
+
};
|
|
344
|
+
}
|
|
169
345
|
getQueryLogs() {
|
|
170
346
|
return queryLogger_1.QueryLogger.getLogs();
|
|
171
347
|
}
|
|
@@ -206,15 +382,22 @@ class DatabaseConnection {
|
|
|
206
382
|
this.queryCache.resetStats();
|
|
207
383
|
}
|
|
208
384
|
async executeInTransaction(transactionId, sql, params) {
|
|
209
|
-
const
|
|
210
|
-
if (!
|
|
385
|
+
const transaction = this.activeTransactions.get(transactionId);
|
|
386
|
+
if (!transaction) {
|
|
211
387
|
throw new Error(`No active transaction found with ID: ${transactionId}`);
|
|
212
388
|
}
|
|
389
|
+
// Update query tracking before execution
|
|
390
|
+
const now = new Date();
|
|
391
|
+
transaction.lastQueryTime = now;
|
|
392
|
+
transaction.queryCount++;
|
|
213
393
|
const startTime = Date.now();
|
|
214
394
|
try {
|
|
215
|
-
const [results] = await connection.query(sql, params);
|
|
395
|
+
const [results] = await transaction.connection.query(sql, params);
|
|
216
396
|
const duration = Date.now() - startTime;
|
|
217
397
|
queryLogger_1.QueryLogger.log(sql, params, duration, "success");
|
|
398
|
+
// Reset timeout on successful activity and update last activity
|
|
399
|
+
this.resetTransactionTimeout(transactionId);
|
|
400
|
+
transaction.lastActivity = now;
|
|
218
401
|
return results;
|
|
219
402
|
}
|
|
220
403
|
catch (error) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1309,9 +1309,7 @@ export declare class MySQLMCP {
|
|
|
1309
1309
|
column_name: string;
|
|
1310
1310
|
pattern_type: string;
|
|
1311
1311
|
description: string;
|
|
1312
|
-
metrics
|
|
1313
|
-
* Get current schema version
|
|
1314
|
-
*/: Record<string, any>;
|
|
1312
|
+
metrics?: Record<string, any>;
|
|
1315
1313
|
recommendations?: string[];
|
|
1316
1314
|
}>;
|
|
1317
1315
|
summary: {
|
package/dist/index.js
CHANGED
|
@@ -51,8 +51,8 @@ class MySQLMCP {
|
|
|
51
51
|
this.crudTools = new crudTools_1.CrudTools(this.security);
|
|
52
52
|
this.queryTools = new queryTools_1.QueryTools(this.security);
|
|
53
53
|
this.utilityTools = new utilityTools_1.UtilityTools();
|
|
54
|
-
this.ddlTools = new ddlTools_1.DdlTools();
|
|
55
|
-
this.transactionTools = new transactionTools_1.TransactionTools();
|
|
54
|
+
this.ddlTools = new ddlTools_1.DdlTools(this.security);
|
|
55
|
+
this.transactionTools = new transactionTools_1.TransactionTools(this.security);
|
|
56
56
|
this.storedProcedureTools = new storedProcedureTools_1.StoredProcedureTools(this.security);
|
|
57
57
|
this.dataExportTools = new dataExportTools_1.DataExportTools(this.security);
|
|
58
58
|
this.viewTools = new viewTools_1.ViewTools(this.security);
|
|
@@ -8,6 +8,10 @@ export declare class SecurityLayer {
|
|
|
8
8
|
private featureConfig;
|
|
9
9
|
masking: MaskingLayer;
|
|
10
10
|
constructor(featureConfig?: FeatureConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Check if a specific tool is enabled in the feature configuration
|
|
13
|
+
*/
|
|
14
|
+
isToolEnabled(toolName: string): boolean;
|
|
11
15
|
/**
|
|
12
16
|
* Check if a query is a read-only information query (SHOW, DESCRIBE, EXPLAIN, etc.)
|
|
13
17
|
*/
|
|
@@ -27,7 +31,7 @@ export declare class SecurityLayer {
|
|
|
27
31
|
error?: string;
|
|
28
32
|
};
|
|
29
33
|
/**
|
|
30
|
-
*
|
|
34
|
+
* Enhanced SQL query validation for security issues
|
|
31
35
|
* @param query - The SQL query to validate
|
|
32
36
|
* @param bypassDangerousCheck - If true, skips dangerous keyword check (for users with 'execute' permission)
|
|
33
37
|
*/
|
|
@@ -36,6 +40,26 @@ export declare class SecurityLayer {
|
|
|
36
40
|
error?: string;
|
|
37
41
|
queryType?: string;
|
|
38
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* Enhanced comment detection to prevent bypass techniques
|
|
45
|
+
*/
|
|
46
|
+
private detectComments;
|
|
47
|
+
/**
|
|
48
|
+
* Enhanced multiple statement detection
|
|
49
|
+
*/
|
|
50
|
+
private detectMultipleStatements;
|
|
51
|
+
/**
|
|
52
|
+
* Enhanced query type detection
|
|
53
|
+
*/
|
|
54
|
+
private detectQueryType;
|
|
55
|
+
/**
|
|
56
|
+
* Enhanced dangerous keyword detection
|
|
57
|
+
*/
|
|
58
|
+
private detectDangerousKeywords;
|
|
59
|
+
/**
|
|
60
|
+
* Enhanced SELECT query validation
|
|
61
|
+
*/
|
|
62
|
+
private validateSelectQuery;
|
|
39
63
|
/**
|
|
40
64
|
* Validate parameter values to prevent injection
|
|
41
65
|
*/
|