@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,1224 @@
1
+ /**
2
+ * mysql-mcp - Code Mode API
3
+ *
4
+ * Exposes all MySQL tools organized by their 24 groups
5
+ * for use within the sandboxed execution environment.
6
+ */
7
+
8
+ import type { MySQLAdapter } from "../adapters/mysql/MySQLAdapter.js";
9
+ import type { ToolDefinition } from "../types/index.js";
10
+
11
+ /**
12
+ * Method aliases for code mode API.
13
+ * Maps alternate method names to their canonical method names.
14
+ * Format: { groupName: { aliasName: canonicalName } }
15
+ *
16
+ * These aliases handle common naming misguesses where agents
17
+ * might try the redundant prefix pattern (e.g., jsonExtract vs extract).
18
+ */
19
+ const METHOD_ALIASES: Record<string, Record<string, string>> = {
20
+ // JSON: mysql_json_extract → extract, but agent might try jsonExtract
21
+ json: {
22
+ jsonExtract: "extract",
23
+ jsonSet: "set",
24
+ jsonInsert: "insert",
25
+ jsonRemove: "remove",
26
+ jsonContains: "contains",
27
+ jsonKeys: "keys",
28
+ jsonReplace: "replace",
29
+ jsonGet: "get",
30
+ jsonSearch: "search",
31
+ jsonUpdate: "update",
32
+ jsonValidate: "validate",
33
+ jsonMerge: "merge",
34
+ jsonNormalize: "normalize",
35
+ jsonDiff: "diff",
36
+ jsonIndexSuggest: "indexSuggest",
37
+ jsonStats: "stats",
38
+ jsonArrayAppend: "arrayAppend",
39
+ },
40
+ // Text: mysql_regexp_match → regexpMatch, but also regex
41
+ text: {
42
+ regex: "regexpMatch",
43
+ regexp: "regexpMatch",
44
+ like: "likeSearch",
45
+ pattern: "likeSearch",
46
+ sound: "soundex",
47
+ substr: "substring",
48
+ concatenate: "concat",
49
+ collation: "collationConvert",
50
+ },
51
+ // Fulltext: intuitive aliases
52
+ fulltext: {
53
+ create: "fulltextCreate",
54
+ drop: "fulltextDrop",
55
+ search: "fulltextSearch",
56
+ boolean: "fulltextBoolean",
57
+ expand: "fulltextExpand",
58
+ createIndex: "fulltextCreate",
59
+ dropIndex: "fulltextDrop",
60
+ naturalLanguage: "fulltextSearch",
61
+ booleanMode: "fulltextBoolean",
62
+ queryExpansion: "fulltextExpand",
63
+ },
64
+ // Transactions: shorter aliases
65
+ transactions: {
66
+ begin: "transactionBegin",
67
+ commit: "transactionCommit",
68
+ rollback: "transactionRollback",
69
+ savepoint: "transactionSavepoint",
70
+ release: "transactionRelease",
71
+ rollbackTo: "transactionRollbackTo",
72
+ execute: "transactionExecute",
73
+ },
74
+ // Performance: intuitive aliases
75
+ performance: {
76
+ queryPlan: "explain",
77
+ analyze: "explainAnalyze",
78
+ slowLog: "slowQueries",
79
+ slow: "slowQueries",
80
+ trace: "optimizerTrace",
81
+ bufferPool: "bufferPoolStats",
82
+ innodb: "innodbStatus",
83
+ stats: "tableStats",
84
+ threads: "threadStats",
85
+ health: "serverHealth",
86
+ processes: "showProcesslist",
87
+ processlist: "showProcesslist",
88
+ },
89
+ // Optimization: shorter aliases
90
+ optimization: {
91
+ recommend: "indexRecommendation",
92
+ indexAdvice: "indexRecommendation",
93
+ hint: "forceIndex",
94
+ forceHint: "forceIndex",
95
+ rewrite: "queryRewrite",
96
+ },
97
+ // Admin: intuitive aliases
98
+ admin: {
99
+ check: "checkTable",
100
+ repair: "repairTable",
101
+ optimize: "optimizeTable",
102
+ analyze: "analyzeTable",
103
+ flush: "flushTables",
104
+ kill: "killQuery",
105
+ pool: "poolStats",
106
+ },
107
+ // Monitoring: intuitive aliases
108
+ monitoring: {
109
+ status: "showStatus",
110
+ variables: "showVariables",
111
+ processes: "showProcesslist",
112
+ processlist: "showProcesslist",
113
+ queries: "queryStats",
114
+ slowlog: "slowQueries",
115
+ },
116
+ // Backup: shorter aliases
117
+ backup: {
118
+ dump: "createDump",
119
+ export: "exportTable",
120
+ import: "importData",
121
+ restore: "restoreDump",
122
+ },
123
+ // Replication: intuitive aliases
124
+ replication: {
125
+ status: "slaveStatus",
126
+ master: "masterStatus",
127
+ slave: "slaveStatus",
128
+ binlog: "binlogEvents",
129
+ gtid: "gtidStatus",
130
+ },
131
+ // Partitioning: shorter aliases
132
+ partitioning: {
133
+ add: "addPartition",
134
+ drop: "dropPartition",
135
+ reorganize: "reorganizePartition",
136
+ info: "partitionInfo",
137
+ list: "partitionInfo", // list() → partitionInfo()
138
+ },
139
+ // Schema: intuitive aliases
140
+ schema: {
141
+ views: "listViews",
142
+ functions: "listFunctions",
143
+ procedures: "listStoredProcedures",
144
+ triggers: "listTriggers",
145
+ constraints: "listConstraints",
146
+ schemas: "listSchemas",
147
+ createDb: "createSchema",
148
+ dropDb: "dropSchema",
149
+ },
150
+ // Events: shorter aliases
151
+ events: {
152
+ create: "eventCreate",
153
+ drop: "eventDrop",
154
+ alter: "eventAlter",
155
+ list: "eventList",
156
+ status: "eventStatus",
157
+ scheduler: "schedulerStatus",
158
+ },
159
+ // Stats: intuitive aliases
160
+ stats: {
161
+ summary: "descriptive",
162
+ percentile: "percentiles",
163
+ movingAverage: "timeSeries",
164
+ time_series: "timeSeries",
165
+ },
166
+ // Spatial: intuitive aliases
167
+ spatial: {
168
+ addColumn: "createColumn",
169
+ addIndex: "createIndex",
170
+ dist: "distance",
171
+ distSphere: "distanceSphere",
172
+
173
+ pointInPolygon: "contains",
174
+ },
175
+ // Security: intuitive aliases
176
+ security: {
177
+ ssl: "sslStatus",
178
+ encryption: "encryptionStatus",
179
+ firewall: "firewallStatus",
180
+ privileges: "userPrivileges",
181
+ password: "passwordValidate",
182
+ mask: "maskData",
183
+ sensitive: "sensitiveTables",
184
+ },
185
+ // Cluster: intuitive aliases
186
+ cluster: {
187
+ status: "clusterStatus",
188
+ instances: "clusterInstances",
189
+ topology: "clusterTopology",
190
+ switchover: "clusterSwitchover",
191
+ routerStatus: "clusterRouterStatus",
192
+ grStatus: "grStatus",
193
+ grMembers: "grMembers",
194
+ grPrimary: "grPrimary",
195
+ grFlowControl: "grFlowControl",
196
+ grTransactions: "grTransactions",
197
+ },
198
+ // Roles: shorter aliases
199
+ roles: {
200
+ create: "roleCreate",
201
+ drop: "roleDrop",
202
+ list: "roleList",
203
+ assign: "roleAssign",
204
+ grant: "roleGrant",
205
+ revoke: "roleRevoke",
206
+ grants: "roleGrants",
207
+ userRoles: "userRoles",
208
+ },
209
+ // DocStore: shorter aliases
210
+ docstore: {
211
+ add: "docAdd",
212
+ find: "docFind",
213
+ modify: "docModify",
214
+ remove: "docRemove",
215
+ createCollection: "docCreateCollection",
216
+ dropCollection: "docDropCollection",
217
+ listCollections: "docListCollections",
218
+ collectionInfo: "docCollectionInfo",
219
+ createIndex: "docCreateIndex",
220
+ },
221
+ // SysSchema: shorter aliases
222
+ sysschema: {
223
+ schemaStats: "sysSchemaStats",
224
+ lockWaits: "sysInnodbLockWaits",
225
+ memory: "sysMemorySummary",
226
+ statements: "sysStatementSummary",
227
+ waits: "sysWaitSummary",
228
+ io: "sysIoSummary",
229
+ users: "sysUserSummary",
230
+ hosts: "sysHostSummary",
231
+ },
232
+ // Router: shorter aliases
233
+ router: {
234
+ metadata: "metadataStatus",
235
+ pool: "poolStatus",
236
+ connections: "routeConnections",
237
+ destinations: "routeDestinations",
238
+ blocked: "routeBlockedHosts",
239
+ },
240
+ // Shell: shorter aliases
241
+ shell: {
242
+ run: "runScript",
243
+ script: "runScript",
244
+ upgrade: "checkUpgrade",
245
+ dump: "dumpInstance",
246
+ load: "loadDump",
247
+ export: "exportTable",
248
+ import: "importTable",
249
+ },
250
+ };
251
+
252
+ /**
253
+ * Usage examples for each group's help() output.
254
+ * Provides quick-reference examples for common operations.
255
+ */
256
+ const GROUP_EXAMPLES: Record<string, string[]> = {
257
+ core: [
258
+ 'mysql.core.readQuery("SELECT * FROM users LIMIT 10")',
259
+ 'mysql.core.describeTable("users")',
260
+ 'mysql.core.createTable("orders", { columns: [{ name: "id", type: "INT AUTO_INCREMENT PRIMARY KEY" }] })',
261
+ "mysql.core.listTables()",
262
+ ],
263
+ transactions: [
264
+ "const { transactionId } = await mysql.transactions.begin()",
265
+ 'await mysql.transactions.savepoint({ transactionId, name: "sp1" })',
266
+ 'await mysql.transactions.rollbackTo({ transactionId, name: "sp1" })',
267
+ "await mysql.transactions.commit({ transactionId })",
268
+ 'await mysql.transactions.execute({ statements: [{ sql: "INSERT..." }, { sql: "UPDATE..." }] })',
269
+ ],
270
+ json: [
271
+ 'mysql.json.extract({ table: "docs", column: "data", path: "$.user.name" })',
272
+ 'mysql.json.set({ table: "docs", column: "data", path: "$.status", value: "active", where: "id=1" })',
273
+ 'mysql.json.contains({ table: "docs", column: "data", value: \'{"type": "admin"}\' })',
274
+ "mysql.json.merge({ json1: '{\"a\": 1}', json2: '{\"b\": 2}' })",
275
+ 'mysql.json.search({ table: "docs", column: "data", searchValue: "active" })',
276
+ ],
277
+ text: [
278
+ 'mysql.text.regexpMatch({ table: "users", column: "email", pattern: "^admin@" })',
279
+ 'mysql.text.likeSearch({ table: "products", column: "name", pattern: "%widget%" })',
280
+ 'mysql.text.soundex({ table: "users", column: "name", value: "Smith" })',
281
+ ],
282
+ fulltext: [
283
+ 'mysql.fulltext.fulltextSearch({ table: "articles", columns: ["title", "content"], query: "database" })',
284
+ 'mysql.fulltext.fulltextCreate({ table: "articles", columns: ["title", "content"] })',
285
+ 'mysql.fulltext.fulltextBoolean({ table: "articles", columns: ["content"], query: "+MySQL -Oracle" })',
286
+ ],
287
+ performance: [
288
+ "mysql.performance.explain({ sql: 'SELECT * FROM orders WHERE status = ?', params: ['active'] })",
289
+ "mysql.performance.slowQueries({ limit: 10 })",
290
+ "mysql.performance.bufferPoolStats()",
291
+ "mysql.performance.innodbStatus()",
292
+ "mysql.performance.tableStats({ table: 'orders' })",
293
+ ],
294
+ optimization: [
295
+ "mysql.optimization.indexRecommendation({ table: 'orders' })",
296
+ "mysql.optimization.queryRewrite({ query: 'SELECT * FROM orders WHERE status = ?' })",
297
+ 'mysql.optimization.forceIndex({ table: "orders", query: "SELECT * FROM orders WHERE status = ?", indexName: "idx_status" })',
298
+ ],
299
+ admin: [
300
+ "mysql.admin.optimizeTable({ table: 'orders' })",
301
+ "mysql.admin.checkTable({ table: 'orders' })",
302
+ "mysql.admin.analyzeTable({ table: 'orders' })",
303
+ "mysql.admin.flushTables()",
304
+ "mysql.admin.killQuery({ processId: 12345 })",
305
+ ],
306
+ monitoring: [
307
+ "mysql.monitoring.showStatus({ pattern: 'Threads%' })",
308
+ "mysql.monitoring.showVariables({ pattern: 'max_connections' })",
309
+ "mysql.monitoring.showProcesslist()",
310
+ "mysql.monitoring.queryStats()",
311
+ ],
312
+ backup: [
313
+ "mysql.backup.createDump({ tables: ['users', 'orders'] })",
314
+ "mysql.backup.exportTable({ table: 'users', format: 'csv' })",
315
+ "mysql.backup.importData({ table: 'users', data: [{ name: 'Alice', email: 'alice@test.com' }] })",
316
+ "mysql.backup.restoreDump({ filename: 'backup.sql' })",
317
+ ],
318
+ replication: [
319
+ "mysql.replication.slaveStatus()",
320
+ "mysql.replication.lag()",
321
+ "mysql.replication.masterStatus()",
322
+ "mysql.replication.binlogEvents({ limit: 20 })",
323
+ ],
324
+ partitioning: [
325
+ "mysql.partitioning.partitionInfo({ table: 'events' })",
326
+ "mysql.partitioning.addPartition({ table: 'events', partitionName: 'p2024q1', partitionType: 'RANGE', value: '2024040100' })",
327
+ "mysql.partitioning.dropPartition({ table: 'events', partitionName: 'p2023q1' })",
328
+ ],
329
+ schema: [
330
+ "mysql.schema.listViews()",
331
+ "mysql.schema.createView({ name: 'active_users', sql: 'SELECT * FROM users WHERE active = 1' })",
332
+ "mysql.schema.listFunctions()",
333
+ "mysql.schema.listTriggers({ table: 'orders' })",
334
+ ],
335
+ events: [
336
+ "mysql.events.eventCreate({ name: 'cleanup', schedule: { type: 'RECURRING', interval: 1, intervalUnit: 'DAY' }, body: 'DELETE FROM logs WHERE created_at < DATE_SUB(NOW(), INTERVAL 30 DAY)' })",
337
+ "mysql.events.eventList()",
338
+ "mysql.events.schedulerStatus()",
339
+ ],
340
+ sysschema: [
341
+ "mysql.sysschema.sysSchemaStats({ schema: 'testdb' })",
342
+ "mysql.sysschema.sysStatementSummary({ limit: 10 })",
343
+ "mysql.sysschema.sysInnodbLockWaits()",
344
+ "mysql.sysschema.sysMemorySummary()",
345
+ ],
346
+ stats: [
347
+ "mysql.stats.descriptive({ table: 'orders', column: 'amount' })",
348
+ "mysql.stats.percentiles({ table: 'orders', column: 'amount', percentiles: [50, 95, 99] })",
349
+ "mysql.stats.timeSeries({ table: 'metrics', timeColumn: 'ts', valueColumn: 'value', interval: 'hour' })",
350
+ "mysql.stats.histogram({ table: 'orders', column: 'amount', buckets: 10 })",
351
+ ],
352
+ spatial: [
353
+ "mysql.spatial.distance({ table: 'locations', spatialColumn: 'geom', point: { longitude: -74, latitude: 40.7 } })",
354
+ "mysql.spatial.distanceSphere({ table: 'locations', spatialColumn: 'geom', point: { longitude: -74, latitude: 40.7 } })",
355
+ "mysql.spatial.point({ longitude: -74, latitude: 40.7 })",
356
+ "mysql.spatial.buffer({ geometry: 'POINT(-74 40.7)', distance: 1000 })",
357
+ ],
358
+ security: [
359
+ "mysql.security.sslStatus()",
360
+ "mysql.security.userPrivileges({ user: 'app_user' })",
361
+ "mysql.security.audit()",
362
+ "mysql.security.sensitiveTables()",
363
+ "mysql.security.passwordValidate({ password: 'test123' })",
364
+ ],
365
+ cluster: [
366
+ "mysql.cluster.clusterStatus({ summary: true })",
367
+ "mysql.cluster.clusterRouterStatus({ summary: true })",
368
+ "mysql.cluster.clusterSwitchover()",
369
+ "mysql.cluster.grMembers()",
370
+ "mysql.cluster.clusterTopology()",
371
+ ],
372
+ roles: [
373
+ "mysql.roles.roleCreate({ name: 'app_reader' })",
374
+ "mysql.roles.roleGrant({ role: 'app_reader', privileges: ['SELECT'], database: 'mydb' })",
375
+ "mysql.roles.roleAssign({ role: 'app_reader', user: 'app_user' })",
376
+ "mysql.roles.roleList()",
377
+ ],
378
+ docstore: [
379
+ "mysql.docstore.docCreateCollection({ name: 'products', schema: 'mydb' })",
380
+ "mysql.docstore.docAdd({ collection: 'products', documents: [{ name: 'Widget', price: 9.99 }] })",
381
+ "mysql.docstore.docFind({ collection: 'products', filter: '$.name' })",
382
+ ],
383
+ router: [
384
+ "mysql.router.status()",
385
+ "mysql.router.routes()",
386
+ "mysql.router.routeHealth({ routeName: 'myroute' })",
387
+ ],
388
+ proxysql: [
389
+ "// ProxySQL requires external ProxySQL admin connection",
390
+ "// See tool descriptions for connection requirements",
391
+ ],
392
+ shell: [
393
+ "mysql.shell.version()",
394
+ 'mysql.shell.runScript({ script: \'print("hello")\', language: "js" })',
395
+ "mysql.shell.exportTable({ schema: 'mydb', table: 'users', outputPath: '/tmp/users.csv', format: 'csv' })",
396
+ "mysql.shell.dumpSchemas({ schemas: ['mydb'], outputDir: '/backup/mydb', dryRun: true })",
397
+ ],
398
+ };
399
+
400
+ /**
401
+ * Mapping of method names to their parameter names for positional argument support.
402
+ * Single string = first positional arg maps to this key
403
+ * Array = multiple positional args map to these keys in order
404
+ *
405
+ * Enables:
406
+ * - `mysql.core.readQuery("SELECT...")` → `{ sql: "SELECT..." }`
407
+ * - `mysql.core.describeTable("users")` → `{ table: "users" }`
408
+ */
409
+ const POSITIONAL_PARAM_MAP: Record<string, string | string[]> = {
410
+ // ============ CORE GROUP ============
411
+ readQuery: "sql",
412
+ writeQuery: "sql",
413
+ describeTable: "table",
414
+ dropTable: "table",
415
+ listTables: "database",
416
+ getIndexes: "table",
417
+ dropIndex: "name",
418
+ createTable: ["name", "columns"],
419
+ createIndex: ["table", "columns"],
420
+
421
+ // ============ SCHEMA GROUP ============
422
+ createSchema: "name",
423
+ dropSchema: "name",
424
+ listSchemas: "pattern",
425
+ listViews: "database",
426
+ listFunctions: "database",
427
+ listStoredProcedures: "database",
428
+ listTriggers: "table",
429
+ listConstraints: "table",
430
+ createView: ["name", "sql"],
431
+
432
+ // ============ JSON GROUP ============
433
+ extract: ["table", "column", "path", "where"],
434
+ set: ["table", "column", "path", "value", "where"],
435
+ insert: ["table", "column", "path", "value", "where"],
436
+ remove: ["table", "column", "path", "where"],
437
+ contains: ["table", "column", "value"],
438
+ keys: ["table", "column", "where"],
439
+ replace: ["table", "column", "path", "value", "where"],
440
+ get: ["table", "column", "path"],
441
+ search: ["table", "column", "searchValue"],
442
+ update: ["table", "column", "path", "value", "where"],
443
+ validate: ["table", "column"],
444
+ stats: ["table", "column"],
445
+ indexSuggest: ["table", "column"],
446
+ normalize: ["table", "column"],
447
+ merge: ["json1", "json2"],
448
+ diff: ["json1", "json2"],
449
+ arrayAppend: ["table", "column", "path", "value"],
450
+
451
+ // ============ TEXT GROUP ============
452
+ regexpMatch: ["table", "column", "pattern"],
453
+ likeSearch: ["table", "column", "pattern"],
454
+ soundex: ["table", "column", "value"],
455
+ substring: ["table", "column"],
456
+ concat: ["table", "columns"],
457
+ collationConvert: ["table", "column", "collation"],
458
+
459
+ // ============ FULLTEXT GROUP ============
460
+ fulltextCreate: ["table", "columns"],
461
+ fulltextDrop: ["table", "indexName"],
462
+ fulltextSearch: ["table", "columns", "query"],
463
+ fulltextBoolean: ["table", "columns", "query"],
464
+ fulltextExpand: ["table", "columns", "query"],
465
+
466
+ // ============ TRANSACTION GROUP ============
467
+ transactionCommit: "transactionId",
468
+ transactionRollback: "transactionId",
469
+ transactionSavepoint: ["transactionId", "name"],
470
+ transactionRelease: ["transactionId", "name"],
471
+ transactionRollbackTo: ["transactionId", "name"],
472
+ // Short aliases
473
+ commit: "transactionId",
474
+ rollback: "transactionId",
475
+ savepoint: ["transactionId", "name"],
476
+ release: ["transactionId", "name"],
477
+ rollbackTo: ["transactionId", "name"],
478
+
479
+ // ============ PERFORMANCE GROUP ============
480
+ explain: "sql",
481
+ explainAnalyze: "sql",
482
+
483
+ // ============ ADMIN GROUP ============
484
+ checkTable: "table",
485
+ repairTable: "table",
486
+ optimizeTable: "table",
487
+ analyzeTable: "table",
488
+
489
+ // ============ BACKUP GROUP ============
490
+ createDump: "tables",
491
+ exportTable: "table",
492
+ importData: "table",
493
+ restoreDump: "filename",
494
+
495
+ // ============ STATS GROUP ============
496
+ descriptive: ["table", "column"],
497
+ percentiles: ["table", "column", "percentiles"],
498
+ distribution: ["table", "column"],
499
+ histogram: ["table", "column", "buckets"],
500
+ correlation: ["table", "column1", "column2"],
501
+ regression: ["table", "xColumn", "yColumn"],
502
+ sampling: ["table", "sampleSize"],
503
+ timeSeries: ["table", "timeColumn", "valueColumn"],
504
+ // Stats prefixed aliases
505
+ statsTimeSeries: ["table", "timeColumn", "valueColumn"],
506
+ statsDescriptive: ["table", "column"],
507
+ statsPercentiles: ["table", "column", "percentiles"],
508
+ statsDistribution: ["table", "column"],
509
+ statsCorrelation: ["table", "column1", "column2"],
510
+ statsHistogram: ["table", "column", "buckets"],
511
+ statsSampling: ["table", "sampleSize"],
512
+ statsRegression: ["table", "xColumn", "yColumn"],
513
+
514
+ // ============ PARTITIONING GROUP ============
515
+ addPartition: ["table", "partitionName", "partitionType", "value"],
516
+ dropPartition: ["table", "partitionName"],
517
+ reorganizePartition: ["table", "partitions"],
518
+ partitionInfo: "table",
519
+
520
+ // ============ SPATIAL GROUP ============
521
+ distance: ["table", "spatialColumn"],
522
+ distanceSphere: ["table", "spatialColumn"],
523
+ point: ["longitude", "latitude"],
524
+ polygon: "coordinates",
525
+
526
+ // ============ SHELL GROUP ============
527
+ // Note: exportTable omitted — conflicts with backup group's exportTable
528
+ checkUpgrade: "targetVersion",
529
+ runScript: ["script", "language"],
530
+ importTable: ["inputPath", "schema", "table"],
531
+ importJson: ["inputPath", "schema", "collection"],
532
+ dumpInstance: "outputDir",
533
+ dumpSchemas: ["schemas", "outputDir"],
534
+ dumpTables: ["schema", "tables", "outputDir"],
535
+ loadDump: "inputDir",
536
+
537
+ // ============ SECURITY GROUP ============
538
+ passwordValidate: "password",
539
+ };
540
+
541
+ /**
542
+ * Methods where a single array arg should be wrapped in a specific key
543
+ */
544
+ const ARRAY_WRAP_MAP: Record<string, string> = {
545
+ transactionExecute: "statements",
546
+ execute: "statements",
547
+ };
548
+
549
+ /**
550
+ * Normalize parameters to support positional arguments.
551
+ * Handles both single positional args and multiple positional args.
552
+ */
553
+ function normalizeParams(methodName: string, args: unknown[]): unknown {
554
+ // No args - pass through
555
+ if (args.length === 0) return undefined;
556
+
557
+ // Single arg handling
558
+ if (args.length === 1) {
559
+ const arg = args[0];
560
+
561
+ // Object arg - pass through
562
+ if (typeof arg === "object" && arg !== null && !Array.isArray(arg)) {
563
+ return arg;
564
+ }
565
+
566
+ // Array arg - check if we should wrap it
567
+ if (Array.isArray(arg)) {
568
+ const wrapKey = ARRAY_WRAP_MAP[methodName];
569
+ if (wrapKey !== undefined) {
570
+ return { [wrapKey]: arg };
571
+ }
572
+ return arg;
573
+ }
574
+
575
+ // String arg - use positional mapping
576
+ if (typeof arg === "string") {
577
+ const paramMapping = POSITIONAL_PARAM_MAP[methodName];
578
+ if (typeof paramMapping === "string") {
579
+ return { [paramMapping]: arg };
580
+ }
581
+ if (Array.isArray(paramMapping) && paramMapping[0] !== undefined) {
582
+ return { [paramMapping[0]]: arg };
583
+ }
584
+ // Fallback: try common parameter names
585
+ return { sql: arg, query: arg, table: arg, name: arg };
586
+ }
587
+
588
+ return arg;
589
+ }
590
+
591
+ // Multi-arg: check for array+options pattern first
592
+ if (args.length >= 1 && Array.isArray(args[0])) {
593
+ const wrapKey = ARRAY_WRAP_MAP[methodName];
594
+ if (wrapKey !== undefined) {
595
+ const result: Record<string, unknown> = { [wrapKey]: args[0] };
596
+ if (args.length > 1) {
597
+ const lastArg = args[args.length - 1];
598
+ if (
599
+ typeof lastArg === "object" &&
600
+ lastArg !== null &&
601
+ !Array.isArray(lastArg)
602
+ ) {
603
+ Object.assign(result, lastArg);
604
+ }
605
+ }
606
+ return result;
607
+ }
608
+ }
609
+
610
+ // Look up positional parameter mapping
611
+ const paramMapping = POSITIONAL_PARAM_MAP[methodName];
612
+
613
+ if (paramMapping === undefined) {
614
+ return args[0];
615
+ }
616
+
617
+ // Single param mapping - merge trailing options if present
618
+ if (typeof paramMapping === "string") {
619
+ const result: Record<string, unknown> = { [paramMapping]: args[0] };
620
+ if (args.length > 1) {
621
+ const lastArg = args[args.length - 1];
622
+ if (
623
+ typeof lastArg === "object" &&
624
+ lastArg !== null &&
625
+ !Array.isArray(lastArg)
626
+ ) {
627
+ Object.assign(result, lastArg);
628
+ }
629
+ }
630
+ return result;
631
+ }
632
+
633
+ // Multi-param mapping (array)
634
+ const result: Record<string, unknown> = {};
635
+
636
+ // Check if last arg is an options object that should be merged
637
+ const lastArg = args[args.length - 1];
638
+ const lastArgIsOptionsObject =
639
+ typeof lastArg === "object" &&
640
+ lastArg !== null &&
641
+ !Array.isArray(lastArg) &&
642
+ Object.keys(lastArg as Record<string, unknown>).some((k) =>
643
+ paramMapping.includes(k),
644
+ );
645
+
646
+ // Map positional args to their keys
647
+ const argsToMap = lastArgIsOptionsObject ? args.length - 1 : args.length;
648
+ for (let i = 0; i < paramMapping.length && i < argsToMap; i++) {
649
+ const key = paramMapping[i];
650
+ const arg = args[i];
651
+ if (key !== undefined) {
652
+ result[key] = arg;
653
+ }
654
+ }
655
+
656
+ // Merge trailing options object
657
+ if (args.length > paramMapping.length || lastArgIsOptionsObject) {
658
+ if (
659
+ typeof lastArg === "object" &&
660
+ lastArg !== null &&
661
+ !Array.isArray(lastArg)
662
+ ) {
663
+ Object.assign(result, lastArg);
664
+ }
665
+ }
666
+
667
+ return result;
668
+ }
669
+
670
+ /**
671
+ * Dynamic API generator for tool groups
672
+ * Creates methods for each tool in the group
673
+ */
674
+ function createGroupApi(
675
+ adapter: MySQLAdapter,
676
+ groupName: string,
677
+ tools: ToolDefinition[],
678
+ ): Record<string, (...args: unknown[]) => Promise<unknown>> {
679
+ const api: Record<string, (...args: unknown[]) => Promise<unknown>> = {};
680
+
681
+ for (const tool of tools) {
682
+ // Convert tool name to method name
683
+ // e.g., mysql_read_query -> readQuery, mysql_json_extract -> extract
684
+ const methodName = toolNameToMethodName(tool.name, groupName);
685
+
686
+ api[methodName] = async (...args: unknown[]) => {
687
+ // Normalize positional arguments to object parameters
688
+ const normalizedParams = normalizeParams(methodName, args) ?? {};
689
+ const context = adapter.createContext();
690
+ return tool.handler(normalizedParams, context);
691
+ };
692
+ }
693
+
694
+ // Add method aliases for this group
695
+ const aliases = METHOD_ALIASES[groupName];
696
+ if (aliases !== undefined) {
697
+ for (const [aliasName, canonicalName] of Object.entries(aliases)) {
698
+ if (api[canonicalName] !== undefined) {
699
+ api[aliasName] = api[canonicalName];
700
+ }
701
+ }
702
+ }
703
+
704
+ return api;
705
+ }
706
+
707
+ /**
708
+ * Convert tool name to camelCase method name
709
+ * Examples:
710
+ * mysql_read_query (core) -> readQuery
711
+ * mysql_json_extract (json) -> extract
712
+ * mysql_fulltext_search (fulltext) -> fulltextSearch
713
+ * mysql_sys_schema_stats (sysschema) -> sysSchemaStats
714
+ */
715
+ function toolNameToMethodName(toolName: string, groupName: string): string {
716
+ // Remove mysql_ prefix
717
+ let name = toolName.replace(/^mysql_/, "");
718
+
719
+ // Map group name to its tool name prefix
720
+ // Some groups use different prefixes in tool names
721
+ const groupPrefixMap: Record<string, string> = {
722
+ sysschema: "sys_",
723
+ fulltext: "fulltext_",
724
+ docstore: "doc_",
725
+ transactions: "transaction_",
726
+ shell: "mysqlsh_",
727
+ // Default: use groupName + "_"
728
+ };
729
+
730
+ const groupPrefix = groupPrefixMap[groupName] ?? groupName + "_";
731
+
732
+ // For certain groups, keep the prefix as part of the method name
733
+ // because the tool names use a prefix that differs from the group
734
+ const keepPrefix = new Set([
735
+ "fulltext",
736
+ "sysschema",
737
+ "docstore",
738
+ "transactions",
739
+ "cluster",
740
+
741
+ "roles",
742
+ "events",
743
+ ]);
744
+
745
+ if (!keepPrefix.has(groupName) && name.startsWith(groupPrefix)) {
746
+ name = name.substring(groupPrefix.length);
747
+ }
748
+
749
+ // Convert snake_case to camelCase
750
+ return name.replace(/_([a-z])/g, (_, letter: string) => letter.toUpperCase());
751
+ }
752
+
753
+ // Type alias for group API record
754
+ type GroupApiRecord = Record<string, (...args: unknown[]) => Promise<unknown>>;
755
+
756
+ /**
757
+ * Main API class exposing all tool groups
758
+ */
759
+ export class MysqlApi {
760
+ // Core groups (15 original)
761
+ readonly core: GroupApiRecord;
762
+ readonly transactions: GroupApiRecord;
763
+ readonly json: GroupApiRecord;
764
+ readonly text: GroupApiRecord;
765
+ readonly fulltext: GroupApiRecord;
766
+ readonly performance: GroupApiRecord;
767
+ readonly optimization: GroupApiRecord;
768
+ readonly admin: GroupApiRecord;
769
+ readonly monitoring: GroupApiRecord;
770
+ readonly backup: GroupApiRecord;
771
+ readonly replication: GroupApiRecord;
772
+ readonly partitioning: GroupApiRecord;
773
+ readonly router: GroupApiRecord;
774
+ readonly proxysql: GroupApiRecord;
775
+ readonly shell: GroupApiRecord;
776
+ // New groups (9 added in v2.0.0)
777
+ readonly schema: GroupApiRecord;
778
+ readonly events: GroupApiRecord;
779
+ readonly sysschema: GroupApiRecord;
780
+ readonly stats: GroupApiRecord;
781
+ readonly spatial: GroupApiRecord;
782
+ readonly security: GroupApiRecord;
783
+ readonly cluster: GroupApiRecord;
784
+ readonly roles: GroupApiRecord;
785
+ readonly docstore: GroupApiRecord;
786
+
787
+ private readonly toolsByGroup: Map<string, ToolDefinition[]>;
788
+
789
+ constructor(adapter: MySQLAdapter) {
790
+ // Get all tool definitions and group them
791
+ const allTools = adapter.getToolDefinitions();
792
+ this.toolsByGroup = this.groupTools(allTools);
793
+
794
+ // Create group-specific APIs - 24 groups
795
+ this.core = createGroupApi(
796
+ adapter,
797
+ "core",
798
+ this.toolsByGroup.get("core") ?? [],
799
+ );
800
+ this.transactions = createGroupApi(
801
+ adapter,
802
+ "transactions",
803
+ this.toolsByGroup.get("transactions") ?? [],
804
+ );
805
+ this.json = createGroupApi(
806
+ adapter,
807
+ "json",
808
+ this.toolsByGroup.get("json") ?? [],
809
+ );
810
+ this.text = createGroupApi(
811
+ adapter,
812
+ "text",
813
+ this.toolsByGroup.get("text") ?? [],
814
+ );
815
+ this.fulltext = createGroupApi(
816
+ adapter,
817
+ "fulltext",
818
+ this.toolsByGroup.get("fulltext") ?? [],
819
+ );
820
+ this.performance = createGroupApi(
821
+ adapter,
822
+ "performance",
823
+ this.toolsByGroup.get("performance") ?? [],
824
+ );
825
+ this.optimization = createGroupApi(
826
+ adapter,
827
+ "optimization",
828
+ this.toolsByGroup.get("optimization") ?? [],
829
+ );
830
+ this.admin = createGroupApi(
831
+ adapter,
832
+ "admin",
833
+ this.toolsByGroup.get("admin") ?? [],
834
+ );
835
+ this.monitoring = createGroupApi(
836
+ adapter,
837
+ "monitoring",
838
+ this.toolsByGroup.get("monitoring") ?? [],
839
+ );
840
+ this.backup = createGroupApi(
841
+ adapter,
842
+ "backup",
843
+ this.toolsByGroup.get("backup") ?? [],
844
+ );
845
+ this.replication = createGroupApi(
846
+ adapter,
847
+ "replication",
848
+ this.toolsByGroup.get("replication") ?? [],
849
+ );
850
+ this.partitioning = createGroupApi(
851
+ adapter,
852
+ "partitioning",
853
+ this.toolsByGroup.get("partitioning") ?? [],
854
+ );
855
+ this.router = createGroupApi(
856
+ adapter,
857
+ "router",
858
+ this.toolsByGroup.get("router") ?? [],
859
+ );
860
+ this.proxysql = createGroupApi(
861
+ adapter,
862
+ "proxysql",
863
+ this.toolsByGroup.get("proxysql") ?? [],
864
+ );
865
+ this.shell = createGroupApi(
866
+ adapter,
867
+ "shell",
868
+ this.toolsByGroup.get("shell") ?? [],
869
+ );
870
+ // New groups (9)
871
+ this.schema = createGroupApi(
872
+ adapter,
873
+ "schema",
874
+ this.toolsByGroup.get("schema") ?? [],
875
+ );
876
+ this.events = createGroupApi(
877
+ adapter,
878
+ "events",
879
+ this.toolsByGroup.get("events") ?? [],
880
+ );
881
+ this.sysschema = createGroupApi(
882
+ adapter,
883
+ "sysschema",
884
+ this.toolsByGroup.get("sysschema") ?? [],
885
+ );
886
+ this.stats = createGroupApi(
887
+ adapter,
888
+ "stats",
889
+ this.toolsByGroup.get("stats") ?? [],
890
+ );
891
+ this.spatial = createGroupApi(
892
+ adapter,
893
+ "spatial",
894
+ this.toolsByGroup.get("spatial") ?? [],
895
+ );
896
+ this.security = createGroupApi(
897
+ adapter,
898
+ "security",
899
+ this.toolsByGroup.get("security") ?? [],
900
+ );
901
+ this.cluster = createGroupApi(
902
+ adapter,
903
+ "cluster",
904
+ this.toolsByGroup.get("cluster") ?? [],
905
+ );
906
+ this.roles = createGroupApi(
907
+ adapter,
908
+ "roles",
909
+ this.toolsByGroup.get("roles") ?? [],
910
+ );
911
+ this.docstore = createGroupApi(
912
+ adapter,
913
+ "docstore",
914
+ this.toolsByGroup.get("docstore") ?? [],
915
+ );
916
+ }
917
+
918
+ /**
919
+ * Group tools by their tool group
920
+ */
921
+ private groupTools(tools: ToolDefinition[]): Map<string, ToolDefinition[]> {
922
+ const grouped = new Map<string, ToolDefinition[]>();
923
+
924
+ for (const tool of tools) {
925
+ const group = tool.group;
926
+ const existing = grouped.get(group);
927
+ if (existing) {
928
+ existing.push(tool);
929
+ } else {
930
+ grouped.set(group, [tool]);
931
+ }
932
+ }
933
+
934
+ return grouped;
935
+ }
936
+
937
+ /**
938
+ * Get list of available groups and their method counts
939
+ */
940
+ getAvailableGroups(): Record<string, number> {
941
+ const groups: Record<string, number> = {};
942
+ for (const [group, tools] of this.toolsByGroup) {
943
+ groups[group] = tools.length;
944
+ }
945
+ return groups;
946
+ }
947
+
948
+ /**
949
+ * Get list of methods available in a group
950
+ */
951
+ getGroupMethods(groupName: string): string[] {
952
+ const groupApi = this[groupName as keyof MysqlApi];
953
+ if (typeof groupApi === "object" && groupApi !== null) {
954
+ return Object.keys(groupApi as Record<string, unknown>);
955
+ }
956
+ return [];
957
+ }
958
+
959
+ /**
960
+ * Get help information listing all groups and their methods.
961
+ * Call mysql.help() in code mode to discover available APIs.
962
+ *
963
+ * @returns Object with group names as keys and arrays of method names as values
964
+ */
965
+ help(): Record<string, string[]> {
966
+ const result: Record<string, string[]> = {};
967
+ for (const [group, tools] of this.toolsByGroup) {
968
+ // Skip codemode group itself
969
+ if (group === "codemode") continue;
970
+ result[group] = tools.map((t) => toolNameToMethodName(t.name, group));
971
+ }
972
+ return result;
973
+ }
974
+
975
+ /**
976
+ * Create a serializable API binding for the sandbox
977
+ * This creates references that can be called from the vm context
978
+ */
979
+ createSandboxBindings(): Record<string, unknown> {
980
+ const bindings: Record<string, unknown> = {};
981
+
982
+ const groupNames = [
983
+ "core",
984
+ "transactions",
985
+ "json",
986
+ "text",
987
+ "fulltext",
988
+ "performance",
989
+ "optimization",
990
+ "admin",
991
+ "monitoring",
992
+ "backup",
993
+ "replication",
994
+ "partitioning",
995
+ "router",
996
+ "proxysql",
997
+ "shell",
998
+ "schema",
999
+ "events",
1000
+ "sysschema",
1001
+ "stats",
1002
+ "spatial",
1003
+ "security",
1004
+ "cluster",
1005
+ "roles",
1006
+ "docstore",
1007
+ ] as const;
1008
+
1009
+ for (const groupName of groupNames) {
1010
+ const groupApi = this[groupName];
1011
+ const allMethodNames = Object.keys(groupApi);
1012
+
1013
+ // Separate canonical methods from aliases for structured help output
1014
+ const aliases = METHOD_ALIASES[groupName] ?? {};
1015
+ const aliasNames = new Set(Object.keys(aliases));
1016
+ const canonicalMethodNames = allMethodNames.filter(
1017
+ (name) => !aliasNames.has(name),
1018
+ );
1019
+
1020
+ // Filter aliases to only show useful shorthand aliases in help output
1021
+ const usefulAliases = allMethodNames.filter((name) => {
1022
+ if (!aliasNames.has(name)) return false;
1023
+ const lowerGroupName = groupName.toLowerCase();
1024
+ const lowerAlias = name.toLowerCase();
1025
+ return !lowerAlias.startsWith(lowerGroupName);
1026
+ });
1027
+
1028
+ // Add all methods plus a 'help' property that lists them
1029
+ bindings[groupName] = {
1030
+ ...groupApi,
1031
+ help: () => ({
1032
+ methods: canonicalMethodNames,
1033
+ methodAliases: usefulAliases,
1034
+ examples: GROUP_EXAMPLES[groupName],
1035
+ }),
1036
+ };
1037
+ }
1038
+
1039
+ // Add top-level help as directly callable mysql.help()
1040
+ bindings["help"] = () => this.help();
1041
+
1042
+ // =========================================================================
1043
+ // Top-level convenience aliases
1044
+ // =========================================================================
1045
+
1046
+ // Core aliases: mysql.readQuery() → mysql.core.readQuery()
1047
+ const coreApi = bindings["core"] as GroupApiRecord | undefined;
1048
+ if (coreApi !== undefined) {
1049
+ // Query tools
1050
+ if (coreApi["readQuery"] !== undefined) {
1051
+ bindings["readQuery"] = coreApi["readQuery"];
1052
+ }
1053
+ if (coreApi["writeQuery"] !== undefined) {
1054
+ bindings["writeQuery"] = coreApi["writeQuery"];
1055
+ }
1056
+ // Table metadata
1057
+ if (coreApi["listTables"] !== undefined) {
1058
+ bindings["listTables"] = coreApi["listTables"];
1059
+ }
1060
+ if (coreApi["describeTable"] !== undefined) {
1061
+ bindings["describeTable"] = coreApi["describeTable"];
1062
+ }
1063
+ // Table DDL
1064
+ if (coreApi["createTable"] !== undefined) {
1065
+ bindings["createTable"] = coreApi["createTable"];
1066
+ }
1067
+ if (coreApi["dropTable"] !== undefined) {
1068
+ bindings["dropTable"] = coreApi["dropTable"];
1069
+ }
1070
+ // Index tools
1071
+ if (coreApi["createIndex"] !== undefined) {
1072
+ bindings["createIndex"] = coreApi["createIndex"];
1073
+ }
1074
+ if (coreApi["getIndexes"] !== undefined) {
1075
+ bindings["getIndexes"] = coreApi["getIndexes"];
1076
+ }
1077
+ }
1078
+
1079
+ // Transaction aliases: mysql.transactionBegin() → mysql.transactions.transactionBegin()
1080
+ const transactionsApi = bindings["transactions"] as
1081
+ | GroupApiRecord
1082
+ | undefined;
1083
+ if (transactionsApi !== undefined) {
1084
+ for (const method of [
1085
+ "transactionBegin",
1086
+ "transactionCommit",
1087
+ "transactionRollback",
1088
+ "transactionSavepoint",
1089
+ "transactionRelease",
1090
+ "transactionRollbackTo",
1091
+ "transactionExecute",
1092
+ ]) {
1093
+ if (transactionsApi[method] !== undefined) {
1094
+ bindings[method] = transactionsApi[method];
1095
+ }
1096
+ }
1097
+ }
1098
+
1099
+ // JSON aliases: mysql.jsonExtract() → mysql.json.extract()
1100
+ const jsonApi = bindings["json"] as GroupApiRecord | undefined;
1101
+ if (jsonApi !== undefined) {
1102
+ for (const method of [
1103
+ "extract",
1104
+ "set",
1105
+ "insert",
1106
+ "remove",
1107
+ "contains",
1108
+ "keys",
1109
+ "replace",
1110
+ "get",
1111
+ "search",
1112
+ "update",
1113
+ "validate",
1114
+ "merge",
1115
+ "diff",
1116
+ "stats",
1117
+ "indexSuggest",
1118
+ "normalize",
1119
+ "arrayAppend",
1120
+ ]) {
1121
+ if (jsonApi[method] !== undefined) {
1122
+ bindings[`json${method.charAt(0).toUpperCase()}${method.slice(1)}`] =
1123
+ jsonApi[method];
1124
+ }
1125
+ }
1126
+ }
1127
+
1128
+ // Performance aliases: mysql.explain() → mysql.performance.explain()
1129
+ const performanceApi = bindings["performance"] as
1130
+ | GroupApiRecord
1131
+ | undefined;
1132
+ if (performanceApi !== undefined) {
1133
+ for (const method of [
1134
+ "explain",
1135
+ "explainAnalyze",
1136
+ "slowQueries",
1137
+ "bufferPoolStats",
1138
+ "innodbStatus",
1139
+ "tableStats",
1140
+ "threadStats",
1141
+ "serverHealth",
1142
+ ]) {
1143
+ if (performanceApi[method] !== undefined) {
1144
+ bindings[method] = performanceApi[method];
1145
+ }
1146
+ }
1147
+ }
1148
+
1149
+ // Admin aliases: mysql.optimizeTable() → mysql.admin.optimizeTable()
1150
+ const adminApi = bindings["admin"] as GroupApiRecord | undefined;
1151
+ if (adminApi !== undefined) {
1152
+ for (const method of [
1153
+ "checkTable",
1154
+ "repairTable",
1155
+ "optimizeTable",
1156
+ "analyzeTable",
1157
+ "flushTables",
1158
+ "killQuery",
1159
+ ]) {
1160
+ if (adminApi[method] !== undefined) {
1161
+ bindings[method] = adminApi[method];
1162
+ }
1163
+ }
1164
+ }
1165
+
1166
+ // Monitoring aliases: mysql.showStatus() → mysql.monitoring.showStatus()
1167
+ const monitoringApi = bindings["monitoring"] as GroupApiRecord | undefined;
1168
+ if (monitoringApi !== undefined) {
1169
+ for (const method of [
1170
+ "showStatus",
1171
+ "showVariables",
1172
+ "showProcesslist",
1173
+ "queryStats",
1174
+ ]) {
1175
+ if (monitoringApi[method] !== undefined) {
1176
+ bindings[method] = monitoringApi[method];
1177
+ }
1178
+ }
1179
+ }
1180
+
1181
+ // Backup aliases: mysql.createDump() → mysql.backup.createDump()
1182
+ const backupApi = bindings["backup"] as GroupApiRecord | undefined;
1183
+ if (backupApi !== undefined) {
1184
+ for (const method of [
1185
+ "createDump",
1186
+ "exportTable",
1187
+ "importData",
1188
+ "restoreDump",
1189
+ ]) {
1190
+ if (backupApi[method] !== undefined) {
1191
+ bindings[method] = backupApi[method];
1192
+ }
1193
+ }
1194
+ }
1195
+
1196
+ // Stats aliases: mysql.descriptive() → mysql.stats.descriptive()
1197
+ const statsApi = bindings["stats"] as GroupApiRecord | undefined;
1198
+ if (statsApi !== undefined) {
1199
+ for (const method of [
1200
+ "descriptive",
1201
+ "percentiles",
1202
+ "correlation",
1203
+ "regression",
1204
+ "timeSeries",
1205
+ "distribution",
1206
+ "histogram",
1207
+ "sampling",
1208
+ ]) {
1209
+ if (statsApi[method] !== undefined) {
1210
+ bindings[method] = statsApi[method];
1211
+ }
1212
+ }
1213
+ }
1214
+
1215
+ return bindings;
1216
+ }
1217
+ }
1218
+
1219
+ /**
1220
+ * Create a MysqlApi instance for an adapter
1221
+ */
1222
+ export function createMysqlApi(adapter: MySQLAdapter): MysqlApi {
1223
+ return new MysqlApi(adapter);
1224
+ }