@neverinfamous/mysql-mcp 2.3.0 → 3.0.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 (347) hide show
  1. package/.dockerignore +1 -0
  2. package/.gitattributes +18 -0
  3. package/.github/workflows/codeql.yml +2 -10
  4. package/.github/workflows/docker-publish.yml +15 -13
  5. package/CHANGELOG.md +287 -1
  6. package/DOCKER_README.md +100 -265
  7. package/Dockerfile +5 -0
  8. package/README.md +124 -59
  9. package/VERSION +1 -1
  10. package/dist/__tests__/mocks/adapter.d.ts.map +1 -1
  11. package/dist/__tests__/mocks/adapter.js +2 -0
  12. package/dist/__tests__/mocks/adapter.js.map +1 -1
  13. package/dist/adapters/DatabaseAdapter.d.ts.map +1 -1
  14. package/dist/adapters/DatabaseAdapter.js +50 -9
  15. package/dist/adapters/DatabaseAdapter.js.map +1 -1
  16. package/dist/adapters/mysql/MySQLAdapter.d.ts +6 -0
  17. package/dist/adapters/mysql/MySQLAdapter.d.ts.map +1 -1
  18. package/dist/adapters/mysql/MySQLAdapter.js +8 -0
  19. package/dist/adapters/mysql/MySQLAdapter.js.map +1 -1
  20. package/dist/adapters/mysql/SchemaManager.js +16 -15
  21. package/dist/adapters/mysql/SchemaManager.js.map +1 -1
  22. package/dist/adapters/mysql/prompts/index.js +10 -20
  23. package/dist/adapters/mysql/prompts/index.js.map +1 -1
  24. package/dist/adapters/mysql/prompts/proxysqlSetup.js +1 -1
  25. package/dist/adapters/mysql/resources/docstore.d.ts.map +1 -1
  26. package/dist/adapters/mysql/resources/docstore.js +10 -7
  27. package/dist/adapters/mysql/resources/docstore.js.map +1 -1
  28. package/dist/adapters/mysql/resources/events.js +11 -8
  29. package/dist/adapters/mysql/resources/events.js.map +1 -1
  30. package/dist/adapters/mysql/resources/indexes.d.ts.map +1 -1
  31. package/dist/adapters/mysql/resources/indexes.js +12 -15
  32. package/dist/adapters/mysql/resources/indexes.js.map +1 -1
  33. package/dist/adapters/mysql/resources/innodb.d.ts.map +1 -1
  34. package/dist/adapters/mysql/resources/innodb.js +20 -17
  35. package/dist/adapters/mysql/resources/innodb.js.map +1 -1
  36. package/dist/adapters/mysql/resources/locks.d.ts.map +1 -1
  37. package/dist/adapters/mysql/resources/locks.js +9 -6
  38. package/dist/adapters/mysql/resources/locks.js.map +1 -1
  39. package/dist/adapters/mysql/resources/performance.d.ts.map +1 -1
  40. package/dist/adapters/mysql/resources/performance.js +15 -15
  41. package/dist/adapters/mysql/resources/performance.js.map +1 -1
  42. package/dist/adapters/mysql/resources/spatial.d.ts.map +1 -1
  43. package/dist/adapters/mysql/resources/spatial.js +9 -6
  44. package/dist/adapters/mysql/resources/spatial.js.map +1 -1
  45. package/dist/adapters/mysql/resources/sysschema.d.ts.map +1 -1
  46. package/dist/adapters/mysql/resources/sysschema.js +12 -9
  47. package/dist/adapters/mysql/resources/sysschema.js.map +1 -1
  48. package/dist/adapters/mysql/tools/admin/backup.d.ts.map +1 -1
  49. package/dist/adapters/mysql/tools/admin/backup.js +170 -121
  50. package/dist/adapters/mysql/tools/admin/backup.js.map +1 -1
  51. package/dist/adapters/mysql/tools/admin/maintenance.d.ts.map +1 -1
  52. package/dist/adapters/mysql/tools/admin/maintenance.js +106 -57
  53. package/dist/adapters/mysql/tools/admin/maintenance.js.map +1 -1
  54. package/dist/adapters/mysql/tools/admin/monitoring.d.ts.map +1 -1
  55. package/dist/adapters/mysql/tools/admin/monitoring.js +183 -101
  56. package/dist/adapters/mysql/tools/admin/monitoring.js.map +1 -1
  57. package/dist/adapters/mysql/tools/cluster/group-replication.d.ts.map +1 -1
  58. package/dist/adapters/mysql/tools/cluster/group-replication.js +164 -120
  59. package/dist/adapters/mysql/tools/cluster/group-replication.js.map +1 -1
  60. package/dist/adapters/mysql/tools/cluster/innodb-cluster.d.ts.map +1 -1
  61. package/dist/adapters/mysql/tools/cluster/innodb-cluster.js +212 -145
  62. package/dist/adapters/mysql/tools/cluster/innodb-cluster.js.map +1 -1
  63. package/dist/adapters/mysql/tools/codemode/index.d.ts.map +1 -1
  64. package/dist/adapters/mysql/tools/codemode/index.js +6 -4
  65. package/dist/adapters/mysql/tools/codemode/index.js.map +1 -1
  66. package/dist/adapters/mysql/tools/core.d.ts.map +1 -1
  67. package/dist/adapters/mysql/tools/core.js +152 -29
  68. package/dist/adapters/mysql/tools/core.js.map +1 -1
  69. package/dist/adapters/mysql/tools/docstore.d.ts.map +1 -1
  70. package/dist/adapters/mysql/tools/docstore.js +340 -163
  71. package/dist/adapters/mysql/tools/docstore.js.map +1 -1
  72. package/dist/adapters/mysql/tools/events.d.ts.map +1 -1
  73. package/dist/adapters/mysql/tools/events.js +284 -198
  74. package/dist/adapters/mysql/tools/events.js.map +1 -1
  75. package/dist/adapters/mysql/tools/json/core.d.ts.map +1 -1
  76. package/dist/adapters/mysql/tools/json/core.js +11 -39
  77. package/dist/adapters/mysql/tools/json/core.js.map +1 -1
  78. package/dist/adapters/mysql/tools/json/enhanced.d.ts.map +1 -1
  79. package/dist/adapters/mysql/tools/json/enhanced.js +15 -33
  80. package/dist/adapters/mysql/tools/json/enhanced.js.map +1 -1
  81. package/dist/adapters/mysql/tools/json/helpers.d.ts.map +1 -1
  82. package/dist/adapters/mysql/tools/json/helpers.js +13 -24
  83. package/dist/adapters/mysql/tools/json/helpers.js.map +1 -1
  84. package/dist/adapters/mysql/tools/partitioning.js +3 -0
  85. package/dist/adapters/mysql/tools/partitioning.js.map +1 -1
  86. package/dist/adapters/mysql/tools/performance/analysis.d.ts.map +1 -1
  87. package/dist/adapters/mysql/tools/performance/analysis.js +89 -60
  88. package/dist/adapters/mysql/tools/performance/analysis.js.map +1 -1
  89. package/dist/adapters/mysql/tools/performance/optimization.d.ts.map +1 -1
  90. package/dist/adapters/mysql/tools/performance/optimization.js +151 -127
  91. package/dist/adapters/mysql/tools/performance/optimization.js.map +1 -1
  92. package/dist/adapters/mysql/tools/proxysql.d.ts +1 -1
  93. package/dist/adapters/mysql/tools/proxysql.d.ts.map +1 -1
  94. package/dist/adapters/mysql/tools/proxysql.js +289 -176
  95. package/dist/adapters/mysql/tools/proxysql.js.map +1 -1
  96. package/dist/adapters/mysql/tools/replication.js +75 -49
  97. package/dist/adapters/mysql/tools/replication.js.map +1 -1
  98. package/dist/adapters/mysql/tools/roles.d.ts.map +1 -1
  99. package/dist/adapters/mysql/tools/roles.js +224 -182
  100. package/dist/adapters/mysql/tools/roles.js.map +1 -1
  101. package/dist/adapters/mysql/tools/router.d.ts.map +1 -1
  102. package/dist/adapters/mysql/tools/router.js +168 -67
  103. package/dist/adapters/mysql/tools/router.js.map +1 -1
  104. package/dist/adapters/mysql/tools/schema/constraints.d.ts.map +1 -1
  105. package/dist/adapters/mysql/tools/schema/constraints.js +21 -3
  106. package/dist/adapters/mysql/tools/schema/constraints.js.map +1 -1
  107. package/dist/adapters/mysql/tools/schema/management.d.ts.map +1 -1
  108. package/dist/adapters/mysql/tools/schema/management.js +61 -14
  109. package/dist/adapters/mysql/tools/schema/management.js.map +1 -1
  110. package/dist/adapters/mysql/tools/schema/routines.d.ts.map +1 -1
  111. package/dist/adapters/mysql/tools/schema/routines.js +27 -4
  112. package/dist/adapters/mysql/tools/schema/routines.js.map +1 -1
  113. package/dist/adapters/mysql/tools/schema/scheduled_events.d.ts.map +1 -1
  114. package/dist/adapters/mysql/tools/schema/scheduled_events.js +24 -3
  115. package/dist/adapters/mysql/tools/schema/scheduled_events.js.map +1 -1
  116. package/dist/adapters/mysql/tools/schema/triggers.d.ts.map +1 -1
  117. package/dist/adapters/mysql/tools/schema/triggers.js +23 -2
  118. package/dist/adapters/mysql/tools/schema/triggers.js.map +1 -1
  119. package/dist/adapters/mysql/tools/schema/views.d.ts.map +1 -1
  120. package/dist/adapters/mysql/tools/schema/views.js +47 -7
  121. package/dist/adapters/mysql/tools/schema/views.js.map +1 -1
  122. package/dist/adapters/mysql/tools/security/audit.d.ts.map +1 -1
  123. package/dist/adapters/mysql/tools/security/audit.js +102 -34
  124. package/dist/adapters/mysql/tools/security/audit.js.map +1 -1
  125. package/dist/adapters/mysql/tools/security/data-protection.d.ts.map +1 -1
  126. package/dist/adapters/mysql/tools/security/data-protection.js +264 -205
  127. package/dist/adapters/mysql/tools/security/data-protection.js.map +1 -1
  128. package/dist/adapters/mysql/tools/security/encryption.d.ts.map +1 -1
  129. package/dist/adapters/mysql/tools/security/encryption.js +137 -104
  130. package/dist/adapters/mysql/tools/security/encryption.js.map +1 -1
  131. package/dist/adapters/mysql/tools/shell/backup.d.ts.map +1 -1
  132. package/dist/adapters/mysql/tools/shell/backup.js +71 -59
  133. package/dist/adapters/mysql/tools/shell/backup.js.map +1 -1
  134. package/dist/adapters/mysql/tools/shell/restore.d.ts.map +1 -1
  135. package/dist/adapters/mysql/tools/shell/restore.js +61 -47
  136. package/dist/adapters/mysql/tools/shell/restore.js.map +1 -1
  137. package/dist/adapters/mysql/tools/spatial/geometry.d.ts.map +1 -1
  138. package/dist/adapters/mysql/tools/spatial/geometry.js +19 -5
  139. package/dist/adapters/mysql/tools/spatial/geometry.js.map +1 -1
  140. package/dist/adapters/mysql/tools/spatial/operations.d.ts.map +1 -1
  141. package/dist/adapters/mysql/tools/spatial/operations.js +42 -17
  142. package/dist/adapters/mysql/tools/spatial/operations.js.map +1 -1
  143. package/dist/adapters/mysql/tools/spatial/queries.d.ts.map +1 -1
  144. package/dist/adapters/mysql/tools/spatial/queries.js +109 -57
  145. package/dist/adapters/mysql/tools/spatial/queries.js.map +1 -1
  146. package/dist/adapters/mysql/tools/spatial/setup.d.ts.map +1 -1
  147. package/dist/adapters/mysql/tools/spatial/setup.js +103 -50
  148. package/dist/adapters/mysql/tools/spatial/setup.js.map +1 -1
  149. package/dist/adapters/mysql/tools/stats/comparative.d.ts.map +1 -1
  150. package/dist/adapters/mysql/tools/stats/comparative.js +128 -79
  151. package/dist/adapters/mysql/tools/stats/comparative.js.map +1 -1
  152. package/dist/adapters/mysql/tools/stats/descriptive.d.ts.map +1 -1
  153. package/dist/adapters/mysql/tools/stats/descriptive.js +174 -102
  154. package/dist/adapters/mysql/tools/stats/descriptive.js.map +1 -1
  155. package/dist/adapters/mysql/tools/sysschema/activity.d.ts.map +1 -1
  156. package/dist/adapters/mysql/tools/sysschema/activity.js +50 -25
  157. package/dist/adapters/mysql/tools/sysschema/activity.js.map +1 -1
  158. package/dist/adapters/mysql/tools/sysschema/performance.d.ts.map +1 -1
  159. package/dist/adapters/mysql/tools/sysschema/performance.js +121 -66
  160. package/dist/adapters/mysql/tools/sysschema/performance.js.map +1 -1
  161. package/dist/adapters/mysql/tools/sysschema/resources.d.ts.map +1 -1
  162. package/dist/adapters/mysql/tools/sysschema/resources.js +101 -64
  163. package/dist/adapters/mysql/tools/sysschema/resources.js.map +1 -1
  164. package/dist/adapters/mysql/tools/text/fulltext.d.ts.map +1 -1
  165. package/dist/adapters/mysql/tools/text/fulltext.js +18 -32
  166. package/dist/adapters/mysql/tools/text/fulltext.js.map +1 -1
  167. package/dist/adapters/mysql/tools/transactions.d.ts.map +1 -1
  168. package/dist/adapters/mysql/tools/transactions.js +48 -23
  169. package/dist/adapters/mysql/tools/transactions.js.map +1 -1
  170. package/dist/adapters/mysql/types/proxysql-types.d.ts +15 -0
  171. package/dist/adapters/mysql/types/proxysql-types.d.ts.map +1 -1
  172. package/dist/adapters/mysql/types/proxysql-types.js +33 -1
  173. package/dist/adapters/mysql/types/proxysql-types.js.map +1 -1
  174. package/dist/adapters/mysql/types/router-types.d.ts +1 -1
  175. package/dist/adapters/mysql/types/router-types.js +1 -1
  176. package/dist/adapters/mysql/types/router-types.js.map +1 -1
  177. package/dist/adapters/mysql/types/shell-types.js +2 -2
  178. package/dist/adapters/mysql/types/shell-types.js.map +1 -1
  179. package/dist/adapters/mysql/types.d.ts +485 -21
  180. package/dist/adapters/mysql/types.d.ts.map +1 -1
  181. package/dist/adapters/mysql/types.js +546 -19
  182. package/dist/adapters/mysql/types.js.map +1 -1
  183. package/dist/auth/scopes.js +1 -1
  184. package/dist/auth/scopes.js.map +1 -1
  185. package/dist/codemode/api.d.ts +3 -2
  186. package/dist/codemode/api.d.ts.map +1 -1
  187. package/dist/codemode/api.js +80 -5
  188. package/dist/codemode/api.js.map +1 -1
  189. package/dist/codemode/sandbox-factory.js +1 -1
  190. package/dist/codemode/sandbox-factory.js.map +1 -1
  191. package/dist/codemode/types.d.ts +26 -0
  192. package/dist/codemode/types.d.ts.map +1 -1
  193. package/dist/codemode/types.js +2 -0
  194. package/dist/codemode/types.js.map +1 -1
  195. package/dist/codemode/worker-sandbox.d.ts +4 -2
  196. package/dist/codemode/worker-sandbox.d.ts.map +1 -1
  197. package/dist/codemode/worker-sandbox.js +66 -7
  198. package/dist/codemode/worker-sandbox.js.map +1 -1
  199. package/dist/codemode/worker-script.d.ts +3 -0
  200. package/dist/codemode/worker-script.d.ts.map +1 -1
  201. package/dist/codemode/worker-script.js +128 -75
  202. package/dist/codemode/worker-script.js.map +1 -1
  203. package/dist/constants/ServerInstructions.d.ts +1 -1
  204. package/dist/constants/ServerInstructions.d.ts.map +1 -1
  205. package/dist/constants/ServerInstructions.js +37 -31
  206. package/dist/constants/ServerInstructions.js.map +1 -1
  207. package/dist/filtering/ToolConstants.d.ts +1 -1
  208. package/dist/filtering/ToolConstants.d.ts.map +1 -1
  209. package/dist/filtering/ToolConstants.js +1 -2
  210. package/dist/filtering/ToolConstants.js.map +1 -1
  211. package/dist/pool/ConnectionPool.d.ts.map +1 -1
  212. package/dist/pool/ConnectionPool.js.map +1 -1
  213. package/dist/transports/http.d.ts.map +1 -1
  214. package/dist/transports/http.js +6 -0
  215. package/dist/transports/http.js.map +1 -1
  216. package/dist/utils/validators.d.ts +1 -1
  217. package/dist/utils/validators.d.ts.map +1 -1
  218. package/dist/utils/validators.js.map +1 -1
  219. package/package.json +4 -4
  220. package/releases/v2.3.0-release-notes.md +20 -20
  221. package/releases/v2.3.1-release-notes.md +34 -0
  222. package/releases/v3.0.0-release-notes.md +81 -0
  223. package/src/__tests__/mocks/adapter.ts +3 -0
  224. package/src/__tests__/perf.test.ts +6 -6
  225. package/src/adapters/DatabaseAdapter.ts +58 -9
  226. package/src/adapters/__tests__/DatabaseAdapter.test.ts +89 -8
  227. package/src/adapters/mysql/MySQLAdapter.ts +17 -2
  228. package/src/adapters/mysql/SchemaManager.ts +21 -21
  229. package/src/adapters/mysql/__tests__/MySQLAdapter.test.ts +1 -1
  230. package/src/adapters/mysql/prompts/index.ts +12 -22
  231. package/src/adapters/mysql/prompts/proxysqlSetup.ts +1 -1
  232. package/src/adapters/mysql/resources/docstore.ts +13 -10
  233. package/src/adapters/mysql/resources/events.ts +12 -12
  234. package/src/adapters/mysql/resources/indexes.ts +17 -19
  235. package/src/adapters/mysql/resources/innodb.ts +23 -22
  236. package/src/adapters/mysql/resources/locks.ts +9 -7
  237. package/src/adapters/mysql/resources/performance.ts +23 -18
  238. package/src/adapters/mysql/resources/spatial.ts +9 -7
  239. package/src/adapters/mysql/resources/sysschema.ts +12 -11
  240. package/src/adapters/mysql/tools/__tests__/core.test.ts +126 -55
  241. package/src/adapters/mysql/tools/__tests__/docstore.test.ts +459 -88
  242. package/src/adapters/mysql/tools/__tests__/events.test.ts +281 -103
  243. package/src/adapters/mysql/tools/__tests__/proxysql.test.ts +128 -28
  244. package/src/adapters/mysql/tools/__tests__/replication.test.ts +48 -2
  245. package/src/adapters/mysql/tools/__tests__/roles.test.ts +15 -18
  246. package/src/adapters/mysql/tools/__tests__/router.test.ts +32 -5
  247. package/src/adapters/mysql/tools/__tests__/security.test.ts +126 -2
  248. package/src/adapters/mysql/tools/__tests__/security_injection.test.ts +84 -76
  249. package/src/adapters/mysql/tools/__tests__/security_integration.test.ts +47 -50
  250. package/src/adapters/mysql/tools/__tests__/spatial.test.ts +11 -10
  251. package/src/adapters/mysql/tools/__tests__/spatial_handler.test.ts +54 -38
  252. package/src/adapters/mysql/tools/__tests__/stats.test.ts +285 -152
  253. package/src/adapters/mysql/tools/__tests__/transactions.test.ts +13 -13
  254. package/src/adapters/mysql/tools/admin/__tests__/backup.test.ts +171 -25
  255. package/src/adapters/mysql/tools/admin/__tests__/maintenance.test.ts +240 -4
  256. package/src/adapters/mysql/tools/admin/__tests__/monitoring-summary.test.ts +274 -0
  257. package/src/adapters/mysql/tools/admin/__tests__/monitoring.test.ts +94 -5
  258. package/src/adapters/mysql/tools/admin/backup.ts +193 -143
  259. package/src/adapters/mysql/tools/admin/maintenance.ts +118 -69
  260. package/src/adapters/mysql/tools/admin/monitoring.ts +201 -125
  261. package/src/adapters/mysql/tools/cluster/__tests__/group-replication.test.ts +69 -0
  262. package/src/adapters/mysql/tools/cluster/__tests__/innodb-cluster.test.ts +141 -0
  263. package/src/adapters/mysql/tools/cluster/group-replication.ts +172 -132
  264. package/src/adapters/mysql/tools/cluster/innodb-cluster.ts +231 -157
  265. package/src/adapters/mysql/tools/codemode/__tests__/codemode-tool.test.ts +227 -0
  266. package/src/adapters/mysql/tools/codemode/index.ts +5 -3
  267. package/src/adapters/mysql/tools/core.ts +152 -38
  268. package/src/adapters/mysql/tools/docstore.ts +422 -205
  269. package/src/adapters/mysql/tools/events.ts +334 -233
  270. package/src/adapters/mysql/tools/json/__tests__/core.test.ts +20 -0
  271. package/src/adapters/mysql/tools/json/__tests__/enhanced.test.ts +82 -50
  272. package/src/adapters/mysql/tools/json/__tests__/helpers.test.ts +42 -3
  273. package/src/adapters/mysql/tools/json/core.ts +21 -42
  274. package/src/adapters/mysql/tools/json/enhanced.ts +22 -37
  275. package/src/adapters/mysql/tools/json/helpers.ts +21 -25
  276. package/src/adapters/mysql/tools/partitioning.ts +3 -0
  277. package/src/adapters/mysql/tools/performance/__tests__/analysis.test.ts +98 -5
  278. package/src/adapters/mysql/tools/performance/__tests__/optimization-coverage.test.ts +515 -0
  279. package/src/adapters/mysql/tools/performance/__tests__/optimization.test.ts +187 -0
  280. package/src/adapters/mysql/tools/performance/analysis.ts +95 -69
  281. package/src/adapters/mysql/tools/performance/optimization.ts +182 -153
  282. package/src/adapters/mysql/tools/proxysql.ts +314 -209
  283. package/src/adapters/mysql/tools/replication.ts +84 -57
  284. package/src/adapters/mysql/tools/roles.ts +274 -226
  285. package/src/adapters/mysql/tools/router.ts +181 -85
  286. package/src/adapters/mysql/tools/schema/__tests__/constraints.test.ts +13 -0
  287. package/src/adapters/mysql/tools/schema/__tests__/management.test.ts +60 -25
  288. package/src/adapters/mysql/tools/schema/__tests__/scheduled_events.test.ts +11 -0
  289. package/src/adapters/mysql/tools/schema/__tests__/triggers.test.ts +25 -4
  290. package/src/adapters/mysql/tools/schema/__tests__/views.test.ts +46 -14
  291. package/src/adapters/mysql/tools/schema/constraints.ts +22 -3
  292. package/src/adapters/mysql/tools/schema/management.ts +60 -15
  293. package/src/adapters/mysql/tools/schema/routines.ts +26 -4
  294. package/src/adapters/mysql/tools/schema/scheduled_events.ts +25 -3
  295. package/src/adapters/mysql/tools/schema/triggers.ts +27 -2
  296. package/src/adapters/mysql/tools/schema/views.ts +46 -8
  297. package/src/adapters/mysql/tools/security/__tests__/audit.test.ts +90 -4
  298. package/src/adapters/mysql/tools/security/audit.ts +113 -39
  299. package/src/adapters/mysql/tools/security/data-protection.ts +293 -233
  300. package/src/adapters/mysql/tools/security/encryption.ts +172 -139
  301. package/src/adapters/mysql/tools/shell/__tests__/backup.test.ts +29 -0
  302. package/src/adapters/mysql/tools/shell/backup.ts +90 -73
  303. package/src/adapters/mysql/tools/shell/restore.ts +62 -48
  304. package/src/adapters/mysql/tools/spatial/__tests__/operations.test.ts +22 -14
  305. package/src/adapters/mysql/tools/spatial/__tests__/queries.test.ts +65 -51
  306. package/src/adapters/mysql/tools/spatial/geometry.ts +23 -7
  307. package/src/adapters/mysql/tools/spatial/operations.ts +60 -31
  308. package/src/adapters/mysql/tools/spatial/queries.ts +142 -65
  309. package/src/adapters/mysql/tools/spatial/setup.ts +121 -55
  310. package/src/adapters/mysql/tools/stats/__tests__/comparative.test.ts +12 -10
  311. package/src/adapters/mysql/tools/stats/comparative.ts +150 -98
  312. package/src/adapters/mysql/tools/stats/descriptive.ts +204 -127
  313. package/src/adapters/mysql/tools/sysschema/__tests__/error-paths.test.ts +222 -0
  314. package/src/adapters/mysql/tools/sysschema/__tests__/performance.test.ts +45 -0
  315. package/src/adapters/mysql/tools/sysschema/__tests__/resources.test.ts +6 -3
  316. package/src/adapters/mysql/tools/sysschema/activity.ts +52 -27
  317. package/src/adapters/mysql/tools/sysschema/performance.ts +132 -68
  318. package/src/adapters/mysql/tools/sysschema/resources.ts +105 -67
  319. package/src/adapters/mysql/tools/text/__tests__/fulltext.test.ts +45 -17
  320. package/src/adapters/mysql/tools/text/fulltext.ts +27 -38
  321. package/src/adapters/mysql/tools/transactions.ts +49 -24
  322. package/src/adapters/mysql/types/proxysql-types.ts +38 -1
  323. package/src/adapters/mysql/types/router-types.ts +1 -1
  324. package/src/adapters/mysql/types/shell-types.ts +2 -2
  325. package/src/adapters/mysql/types.ts +632 -19
  326. package/src/auth/__tests__/scopes.test.ts +2 -2
  327. package/src/auth/scopes.ts +1 -1
  328. package/src/codemode/__tests__/api.test.ts +417 -0
  329. package/src/codemode/__tests__/sandbox-factory.test.ts +158 -0
  330. package/src/codemode/__tests__/sandbox.test.ts +301 -0
  331. package/src/codemode/__tests__/security.test.ts +368 -0
  332. package/src/codemode/__tests__/worker-sandbox.test.ts +179 -0
  333. package/src/codemode/__tests__/worker-script.test.ts +226 -0
  334. package/src/codemode/api.ts +89 -5
  335. package/src/codemode/sandbox-factory.ts +1 -1
  336. package/src/codemode/types.ts +34 -0
  337. package/src/codemode/worker-sandbox.ts +74 -7
  338. package/src/codemode/worker-script.ts +157 -86
  339. package/src/constants/ServerInstructions.ts +37 -31
  340. package/src/filtering/ToolConstants.ts +1 -2
  341. package/src/filtering/__tests__/ToolFilter.test.ts +9 -9
  342. package/src/pool/ConnectionPool.ts +4 -1
  343. package/src/transports/__tests__/http.test.ts +15 -3
  344. package/src/transports/http.ts +12 -0
  345. package/src/utils/validators.ts +2 -1
  346. package/vitest.config.ts +3 -1
  347. package/CODE_MODE.md +0 -245
@@ -1,6 +1,9 @@
1
1
  import { describe, it, expect, vi, beforeEach, type Mock } from "vitest";
2
2
  import {
3
3
  createGRStatusTool,
4
+ createGRMembersTool,
5
+ createGRPrimaryTool,
6
+ createGRTransactionsTool,
4
7
  createGRFlowControlTool,
5
8
  } from "../group-replication.js";
6
9
  import { MySQLAdapter } from "../../../MySQLAdapter.js";
@@ -216,3 +219,69 @@ describe("Group Replication Tools", () => {
216
219
  });
217
220
  });
218
221
  });
222
+
223
+ describe("Group Replication Tools - Error Handling", () => {
224
+ let mockAdapter: MySQLAdapter;
225
+ let mockExecuteQuery: Mock;
226
+
227
+ beforeEach(() => {
228
+ mockExecuteQuery = vi.fn();
229
+ mockAdapter = {
230
+ executeQuery: mockExecuteQuery,
231
+ } as unknown as MySQLAdapter;
232
+ });
233
+
234
+ it("mysql_gr_status should return structured error when query fails", async () => {
235
+ const tool = createGRStatusTool(mockAdapter);
236
+ mockExecuteQuery.mockRejectedValue(new Error("Connection refused"));
237
+
238
+ const result = (await tool.handler({}, {} as any)) as any;
239
+
240
+ expect(result.enabled).toBe(false);
241
+ expect(result.error).toBe("Connection refused");
242
+ });
243
+
244
+ it("mysql_gr_members should return structured error when query fails", async () => {
245
+ const tool = createGRMembersTool(mockAdapter);
246
+ mockExecuteQuery.mockRejectedValue(new Error("Access denied"));
247
+
248
+ const result = (await tool.handler({}, {} as any)) as any;
249
+
250
+ expect(result.members).toEqual([]);
251
+ expect(result.count).toBe(0);
252
+ expect(result.error).toBe("Access denied");
253
+ });
254
+
255
+ it("mysql_gr_primary should return structured error when query fails", async () => {
256
+ const tool = createGRPrimaryTool(mockAdapter);
257
+ mockExecuteQuery.mockRejectedValue(new Error("Connection lost"));
258
+
259
+ const result = (await tool.handler({}, {} as any)) as any;
260
+
261
+ expect(result.hasPrimary).toBe(false);
262
+ expect(result.error).toBe("Connection lost");
263
+ });
264
+
265
+ it("mysql_gr_transactions should return structured error when query fails", async () => {
266
+ const tool = createGRTransactionsTool(mockAdapter);
267
+ mockExecuteQuery.mockRejectedValue(new Error("Permission denied"));
268
+
269
+ const result = (await tool.handler({}, {} as any)) as any;
270
+
271
+ expect(result.memberStats).toEqual([]);
272
+ expect(result.gtid).toEqual({ executed: "", purged: "" });
273
+ expect(result.error).toBe("Permission denied");
274
+ });
275
+
276
+ it("mysql_gr_flow_control should return structured error when query fails", async () => {
277
+ const tool = createGRFlowControlTool(mockAdapter);
278
+ mockExecuteQuery.mockRejectedValue(new Error("Timeout"));
279
+
280
+ const result = (await tool.handler({}, {} as any)) as any;
281
+
282
+ expect(result.configuration).toEqual({});
283
+ expect(result.memberQueues).toEqual([]);
284
+ expect(result.isThrottling).toBe(false);
285
+ expect(result.error).toBe("Timeout");
286
+ });
287
+ });
@@ -125,6 +125,22 @@ describe("InnoDB Cluster Tools", () => {
125
125
  });
126
126
 
127
127
  describe("createClusterInstancesTool", () => {
128
+ it("should include primaryError when both queries fail", async () => {
129
+ mockAdapter.executeQuery
130
+ .mockRejectedValueOnce(new Error("Metadata query failed")) // Primary fails
131
+ .mockRejectedValueOnce(new Error("GR query also failed")); // Fallback fails
132
+
133
+ const tool = createClusterInstancesTool(
134
+ mockAdapter as unknown as MySQLAdapter,
135
+ );
136
+ const result = (await tool.handler({ limit: 10 }, mockContext)) as any;
137
+
138
+ expect(result.instances).toEqual([]);
139
+ expect(result.count).toBe(0);
140
+ expect(result.error).toBe("GR query also failed");
141
+ expect(result.primaryError).toBe("Metadata query failed");
142
+ });
143
+
128
144
  it("should fallback to GR members when InnoDB Cluster metadata query fails", async () => {
129
145
  mockAdapter.executeQuery
130
146
  .mockRejectedValueOnce(new Error("Table not found")) // First query fails
@@ -388,11 +404,36 @@ describe("InnoDB Cluster Tools", () => {
388
404
 
389
405
  expect(result.canSwitchover).toBe(false);
390
406
  expect(result.candidates).toHaveLength(0);
407
+ expect(result.currentPrimary).toBeDefined();
391
408
  expect(result.warning).toBe(
392
409
  "No online secondaries available for switchover.",
393
410
  );
394
411
  });
395
412
 
413
+ it("should return currentPrimary as null when no primary exists", async () => {
414
+ mockAdapter.executeQuery.mockResolvedValueOnce(
415
+ createMockQueryResult([
416
+ {
417
+ memberId: "uuid1",
418
+ host: "node1",
419
+ port: 3306,
420
+ state: "OFFLINE",
421
+ role: "SECONDARY",
422
+ version: "9.2.0",
423
+ txQueue: 0,
424
+ applierQueue: 0,
425
+ },
426
+ ]),
427
+ );
428
+
429
+ const tool = createClusterSwitchoverTool(
430
+ mockAdapter as unknown as MySQLAdapter,
431
+ );
432
+ const result = (await tool.handler({}, mockContext)) as any;
433
+
434
+ expect(result.currentPrimary).toBeNull();
435
+ });
436
+
396
437
  it("should recommend good switchover candidate", async () => {
397
438
  mockAdapter.executeQuery.mockResolvedValueOnce(
398
439
  createMockQueryResult([
@@ -431,4 +472,104 @@ describe("InnoDB Cluster Tools", () => {
431
472
  expect(result.warning).toBeUndefined();
432
473
  });
433
474
  });
475
+
476
+ describe("createClusterTopologyTool - error handling", () => {
477
+ it("should return structured error when first query fails", async () => {
478
+ mockAdapter.executeQuery.mockRejectedValue(
479
+ new Error("Connection refused"),
480
+ );
481
+
482
+ const tool = createClusterTopologyTool(
483
+ mockAdapter as unknown as MySQLAdapter,
484
+ );
485
+ const result = (await tool.handler({}, mockContext)) as any;
486
+
487
+ expect(result.topology).toEqual({
488
+ primary: [],
489
+ secondaries: [],
490
+ recovering: [],
491
+ offline: [],
492
+ });
493
+ expect(result.visualization).toBe("");
494
+ expect(result.totalMembers).toBe(0);
495
+ expect(result.onlineMembers).toBe(0);
496
+ expect(result.error).toBe("Connection refused");
497
+ });
498
+ });
499
+
500
+ describe("createClusterSwitchoverTool - error handling", () => {
501
+ it("should return structured error when query fails", async () => {
502
+ mockAdapter.executeQuery.mockRejectedValue(new Error("Access denied"));
503
+
504
+ const tool = createClusterSwitchoverTool(
505
+ mockAdapter as unknown as MySQLAdapter,
506
+ );
507
+ const result = (await tool.handler({}, mockContext)) as any;
508
+
509
+ expect(result.candidates).toEqual([]);
510
+ expect(result.canSwitchover).toBe(false);
511
+ expect(result.error).toBe("Access denied");
512
+ });
513
+ });
514
+
515
+ describe("Zod validation leak prevention", () => {
516
+ it("cluster_status should return structured error for invalid summary type", async () => {
517
+ const tool = createClusterStatusTool(
518
+ mockAdapter as unknown as MySQLAdapter,
519
+ );
520
+ const result = (await tool.handler(
521
+ { summary: "yes" },
522
+ mockContext,
523
+ )) as any;
524
+
525
+ expect(result.isInnoDBCluster).toBe(false);
526
+ expect(result.error).toBeDefined();
527
+ expect(result.error).toContain("expected boolean");
528
+ });
529
+
530
+ it("cluster_instances should return structured error for invalid limit type", async () => {
531
+ const tool = createClusterInstancesTool(
532
+ mockAdapter as unknown as MySQLAdapter,
533
+ );
534
+ const result = (await tool.handler({ limit: "abc" }, mockContext)) as any;
535
+
536
+ expect(result.instances).toEqual([]);
537
+ expect(result.count).toBe(0);
538
+ expect(result.error).toBeDefined();
539
+ expect(result.error).toContain("expected number");
540
+ });
541
+
542
+ it("cluster_instances should return structured error for negative limit", async () => {
543
+ const tool = createClusterInstancesTool(
544
+ mockAdapter as unknown as MySQLAdapter,
545
+ );
546
+ const result = (await tool.handler({ limit: -5 }, mockContext)) as any;
547
+
548
+ expect(result.instances).toEqual([]);
549
+ expect(result.count).toBe(0);
550
+ expect(result.error).toBeDefined();
551
+ });
552
+
553
+ it("cluster_instances should return structured error for float limit", async () => {
554
+ const tool = createClusterInstancesTool(
555
+ mockAdapter as unknown as MySQLAdapter,
556
+ );
557
+ const result = (await tool.handler({ limit: 0.5 }, mockContext)) as any;
558
+
559
+ expect(result.instances).toEqual([]);
560
+ expect(result.count).toBe(0);
561
+ expect(result.error).toBeDefined();
562
+ });
563
+
564
+ it("cluster_router_status should return structured error for invalid summary type", async () => {
565
+ const tool = createClusterRouterStatusTool(
566
+ mockAdapter as unknown as MySQLAdapter,
567
+ );
568
+ const result = (await tool.handler({ summary: 123 }, mockContext)) as any;
569
+
570
+ expect(result.available).toBe(false);
571
+ expect(result.error).toBeDefined();
572
+ expect(result.error).toContain("expected boolean");
573
+ });
574
+ });
434
575
  });
@@ -41,18 +41,19 @@ export function createGRStatusTool(adapter: MySQLAdapter): ToolDefinition {
41
41
  idempotentHint: true,
42
42
  },
43
43
  handler: async (_params: unknown, _context: RequestContext) => {
44
- // Check if GR is running
45
- const pluginResult = await adapter.executeQuery(
46
- "SELECT PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'group_replication'",
47
- );
48
- if (pluginResult.rows?.[0]?.["PLUGIN_STATUS"] !== "ACTIVE") {
49
- return {
50
- enabled: false,
51
- message: "Group Replication plugin is not active",
52
- };
53
- }
44
+ try {
45
+ // Check if GR is running
46
+ const pluginResult = await adapter.executeQuery(
47
+ "SELECT PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'group_replication'",
48
+ );
49
+ if (pluginResult.rows?.[0]?.["PLUGIN_STATUS"] !== "ACTIVE") {
50
+ return {
51
+ enabled: false,
52
+ message: "Group Replication plugin is not active",
53
+ };
54
+ }
54
55
 
55
- const statusResult = await adapter.executeQuery(`
56
+ const statusResult = await adapter.executeQuery(`
56
57
  SELECT
57
58
  @@group_replication_group_name as groupName,
58
59
  @@group_replication_single_primary_mode as singlePrimaryMode,
@@ -61,10 +62,10 @@ export function createGRStatusTool(adapter: MySQLAdapter): ToolDefinition {
61
62
  @@group_replication_bootstrap_group as bootstrapGroup
62
63
  `);
63
64
 
64
- const config = statusResult.rows?.[0];
65
+ const config = statusResult.rows?.[0];
65
66
 
66
- // Get member status from performance_schema
67
- const memberResult = await adapter.executeQuery(`
67
+ // Get member status from performance_schema
68
+ const memberResult = await adapter.executeQuery(`
68
69
  SELECT
69
70
  CHANNEL_NAME,
70
71
  MEMBER_ID,
@@ -76,35 +77,41 @@ export function createGRStatusTool(adapter: MySQLAdapter): ToolDefinition {
76
77
  FROM performance_schema.replication_group_members
77
78
  `);
78
79
 
79
- // Get local member info
80
- const localResult = await adapter.executeQuery(`
80
+ // Get local member info
81
+ const localResult = await adapter.executeQuery(`
81
82
  SELECT @@server_uuid as serverUuid
82
83
  `);
83
84
 
84
- const localUuid = localResult.rows?.[0]?.["serverUuid"] as string;
85
- const members = memberResult.rows ?? [];
86
- const localMember = members.find((m) => m["MEMBER_ID"] === localUuid);
85
+ const localUuid = localResult.rows?.[0]?.["serverUuid"] as string;
86
+ const members = memberResult.rows ?? [];
87
+ const localMember = members.find((m) => m["MEMBER_ID"] === localUuid);
87
88
 
88
- return {
89
- enabled: members.length > 0,
90
- groupName: config?.["groupName"] ?? null,
91
- singlePrimaryMode: config?.["singlePrimaryMode"] === 1,
92
- localAddress: config?.["localAddress"] ?? null,
93
- localMember: localMember ?? null,
94
- memberCount: members.length,
95
- members: members.map((m) => {
96
- const member = m;
97
- return {
98
- id: member["MEMBER_ID"],
99
- host: member["MEMBER_HOST"],
100
- port: member["MEMBER_PORT"],
101
- state: member["MEMBER_STATE"],
102
- role: member["MEMBER_ROLE"],
103
- version: member["MEMBER_VERSION"],
104
- isLocal: member["MEMBER_ID"] === localUuid,
105
- };
106
- }),
107
- };
89
+ return {
90
+ enabled: members.length > 0,
91
+ groupName: config?.["groupName"] ?? null,
92
+ singlePrimaryMode: config?.["singlePrimaryMode"] === 1,
93
+ localAddress: config?.["localAddress"] ?? null,
94
+ localMember: localMember ?? null,
95
+ memberCount: members.length,
96
+ members: members.map((m) => {
97
+ const member = m;
98
+ return {
99
+ id: member["MEMBER_ID"],
100
+ host: member["MEMBER_HOST"],
101
+ port: member["MEMBER_PORT"],
102
+ state: member["MEMBER_STATE"],
103
+ role: member["MEMBER_ROLE"],
104
+ version: member["MEMBER_VERSION"],
105
+ isLocal: member["MEMBER_ID"] === localUuid,
106
+ };
107
+ }),
108
+ };
109
+ } catch (error) {
110
+ return {
111
+ enabled: false,
112
+ error: error instanceof Error ? error.message : String(error),
113
+ };
114
+ }
108
115
  },
109
116
  };
110
117
  }
@@ -126,21 +133,22 @@ export function createGRMembersTool(adapter: MySQLAdapter): ToolDefinition {
126
133
  idempotentHint: true,
127
134
  },
128
135
  handler: async (params: unknown, _context: RequestContext) => {
129
- const { memberId } = MemberSchema.parse(params);
136
+ try {
137
+ const { memberId } = MemberSchema.parse(params);
130
138
 
131
- // Check if GR is running
132
- const pluginResult = await adapter.executeQuery(
133
- "SELECT PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'group_replication'",
134
- );
135
- if (pluginResult.rows?.[0]?.["PLUGIN_STATUS"] !== "ACTIVE") {
136
- return {
137
- members: [],
138
- count: 0,
139
- message: "Group Replication not active",
140
- };
141
- }
139
+ // Check if GR is running
140
+ const pluginResult = await adapter.executeQuery(
141
+ "SELECT PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'group_replication'",
142
+ );
143
+ if (pluginResult.rows?.[0]?.["PLUGIN_STATUS"] !== "ACTIVE") {
144
+ return {
145
+ members: [],
146
+ count: 0,
147
+ message: "Group Replication not active",
148
+ };
149
+ }
142
150
 
143
- let query = `
151
+ let query = `
144
152
  SELECT
145
153
  m.MEMBER_ID as memberId,
146
154
  m.MEMBER_HOST as host,
@@ -157,17 +165,24 @@ export function createGRMembersTool(adapter: MySQLAdapter): ToolDefinition {
157
165
  ON m.MEMBER_ID = s.MEMBER_ID
158
166
  `;
159
167
 
160
- const queryParams: unknown[] = [];
161
- if (memberId) {
162
- query += " WHERE m.MEMBER_ID = ?";
163
- queryParams.push(memberId);
164
- }
168
+ const queryParams: unknown[] = [];
169
+ if (memberId) {
170
+ query += " WHERE m.MEMBER_ID = ?";
171
+ queryParams.push(memberId);
172
+ }
165
173
 
166
- const result = await adapter.executeQuery(query, queryParams);
167
- return {
168
- members: result.rows ?? [],
169
- count: result.rows?.length ?? 0,
170
- };
174
+ const result = await adapter.executeQuery(query, queryParams);
175
+ return {
176
+ members: result.rows ?? [],
177
+ count: result.rows?.length ?? 0,
178
+ };
179
+ } catch (error) {
180
+ return {
181
+ members: [],
182
+ count: 0,
183
+ error: error instanceof Error ? error.message : String(error),
184
+ };
185
+ }
171
186
  },
172
187
  };
173
188
  }
@@ -189,7 +204,8 @@ export function createGRPrimaryTool(adapter: MySQLAdapter): ToolDefinition {
189
204
  idempotentHint: true,
190
205
  },
191
206
  handler: async (_params: unknown, _context: RequestContext) => {
192
- const result = await adapter.executeQuery(`
207
+ try {
208
+ const result = await adapter.executeQuery(`
193
209
  SELECT
194
210
  MEMBER_ID as memberId,
195
211
  MEMBER_HOST as host,
@@ -200,19 +216,25 @@ export function createGRPrimaryTool(adapter: MySQLAdapter): ToolDefinition {
200
216
  WHERE MEMBER_ROLE = 'PRIMARY'
201
217
  `);
202
218
 
203
- const primary = result.rows?.[0];
219
+ const primary = result.rows?.[0];
204
220
 
205
- // Check if we are the primary
206
- const localResult = await adapter.executeQuery(
207
- "SELECT @@server_uuid as serverUuid",
208
- );
209
- const localUuid = localResult.rows?.[0]?.["serverUuid"];
221
+ // Check if we are the primary
222
+ const localResult = await adapter.executeQuery(
223
+ "SELECT @@server_uuid as serverUuid",
224
+ );
225
+ const localUuid = localResult.rows?.[0]?.["serverUuid"];
210
226
 
211
- return {
212
- primary: primary ?? null,
213
- hasPrimary: !!primary,
214
- isLocalPrimary: primary?.["memberId"] === localUuid,
215
- };
227
+ return {
228
+ primary: primary ?? null,
229
+ hasPrimary: !!primary,
230
+ isLocalPrimary: primary?.["memberId"] === localUuid,
231
+ };
232
+ } catch (error) {
233
+ return {
234
+ hasPrimary: false,
235
+ error: error instanceof Error ? error.message : String(error),
236
+ };
237
+ }
216
238
  },
217
239
  };
218
240
  }
@@ -236,20 +258,21 @@ export function createGRTransactionsTool(
236
258
  idempotentHint: true,
237
259
  },
238
260
  handler: async (_params: unknown, _context: RequestContext) => {
239
- // Check if GR is running
240
- const pluginResult = await adapter.executeQuery(
241
- "SELECT PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'group_replication'",
242
- );
243
- if (pluginResult.rows?.[0]?.["PLUGIN_STATUS"] !== "ACTIVE") {
244
- return {
245
- memberStats: [],
246
- gtid: { executed: "", purged: "" },
247
- message: "Group Replication not active",
248
- };
249
- }
261
+ try {
262
+ // Check if GR is running
263
+ const pluginResult = await adapter.executeQuery(
264
+ "SELECT PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'group_replication'",
265
+ );
266
+ if (pluginResult.rows?.[0]?.["PLUGIN_STATUS"] !== "ACTIVE") {
267
+ return {
268
+ memberStats: [],
269
+ gtid: { executed: "", purged: "" },
270
+ message: "Group Replication not active",
271
+ };
272
+ }
250
273
 
251
- // Get transaction statistics
252
- const statsResult = await adapter.executeQuery(`
274
+ // Get transaction statistics
275
+ const statsResult = await adapter.executeQuery(`
253
276
  SELECT
254
277
  MEMBER_ID as memberId,
255
278
  COUNT_TRANSACTIONS_IN_QUEUE as txInQueue,
@@ -263,22 +286,29 @@ export function createGRTransactionsTool(
263
286
  FROM performance_schema.replication_group_member_stats
264
287
  `);
265
288
 
266
- // Get GTID info
267
- const gtidResult = await adapter.executeQuery(`
289
+ // Get GTID info
290
+ const gtidResult = await adapter.executeQuery(`
268
291
  SELECT
269
292
  @@gtid_executed as gtidExecuted,
270
293
  @@gtid_purged as gtidPurged
271
294
  `);
272
295
 
273
- const gtid = gtidResult.rows?.[0];
296
+ const gtid = gtidResult.rows?.[0];
274
297
 
275
- return {
276
- memberStats: statsResult.rows ?? [],
277
- gtid: {
278
- executed: gtid?.["gtidExecuted"] ?? "",
279
- purged: gtid?.["gtidPurged"] ?? "",
280
- },
281
- };
298
+ return {
299
+ memberStats: statsResult.rows ?? [],
300
+ gtid: {
301
+ executed: gtid?.["gtidExecuted"] ?? "",
302
+ purged: gtid?.["gtidPurged"] ?? "",
303
+ },
304
+ };
305
+ } catch (error) {
306
+ return {
307
+ memberStats: [],
308
+ gtid: { executed: "", purged: "" },
309
+ error: error instanceof Error ? error.message : String(error),
310
+ };
311
+ }
282
312
  },
283
313
  };
284
314
  }
@@ -300,21 +330,22 @@ export function createGRFlowControlTool(adapter: MySQLAdapter): ToolDefinition {
300
330
  idempotentHint: true,
301
331
  },
302
332
  handler: async (_params: unknown, _context: RequestContext) => {
303
- // Check if GR is running
304
- const pluginResult = await adapter.executeQuery(
305
- "SELECT PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'group_replication'",
306
- );
307
- if (pluginResult.rows?.[0]?.["PLUGIN_STATUS"] !== "ACTIVE") {
308
- return {
309
- configuration: {},
310
- memberQueues: [],
311
- isThrottling: false,
312
- message: "Group Replication not active",
313
- };
314
- }
333
+ try {
334
+ // Check if GR is running
335
+ const pluginResult = await adapter.executeQuery(
336
+ "SELECT PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'group_replication'",
337
+ );
338
+ if (pluginResult.rows?.[0]?.["PLUGIN_STATUS"] !== "ACTIVE") {
339
+ return {
340
+ configuration: {},
341
+ memberQueues: [],
342
+ isThrottling: false,
343
+ message: "Group Replication not active",
344
+ };
345
+ }
315
346
 
316
- // Get flow control configuration
317
- const configResult = await adapter.executeQuery(`
347
+ // Get flow control configuration
348
+ const configResult = await adapter.executeQuery(`
318
349
  SELECT
319
350
  @@group_replication_flow_control_mode as flowControlMode,
320
351
  @@group_replication_flow_control_certifier_threshold as certifierThreshold,
@@ -324,10 +355,10 @@ export function createGRFlowControlTool(adapter: MySQLAdapter): ToolDefinition {
324
355
  @@group_replication_flow_control_max_quota as maxQuota
325
356
  `);
326
357
 
327
- const config = configResult.rows?.[0];
358
+ const config = configResult.rows?.[0];
328
359
 
329
- // Get current queue depths
330
- const queueResult = await adapter.executeQuery(`
360
+ // Get current queue depths
361
+ const queueResult = await adapter.executeQuery(`
331
362
  SELECT
332
363
  MEMBER_ID as memberId,
333
364
  COUNT_TRANSACTIONS_IN_QUEUE as certifyQueue,
@@ -335,25 +366,34 @@ export function createGRFlowControlTool(adapter: MySQLAdapter): ToolDefinition {
335
366
  FROM performance_schema.replication_group_member_stats
336
367
  `);
337
368
 
338
- // Determine if flow control is active
339
- const isThrottling = (queueResult.rows ?? []).some((row) => {
340
- const r = row;
341
- const certQueue = r["certifyQueue"] as number;
342
- const appQueue = r["applierQueue"] as number;
343
- const certThreshold =
344
- (config?.["certifierThreshold"] as number) ?? 25000;
345
- const appThreshold = (config?.["applierThreshold"] as number) ?? 25000;
346
- return certQueue > certThreshold || appQueue > appThreshold;
347
- });
369
+ // Determine if flow control is active
370
+ const isThrottling = (queueResult.rows ?? []).some((row) => {
371
+ const r = row;
372
+ const certQueue = r["certifyQueue"] as number;
373
+ const appQueue = r["applierQueue"] as number;
374
+ const certThreshold =
375
+ (config?.["certifierThreshold"] as number) ?? 25000;
376
+ const appThreshold =
377
+ (config?.["applierThreshold"] as number) ?? 25000;
378
+ return certQueue > certThreshold || appQueue > appThreshold;
379
+ });
348
380
 
349
- return {
350
- configuration: config ?? {},
351
- memberQueues: queueResult.rows ?? [],
352
- isThrottling,
353
- recommendation: isThrottling
354
- ? "Flow control is active. Consider investigating slow members or adjusting thresholds."
355
- : "Flow control is not currently throttling.",
356
- };
381
+ return {
382
+ configuration: config ?? {},
383
+ memberQueues: queueResult.rows ?? [],
384
+ isThrottling,
385
+ recommendation: isThrottling
386
+ ? "Flow control is active. Consider investigating slow members or adjusting thresholds."
387
+ : "Flow control is not currently throttling.",
388
+ };
389
+ } catch (error) {
390
+ return {
391
+ configuration: {},
392
+ memberQueues: [],
393
+ isThrottling: false,
394
+ error: error instanceof Error ? error.message : String(error),
395
+ };
396
+ }
357
397
  },
358
398
  };
359
399
  }