@neverinfamous/mysql-mcp 2.2.0 → 2.3.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.
Files changed (213) hide show
  1. package/.github/workflows/docker-publish.yml +1 -2
  2. package/CHANGELOG.md +85 -0
  3. package/CODE_MODE.md +245 -0
  4. package/DOCKER_README.md +59 -36
  5. package/README.md +65 -42
  6. package/VERSION +1 -1
  7. package/dist/adapters/mysql/MySQLAdapter.d.ts +4 -0
  8. package/dist/adapters/mysql/MySQLAdapter.d.ts.map +1 -1
  9. package/dist/adapters/mysql/MySQLAdapter.js +9 -0
  10. package/dist/adapters/mysql/MySQLAdapter.js.map +1 -1
  11. package/dist/adapters/mysql/prompts/index.d.ts +8 -1
  12. package/dist/adapters/mysql/prompts/index.d.ts.map +1 -1
  13. package/dist/adapters/mysql/prompts/index.js +8 -1
  14. package/dist/adapters/mysql/prompts/index.js.map +1 -1
  15. package/dist/adapters/mysql/prompts/routerSetup.d.ts.map +1 -1
  16. package/dist/adapters/mysql/prompts/routerSetup.js +5 -0
  17. package/dist/adapters/mysql/prompts/routerSetup.js.map +1 -1
  18. package/dist/adapters/mysql/resources/capabilities.d.ts.map +1 -1
  19. package/dist/adapters/mysql/resources/capabilities.js +6 -5
  20. package/dist/adapters/mysql/resources/capabilities.js.map +1 -1
  21. package/dist/adapters/mysql/resources/index.d.ts +9 -1
  22. package/dist/adapters/mysql/resources/index.d.ts.map +1 -1
  23. package/dist/adapters/mysql/resources/index.js +9 -1
  24. package/dist/adapters/mysql/resources/index.js.map +1 -1
  25. package/dist/adapters/mysql/tools/admin/backup.d.ts.map +1 -1
  26. package/dist/adapters/mysql/tools/admin/backup.js +3 -3
  27. package/dist/adapters/mysql/tools/admin/backup.js.map +1 -1
  28. package/dist/adapters/mysql/tools/admin/maintenance.d.ts.map +1 -1
  29. package/dist/adapters/mysql/tools/admin/maintenance.js +5 -5
  30. package/dist/adapters/mysql/tools/admin/maintenance.js.map +1 -1
  31. package/dist/adapters/mysql/tools/cluster/innodb-cluster.d.ts.map +1 -1
  32. package/dist/adapters/mysql/tools/cluster/innodb-cluster.js +26 -5
  33. package/dist/adapters/mysql/tools/cluster/innodb-cluster.js.map +1 -1
  34. package/dist/adapters/mysql/tools/codemode/index.d.ts +38 -0
  35. package/dist/adapters/mysql/tools/codemode/index.d.ts.map +1 -0
  36. package/dist/adapters/mysql/tools/codemode/index.js +203 -0
  37. package/dist/adapters/mysql/tools/codemode/index.js.map +1 -0
  38. package/dist/adapters/mysql/tools/core.d.ts.map +1 -1
  39. package/dist/adapters/mysql/tools/core.js +32 -20
  40. package/dist/adapters/mysql/tools/core.js.map +1 -1
  41. package/dist/adapters/mysql/tools/events.js +18 -6
  42. package/dist/adapters/mysql/tools/events.js.map +1 -1
  43. package/dist/adapters/mysql/tools/json/core.d.ts.map +1 -1
  44. package/dist/adapters/mysql/tools/json/core.js +5 -5
  45. package/dist/adapters/mysql/tools/json/core.js.map +1 -1
  46. package/dist/adapters/mysql/tools/json/helpers.d.ts.map +1 -1
  47. package/dist/adapters/mysql/tools/json/helpers.js +9 -3
  48. package/dist/adapters/mysql/tools/json/helpers.js.map +1 -1
  49. package/dist/adapters/mysql/tools/partitioning.d.ts.map +1 -1
  50. package/dist/adapters/mysql/tools/partitioning.js +38 -6
  51. package/dist/adapters/mysql/tools/partitioning.js.map +1 -1
  52. package/dist/adapters/mysql/tools/performance/analysis.d.ts.map +1 -1
  53. package/dist/adapters/mysql/tools/performance/analysis.js +67 -20
  54. package/dist/adapters/mysql/tools/performance/analysis.js.map +1 -1
  55. package/dist/adapters/mysql/tools/performance/optimization.d.ts.map +1 -1
  56. package/dist/adapters/mysql/tools/performance/optimization.js +36 -6
  57. package/dist/adapters/mysql/tools/performance/optimization.js.map +1 -1
  58. package/dist/adapters/mysql/tools/security/data-protection.d.ts.map +1 -1
  59. package/dist/adapters/mysql/tools/security/data-protection.js +9 -4
  60. package/dist/adapters/mysql/tools/security/data-protection.js.map +1 -1
  61. package/dist/adapters/mysql/tools/shell/common.d.ts.map +1 -1
  62. package/dist/adapters/mysql/tools/shell/common.js +28 -2
  63. package/dist/adapters/mysql/tools/shell/common.js.map +1 -1
  64. package/dist/adapters/mysql/tools/shell/restore.d.ts.map +1 -1
  65. package/dist/adapters/mysql/tools/shell/restore.js +54 -4
  66. package/dist/adapters/mysql/tools/shell/restore.js.map +1 -1
  67. package/dist/adapters/mysql/tools/spatial/operations.d.ts.map +1 -1
  68. package/dist/adapters/mysql/tools/spatial/operations.js +10 -2
  69. package/dist/adapters/mysql/tools/spatial/operations.js.map +1 -1
  70. package/dist/adapters/mysql/tools/spatial/setup.d.ts.map +1 -1
  71. package/dist/adapters/mysql/tools/spatial/setup.js +18 -0
  72. package/dist/adapters/mysql/tools/spatial/setup.js.map +1 -1
  73. package/dist/adapters/mysql/tools/sysschema/resources.d.ts.map +1 -1
  74. package/dist/adapters/mysql/tools/sysschema/resources.js +5 -0
  75. package/dist/adapters/mysql/tools/sysschema/resources.js.map +1 -1
  76. package/dist/adapters/mysql/tools/text/fulltext.d.ts.map +1 -1
  77. package/dist/adapters/mysql/tools/text/fulltext.js +6 -4
  78. package/dist/adapters/mysql/tools/text/fulltext.js.map +1 -1
  79. package/dist/adapters/mysql/tools/text/processing.d.ts.map +1 -1
  80. package/dist/adapters/mysql/tools/text/processing.js +10 -45
  81. package/dist/adapters/mysql/tools/text/processing.js.map +1 -1
  82. package/dist/adapters/mysql/tools/transactions.d.ts.map +1 -1
  83. package/dist/adapters/mysql/tools/transactions.js +8 -8
  84. package/dist/adapters/mysql/tools/transactions.js.map +1 -1
  85. package/dist/adapters/mysql/types.d.ts +968 -78
  86. package/dist/adapters/mysql/types.d.ts.map +1 -1
  87. package/dist/adapters/mysql/types.js +1084 -78
  88. package/dist/adapters/mysql/types.js.map +1 -1
  89. package/dist/auth/scopes.d.ts.map +1 -1
  90. package/dist/auth/scopes.js +1 -0
  91. package/dist/auth/scopes.js.map +1 -1
  92. package/dist/cli/args.d.ts.map +1 -1
  93. package/dist/cli/args.js +12 -0
  94. package/dist/cli/args.js.map +1 -1
  95. package/dist/codemode/api.d.ts +69 -0
  96. package/dist/codemode/api.d.ts.map +1 -0
  97. package/dist/codemode/api.js +1035 -0
  98. package/dist/codemode/api.js.map +1 -0
  99. package/dist/codemode/index.d.ts +13 -0
  100. package/dist/codemode/index.d.ts.map +1 -0
  101. package/dist/codemode/index.js +17 -0
  102. package/dist/codemode/index.js.map +1 -0
  103. package/dist/codemode/sandbox-factory.d.ts +72 -0
  104. package/dist/codemode/sandbox-factory.d.ts.map +1 -0
  105. package/dist/codemode/sandbox-factory.js +88 -0
  106. package/dist/codemode/sandbox-factory.js.map +1 -0
  107. package/dist/codemode/sandbox.d.ts +96 -0
  108. package/dist/codemode/sandbox.d.ts.map +1 -0
  109. package/dist/codemode/sandbox.js +345 -0
  110. package/dist/codemode/sandbox.js.map +1 -0
  111. package/dist/codemode/security.d.ts +44 -0
  112. package/dist/codemode/security.d.ts.map +1 -0
  113. package/dist/codemode/security.js +149 -0
  114. package/dist/codemode/security.js.map +1 -0
  115. package/dist/codemode/types.d.ts +137 -0
  116. package/dist/codemode/types.d.ts.map +1 -0
  117. package/dist/codemode/types.js +46 -0
  118. package/dist/codemode/types.js.map +1 -0
  119. package/dist/codemode/worker-sandbox.d.ts +82 -0
  120. package/dist/codemode/worker-sandbox.d.ts.map +1 -0
  121. package/dist/codemode/worker-sandbox.js +244 -0
  122. package/dist/codemode/worker-sandbox.js.map +1 -0
  123. package/dist/codemode/worker-script.d.ts +8 -0
  124. package/dist/codemode/worker-script.d.ts.map +1 -0
  125. package/dist/codemode/worker-script.js +113 -0
  126. package/dist/codemode/worker-script.js.map +1 -0
  127. package/dist/constants/ServerInstructions.d.ts +1 -1
  128. package/dist/constants/ServerInstructions.d.ts.map +1 -1
  129. package/dist/constants/ServerInstructions.js +33 -9
  130. package/dist/constants/ServerInstructions.js.map +1 -1
  131. package/dist/filtering/ToolConstants.d.ts +11 -11
  132. package/dist/filtering/ToolConstants.d.ts.map +1 -1
  133. package/dist/filtering/ToolConstants.js +37 -19
  134. package/dist/filtering/ToolConstants.js.map +1 -1
  135. package/dist/filtering/ToolFilter.d.ts.map +1 -1
  136. package/dist/filtering/ToolFilter.js +12 -0
  137. package/dist/filtering/ToolFilter.js.map +1 -1
  138. package/dist/server/McpServer.js +1 -1
  139. package/dist/server/McpServer.js.map +1 -1
  140. package/dist/types/modules/server.d.ts +2 -0
  141. package/dist/types/modules/server.d.ts.map +1 -1
  142. package/dist/types/modules/tools.d.ts +1 -1
  143. package/dist/types/modules/tools.d.ts.map +1 -1
  144. package/dist/utils/logger.d.ts +1 -1
  145. package/dist/utils/logger.d.ts.map +1 -1
  146. package/dist/utils/logger.js.map +1 -1
  147. package/package.json +12 -7
  148. package/releases/v2.2.0-release-notes.md +18 -18
  149. package/releases/v2.3.0-release-notes.md +191 -0
  150. package/src/__tests__/perf.test.ts +12 -12
  151. package/src/adapters/mysql/MySQLAdapter.ts +10 -0
  152. package/src/adapters/mysql/__tests__/MySQLAdapter.test.ts +1 -1
  153. package/src/adapters/mysql/prompts/index.ts +8 -1
  154. package/src/adapters/mysql/prompts/routerSetup.ts +5 -0
  155. package/src/adapters/mysql/resources/__tests__/capabilities.test.ts +50 -1
  156. package/src/adapters/mysql/resources/capabilities.ts +6 -4
  157. package/src/adapters/mysql/resources/index.ts +9 -1
  158. package/src/adapters/mysql/tools/__tests__/core.test.ts +68 -0
  159. package/src/adapters/mysql/tools/__tests__/events.test.ts +56 -2
  160. package/src/adapters/mysql/tools/__tests__/json_core.test.ts +1 -1
  161. package/src/adapters/mysql/tools/__tests__/json_helpers.test.ts +46 -4
  162. package/src/adapters/mysql/tools/__tests__/replication.test.ts +144 -42
  163. package/src/adapters/mysql/tools/__tests__/security.test.ts +39 -0
  164. package/src/adapters/mysql/tools/__tests__/spatial.test.ts +39 -7
  165. package/src/adapters/mysql/tools/__tests__/spatial_handler.test.ts +35 -3
  166. package/src/adapters/mysql/tools/__tests__/transactions.test.ts +3 -5
  167. package/src/adapters/mysql/tools/admin/backup.ts +8 -3
  168. package/src/adapters/mysql/tools/admin/maintenance.ts +8 -4
  169. package/src/adapters/mysql/tools/cluster/__tests__/innodb-cluster.test.ts +35 -0
  170. package/src/adapters/mysql/tools/cluster/innodb-cluster.ts +26 -5
  171. package/src/adapters/mysql/tools/codemode/index.ts +249 -0
  172. package/src/adapters/mysql/tools/core.ts +44 -27
  173. package/src/adapters/mysql/tools/events.ts +23 -7
  174. package/src/adapters/mysql/tools/json/__tests__/helpers.test.ts +59 -14
  175. package/src/adapters/mysql/tools/json/core.ts +8 -4
  176. package/src/adapters/mysql/tools/json/helpers.ts +13 -3
  177. package/src/adapters/mysql/tools/partitioning.ts +53 -6
  178. package/src/adapters/mysql/tools/performance/__tests__/analysis.test.ts +227 -4
  179. package/src/adapters/mysql/tools/performance/__tests__/optimization.test.ts +35 -0
  180. package/src/adapters/mysql/tools/performance/analysis.ts +75 -21
  181. package/src/adapters/mysql/tools/performance/optimization.ts +44 -6
  182. package/src/adapters/mysql/tools/security/data-protection.ts +10 -4
  183. package/src/adapters/mysql/tools/shell/__tests__/common.test.ts +46 -0
  184. package/src/adapters/mysql/tools/shell/__tests__/restore.test.ts +28 -1
  185. package/src/adapters/mysql/tools/shell/common.ts +34 -2
  186. package/src/adapters/mysql/tools/shell/restore.ts +70 -7
  187. package/src/adapters/mysql/tools/spatial/__tests__/operations.test.ts +29 -0
  188. package/src/adapters/mysql/tools/spatial/operations.ts +13 -2
  189. package/src/adapters/mysql/tools/spatial/setup.ts +23 -0
  190. package/src/adapters/mysql/tools/sysschema/__tests__/resources.test.ts +21 -0
  191. package/src/adapters/mysql/tools/sysschema/resources.ts +5 -0
  192. package/src/adapters/mysql/tools/text/fulltext.ts +13 -5
  193. package/src/adapters/mysql/tools/text/processing.ts +20 -49
  194. package/src/adapters/mysql/tools/transactions.ts +11 -7
  195. package/src/adapters/mysql/types.ts +1241 -87
  196. package/src/auth/scopes.ts +1 -0
  197. package/src/cli/args.ts +14 -0
  198. package/src/codemode/api.ts +1224 -0
  199. package/src/codemode/index.ts +51 -0
  200. package/src/codemode/sandbox-factory.ts +146 -0
  201. package/src/codemode/sandbox.ts +450 -0
  202. package/src/codemode/security.ts +188 -0
  203. package/src/codemode/types.ts +194 -0
  204. package/src/codemode/worker-sandbox.ts +326 -0
  205. package/src/codemode/worker-script.ts +144 -0
  206. package/src/constants/ServerInstructions.ts +33 -9
  207. package/src/filtering/ToolConstants.ts +37 -19
  208. package/src/filtering/ToolFilter.ts +15 -0
  209. package/src/filtering/__tests__/ToolFilter.test.ts +65 -38
  210. package/src/server/McpServer.ts +1 -1
  211. package/src/types/modules/server.ts +3 -0
  212. package/src/types/modules/tools.ts +2 -1
  213. package/src/utils/logger.ts +2 -1
@@ -0,0 +1,144 @@
1
+ /**
2
+ * mysql-mcp - Code Mode Worker Script
3
+ *
4
+ * This script runs in a worker thread to execute user code in isolation.
5
+ * It uses Node.js vm module within the worker for additional sandboxing.
6
+ */
7
+
8
+ import { parentPort, workerData } from "node:worker_threads";
9
+ import vm from "node:vm";
10
+
11
+ interface WorkerData {
12
+ code: string;
13
+ apiBindings: Record<string, string[]>;
14
+ timeout: number;
15
+ }
16
+
17
+ interface WorkerResult {
18
+ success: boolean;
19
+ result?: unknown;
20
+ error?: string | undefined;
21
+ stack?: string | undefined;
22
+ }
23
+
24
+ /**
25
+ * Execute code in a sandboxed vm context within the worker
26
+ */
27
+ async function executeCode(): Promise<void> {
28
+ const { code, timeout } = workerData as WorkerData;
29
+
30
+ try {
31
+ // Create minimal sandbox context
32
+ const logBuffer: string[] = [];
33
+ const sandbox = {
34
+ console: {
35
+ log: (...args: unknown[]) => {
36
+ logBuffer.push(
37
+ args
38
+ .map((a) =>
39
+ typeof a === "object" && a !== null
40
+ ? JSON.stringify(a)
41
+ : String(a),
42
+ )
43
+ .join(" "),
44
+ );
45
+ },
46
+ warn: (...args: unknown[]) =>
47
+ logBuffer.push("[WARN] " + args.map((a) => String(a)).join(" ")),
48
+ error: (...args: unknown[]) =>
49
+ logBuffer.push("[ERROR] " + args.map((a) => String(a)).join(" ")),
50
+ info: (...args: unknown[]) =>
51
+ logBuffer.push("[INFO] " + args.map((a) => String(a)).join(" ")),
52
+ },
53
+ // Block dangerous globals
54
+ require: undefined,
55
+ process: undefined,
56
+ global: undefined,
57
+ globalThis: undefined,
58
+ __dirname: undefined,
59
+ __filename: undefined,
60
+ module: undefined,
61
+ exports: undefined,
62
+ // Safe built-ins
63
+ JSON,
64
+ Math,
65
+ Date,
66
+ Array,
67
+ Object,
68
+ String,
69
+ Number,
70
+ Boolean,
71
+ Map,
72
+ Set,
73
+ Promise,
74
+ Error,
75
+ TypeError,
76
+ RangeError,
77
+ SyntaxError,
78
+ // Disabled for security
79
+ setTimeout: undefined,
80
+ setInterval: undefined,
81
+ setImmediate: undefined,
82
+ // mysql API placeholder (populated by main thread via message passing)
83
+ mysql: {},
84
+ };
85
+
86
+ const context = vm.createContext(sandbox);
87
+
88
+ // Wrap code in async IIFE to support await
89
+ const wrappedCode = `
90
+ (async () => {
91
+ ${code}
92
+ })();
93
+ `;
94
+
95
+ // Compile and run with timeout
96
+ const script = new vm.Script(wrappedCode, {
97
+ filename: "worker-codemode-script.js",
98
+ });
99
+
100
+ const result = await (script.runInContext(context, {
101
+ timeout,
102
+ breakOnSigint: true,
103
+ }) as Promise<unknown>);
104
+
105
+ const response: WorkerResult = {
106
+ success: true,
107
+ result,
108
+ };
109
+
110
+ parentPort?.postMessage(response);
111
+ } catch (error) {
112
+ const errorMessage = error instanceof Error ? error.message : String(error);
113
+ const stack = error instanceof Error ? error.stack : undefined;
114
+
115
+ // Check for timeout
116
+ if (errorMessage.includes("Script execution timed out")) {
117
+ const response: WorkerResult = {
118
+ success: false,
119
+ error: `Execution timeout: exceeded ${String(timeout)}ms limit`,
120
+ stack,
121
+ };
122
+ parentPort?.postMessage(response);
123
+ return;
124
+ }
125
+
126
+ const response: WorkerResult = {
127
+ success: false,
128
+ error: errorMessage,
129
+ stack,
130
+ };
131
+
132
+ parentPort?.postMessage(response);
133
+ }
134
+ }
135
+
136
+ // Execute immediately
137
+ executeCode().catch((error: unknown) => {
138
+ const response: WorkerResult = {
139
+ success: false,
140
+ error: error instanceof Error ? error.message : String(error),
141
+ stack: error instanceof Error ? error.stack : undefined,
142
+ };
143
+ parentPort?.postMessage(response);
144
+ });
@@ -86,6 +86,7 @@ const BASE_INSTRUCTIONS = `# mysql-mcp Usage Instructions
86
86
 
87
87
  - **Prepared statements**: \`mysql_read_query\` and \`mysql_write_query\` support parameterized queries via the \`params\` array. Use \`?\` placeholders: \`query: "SELECT * FROM users WHERE id = ?", params: [123]\`.
88
88
  - **DDL statements**: DDL (e.g., \`CREATE TABLE\`, \`ALTER TABLE\`) is automatically handled via text protocol fallback in \`mysql_write_query\`.
89
+ - **Query error handling**: \`mysql_read_query\` and \`mysql_write_query\` return \`{ success: false, error }\` for all query errors (nonexistent table, syntax, permissions, etc.), instead of throwing raw errors.
89
90
  - **Boolean defaults**: \`mysql_create_table\` auto-converts boolean \`default: true\` to \`1\` and \`default: false\` to \`0\` for MySQL compatibility. Alternatively, use \`TINYINT(1)\` with numeric defaults directly.
90
91
  - **Existence checks**: \`mysql_describe_table\` and \`mysql_get_indexes\` return \`{ exists: false, table: "..." }\` gracefully when the table does not exist, avoiding raw SQL errors.
91
92
  - **Create/Drop safety**: \`mysql_create_table\` returns \`{ success: false, reason }\` when the table already exists (without \`ifNotExists\`). \`mysql_drop_table\` returns \`{ success: false, reason }\` when the table does not exist (without \`ifExists\`). With \`ifExists: true\`, dropping a nonexistent table returns \`{ success: true, skipped: true, reason: "Table did not exist" }\`.
@@ -115,8 +116,8 @@ const BASE_INSTRUCTIONS = `# mysql-mcp Usage Instructions
115
116
  - **Cluster status**: \`mysql_cluster_status\` returns cluster metadata. Use \`summary: true\` for condensed output without Router configuration schemas. Returns \`isInnoDBCluster: false\` if not in a cluster.
116
117
  - **Instance list**: \`mysql_cluster_instances\` lists all configured instances with their current member state and role.
117
118
  - **Topology**: \`mysql_cluster_topology\` returns a structured \`topology\` object (with \`primary\`, \`secondaries\`, \`recovering\`, \`offline\` arrays) and a \`visualization\` string grouping members by role.
118
- - **Router status**: \`mysql_cluster_router_status\` lists registered routers from cluster metadata. Use \`summary: true\` to return only essential router info without full configuration blobs.
119
- - **Switchover analysis**: \`mysql_cluster_switchover\` evaluates replication lag on secondaries and provides target recommendations. Returns \`canSwitchover: false\` with a \`warning\` field if no viable candidates exist.
119
+ - **Router status**: \`mysql_cluster_router_status\` lists registered routers from cluster metadata. Use \`summary: true\` to return routerId, routerName, address, version, lastCheckIn, roPort, rwPort, and localCluster. Each router includes \`isStale\` (true if lastCheckIn is null or >1 hour old). The response includes \`staleCount\` for quick filtering.
120
+ - **Switchover analysis**: \`mysql_cluster_switchover\` evaluates replication lag on secondaries and rates each as GOOD (fully synced), ACCEPTABLE (<100 pending), or NOT_RECOMMENDED (>=100 pending). Returns \`canSwitchover: false\` with a \`warning\` field if no viable candidates exist.
120
121
 
121
122
  ## MySQL Router Tools (\`mysql_router_*\`)
122
123
 
@@ -124,7 +125,7 @@ const BASE_INSTRUCTIONS = `# mysql-mcp Usage Instructions
124
125
  - **Self-signed certificates**: Set \`MYSQL_ROUTER_INSECURE=true\` to bypass TLS certificate verification for development/testing environments.
125
126
  - **Route names**: Use \`mysql_router_routes\` to list available routes (e.g., \`bootstrap_rw\`, \`bootstrap_ro\`).
126
127
  - **Metadata cache**: The \`metadataName\` parameter is typically \`bootstrap\` for bootstrapped routers.
127
- - **Connection pools**: Pool name is typically \`main\` for standard Router configurations.
128
+ - **Connection pools**: \`mysql_router_pool_status\` requires the \`[rest_connection_pool]\` REST plugin AND \`connection_sharing=1\` on routes. Without these, the endpoint returns 404. When enabled, pool name is \`main\`.
128
129
  - **Unavailability handling**: When Router REST API is unreachable, tools return \`{ available: false, reason: "..." }\` with descriptive error message instead of throwing.
129
130
 
130
131
  ## Partitioning Tools (\`mysql_partition_*\`, \`mysql_add_partition\`, \`mysql_drop_partition\`, \`mysql_reorganize_partition\`)
@@ -167,7 +168,7 @@ const BASE_INSTRUCTIONS = `# mysql-mcp Usage Instructions
167
168
 
168
169
  - **EXPLAIN formats**: \`mysql_explain\` supports JSON (default), TREE, and TRADITIONAL formats.
169
170
  - **EXPLAIN ANALYZE**: \`mysql_explain_analyze\` shows actual execution times (MySQL 8.0+). Only TREE format is supported; JSON format returns \`{ supported: false, reason }\`.
170
- - **Performance schema**: \`mysql_slow_queries\`, \`mysql_query_stats\`, and \`mysql_index_usage\` require \`performance_schema\` enabled. \`mysql_slow_queries\` and \`mysql_query_stats\` truncate query digests to 200 characters for payload efficiency.
171
+ - **Performance schema**: \`mysql_slow_queries\`, \`mysql_query_stats\`, and \`mysql_index_usage\` require \`performance_schema\` enabled. \`mysql_slow_queries\` and \`mysql_query_stats\` truncate query digests to 200 characters for payload efficiency. Timer values exceeding 24 hours are clamped to \`-1\` with \`overflow: true\` on the row (indicates a \`performance_schema\` counter overflow artifact, not a real value).
171
172
  - **Index usage**: \`mysql_index_usage\` filters to the current database by default. Use \`table\` parameter to filter further. Use \`limit\` (default: 10) to cap results. Returns \`{ exists: false, table }\` when the specified table does not exist.
172
173
  - **Table stats**: \`mysql_table_stats\` returns \`{ exists: false, table: "..." }\` gracefully when the table does not exist.
173
174
  - **Server-level tools**: \`mysql_slow_queries\`, \`mysql_query_stats\`, \`mysql_buffer_pool_stats\`, and \`mysql_thread_stats\` query server-level \`performance_schema\` metadata. They do not take a table parameter and return empty results when no data is available. No table existence checks apply.
@@ -234,8 +235,8 @@ const BASE_INSTRUCTIONS = `# mysql-mcp Usage Instructions
234
235
  - **I/O analysis**: \`mysql_sys_io_summary\` supports \`table\` (default), \`file\`, and \`global\` types for I/O breakdown (default \`limit: 20\`).
235
236
  - **Wait events**: \`mysql_sys_wait_summary\` supports \`global\` (default), \`by_host\`, \`by_user\`, and \`by_instance\` types for wait analysis. The \`by_instance\` type queries \`performance_schema\` directly (no sys view exists) and returns \`event\`, \`total\`, \`total_latency\`, and \`avg_latency\` columns with formatted latencies.
236
237
  - **Lock contention**: \`mysql_sys_innodb_lock_waits\` shows active lock waits. Returns \`hasContention: false\` when none.
237
- - **Memory usage**: \`mysql_sys_memory_summary\` returns \`globalMemory\` (by event type) and \`memoryByUser\` arrays. The \`limit\` parameter (default 10) applies to both arrays.
238
- - **Schema stats**: \`mysql_sys_schema_stats\` returns 3 arrays: \`tableStatistics\` (DML and I/O per table), \`indexStatistics\` (per-index usage), and \`autoIncrementStatus\` (usage ratios). Filter by \`schema\` (defaults to current database). Returns \`{ exists: false, schema }\` when the specified schema does not exist. The \`limit\` parameter (default 10) applies per array.
238
+ - **Memory usage**: \`mysql_sys_memory_summary\` returns \`globalMemory\` (by event type) and \`memoryByUser\` arrays with corresponding \`globalMemoryCount\` and \`memoryByUserCount\` fields. The \`limit\` parameter (default 10) applies to both arrays.
239
+ - **Schema stats**: \`mysql_sys_schema_stats\` returns 3 arrays: \`tableStatistics\` (DML and I/O per table), \`indexStatistics\` (per-index usage), and \`autoIncrementStatus\` (usage ratios), each with a corresponding count field (\`tableStatisticsCount\`, \`indexStatisticsCount\`, \`autoIncrementStatusCount\`). Filter by \`schema\` (defaults to current database). Returns \`{ exists: false, schema }\` when the specified schema does not exist. The \`limit\` parameter (default 10) applies per array.
239
240
 
240
241
  ## Stats Tools (\`mysql_stats_*\`)
241
242
 
@@ -254,7 +255,7 @@ const BASE_INSTRUCTIONS = `# mysql-mcp Usage Instructions
254
255
  - **SSL status**: \`mysql_security_ssl_status\` returns SSL/TLS connection status, cipher, certificate paths, and session statistics.
255
256
  - **Encryption status**: \`mysql_security_encryption_status\` checks TDE availability, keyring plugins, encrypted tablespaces, and encryption settings.
256
257
  - **Password validation**: \`mysql_security_password_validate\` uses MySQL \`validate_password\` component to check password strength (0-100 scale). Returns \`available: false\` if component not installed.
257
- - **Data masking**: \`mysql_security_mask_data\` masks sensitive data. Types: \`email\` (preserves domain), \`phone\` (shows last 4), \`ssn\` (shows last 4), \`credit_card\` (shows first/last 4), \`partial\` (uses \`keepFirst\`/\`keepLast\`). Credit card masking requires at least 8 digits; shorter values are fully masked with a \`warning\` field.
258
+ - **Data masking**: \`mysql_security_mask_data\` masks sensitive data. Types: \`email\` (preserves domain), \`phone\` (shows last 4), \`ssn\` (shows last 4), \`credit_card\` (shows first/last 4), \`partial\` (uses \`keepFirst\`/\`keepLast\`). Credit card masking requires more than 8 digits; values with 8 or fewer digits are fully masked with a \`warning\` field.
258
259
  - **User privileges**: \`mysql_security_user_privileges\` returns comprehensive user privilege report. Filter with \`user\` parameter to reduce payload. Returns \`{ exists: false, user }\` for nonexistent users (P154). Use \`summary: true\` for condensed output (privilege counts instead of raw GRANT strings). Summary mode caps \`globalPrivileges\` at 10 entries and includes \`totalGlobalPrivileges\` for the full count.
259
260
  - **Sensitive tables**: \`mysql_security_sensitive_tables\` identifies columns matching sensitive patterns (password, email, ssn, etc.). Use \`schema\` parameter to limit scope. Returns \`{ exists: false, schema }\` for nonexistent schemas (P154).
260
261
  - **Enterprise features**: \`mysql_security_audit\`, \`mysql_security_firewall_status\`, \`mysql_security_firewall_rules\` report availability and suggest installation for MySQL Enterprise Edition.
@@ -275,15 +276,38 @@ const BASE_INSTRUCTIONS = `# mysql-mcp Usage Instructions
275
276
 
276
277
  - **Prerequisites**: MySQL Shell must be installed and accessible via \`MYSQLSH_PATH\` environment variable or system PATH.
277
278
  - **Version check**: \`mysqlsh_version\` verifies MySQL Shell availability before running other shell tools.
278
- - **Upgrade checking**: \`mysqlsh_check_upgrade\` analyzes MySQL server for upgrade compatibility issues. Returns \`errorCount\`, \`warningCount\`, and \`noticeCount\` summary with full JSON report. **Note**: Returns \`{ success: false, error }\` when \`targetVersion\` is lower than the current server version (no downgrade analysis is possible).
279
+ - **Upgrade checking**: \`mysqlsh_check_upgrade\` analyzes MySQL server for upgrade compatibility issues. Returns \`errorCount\`, \`warningCount\`, and \`noticeCount\` summary with full JSON report. **Note**: Returns \`{ success: false, error }\` when MySQL Shell's version is lower than the current server version—Shell cannot analyze a server newer than itself. Also fails when \`targetVersion\` is lower than the current server version (no downgrade analysis).
279
280
  - **Script execution**: \`mysqlsh_run_script\` supports JavaScript (\`js\`), Python (\`py\`), and SQL (\`sql\`) languages with full access to MySQL Shell APIs. SQL scripts support comments and multi-statement syntax.
280
281
  - **Table export**: \`mysqlsh_export_table\` uses \`util.exportTable()\` for CSV or TSV export. Use \`where\` parameter for filtered exports. Returns structured error for privilege issues.
281
282
  - **Parallel import**: \`mysqlsh_import_table\` uses \`util.importTable()\` for high-performance parallel import. **Important**: For CSV files, explicitly set \`fieldsTerminatedBy: ","\` as the delimiter is not auto-detected. Requires \`local_infile\` enabled on server (use \`updateServerSettings: true\` to auto-enable). Use \`skipRows: 1\` to skip header row. The \`columns\` parameter maps input fields **by position** to the specified table columns. **Note**: On InnoDB Cluster (Group Replication), target tables must have a PRIMARY KEY.
282
283
  - **JSON import**: \`mysqlsh_import_json\` uses \`util.importJson()\` for document import. Supports both NDJSON (one JSON object per line) and multi-line JSON objects. **Does NOT support JSON arrays.** **Requires X Protocol (port 33060)**.
283
284
  - **Dump utilities**: \`mysqlsh_dump_instance\`, \`mysqlsh_dump_schemas\`, \`mysqlsh_dump_tables\` create compressed parallel dumps. Use \`dryRun: true\` to preview. All dump tools return structured error messages for privilege issues with actionable guidance.
284
- - **Load utility**: \`mysqlsh_load_dump\` restores dumps. Requires \`local_infile\` enabled or \`updateServerSettings: true\`. Returns \`{ success: false, error, hint }\` for duplicate object conflicts.
285
+ - **Load utility**: \`mysqlsh_load_dump\` restores dumps. Requires \`local_infile\` enabled or \`updateServerSettings: true\`. Use \`dryRun: true\` to preview what would be loaded without applying changes. Returns \`{ success: false, error, hint }\` for duplicate object conflicts.
285
286
  - **Privilege note**: Dump operations may require EVENT, TRIGGER, or ROUTINE privileges. Use \`ddlOnly: true\` (schemas) or \`all: false\` (tables) to skip restricted metadata.
286
287
  - **Error handling**: All shell tools return \`{ success: false, error }\` for operational failures instead of throwing raw exceptions. Privilege, local_infile, and X Protocol errors include a \`hint\` field with actionable remediation guidance.
288
+
289
+ ## Parameter Aliases
290
+
291
+ Many tools accept **alternative parameter names** (aliases) for commonly used fields. The server normalizes these automatically—use whichever feels most natural:
292
+
293
+ - **Table name**: \`table\`, \`tableName\`, or \`name\` — accepted by Core tools (\`mysql_describe_table\`, \`mysql_get_indexes\`, \`mysql_drop_table\`, \`mysql_create_index\`), Text tools (\`mysql_like_search\`, \`mysql_regexp_match\`, \`mysql_soundex\`, \`mysql_substring\`, \`mysql_concat\`, \`mysql_collation_convert\`), Backup tools (\`mysql_export_table\`, \`mysql_import_data\`), Partitioning tools (\`mysql_partition_info\`, \`mysql_add_partition\`, \`mysql_drop_partition\`, \`mysql_reorganize_partition\`), Performance tools (\`mysql_table_stats\`, \`mysql_index_usage\`), and Admin tools (\`mysql_optimize_table\`, \`mysql_analyze_table\`, \`mysql_check_table\`, \`mysql_flush_tables\`).
294
+ - **Query/SQL**: \`query\` or \`sql\` — accepted by \`mysql_read_query\`, \`mysql_write_query\`, \`mysql_explain\`, \`mysql_explain_analyze\`, \`mysql_query_rewrite\`, and \`mysql_optimizer_trace\`.
295
+ - **WHERE clause**: \`where\` or \`filter\` — accepted by \`mysql_export_table\` and Text tools (\`mysql_like_search\`, \`mysql_regexp_match\`, \`mysql_soundex\`, \`mysql_substring\`, \`mysql_concat\`, \`mysql_collation_convert\`).
296
+ - **Column name**: \`column\` or \`col\` — accepted by Text tools (\`mysql_like_search\`, \`mysql_regexp_match\`, \`mysql_soundex\`, \`mysql_substring\`, \`mysql_collation_convert\`).
297
+ - **Admin tables array**: Admin maintenance tools accept a singular \`table\` (or \`tableName\`/\`name\`) as an alias for the \`tables\` array parameter, automatically wrapping it in an array.
298
+
299
+ ## Code Mode (\`mysql_execute_code\`)
300
+
301
+ - **Purpose**: Execute JavaScript/TypeScript code in a sandboxed VM with access to all MySQL tools via the \`mysql.*\` API namespace. Ideal for multi-step workflows, data aggregation, conditional logic, and complex orchestrations that would otherwise require many sequential tool calls.
302
+ - **When to use**: Prefer Code Mode when a task requires 3+ sequential tool calls, conditional branching based on query results, data transformation between steps, or aggregation across multiple tables.
303
+ - **API namespace**: The \`mysql\` object exposes 24 groups matching the tool groups: \`mysql.core\`, \`mysql.json\`, \`mysql.transactions\`, \`mysql.text\`, \`mysql.fulltext\`, \`mysql.performance\`, \`mysql.optimization\`, \`mysql.admin\`, \`mysql.monitoring\`, \`mysql.backup\`, \`mysql.replication\`, \`mysql.partitioning\`, \`mysql.schema\`, \`mysql.shell\`, \`mysql.events\`, \`mysql.sysschema\`, \`mysql.stats\`, \`mysql.spatial\`, \`mysql.security\`, \`mysql.roles\`, \`mysql.docstore\`, \`mysql.cluster\`, \`mysql.proxysql\`, \`mysql.router\`.
304
+ - **Method naming**: Tool names map to methods by stripping the prefix: \`mysql_read_query\` → \`mysql.core.readQuery(sql)\`, \`mysql_json_extract\` → \`mysql.json.extract({...})\`, \`mysqlsh_version\` → \`mysql.shell.version()\`.
305
+ - **Positional shorthand**: Common tools accept positional arguments: \`mysql.core.readQuery("SELECT 1")\` instead of \`mysql.core.readQuery({ query: "SELECT 1" })\`.
306
+ - **Help**: Call \`mysql.help()\` for a full API overview, or \`mysql.<group>.help()\` for group-specific methods and examples.
307
+ - **Return value**: The last expression in the code block is returned as the result. Use \`return\` in async functions or let the final expression evaluate.
308
+ - **Security**: Code runs in an isolated VM sandbox. Blocked patterns include \`require\`, \`import\`, \`process\`, \`eval\`, \`Function\`, filesystem/network access. Rate-limited to prevent abuse.
309
+ - **Transaction cleanup**: Any transactions opened but not committed are automatically rolled back when execution completes.
310
+ - **Scope**: Requires \`admin\` scope.
287
311
  `;
288
312
 
289
313
  /**
@@ -253,6 +253,7 @@ export const TOOL_GROUPS: Record<ToolGroup, string[]> = {
253
253
  "mysql_doc_create_index",
254
254
  "mysql_doc_collection_info",
255
255
  ],
256
+ codemode: ["mysql_execute_code"],
256
257
  };
257
258
 
258
259
  /**
@@ -262,22 +263,22 @@ export const TOOL_GROUPS: Record<ToolGroup, string[]> = {
262
263
  * STRICT LIMIT: NO group may exceed 50 tools.
263
264
  *
264
265
  * Tool counts (verified):
265
- * starter: 38
266
- * essential: 15
267
- * dev-power: 46 (core:8 + schema:10 + performance:8 + stats:8 + fulltext:5 + transactions:7)
268
- * ai-data: 45 (core:8 + json:17 + docstore:9 + text:6 + fulltext:5)
269
- * ai-spatial: 43 (core:8 + spatial:12 + stats:8 + performance:8 + transactions:7)
270
- * dba-monitor: 35 (core:8 + monitoring:7 + performance:8 + sysschema:8 + optimization:4)
271
- * dba-manage: 33 (core:8 + admin:6 + backup:4 + replication:5 + partitioning:4 + events:6)
272
- * dba-secure: 32 (core:8 + security:9 + roles:8 + transactions:7)
273
- * base-core: 48 (core:8 + json:17 + transactions:7 + text:6 + schema:10)
274
- * base-advanced: 40 (docstore:9 + spatial:12 + stats:8 + fulltext:5 + events:6)
275
- * ecosystem: 41 (router:9 + proxysql:12 + shell:10 + cluster:10)
266
+ * starter: 39 (core:8 + json:17 + transactions:7 + text:6 + codemode:1)
267
+ * essential: 16 (core:8 + transactions:7 + codemode:1)
268
+ * dev-power: 47 (core:8 + schema:10 + performance:8 + stats:8 + fulltext:5 + transactions:7 + codemode:1)
269
+ * ai-data: 46 (core:8 + json:17 + docstore:9 + text:6 + fulltext:5 + codemode:1)
270
+ * ai-spatial: 44 (core:8 + spatial:12 + stats:8 + performance:8 + transactions:7 + codemode:1)
271
+ * dba-monitor: 36 (core:8 + monitoring:7 + performance:8 + sysschema:8 + optimization:4 + codemode:1)
272
+ * dba-manage: 34 (core:8 + admin:6 + backup:4 + replication:5 + partitioning:4 + events:6 + codemode:1)
273
+ * dba-secure: 33 (core:8 + security:9 + roles:8 + transactions:7 + codemode:1)
274
+ * base-core: 49 (core:8 + json:17 + transactions:7 + text:6 + schema:10 + codemode:1)
275
+ * base-advanced: 41 (docstore:9 + spatial:12 + stats:8 + fulltext:5 + events:6 + codemode:1)
276
+ * ecosystem: 42 (router:9 + proxysql:12 + shell:10 + cluster:10 + codemode:1)
276
277
  */
277
278
  export const META_GROUPS: Record<MetaGroup, ToolGroup[]> = {
278
279
  // 1. General Use
279
- starter: ["core", "json", "transactions", "text"],
280
- essential: ["core", "transactions"],
280
+ starter: ["core", "json", "transactions", "text", "codemode"],
281
+ essential: ["core", "transactions", "codemode"],
281
282
  "dev-power": [
282
283
  "core",
283
284
  "schema",
@@ -285,11 +286,19 @@ export const META_GROUPS: Record<MetaGroup, ToolGroup[]> = {
285
286
  "stats",
286
287
  "fulltext",
287
288
  "transactions",
289
+ "codemode",
288
290
  ],
289
291
 
290
292
  // 2. AI Workloads
291
- "ai-data": ["core", "json", "docstore", "text", "fulltext"],
292
- "ai-spatial": ["core", "spatial", "stats", "performance", "transactions"],
293
+ "ai-data": ["core", "json", "docstore", "text", "fulltext", "codemode"],
294
+ "ai-spatial": [
295
+ "core",
296
+ "spatial",
297
+ "stats",
298
+ "performance",
299
+ "transactions",
300
+ "codemode",
301
+ ],
293
302
 
294
303
  // 3. DBA Workloads
295
304
  "dba-monitor": [
@@ -298,6 +307,7 @@ export const META_GROUPS: Record<MetaGroup, ToolGroup[]> = {
298
307
  "performance",
299
308
  "sysschema",
300
309
  "optimization",
310
+ "codemode",
301
311
  ],
302
312
  "dba-manage": [
303
313
  "core",
@@ -306,13 +316,21 @@ export const META_GROUPS: Record<MetaGroup, ToolGroup[]> = {
306
316
  "replication",
307
317
  "partitioning",
308
318
  "events",
319
+ "codemode",
309
320
  ],
310
- "dba-secure": ["core", "security", "roles", "transactions"],
321
+ "dba-secure": ["core", "security", "roles", "transactions", "codemode"],
311
322
 
312
323
  // 4. Base Blocks (Building Blocks)
313
- "base-core": ["core", "json", "transactions", "text", "schema"],
314
- "base-advanced": ["docstore", "spatial", "stats", "fulltext", "events"],
324
+ "base-core": ["core", "json", "transactions", "text", "schema", "codemode"],
325
+ "base-advanced": [
326
+ "docstore",
327
+ "spatial",
328
+ "stats",
329
+ "fulltext",
330
+ "events",
331
+ "codemode",
332
+ ],
315
333
 
316
334
  // 5. Ecosystem
317
- ecosystem: ["router", "proxysql", "shell", "cluster"],
335
+ ecosystem: ["router", "proxysql", "shell", "cluster", "codemode"],
318
336
  };
@@ -230,6 +230,21 @@ export function parseToolFilter(
230
230
  }
231
231
  }
232
232
 
233
+ // Auto-inject codemode tools (mysql_execute_code) in whitelist mode only.
234
+ // In blacklist mode (starts with -), codemode is already in the initial set
235
+ // and user exclusions are respected. In whitelist mode, raw group filters
236
+ // (e.g., "core") would otherwise miss codemode — every meta-group includes it.
237
+ if (!startsWithExclude && enabledTools.size > 0) {
238
+ const codemodeExplicitlyExcluded = parts.some(
239
+ (p) => p === "-codemode" || p === "-mysql_execute_code",
240
+ );
241
+ if (!codemodeExplicitlyExcluded) {
242
+ for (const tool of TOOL_GROUPS.codemode) {
243
+ enabledTools.add(tool);
244
+ }
245
+ }
246
+ }
247
+
233
248
  return {
234
249
  raw: filterString,
235
250
  rules,
@@ -23,7 +23,7 @@ import {
23
23
  import type { ToolDefinition } from "../../types/index.js";
24
24
 
25
25
  describe("TOOL_GROUPS", () => {
26
- it("should contain all 24 tool groups", () => {
26
+ it("should contain all 25 tool groups", () => {
27
27
  const expectedGroups = [
28
28
  "core",
29
29
  "json",
@@ -49,9 +49,10 @@ describe("TOOL_GROUPS", () => {
49
49
  "cluster",
50
50
  "roles",
51
51
  "docstore",
52
+ "codemode",
52
53
  ];
53
54
 
54
- expect(Object.keys(TOOL_GROUPS)).toHaveLength(24);
55
+ expect(Object.keys(TOOL_GROUPS)).toHaveLength(25);
55
56
  for (const group of expectedGroups) {
56
57
  expect(TOOL_GROUPS).toHaveProperty(group);
57
58
  }
@@ -82,11 +83,12 @@ describe("TOOL_GROUPS", () => {
82
83
  expect(TOOL_GROUPS.cluster).toHaveLength(10);
83
84
  expect(TOOL_GROUPS.roles).toHaveLength(8);
84
85
  expect(TOOL_GROUPS.docstore).toHaveLength(9);
86
+ expect(TOOL_GROUPS.codemode).toHaveLength(1);
85
87
  });
86
88
 
87
- it("should total 192 tools across all groups", () => {
89
+ it("should total 193 tools across all groups", () => {
88
90
  const totalTools = Object.values(TOOL_GROUPS).flat().length;
89
- expect(totalTools).toBe(192);
91
+ expect(totalTools).toBe(193);
90
92
  });
91
93
  });
92
94
 
@@ -128,9 +130,9 @@ describe("META_GROUPS", () => {
128
130
  });
129
131
 
130
132
  describe("getAllToolNames", () => {
131
- it("should return all 192 tool names", () => {
133
+ it("should return all 193 tool names", () => {
132
134
  const tools = getAllToolNames();
133
- expect(tools).toHaveLength(192);
135
+ expect(tools).toHaveLength(193);
134
136
  });
135
137
 
136
138
  it("should return unique tool names", () => {
@@ -168,81 +170,81 @@ describe("getToolGroup", () => {
168
170
  describe("getMetaGroupTools", () => {
169
171
  it("should return all tools for starter meta-group", () => {
170
172
  const tools = getMetaGroupTools("starter");
171
- // starter = core(8) + json(17) + transactions(7) + text(6) = 38
172
- expect(tools).toHaveLength(38);
173
+ // starter = core(8) + json(17) + transactions(7) + text(6) + codemode(1) = 39
174
+ expect(tools).toHaveLength(39);
173
175
  });
174
176
 
175
177
  it("should return all tools for essential meta-group", () => {
176
178
  const tools = getMetaGroupTools("essential");
177
- // essential = core(8) + transactions(7) = 15
178
- expect(tools).toHaveLength(15);
179
+ // essential = core(8) + transactions(7) + codemode(1) = 16
180
+ expect(tools).toHaveLength(16);
179
181
  });
180
182
 
181
183
  it("should return all tools for ecosystem meta-group", () => {
182
184
  const tools = getMetaGroupTools("ecosystem");
183
- // ecosystem = router(9) + proxysql(12) + shell(10) + cluster(10) = 41
184
- expect(tools).toHaveLength(41);
185
+ // ecosystem = router(9) + proxysql(12) + shell(10) + cluster(10) + codemode(1) = 42
186
+ expect(tools).toHaveLength(42);
185
187
  });
186
188
 
187
189
  it("should return correct tools for base-core meta-group", () => {
188
190
  const tools = getMetaGroupTools("base-core");
189
- // base-core = core(8) + json(17) + transactions(7) + text(6) + schema(10) = 48
190
- expect(tools).toHaveLength(48);
191
+ // base-core = core(8) + json(17) + transactions(7) + text(6) + schema(10) + codemode(1) = 49
192
+ expect(tools).toHaveLength(49);
191
193
  });
192
194
 
193
195
  it("should return correct tools for base-advanced meta-group", () => {
194
196
  const tools = getMetaGroupTools("base-advanced");
195
- // base-advanced = docstore(9) + spatial(12) + stats(8) + fulltext(5) + events(6) = 40
196
- expect(tools).toHaveLength(40);
197
+ // base-advanced = docstore(9) + spatial(12) + stats(8) + fulltext(5) + events(6) + codemode(1) = 41
198
+ expect(tools).toHaveLength(41);
197
199
  });
198
200
 
199
201
  it("should return correct tools for dba-monitor meta-group", () => {
200
202
  const tools = getMetaGroupTools("dba-monitor");
201
- expect(tools).toHaveLength(35);
203
+ expect(tools).toHaveLength(36);
202
204
  });
203
205
 
204
206
  it("should return correct tools for dba-manage meta-group", () => {
205
207
  const tools = getMetaGroupTools("dba-manage");
206
- expect(tools).toHaveLength(33);
208
+ expect(tools).toHaveLength(34);
207
209
  });
208
210
 
209
211
  it("should return correct tools for dba-secure meta-group", () => {
210
212
  const tools = getMetaGroupTools("dba-secure");
211
- expect(tools).toHaveLength(32);
213
+ expect(tools).toHaveLength(33);
212
214
  });
213
215
  });
214
216
 
215
217
  describe("parseToolFilter", () => {
216
- it("should return starter tools (38) enabled for empty filter", () => {
218
+ it("should return starter tools (39) enabled for empty filter", () => {
217
219
  const config = parseToolFilter("");
218
- expect(config.enabledTools.size).toBe(38);
220
+ expect(config.enabledTools.size).toBe(39);
219
221
  expect(config.rules).toHaveLength(0);
220
222
  expect(config.enabledTools.has("mysql_read_query")).toBe(true);
221
223
  });
222
224
 
223
- it("should return starter tools (38) enabled for undefined filter", () => {
225
+ it("should return starter tools (39) enabled for undefined filter", () => {
224
226
  const config = parseToolFilter(undefined);
225
- expect(config.enabledTools.size).toBe(38);
227
+ expect(config.enabledTools.size).toBe(39);
226
228
  expect(config.rules).toHaveLength(0);
227
229
  });
228
230
 
229
231
  it("should disable a single tool", () => {
230
232
  const config = parseToolFilter("-mysql_read_query");
231
- expect(config.enabledTools.size).toBe(191);
233
+ expect(config.enabledTools.size).toBe(192);
232
234
  expect(config.enabledTools.has("mysql_read_query")).toBe(false);
233
235
  expect(config.enabledTools.has("mysql_write_query")).toBe(true);
234
236
  });
235
237
 
236
238
  it("should disable a tool group", () => {
237
239
  const config = parseToolFilter("-core");
238
- expect(config.enabledTools.size).toBe(184); // 192 - 8
240
+ expect(config.enabledTools.size).toBe(185); // 193 - 8
239
241
  expect(config.enabledTools.has("mysql_read_query")).toBe(false);
240
242
  expect(config.enabledTools.has("mysql_json_extract")).toBe(true);
241
243
  });
242
244
 
243
245
  it("should disable a meta-group", () => {
244
246
  const config = parseToolFilter("-ecosystem");
245
- expect(config.enabledTools.size).toBe(151); // 192 - 41
247
+ expect(config.enabledTools.size).toBe(151); // 193 - 42
246
248
  expect(config.enabledTools.has("mysql_router_status")).toBe(false);
247
249
  expect(config.enabledTools.has("proxysql_status")).toBe(false);
248
250
  expect(config.enabledTools.has("mysqlsh_version")).toBe(false);
@@ -258,18 +260,18 @@ describe("parseToolFilter", () => {
258
260
  it("should handle complex filter chains", () => {
259
261
  // Disable all, then enable starter
260
262
  const config = parseToolFilter("starter");
261
- expect(config.enabledTools.size).toBe(38); // starter has 38 tools
263
+ expect(config.enabledTools.size).toBe(39); // starter has 39 tools
262
264
  });
263
265
 
264
266
  it("should handle explicit whitelist syntax (+group)", () => {
265
267
  const config = parseToolFilter("+starter");
266
- expect(config.enabledTools.size).toBe(38);
268
+ expect(config.enabledTools.size).toBe(39);
267
269
  });
268
270
 
269
271
  it("should handle whitelist with exclusion (starter,-json)", () => {
270
- // starter(38) - json(17) = 21
272
+ // starter(39) - json(17) = 22
271
273
  const config = parseToolFilter("starter,-json");
272
- expect(config.enabledTools.size).toBe(21);
274
+ expect(config.enabledTools.size).toBe(22);
273
275
  });
274
276
 
275
277
  it("should process rules left-to-right", () => {
@@ -278,7 +280,7 @@ describe("parseToolFilter", () => {
278
280
  const config1 = parseToolFilter("+core,-mysql_read_query");
279
281
  expect(config1.enabledTools.has("mysql_read_query")).toBe(false);
280
282
  expect(config1.enabledTools.has("mysql_write_query")).toBe(true);
281
- expect(config1.enabledTools.size).toBe(7); // core(8) - 1 = 7
283
+ expect(config1.enabledTools.size).toBe(8); // core(8) - 1 + codemode(1) = 8
282
284
  });
283
285
 
284
286
  it("should handle whitespace in filter string", () => {
@@ -286,6 +288,31 @@ describe("parseToolFilter", () => {
286
288
  expect(config.enabledTools.has("mysql_read_query")).toBe(true);
287
289
  expect(config.enabledTools.has("mysql_write_query")).toBe(false);
288
290
  });
291
+
292
+ // Codemode auto-injection tests
293
+ it("should auto-inject codemode when using a raw group filter", () => {
294
+ const config = parseToolFilter("core");
295
+ expect(config.enabledTools.has("mysql_execute_code")).toBe(true);
296
+ expect(config.enabledTools.size).toBe(9); // core(8) + codemode(1)
297
+ });
298
+
299
+ it("should not inject codemode when explicitly excluded with -codemode", () => {
300
+ const config = parseToolFilter("core,-codemode");
301
+ expect(config.enabledTools.has("mysql_execute_code")).toBe(false);
302
+ expect(config.enabledTools.size).toBe(8); // core(8) only
303
+ });
304
+
305
+ it("should not inject codemode when mysql_execute_code explicitly excluded", () => {
306
+ const config = parseToolFilter("core,-mysql_execute_code");
307
+ expect(config.enabledTools.has("mysql_execute_code")).toBe(false);
308
+ expect(config.enabledTools.size).toBe(8); // core(8) only
309
+ });
310
+
311
+ it("should not inject codemode when all tools are excluded", () => {
312
+ const config = parseToolFilter("-all");
313
+ expect(config.enabledTools.size).toBe(0);
314
+ expect(config.enabledTools.has("mysql_execute_code")).toBe(false);
315
+ });
289
316
  });
290
317
 
291
318
  describe("isToolEnabled", () => {
@@ -355,14 +382,14 @@ describe("filterTools", () => {
355
382
 
356
383
  describe("calculateTokenSavings", () => {
357
384
  it("should calculate correct savings", () => {
358
- const result = calculateTokenSavings(191, 38);
359
- // (191 - 38) * 200 = 30600 tokens
385
+ const result = calculateTokenSavings(192, 39);
386
+ // (192 - 39) * 200 = 30600 tokens
360
387
  expect(result.tokensSaved).toBe(30600);
361
388
  expect(result.percentSaved).toBe(80); // ~80% disabled
362
389
  });
363
390
 
364
391
  it("should return 0 for no filtering", () => {
365
- const result = calculateTokenSavings(191, 191);
392
+ const result = calculateTokenSavings(192, 192);
366
393
  expect(result.tokensSaved).toBe(0);
367
394
  expect(result.percentSaved).toBe(0);
368
395
  });
@@ -384,7 +411,7 @@ describe("getFilterSummary", () => {
384
411
  it("should generate summary for no filter", () => {
385
412
  const config = parseToolFilter("");
386
413
  const summary = getFilterSummary(config);
387
- expect(summary).toContain("38/192 tools");
414
+ expect(summary).toContain("39/193 tools");
388
415
  expect(summary).toContain("Token savings");
389
416
  });
390
417
 
@@ -416,9 +443,9 @@ describe("getFilterSummary", () => {
416
443
  });
417
444
 
418
445
  describe("getToolGroupInfo", () => {
419
- it("should return info for all 24 groups", () => {
446
+ it("should return info for all 25 groups", () => {
420
447
  const info = getToolGroupInfo();
421
- expect(info).toHaveLength(24);
448
+ expect(info).toHaveLength(25);
422
449
  });
423
450
 
424
451
  it("should include correct counts", () => {
@@ -440,7 +467,7 @@ describe("getMetaGroupInfo", () => {
440
467
  const info = getMetaGroupInfo();
441
468
  const starterInfo = info.find((g) => g.metaGroup === "starter");
442
469
  expect(starterInfo).toBeDefined();
443
- expect(starterInfo?.count).toBe(38);
470
+ expect(starterInfo?.count).toBe(39);
444
471
  expect(starterInfo?.groups).toContain("core");
445
472
  });
446
473
  });
@@ -182,7 +182,7 @@ export class McpServer {
182
182
  const transport = createHttpTransport(
183
183
  {
184
184
  port,
185
- host: "localhost", // Default to localhost, could be configurable
185
+ host: this.config.host ?? "localhost",
186
186
  corsOrigins: ["*"], // Allow all for now, or make configurable
187
187
  // Pass OAuth config if enabled
188
188
  ...(this.config.oauth?.enabled
@@ -28,6 +28,9 @@ export interface McpServerConfig {
28
28
  /** HTTP port (for http/sse transports) */
29
29
  port?: number;
30
30
 
31
+ /** Host to bind HTTP transport to (default: localhost) */
32
+ host?: string;
33
+
31
34
  /** Database configurations */
32
35
  databases: DatabaseConfig[];
33
36