Skip to content

Commit 0fe17be

Browse files
neverinfamousTemp
andauthored
docs: expand Performance Tuning section, fix insecure temp file, update CI (#40)
Co-authored-by: Temp <mike@adamic.ai>
1 parent dce2f84 commit 0fe17be

File tree

6 files changed

+54
-7
lines changed

6 files changed

+54
-7
lines changed

.github/workflows/docker-publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ jobs:
311311
password: ${{ secrets.DOCKER_PASSWORD }}
312312
repository: ${{ env.IMAGE_NAME }}
313313
readme-filepath: ./DOCKER_README.md
314-
short-description: "MySQL MCP with 191 tools, OAuth 2.1, HTTP Streamable, Smart Tool Filtering & Connection Pooling."
314+
short-description: "MySQL MCP with 192 tools, OAuth 2.1, HTTP Streamable, Smart Tool Filtering & Connection Pooling."
315315

316316
- name: Deployment Summary
317317
if: github.ref == 'refs/heads/master'

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Security
11+
12+
- **`mysqlsh_run_script` Secure Temporary File Handling (CodeQL)** — Replaced insecure `os.tmpdir()` + manual filename pattern with `fs.mkdtemp()` for SQL script temp files. The previous approach created predictable files in the shared OS temp directory, flagged by CodeQL as `js/insecure-temporary-file`. Now creates a unique temporary directory with restrictive permissions via `mkdtemp`, writes the script inside it, and recursively removes the directory after execution.
13+
1014
## [2.2.0] - 2026-02-08
1115

1216
### Fixed

DOCKER_README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ Use the remote hostname directly:
236236
> [!IMPORTANT]
237237
> **AI IDEs like Cursor have tool limits (typically 40-50 tools).** With 192 tools available, you MUST use tool filtering to stay within your IDE's limits. We recommend `starter` (38 tools) as a starting point.
238238
239+
> **AntiGravity Users:** Server instructions are automatically sent to MCP clients during initialization. However, AntiGravity does not currently support MCP server instructions. For optimal usage in AntiGravity, manually provide the contents of [`src/constants/ServerInstructions.ts`](src/constants/ServerInstructions.ts) to the agent in your prompt or user rules.
240+
239241
### What Can You Filter?
240242

241243
The `--tool-filter` argument accepts **shortcuts**, **groups**, or **tool names** — mix and match freely:
@@ -497,13 +499,17 @@ For specialized setups, see these Wiki pages:
497499

498500
## ⚡ Performance Tuning
499501

502+
Schema metadata is cached to reduce repeated queries during tool/resource invocations.
503+
500504
| Variable | Default | Description |
501505
| ----------------------- | ------- | -------------------------------------------------- |
502506
| `METADATA_CACHE_TTL_MS` | `30000` | Cache TTL for schema metadata (milliseconds) |
503507
| `LOG_LEVEL` | `info` | Log verbosity: `debug`, `info`, `warning`, `error` |
504508

505509
> **Tip:** Lower `METADATA_CACHE_TTL_MS` for development (e.g., `5000`), or increase it for production with stable schemas (e.g., `300000` = 5 min).
506510
511+
> **Built-in payload optimization:** Many tools support optional `summary: true` for condensed responses and `limit` parameters to cap result sizes. These are particularly useful for cluster status, monitoring, and sys schema tools where full responses can be large. See [`ServerInstructions.ts`](https://github.com/neverinfamous/mysql-mcp/blob/master/src/constants/ServerInstructions.ts) for per-tool details.
512+
507513
---
508514

509515
### CLI Options

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@ Use the remote hostname directly:
238238
> [!IMPORTANT]
239239
> **AI IDEs like Cursor have tool limits (typically 40-50 tools).** With 192 tools available, you MUST use tool filtering to stay within your IDE's limits. We recommend `starter` (38 tools) as a starting point.
240240
241+
> **AntiGravity Users:** Server instructions are automatically sent to MCP clients during initialization. However, AntiGravity does not currently support MCP server instructions. For optimal usage in AntiGravity, manually provide the contents of [`src/constants/ServerInstructions.ts`](src/constants/ServerInstructions.ts) to the agent in your prompt or user rules.
242+
241243
### What Can You Filter?
242244

243245
The `--tool-filter` argument accepts **shortcuts**, **groups**, or **tool names** — mix and match freely:
@@ -515,13 +517,17 @@ For specialized setups, see these Wiki pages:
515517

516518
## ⚡ Performance Tuning
517519

520+
Schema metadata is cached to reduce repeated queries during tool/resource invocations.
521+
518522
| Variable | Default | Description |
519523
| ----------------------- | ------- | -------------------------------------------------- |
520524
| `METADATA_CACHE_TTL_MS` | `30000` | Cache TTL for schema metadata (milliseconds) |
521525
| `LOG_LEVEL` | `info` | Log verbosity: `debug`, `info`, `warning`, `error` |
522526

523527
> **Tip:** Lower `METADATA_CACHE_TTL_MS` for development (e.g., `5000`), or increase it for production with stable schemas (e.g., `300000` = 5 min).
524528
529+
> **Built-in payload optimization:** Many tools support optional `summary: true` for condensed responses and `limit` parameters to cap result sizes. These are particularly useful for cluster status, monitoring, and sys schema tools where full responses can be large. See [ServerInstructions.ts](src/constants/ServerInstructions.ts) for per-tool details.
530+
525531
---
526532

527533
### CLI Options

src/adapters/mysql/tools/shell/__tests__/restore.test.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
22
import * as child_process from "child_process";
3+
import * as fsModule from "fs";
34
import {
45
createMockMySQLAdapter,
56
createMockRequestContext,
@@ -13,6 +14,20 @@ vi.mock("child_process", () => ({
1314
spawn: vi.fn(),
1415
}));
1516

17+
vi.mock("fs", async () => {
18+
const actual =
19+
await vi.importActual<typeof import("fs")>("fs");
20+
return {
21+
...actual,
22+
promises: {
23+
...actual.promises,
24+
mkdtemp: vi.fn().mockResolvedValue("/tmp/mysqlsh_script_abc123"),
25+
writeFile: vi.fn().mockResolvedValue(undefined),
26+
rm: vi.fn().mockResolvedValue(undefined),
27+
},
28+
};
29+
});
30+
1631
describe("Shell Restore and Script Tools", () => {
1732
let mockAdapter: ReturnType<typeof createMockMySQLAdapter>;
1833
let mockContext: ReturnType<typeof createMockRequestContext>;
@@ -226,7 +241,7 @@ describe("Shell Restore and Script Tools", () => {
226241
expect(args).toContain("--py");
227242
});
228243

229-
it("should run sql script", async () => {
244+
it("should run sql script via secure temp file", async () => {
230245
setupMockSpawn("SQL output");
231246

232247
const tool = createShellRunScriptTool();
@@ -241,6 +256,20 @@ describe("Shell Restore and Script Tools", () => {
241256
expect(result.success).toBe(true);
242257
const args = mockSpawn.mock.calls[0][1];
243258
expect(args).toContain("--sql");
259+
expect(args).toContain("--file");
260+
261+
// Verify secure temp dir was created and cleaned up
262+
const fsp = fsModule.promises;
263+
expect(fsp.mkdtemp).toHaveBeenCalled();
264+
expect(fsp.writeFile).toHaveBeenCalledWith(
265+
expect.stringContaining("script.sql"),
266+
"SELECT 1",
267+
"utf8",
268+
);
269+
expect(fsp.rm).toHaveBeenCalledWith(
270+
"/tmp/mysqlsh_script_abc123",
271+
{ recursive: true },
272+
);
244273
});
245274
});
246275
});

src/adapters/mysql/tools/shell/restore.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,12 @@ export function createShellRunScriptTool(): ToolDefinition {
169169
// SQL scripts with comments or multi-line content break when passed via -e
170170
// Use --file approach for SQL to properly handle all syntax
171171
if (language === "sql") {
172-
const tempFile = join(
173-
tmpdir(),
174-
`mysqlsh_script_${Date.now()}_${Math.random().toString(36).slice(2)}.sql`,
172+
// Create a secure temp directory via mkdtemp (restrictive permissions,
173+
// unique path) to avoid CodeQL js/insecure-temporary-file alert.
174+
const tempDir = await fs.mkdtemp(
175+
join(tmpdir(), `mysqlsh_script_`),
175176
);
177+
const tempFile = join(tempDir, "script.sql");
176178
try {
177179
await fs.writeFile(tempFile, script, "utf8");
178180
const args = [
@@ -184,8 +186,8 @@ export function createShellRunScriptTool(): ToolDefinition {
184186
];
185187
result = await execMySQLShell(args, { timeout });
186188
} finally {
187-
// Cleanup temp file
188-
await fs.unlink(tempFile).catch(() => void 0);
189+
// Cleanup temp directory and its contents
190+
await fs.rm(tempDir, { recursive: true }).catch(() => void 0);
189191
}
190192
} else {
191193
// JS and Python work fine with -e

0 commit comments

Comments
 (0)