@apono-io/mcp-mysql 0.3.0 → 0.4.1
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 +13 -0
- package/dist/__tests__/db.test.js +1 -1
- package/dist/__tests__/db.test.js.map +1 -1
- package/dist/__tests__/timeout.test.d.ts +2 -0
- package/dist/__tests__/timeout.test.d.ts.map +1 -0
- package/dist/__tests__/timeout.test.js +118 -0
- package/dist/__tests__/timeout.test.js.map +1 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +30 -0
- package/dist/db.js.map +1 -1
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -51,3 +51,16 @@ driver, so a call holding several is rejected.
|
|
|
51
51
|
| `MYSQL_PORT` | MySQL server port (default: 3306) |
|
|
52
52
|
| `MYSQL_USER` | Database username |
|
|
53
53
|
| `MYSQL_PASSWORD` | Database password |
|
|
54
|
+
| `MYSQL_MAX_EXECUTION_TIME_MS` | How long a `SELECT` may run, in milliseconds (default: 600000, `0` keeps the server's own setting) |
|
|
55
|
+
|
|
56
|
+
## How long a statement may run
|
|
57
|
+
|
|
58
|
+
Every `SELECT` runs with `max_execution_time` applied, so one that outlives its
|
|
59
|
+
client still ends at the server rather than running to completion. A pooled
|
|
60
|
+
connection keeps whatever a caller `SET` on it, so the limit is reapplied on each
|
|
61
|
+
checkout.
|
|
62
|
+
|
|
63
|
+
MySQL has no general statement timeout. `max_execution_time` is the nearest
|
|
64
|
+
equivalent and covers read-only `SELECT` only, so a long write is not bounded by it.
|
|
65
|
+
A caller can also raise it for the duration of its own statement.
|
|
66
|
+
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.test.js","sourceRoot":"","sources":["../../src/__tests__/db.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAE9D,SAAS,QAAQ,CAAC,EAAU;IAC1B,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"db.test.js","sourceRoot":"","sources":["../../src/__tests__/db.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeout.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/timeout.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, afterAll, afterEach } from 'vitest';
|
|
2
|
+
import { connect, useTestCredentials } from './helpers/database.js';
|
|
3
|
+
const DATABASE = 'mcp_mysql_timeout_test';
|
|
4
|
+
describe('execution time limit', () => {
|
|
5
|
+
let admin;
|
|
6
|
+
let tools;
|
|
7
|
+
let closeAllPools;
|
|
8
|
+
async function execute(sql) {
|
|
9
|
+
return tools.get('execute')({ database: DATABASE, sql });
|
|
10
|
+
}
|
|
11
|
+
async function withLimit(value, run) {
|
|
12
|
+
if (value === undefined)
|
|
13
|
+
delete process.env.MYSQL_MAX_EXECUTION_TIME_MS;
|
|
14
|
+
else
|
|
15
|
+
process.env.MYSQL_MAX_EXECUTION_TIME_MS = value;
|
|
16
|
+
await closeAllPools();
|
|
17
|
+
try {
|
|
18
|
+
await run();
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
delete process.env.MYSQL_MAX_EXECUTION_TIME_MS;
|
|
22
|
+
await closeAllPools();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
beforeAll(async () => {
|
|
26
|
+
admin = await connect();
|
|
27
|
+
await admin.query(`DROP DATABASE IF EXISTS \`${DATABASE}\``);
|
|
28
|
+
await admin.query(`CREATE DATABASE \`${DATABASE}\``);
|
|
29
|
+
useTestCredentials();
|
|
30
|
+
const toolsModule = await import('../tools.js');
|
|
31
|
+
closeAllPools = (await import('../db.js')).closeAllPools;
|
|
32
|
+
tools = new Map();
|
|
33
|
+
toolsModule.registerTools({
|
|
34
|
+
tool: (name, _d, _s, handler) => {
|
|
35
|
+
tools.set(name, handler);
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
afterEach(async () => {
|
|
40
|
+
await closeAllPools?.();
|
|
41
|
+
});
|
|
42
|
+
afterAll(async () => {
|
|
43
|
+
await closeAllPools?.();
|
|
44
|
+
await admin?.query(`DROP DATABASE IF EXISTS \`${DATABASE}\``);
|
|
45
|
+
await admin?.end();
|
|
46
|
+
});
|
|
47
|
+
it('carries an execution time limit by default', async () => {
|
|
48
|
+
const result = await execute('SELECT @@max_execution_time AS limit_ms');
|
|
49
|
+
expect(result.isError).toBeUndefined();
|
|
50
|
+
expect(result.content[0].text).toContain('600000');
|
|
51
|
+
});
|
|
52
|
+
it('lets the server abort a SELECT that outruns the limit', async () => {
|
|
53
|
+
await withLimit('300', async () => {
|
|
54
|
+
const result = await execute('SELECT COUNT(*) FROM information_schema.columns a, information_schema.columns b, information_schema.columns c');
|
|
55
|
+
expect(result.isError).toBe(true);
|
|
56
|
+
expect(result.content[0].text).toMatch(/exceeded|timeout/i);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
it('cuts a sleeping SELECT short at the limit', async () => {
|
|
60
|
+
await withLimit('300', async () => {
|
|
61
|
+
const result = await execute('SELECT SLEEP(5) AS interrupted');
|
|
62
|
+
expect(result.content[0].text).toContain('1');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
it('aborts the SELECT without the client giving up first', async () => {
|
|
66
|
+
await withLimit('300', async () => {
|
|
67
|
+
const started = Date.now();
|
|
68
|
+
await execute('SELECT SLEEP(5)');
|
|
69
|
+
expect(Date.now() - started).toBeLessThan(4_000);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
it('takes a limit from the environment', async () => {
|
|
73
|
+
await withLimit('2000', async () => {
|
|
74
|
+
const result = await execute('SELECT @@max_execution_time AS limit_ms');
|
|
75
|
+
expect(result.content[0].text).toContain('2000');
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
it('leaves the server setting alone when the limit is zero', async () => {
|
|
79
|
+
await withLimit('0', async () => {
|
|
80
|
+
const result = await execute('SELECT @@max_execution_time AS limit_ms');
|
|
81
|
+
expect(result.content[0].text).toContain('"limit_ms": 0');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
it('refuses a value past what the server accepts, rather than breaking the pool', async () => {
|
|
85
|
+
await withLimit('9999999999', async () => {
|
|
86
|
+
const result = await execute('SELECT @@max_execution_time AS limit_ms');
|
|
87
|
+
expect(result.isError).toBeUndefined();
|
|
88
|
+
expect(result.content[0].text).toContain('600000');
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
it('falls back to the default when the variable is only whitespace', async () => {
|
|
92
|
+
await withLimit(' ', async () => {
|
|
93
|
+
const result = await execute('SELECT @@max_execution_time AS limit_ms');
|
|
94
|
+
expect(result.content[0].text).toContain('600000');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
it('restores the limit for the next call after a caller clears it', async () => {
|
|
98
|
+
await execute('SET SESSION max_execution_time = 0');
|
|
99
|
+
const result = await execute('SELECT @@max_execution_time AS limit_ms');
|
|
100
|
+
expect(result.content[0].text).toContain('600000');
|
|
101
|
+
});
|
|
102
|
+
it('still aborts a long SELECT after a caller clears the limit', async () => {
|
|
103
|
+
await withLimit('300', async () => {
|
|
104
|
+
await execute('SET SESSION max_execution_time = 0');
|
|
105
|
+
const started = Date.now();
|
|
106
|
+
const result = await execute('SELECT SLEEP(5) AS interrupted');
|
|
107
|
+
expect(Date.now() - started).toBeLessThan(4_000);
|
|
108
|
+
expect(result.content[0].text).toContain('1');
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
it('falls back to the default when the variable is not a limit', async () => {
|
|
112
|
+
await withLimit('soon', async () => {
|
|
113
|
+
const result = await execute('SELECT @@max_execution_time AS limit_ms');
|
|
114
|
+
expect(result.content[0].text).toContain('600000');
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
//# sourceMappingURL=timeout.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeout.test.js","sourceRoot":"","sources":["../../src/__tests__/timeout.test.ts"],"names":[],"mappings":"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"}
|
package/dist/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,gBAAgB,CAAC;AAoDnC,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,IAAI,CAQpD;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAOnD"}
|
package/dist/db.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import mysql from 'mysql2/promise';
|
|
2
2
|
import { log } from './logger.js';
|
|
3
3
|
const pools = new Map();
|
|
4
|
+
const DEFAULT_MAX_EXECUTION_TIME_MS = 10 * 60 * 1_000;
|
|
5
|
+
const MAX_EXECUTION_TIME_MS = 4_294_967_295;
|
|
6
|
+
function timeoutMillis(variable, fallback) {
|
|
7
|
+
const raw = process.env[variable];
|
|
8
|
+
if (raw === undefined)
|
|
9
|
+
return fallback;
|
|
10
|
+
const trimmed = raw.trim();
|
|
11
|
+
if (trimmed === '')
|
|
12
|
+
return fallback;
|
|
13
|
+
if (!/^\d+$/.test(trimmed) || Number(trimmed) > MAX_EXECUTION_TIME_MS) {
|
|
14
|
+
log(`Ignoring ${variable}=${raw}, expected whole milliseconds up to ${MAX_EXECUTION_TIME_MS}`);
|
|
15
|
+
return fallback;
|
|
16
|
+
}
|
|
17
|
+
return Number(trimmed);
|
|
18
|
+
}
|
|
4
19
|
function getPoolConfig() {
|
|
5
20
|
return {
|
|
6
21
|
host: process.env.MYSQL_HOST,
|
|
@@ -11,11 +26,26 @@ function getPoolConfig() {
|
|
|
11
26
|
connectionLimit: 5,
|
|
12
27
|
};
|
|
13
28
|
}
|
|
29
|
+
function reapplyOnAcquire(pool) {
|
|
30
|
+
const millis = timeoutMillis('MYSQL_MAX_EXECUTION_TIME_MS', DEFAULT_MAX_EXECUTION_TIME_MS);
|
|
31
|
+
if (millis === 0)
|
|
32
|
+
return;
|
|
33
|
+
let reported = false;
|
|
34
|
+
pool.on('acquire', (connection) => {
|
|
35
|
+
connection.query(`SET SESSION max_execution_time = ${millis}`, (err) => {
|
|
36
|
+
if (!err || reported)
|
|
37
|
+
return;
|
|
38
|
+
reported = true;
|
|
39
|
+
log('Failed to apply max_execution_time:', err);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
}
|
|
14
43
|
export function getPool(database) {
|
|
15
44
|
const existing = pools.get(database);
|
|
16
45
|
if (existing)
|
|
17
46
|
return existing;
|
|
18
47
|
const pool = mysql.createPool({ ...getPoolConfig(), database });
|
|
48
|
+
reapplyOnAcquire(pool);
|
|
19
49
|
pools.set(database, pool);
|
|
20
50
|
return pool;
|
|
21
51
|
}
|
package/dist/db.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,gBAAgB,CAAC;AACnC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;AAE5C,SAAS,aAAa;IACpB,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;QAC5B,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI;QAC1E,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;QAC5B,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;QACpC,kBAAkB,EAAE,IAAI;QACxB,eAAe,EAAE,CAAC;KACnB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,QAAgB;IACtC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,EAAE,GAAG,aAAa,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IAChE,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC1B,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACjC,KAAK,CAAC,KAAK,EAAE,CAAC;IACd,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACzE,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU;YAAE,GAAG,CAAC,uBAAuB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAChF,CAAC;AACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apono-io/mcp-mysql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Apono MCP server for MySQL databases with JIT credential support",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/apono-io/apono-mcp-servers.git",
|
|
8
|
+
"directory": "packages/mcp-mysql"
|
|
9
|
+
},
|
|
5
10
|
"type": "module",
|
|
6
11
|
"main": "dist/index.js",
|
|
7
12
|
"types": "dist/index.d.ts",
|