@neverinfamous/mysql-mcp 2.3.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (345) hide show
  1. package/.dockerignore +1 -0
  2. package/.gitattributes +18 -0
  3. package/.github/workflows/codeql.yml +2 -2
  4. package/.github/workflows/docker-publish.yml +5 -5
  5. package/CHANGELOG.md +348 -122
  6. package/DOCKER_README.md +81 -40
  7. package/README.md +87 -46
  8. package/VERSION +1 -1
  9. package/dist/__tests__/mocks/adapter.d.ts.map +1 -1
  10. package/dist/__tests__/mocks/adapter.js +2 -0
  11. package/dist/__tests__/mocks/adapter.js.map +1 -1
  12. package/dist/adapters/DatabaseAdapter.d.ts.map +1 -1
  13. package/dist/adapters/DatabaseAdapter.js +50 -9
  14. package/dist/adapters/DatabaseAdapter.js.map +1 -1
  15. package/dist/adapters/mysql/MySQLAdapter.d.ts +6 -0
  16. package/dist/adapters/mysql/MySQLAdapter.d.ts.map +1 -1
  17. package/dist/adapters/mysql/MySQLAdapter.js +8 -0
  18. package/dist/adapters/mysql/MySQLAdapter.js.map +1 -1
  19. package/dist/adapters/mysql/SchemaManager.js +16 -15
  20. package/dist/adapters/mysql/SchemaManager.js.map +1 -1
  21. package/dist/adapters/mysql/prompts/index.js +10 -20
  22. package/dist/adapters/mysql/prompts/index.js.map +1 -1
  23. package/dist/adapters/mysql/prompts/proxysqlSetup.js +1 -1
  24. package/dist/adapters/mysql/resources/docstore.d.ts.map +1 -1
  25. package/dist/adapters/mysql/resources/docstore.js +10 -7
  26. package/dist/adapters/mysql/resources/docstore.js.map +1 -1
  27. package/dist/adapters/mysql/resources/events.js +11 -8
  28. package/dist/adapters/mysql/resources/events.js.map +1 -1
  29. package/dist/adapters/mysql/resources/indexes.d.ts.map +1 -1
  30. package/dist/adapters/mysql/resources/indexes.js +12 -15
  31. package/dist/adapters/mysql/resources/indexes.js.map +1 -1
  32. package/dist/adapters/mysql/resources/innodb.d.ts.map +1 -1
  33. package/dist/adapters/mysql/resources/innodb.js +20 -17
  34. package/dist/adapters/mysql/resources/innodb.js.map +1 -1
  35. package/dist/adapters/mysql/resources/locks.d.ts.map +1 -1
  36. package/dist/adapters/mysql/resources/locks.js +9 -6
  37. package/dist/adapters/mysql/resources/locks.js.map +1 -1
  38. package/dist/adapters/mysql/resources/performance.d.ts.map +1 -1
  39. package/dist/adapters/mysql/resources/performance.js +15 -15
  40. package/dist/adapters/mysql/resources/performance.js.map +1 -1
  41. package/dist/adapters/mysql/resources/spatial.d.ts.map +1 -1
  42. package/dist/adapters/mysql/resources/spatial.js +9 -6
  43. package/dist/adapters/mysql/resources/spatial.js.map +1 -1
  44. package/dist/adapters/mysql/resources/sysschema.d.ts.map +1 -1
  45. package/dist/adapters/mysql/resources/sysschema.js +12 -9
  46. package/dist/adapters/mysql/resources/sysschema.js.map +1 -1
  47. package/dist/adapters/mysql/tools/admin/backup.d.ts.map +1 -1
  48. package/dist/adapters/mysql/tools/admin/backup.js +170 -121
  49. package/dist/adapters/mysql/tools/admin/backup.js.map +1 -1
  50. package/dist/adapters/mysql/tools/admin/maintenance.d.ts.map +1 -1
  51. package/dist/adapters/mysql/tools/admin/maintenance.js +106 -57
  52. package/dist/adapters/mysql/tools/admin/maintenance.js.map +1 -1
  53. package/dist/adapters/mysql/tools/admin/monitoring.d.ts.map +1 -1
  54. package/dist/adapters/mysql/tools/admin/monitoring.js +183 -101
  55. package/dist/adapters/mysql/tools/admin/monitoring.js.map +1 -1
  56. package/dist/adapters/mysql/tools/cluster/group-replication.d.ts.map +1 -1
  57. package/dist/adapters/mysql/tools/cluster/group-replication.js +164 -120
  58. package/dist/adapters/mysql/tools/cluster/group-replication.js.map +1 -1
  59. package/dist/adapters/mysql/tools/cluster/innodb-cluster.d.ts.map +1 -1
  60. package/dist/adapters/mysql/tools/cluster/innodb-cluster.js +212 -145
  61. package/dist/adapters/mysql/tools/cluster/innodb-cluster.js.map +1 -1
  62. package/dist/adapters/mysql/tools/codemode/index.d.ts.map +1 -1
  63. package/dist/adapters/mysql/tools/codemode/index.js +6 -4
  64. package/dist/adapters/mysql/tools/codemode/index.js.map +1 -1
  65. package/dist/adapters/mysql/tools/core.d.ts.map +1 -1
  66. package/dist/adapters/mysql/tools/core.js +152 -29
  67. package/dist/adapters/mysql/tools/core.js.map +1 -1
  68. package/dist/adapters/mysql/tools/docstore.d.ts.map +1 -1
  69. package/dist/adapters/mysql/tools/docstore.js +340 -163
  70. package/dist/adapters/mysql/tools/docstore.js.map +1 -1
  71. package/dist/adapters/mysql/tools/events.d.ts.map +1 -1
  72. package/dist/adapters/mysql/tools/events.js +284 -198
  73. package/dist/adapters/mysql/tools/events.js.map +1 -1
  74. package/dist/adapters/mysql/tools/json/core.d.ts.map +1 -1
  75. package/dist/adapters/mysql/tools/json/core.js +11 -39
  76. package/dist/adapters/mysql/tools/json/core.js.map +1 -1
  77. package/dist/adapters/mysql/tools/json/enhanced.d.ts.map +1 -1
  78. package/dist/adapters/mysql/tools/json/enhanced.js +15 -33
  79. package/dist/adapters/mysql/tools/json/enhanced.js.map +1 -1
  80. package/dist/adapters/mysql/tools/json/helpers.d.ts.map +1 -1
  81. package/dist/adapters/mysql/tools/json/helpers.js +13 -24
  82. package/dist/adapters/mysql/tools/json/helpers.js.map +1 -1
  83. package/dist/adapters/mysql/tools/partitioning.js +3 -0
  84. package/dist/adapters/mysql/tools/partitioning.js.map +1 -1
  85. package/dist/adapters/mysql/tools/performance/analysis.d.ts.map +1 -1
  86. package/dist/adapters/mysql/tools/performance/analysis.js +89 -60
  87. package/dist/adapters/mysql/tools/performance/analysis.js.map +1 -1
  88. package/dist/adapters/mysql/tools/performance/optimization.d.ts.map +1 -1
  89. package/dist/adapters/mysql/tools/performance/optimization.js +151 -127
  90. package/dist/adapters/mysql/tools/performance/optimization.js.map +1 -1
  91. package/dist/adapters/mysql/tools/proxysql.d.ts +1 -1
  92. package/dist/adapters/mysql/tools/proxysql.d.ts.map +1 -1
  93. package/dist/adapters/mysql/tools/proxysql.js +289 -176
  94. package/dist/adapters/mysql/tools/proxysql.js.map +1 -1
  95. package/dist/adapters/mysql/tools/replication.js +75 -49
  96. package/dist/adapters/mysql/tools/replication.js.map +1 -1
  97. package/dist/adapters/mysql/tools/roles.d.ts.map +1 -1
  98. package/dist/adapters/mysql/tools/roles.js +224 -182
  99. package/dist/adapters/mysql/tools/roles.js.map +1 -1
  100. package/dist/adapters/mysql/tools/router.d.ts.map +1 -1
  101. package/dist/adapters/mysql/tools/router.js +168 -67
  102. package/dist/adapters/mysql/tools/router.js.map +1 -1
  103. package/dist/adapters/mysql/tools/schema/constraints.d.ts.map +1 -1
  104. package/dist/adapters/mysql/tools/schema/constraints.js +21 -3
  105. package/dist/adapters/mysql/tools/schema/constraints.js.map +1 -1
  106. package/dist/adapters/mysql/tools/schema/management.d.ts.map +1 -1
  107. package/dist/adapters/mysql/tools/schema/management.js +61 -14
  108. package/dist/adapters/mysql/tools/schema/management.js.map +1 -1
  109. package/dist/adapters/mysql/tools/schema/routines.d.ts.map +1 -1
  110. package/dist/adapters/mysql/tools/schema/routines.js +27 -4
  111. package/dist/adapters/mysql/tools/schema/routines.js.map +1 -1
  112. package/dist/adapters/mysql/tools/schema/scheduled_events.d.ts.map +1 -1
  113. package/dist/adapters/mysql/tools/schema/scheduled_events.js +24 -3
  114. package/dist/adapters/mysql/tools/schema/scheduled_events.js.map +1 -1
  115. package/dist/adapters/mysql/tools/schema/triggers.d.ts.map +1 -1
  116. package/dist/adapters/mysql/tools/schema/triggers.js +23 -2
  117. package/dist/adapters/mysql/tools/schema/triggers.js.map +1 -1
  118. package/dist/adapters/mysql/tools/schema/views.d.ts.map +1 -1
  119. package/dist/adapters/mysql/tools/schema/views.js +47 -7
  120. package/dist/adapters/mysql/tools/schema/views.js.map +1 -1
  121. package/dist/adapters/mysql/tools/security/audit.d.ts.map +1 -1
  122. package/dist/adapters/mysql/tools/security/audit.js +102 -34
  123. package/dist/adapters/mysql/tools/security/audit.js.map +1 -1
  124. package/dist/adapters/mysql/tools/security/data-protection.d.ts.map +1 -1
  125. package/dist/adapters/mysql/tools/security/data-protection.js +264 -205
  126. package/dist/adapters/mysql/tools/security/data-protection.js.map +1 -1
  127. package/dist/adapters/mysql/tools/security/encryption.d.ts.map +1 -1
  128. package/dist/adapters/mysql/tools/security/encryption.js +137 -104
  129. package/dist/adapters/mysql/tools/security/encryption.js.map +1 -1
  130. package/dist/adapters/mysql/tools/shell/backup.d.ts.map +1 -1
  131. package/dist/adapters/mysql/tools/shell/backup.js +71 -59
  132. package/dist/adapters/mysql/tools/shell/backup.js.map +1 -1
  133. package/dist/adapters/mysql/tools/shell/restore.d.ts.map +1 -1
  134. package/dist/adapters/mysql/tools/shell/restore.js +61 -47
  135. package/dist/adapters/mysql/tools/shell/restore.js.map +1 -1
  136. package/dist/adapters/mysql/tools/spatial/geometry.d.ts.map +1 -1
  137. package/dist/adapters/mysql/tools/spatial/geometry.js +19 -5
  138. package/dist/adapters/mysql/tools/spatial/geometry.js.map +1 -1
  139. package/dist/adapters/mysql/tools/spatial/operations.d.ts.map +1 -1
  140. package/dist/adapters/mysql/tools/spatial/operations.js +42 -17
  141. package/dist/adapters/mysql/tools/spatial/operations.js.map +1 -1
  142. package/dist/adapters/mysql/tools/spatial/queries.d.ts.map +1 -1
  143. package/dist/adapters/mysql/tools/spatial/queries.js +109 -57
  144. package/dist/adapters/mysql/tools/spatial/queries.js.map +1 -1
  145. package/dist/adapters/mysql/tools/spatial/setup.d.ts.map +1 -1
  146. package/dist/adapters/mysql/tools/spatial/setup.js +103 -50
  147. package/dist/adapters/mysql/tools/spatial/setup.js.map +1 -1
  148. package/dist/adapters/mysql/tools/stats/comparative.d.ts.map +1 -1
  149. package/dist/adapters/mysql/tools/stats/comparative.js +128 -79
  150. package/dist/adapters/mysql/tools/stats/comparative.js.map +1 -1
  151. package/dist/adapters/mysql/tools/stats/descriptive.d.ts.map +1 -1
  152. package/dist/adapters/mysql/tools/stats/descriptive.js +174 -102
  153. package/dist/adapters/mysql/tools/stats/descriptive.js.map +1 -1
  154. package/dist/adapters/mysql/tools/sysschema/activity.d.ts.map +1 -1
  155. package/dist/adapters/mysql/tools/sysschema/activity.js +50 -25
  156. package/dist/adapters/mysql/tools/sysschema/activity.js.map +1 -1
  157. package/dist/adapters/mysql/tools/sysschema/performance.d.ts.map +1 -1
  158. package/dist/adapters/mysql/tools/sysschema/performance.js +121 -66
  159. package/dist/adapters/mysql/tools/sysschema/performance.js.map +1 -1
  160. package/dist/adapters/mysql/tools/sysschema/resources.d.ts.map +1 -1
  161. package/dist/adapters/mysql/tools/sysschema/resources.js +101 -64
  162. package/dist/adapters/mysql/tools/sysschema/resources.js.map +1 -1
  163. package/dist/adapters/mysql/tools/text/fulltext.d.ts.map +1 -1
  164. package/dist/adapters/mysql/tools/text/fulltext.js +18 -32
  165. package/dist/adapters/mysql/tools/text/fulltext.js.map +1 -1
  166. package/dist/adapters/mysql/tools/transactions.d.ts.map +1 -1
  167. package/dist/adapters/mysql/tools/transactions.js +48 -23
  168. package/dist/adapters/mysql/tools/transactions.js.map +1 -1
  169. package/dist/adapters/mysql/types/proxysql-types.d.ts +15 -0
  170. package/dist/adapters/mysql/types/proxysql-types.d.ts.map +1 -1
  171. package/dist/adapters/mysql/types/proxysql-types.js +33 -1
  172. package/dist/adapters/mysql/types/proxysql-types.js.map +1 -1
  173. package/dist/adapters/mysql/types/router-types.d.ts +1 -1
  174. package/dist/adapters/mysql/types/router-types.js +1 -1
  175. package/dist/adapters/mysql/types/router-types.js.map +1 -1
  176. package/dist/adapters/mysql/types/shell-types.js +2 -2
  177. package/dist/adapters/mysql/types/shell-types.js.map +1 -1
  178. package/dist/adapters/mysql/types.d.ts +485 -21
  179. package/dist/adapters/mysql/types.d.ts.map +1 -1
  180. package/dist/adapters/mysql/types.js +546 -19
  181. package/dist/adapters/mysql/types.js.map +1 -1
  182. package/dist/auth/scopes.js +1 -1
  183. package/dist/auth/scopes.js.map +1 -1
  184. package/dist/codemode/api.d.ts +3 -2
  185. package/dist/codemode/api.d.ts.map +1 -1
  186. package/dist/codemode/api.js +80 -5
  187. package/dist/codemode/api.js.map +1 -1
  188. package/dist/codemode/sandbox-factory.js +1 -1
  189. package/dist/codemode/sandbox-factory.js.map +1 -1
  190. package/dist/codemode/types.d.ts +26 -0
  191. package/dist/codemode/types.d.ts.map +1 -1
  192. package/dist/codemode/types.js +2 -0
  193. package/dist/codemode/types.js.map +1 -1
  194. package/dist/codemode/worker-sandbox.d.ts +4 -2
  195. package/dist/codemode/worker-sandbox.d.ts.map +1 -1
  196. package/dist/codemode/worker-sandbox.js +66 -7
  197. package/dist/codemode/worker-sandbox.js.map +1 -1
  198. package/dist/codemode/worker-script.d.ts +3 -0
  199. package/dist/codemode/worker-script.d.ts.map +1 -1
  200. package/dist/codemode/worker-script.js +128 -75
  201. package/dist/codemode/worker-script.js.map +1 -1
  202. package/dist/constants/ServerInstructions.d.ts +1 -1
  203. package/dist/constants/ServerInstructions.d.ts.map +1 -1
  204. package/dist/constants/ServerInstructions.js +37 -31
  205. package/dist/constants/ServerInstructions.js.map +1 -1
  206. package/dist/filtering/ToolConstants.d.ts +1 -1
  207. package/dist/filtering/ToolConstants.d.ts.map +1 -1
  208. package/dist/filtering/ToolConstants.js +1 -2
  209. package/dist/filtering/ToolConstants.js.map +1 -1
  210. package/dist/pool/ConnectionPool.d.ts.map +1 -1
  211. package/dist/pool/ConnectionPool.js.map +1 -1
  212. package/dist/transports/http.d.ts.map +1 -1
  213. package/dist/transports/http.js +6 -0
  214. package/dist/transports/http.js.map +1 -1
  215. package/dist/utils/validators.d.ts +1 -1
  216. package/dist/utils/validators.d.ts.map +1 -1
  217. package/dist/utils/validators.js.map +1 -1
  218. package/package.json +4 -4
  219. package/releases/v3.0.0-release-notes.md +81 -0
  220. package/releases/v3.0.1-release-notes.md +20 -0
  221. package/src/__tests__/mocks/adapter.ts +3 -0
  222. package/src/__tests__/perf.test.ts +6 -6
  223. package/src/adapters/DatabaseAdapter.ts +58 -9
  224. package/src/adapters/__tests__/DatabaseAdapter.test.ts +89 -8
  225. package/src/adapters/mysql/MySQLAdapter.ts +17 -2
  226. package/src/adapters/mysql/SchemaManager.ts +21 -21
  227. package/src/adapters/mysql/__tests__/MySQLAdapter.test.ts +1 -1
  228. package/src/adapters/mysql/prompts/index.ts +12 -22
  229. package/src/adapters/mysql/prompts/proxysqlSetup.ts +1 -1
  230. package/src/adapters/mysql/resources/docstore.ts +13 -10
  231. package/src/adapters/mysql/resources/events.ts +12 -12
  232. package/src/adapters/mysql/resources/indexes.ts +17 -19
  233. package/src/adapters/mysql/resources/innodb.ts +23 -22
  234. package/src/adapters/mysql/resources/locks.ts +9 -7
  235. package/src/adapters/mysql/resources/performance.ts +23 -18
  236. package/src/adapters/mysql/resources/spatial.ts +9 -7
  237. package/src/adapters/mysql/resources/sysschema.ts +12 -11
  238. package/src/adapters/mysql/tools/__tests__/core.test.ts +126 -55
  239. package/src/adapters/mysql/tools/__tests__/docstore.test.ts +459 -88
  240. package/src/adapters/mysql/tools/__tests__/events.test.ts +281 -103
  241. package/src/adapters/mysql/tools/__tests__/proxysql.test.ts +128 -28
  242. package/src/adapters/mysql/tools/__tests__/replication.test.ts +48 -2
  243. package/src/adapters/mysql/tools/__tests__/roles.test.ts +15 -18
  244. package/src/adapters/mysql/tools/__tests__/router.test.ts +32 -5
  245. package/src/adapters/mysql/tools/__tests__/security.test.ts +126 -2
  246. package/src/adapters/mysql/tools/__tests__/security_injection.test.ts +84 -76
  247. package/src/adapters/mysql/tools/__tests__/security_integration.test.ts +47 -51
  248. package/src/adapters/mysql/tools/__tests__/spatial.test.ts +11 -10
  249. package/src/adapters/mysql/tools/__tests__/spatial_handler.test.ts +54 -38
  250. package/src/adapters/mysql/tools/__tests__/stats.test.ts +285 -152
  251. package/src/adapters/mysql/tools/__tests__/transactions.test.ts +13 -13
  252. package/src/adapters/mysql/tools/admin/__tests__/backup.test.ts +171 -25
  253. package/src/adapters/mysql/tools/admin/__tests__/maintenance.test.ts +240 -4
  254. package/src/adapters/mysql/tools/admin/__tests__/monitoring-summary.test.ts +274 -0
  255. package/src/adapters/mysql/tools/admin/__tests__/monitoring.test.ts +94 -5
  256. package/src/adapters/mysql/tools/admin/backup.ts +193 -143
  257. package/src/adapters/mysql/tools/admin/maintenance.ts +118 -69
  258. package/src/adapters/mysql/tools/admin/monitoring.ts +201 -125
  259. package/src/adapters/mysql/tools/cluster/__tests__/group-replication.test.ts +69 -0
  260. package/src/adapters/mysql/tools/cluster/__tests__/innodb-cluster.test.ts +141 -0
  261. package/src/adapters/mysql/tools/cluster/group-replication.ts +172 -132
  262. package/src/adapters/mysql/tools/cluster/innodb-cluster.ts +231 -157
  263. package/src/adapters/mysql/tools/codemode/__tests__/codemode-tool.test.ts +227 -0
  264. package/src/adapters/mysql/tools/codemode/index.ts +5 -3
  265. package/src/adapters/mysql/tools/core.ts +152 -38
  266. package/src/adapters/mysql/tools/docstore.ts +422 -205
  267. package/src/adapters/mysql/tools/events.ts +334 -233
  268. package/src/adapters/mysql/tools/json/__tests__/core.test.ts +20 -0
  269. package/src/adapters/mysql/tools/json/__tests__/enhanced.test.ts +82 -50
  270. package/src/adapters/mysql/tools/json/__tests__/helpers.test.ts +42 -3
  271. package/src/adapters/mysql/tools/json/core.ts +21 -42
  272. package/src/adapters/mysql/tools/json/enhanced.ts +22 -37
  273. package/src/adapters/mysql/tools/json/helpers.ts +21 -25
  274. package/src/adapters/mysql/tools/partitioning.ts +3 -0
  275. package/src/adapters/mysql/tools/performance/__tests__/analysis.test.ts +98 -5
  276. package/src/adapters/mysql/tools/performance/__tests__/optimization-coverage.test.ts +515 -0
  277. package/src/adapters/mysql/tools/performance/__tests__/optimization.test.ts +187 -0
  278. package/src/adapters/mysql/tools/performance/analysis.ts +95 -69
  279. package/src/adapters/mysql/tools/performance/optimization.ts +182 -153
  280. package/src/adapters/mysql/tools/proxysql.ts +314 -209
  281. package/src/adapters/mysql/tools/replication.ts +84 -57
  282. package/src/adapters/mysql/tools/roles.ts +274 -226
  283. package/src/adapters/mysql/tools/router.ts +181 -85
  284. package/src/adapters/mysql/tools/schema/__tests__/constraints.test.ts +13 -0
  285. package/src/adapters/mysql/tools/schema/__tests__/management.test.ts +60 -25
  286. package/src/adapters/mysql/tools/schema/__tests__/scheduled_events.test.ts +11 -0
  287. package/src/adapters/mysql/tools/schema/__tests__/triggers.test.ts +25 -4
  288. package/src/adapters/mysql/tools/schema/__tests__/views.test.ts +46 -14
  289. package/src/adapters/mysql/tools/schema/constraints.ts +22 -3
  290. package/src/adapters/mysql/tools/schema/management.ts +60 -15
  291. package/src/adapters/mysql/tools/schema/routines.ts +26 -4
  292. package/src/adapters/mysql/tools/schema/scheduled_events.ts +25 -3
  293. package/src/adapters/mysql/tools/schema/triggers.ts +27 -2
  294. package/src/adapters/mysql/tools/schema/views.ts +46 -8
  295. package/src/adapters/mysql/tools/security/__tests__/audit.test.ts +90 -4
  296. package/src/adapters/mysql/tools/security/audit.ts +113 -39
  297. package/src/adapters/mysql/tools/security/data-protection.ts +293 -233
  298. package/src/adapters/mysql/tools/security/encryption.ts +172 -139
  299. package/src/adapters/mysql/tools/shell/__tests__/backup.test.ts +29 -0
  300. package/src/adapters/mysql/tools/shell/backup.ts +90 -73
  301. package/src/adapters/mysql/tools/shell/restore.ts +62 -48
  302. package/src/adapters/mysql/tools/spatial/__tests__/operations.test.ts +22 -14
  303. package/src/adapters/mysql/tools/spatial/__tests__/queries.test.ts +65 -51
  304. package/src/adapters/mysql/tools/spatial/geometry.ts +23 -7
  305. package/src/adapters/mysql/tools/spatial/operations.ts +60 -31
  306. package/src/adapters/mysql/tools/spatial/queries.ts +142 -65
  307. package/src/adapters/mysql/tools/spatial/setup.ts +121 -55
  308. package/src/adapters/mysql/tools/stats/__tests__/comparative.test.ts +12 -10
  309. package/src/adapters/mysql/tools/stats/comparative.ts +150 -98
  310. package/src/adapters/mysql/tools/stats/descriptive.ts +204 -127
  311. package/src/adapters/mysql/tools/sysschema/__tests__/error-paths.test.ts +222 -0
  312. package/src/adapters/mysql/tools/sysschema/__tests__/performance.test.ts +45 -0
  313. package/src/adapters/mysql/tools/sysschema/__tests__/resources.test.ts +6 -3
  314. package/src/adapters/mysql/tools/sysschema/activity.ts +52 -27
  315. package/src/adapters/mysql/tools/sysschema/performance.ts +132 -68
  316. package/src/adapters/mysql/tools/sysschema/resources.ts +105 -67
  317. package/src/adapters/mysql/tools/text/__tests__/fulltext.test.ts +45 -17
  318. package/src/adapters/mysql/tools/text/fulltext.ts +27 -38
  319. package/src/adapters/mysql/tools/transactions.ts +49 -24
  320. package/src/adapters/mysql/types/proxysql-types.ts +38 -1
  321. package/src/adapters/mysql/types/router-types.ts +1 -1
  322. package/src/adapters/mysql/types/shell-types.ts +2 -2
  323. package/src/adapters/mysql/types.ts +632 -19
  324. package/src/auth/__tests__/scopes.test.ts +2 -2
  325. package/src/auth/scopes.ts +1 -1
  326. package/src/codemode/__tests__/api.test.ts +417 -0
  327. package/src/codemode/__tests__/sandbox-factory.test.ts +158 -0
  328. package/src/codemode/__tests__/sandbox.test.ts +301 -0
  329. package/src/codemode/__tests__/security.test.ts +368 -0
  330. package/src/codemode/__tests__/worker-sandbox.test.ts +179 -0
  331. package/src/codemode/__tests__/worker-script.test.ts +226 -0
  332. package/src/codemode/api.ts +89 -5
  333. package/src/codemode/sandbox-factory.ts +1 -1
  334. package/src/codemode/types.ts +34 -0
  335. package/src/codemode/worker-sandbox.ts +74 -7
  336. package/src/codemode/worker-script.ts +157 -86
  337. package/src/constants/ServerInstructions.ts +37 -31
  338. package/src/filtering/ToolConstants.ts +1 -2
  339. package/src/filtering/__tests__/ToolFilter.test.ts +9 -9
  340. package/src/pool/ConnectionPool.ts +4 -1
  341. package/src/transports/__tests__/http.test.ts +15 -3
  342. package/src/transports/http.ts +12 -0
  343. package/src/utils/validators.ts +2 -1
  344. package/vitest.config.ts +3 -1
  345. package/CODE_MODE.md +0 -245
@@ -299,6 +299,26 @@ describe("JSON Core Tools", () => {
299
299
  const call = mockAdapter.executeReadQuery.mock.calls[0][0] as string;
300
300
  expect(call).toContain("JSON_KEYS");
301
301
  });
302
+
303
+ it("should include count in response", async () => {
304
+ mockAdapter.executeReadQuery.mockResolvedValue(
305
+ createMockQueryResult([
306
+ { json_keys: '["a", "b"]' },
307
+ { json_keys: '["c"]' },
308
+ ]),
309
+ );
310
+
311
+ const tool = createJsonKeysTool(mockAdapter as unknown as MySQLAdapter);
312
+ const result = (await tool.handler(
313
+ {
314
+ table: "data",
315
+ column: "json_col",
316
+ },
317
+ mockContext,
318
+ )) as { rows: unknown[]; count: number };
319
+
320
+ expect(result.count).toBe(2);
321
+ });
302
322
  });
303
323
 
304
324
  describe("createJsonArrayAppendTool", () => {
@@ -506,67 +506,99 @@ describe("JSON Enhanced Tools", () => {
506
506
 
507
507
  expect(result.suggestions).toHaveLength(5);
508
508
  });
509
- });
510
509
 
511
- describe("P154 Graceful Error Handling", () => {
512
- const tableError = new Error("Table 'testdb.nonexistent' doesn't exist");
510
+ it("should produce valid DDL for qualified table names", async () => {
511
+ mockAdapter.executeQuery
512
+ .mockResolvedValueOnce(createMockQueryResult([{ key_name: "email" }]))
513
+ .mockResolvedValueOnce(
514
+ createMockQueryResult([{ value_type: "STRING", cardinality: 50 }]),
515
+ );
513
516
 
514
- it("json_normalize should return exists: false for nonexistent table", async () => {
515
- mockAdapter.executeQuery.mockRejectedValue(tableError);
516
- const tool = createJsonNormalizeTool(
517
+ const tool = createJsonIndexSuggestTool(
517
518
  mockAdapter as unknown as MySQLAdapter,
518
519
  );
519
- const result = await tool.handler(
520
- { table: "nonexistent", column: "doc" },
520
+ const result = (await tool.handler(
521
+ {
522
+ table: "mydb.users",
523
+ column: "data",
524
+ },
521
525
  mockContext,
522
- );
523
- expect(result).toEqual({ exists: false, table: "nonexistent" });
524
- });
526
+ )) as { suggestions: { indexDdl: string }[] };
525
527
 
526
- it("json_stats should return exists: false for nonexistent table", async () => {
527
- mockAdapter.executeQuery.mockRejectedValue(tableError);
528
- const tool = createJsonStatsTool(mockAdapter as unknown as MySQLAdapter);
529
- const result = await tool.handler(
530
- { table: "nonexistent", column: "doc" },
531
- mockContext,
528
+ expect(result.suggestions).toHaveLength(1);
529
+ // Table reference should be properly escaped as `mydb`.`users`
530
+ expect(result.suggestions[0].indexDdl).toContain(
531
+ "ALTER TABLE `mydb`.`users`",
532
532
  );
533
- expect(result).toEqual({ exists: false, table: "nonexistent" });
533
+ // Index name should use only the table basename (no schema prefix)
534
+ expect(result.suggestions[0].indexDdl).toContain("idx_users_email");
535
+ expect(result.suggestions[0].indexDdl).not.toContain("idx_mydb.users");
534
536
  });
535
537
 
536
- it("json_index_suggest should return exists: false for nonexistent table", async () => {
537
- mockAdapter.executeQuery.mockRejectedValue(tableError);
538
- const tool = createJsonIndexSuggestTool(
539
- mockAdapter as unknown as MySQLAdapter,
540
- );
541
- const result = await tool.handler(
542
- { table: "nonexistent", column: "doc" },
543
- mockContext,
544
- );
545
- expect(result).toEqual({ exists: false, table: "nonexistent" });
546
- });
538
+ describe("P154 Graceful Error Handling", () => {
539
+ const tableError = new Error("Table 'testdb.nonexistent' doesn't exist");
547
540
 
548
- it("json_merge should return success: false for invalid input", async () => {
549
- mockAdapter.executeReadQuery.mockRejectedValue(
550
- new Error("Invalid JSON text"),
551
- );
552
- const tool = createJsonMergeTool(mockAdapter as unknown as MySQLAdapter);
553
- const result = await tool.handler(
554
- { json1: "not-json", json2: "{}" },
555
- mockContext,
556
- );
557
- expect(result).toEqual({ success: false, error: "Invalid JSON text" });
558
- });
541
+ it("json_normalize should return exists: false for nonexistent table", async () => {
542
+ mockAdapter.executeQuery.mockRejectedValue(tableError);
543
+ const tool = createJsonNormalizeTool(
544
+ mockAdapter as unknown as MySQLAdapter,
545
+ );
546
+ const result = await tool.handler(
547
+ { table: "nonexistent", column: "doc" },
548
+ mockContext,
549
+ );
550
+ expect(result).toEqual({ exists: false, table: "nonexistent" });
551
+ });
559
552
 
560
- it("json_diff should return success: false for invalid input", async () => {
561
- mockAdapter.executeReadQuery.mockRejectedValue(
562
- new Error("Invalid JSON text"),
563
- );
564
- const tool = createJsonDiffTool(mockAdapter as unknown as MySQLAdapter);
565
- const result = await tool.handler(
566
- { json1: "not-json", json2: "{}" },
567
- mockContext,
568
- );
569
- expect(result).toEqual({ success: false, error: "Invalid JSON text" });
553
+ it("json_stats should return exists: false for nonexistent table", async () => {
554
+ mockAdapter.executeQuery.mockRejectedValue(tableError);
555
+ const tool = createJsonStatsTool(
556
+ mockAdapter as unknown as MySQLAdapter,
557
+ );
558
+ const result = await tool.handler(
559
+ { table: "nonexistent", column: "doc" },
560
+ mockContext,
561
+ );
562
+ expect(result).toEqual({ exists: false, table: "nonexistent" });
563
+ });
564
+
565
+ it("json_index_suggest should return exists: false for nonexistent table", async () => {
566
+ mockAdapter.executeQuery.mockRejectedValue(tableError);
567
+ const tool = createJsonIndexSuggestTool(
568
+ mockAdapter as unknown as MySQLAdapter,
569
+ );
570
+ const result = await tool.handler(
571
+ { table: "nonexistent", column: "doc" },
572
+ mockContext,
573
+ );
574
+ expect(result).toEqual({ exists: false, table: "nonexistent" });
575
+ });
576
+
577
+ it("json_merge should return success: false for invalid input", async () => {
578
+ mockAdapter.executeReadQuery.mockRejectedValue(
579
+ new Error("Invalid JSON text"),
580
+ );
581
+ const tool = createJsonMergeTool(
582
+ mockAdapter as unknown as MySQLAdapter,
583
+ );
584
+ const result = await tool.handler(
585
+ { json1: "not-json", json2: "{}" },
586
+ mockContext,
587
+ );
588
+ expect(result).toEqual({ success: false, error: "Invalid JSON text" });
589
+ });
590
+
591
+ it("json_diff should return success: false for invalid input", async () => {
592
+ mockAdapter.executeReadQuery.mockRejectedValue(
593
+ new Error("Invalid JSON text"),
594
+ );
595
+ const tool = createJsonDiffTool(mockAdapter as unknown as MySQLAdapter);
596
+ const result = await tool.handler(
597
+ { json1: "not-json", json2: "{}" },
598
+ mockContext,
599
+ );
600
+ expect(result).toEqual({ success: false, error: "Invalid JSON text" });
601
+ });
570
602
  });
571
603
  });
572
604
  });
@@ -52,6 +52,24 @@ describe("JSON Helper Tools", () => {
52
52
  // Value is parsed from JSON string
53
53
  expect(result.value).toEqual({ a: 1 });
54
54
  });
55
+
56
+ it("should return rowFound: false for nonexistent row", async () => {
57
+ mockAdapter.executeReadQuery.mockResolvedValue(createMockQueryResult([]));
58
+
59
+ const tool = createJsonGetTool(mockAdapter as unknown as MySQLAdapter);
60
+ const result = (await tool.handler(
61
+ {
62
+ table: "data",
63
+ column: "json_col",
64
+ path: "$.a",
65
+ id: 999,
66
+ },
67
+ mockContext,
68
+ )) as { value: null; rowFound: boolean };
69
+
70
+ expect(result.value).toBeNull();
71
+ expect(result.rowFound).toBe(false);
72
+ });
55
73
  });
56
74
 
57
75
  describe("createJsonSearchTool", () => {
@@ -72,7 +90,7 @@ describe("JSON Helper Tools", () => {
72
90
 
73
91
  const call = mockAdapter.executeReadQuery.mock.calls[0][0] as string;
74
92
  expect(call).toContain("JSON_SEARCH");
75
- expect(call).toContain("SELECT id, `json_col`");
93
+ expect(call).toContain("SELECT id, JSON_SEARCH");
76
94
  expect(call).not.toContain("SELECT *");
77
95
  });
78
96
  });
@@ -116,10 +134,10 @@ describe("JSON Helper Tools", () => {
116
134
  id: 999,
117
135
  },
118
136
  mockContext,
119
- )) as { success: boolean; reason: string };
137
+ )) as { success: boolean; error: string };
120
138
 
121
139
  expect(result.success).toBe(false);
122
- expect(result.reason).toContain("999");
140
+ expect(result.error).toContain("999");
123
141
  });
124
142
  });
125
143
 
@@ -165,6 +183,27 @@ describe("JSON Helper Tools", () => {
165
183
  expect(sqlParam[0]).toBe("hello");
166
184
  expect(result.valid).toBe(false);
167
185
  });
186
+
187
+ it("should strip Query failed and Execute failed prefixes from errors", async () => {
188
+ mockAdapter.executeReadQuery.mockRejectedValue(
189
+ new Error(
190
+ 'Query failed: Execute failed: Invalid JSON text in argument 1 to function cast_as_json: "Missing a name" at position 1.',
191
+ ),
192
+ );
193
+
194
+ const tool = createJsonValidateTool(
195
+ mockAdapter as unknown as MySQLAdapter,
196
+ );
197
+ const result = (await tool.handler({ value: "{bad" }, mockContext)) as {
198
+ valid: boolean;
199
+ error: string;
200
+ };
201
+
202
+ expect(result.valid).toBe(false);
203
+ expect(result.error).not.toContain("Query failed");
204
+ expect(result.error).not.toContain("Execute failed");
205
+ expect(result.error).toContain("Invalid JSON text");
206
+ });
168
207
  });
169
208
 
170
209
  describe("P154 Graceful Error Handling", () => {
@@ -15,12 +15,19 @@ import {
15
15
  JsonExtractSchemaBase,
16
16
  JsonSetSchema,
17
17
  JsonSetSchemaBase,
18
+ JsonInsertSchema,
19
+ JsonInsertSchemaBase,
20
+ JsonReplaceSchema,
21
+ JsonReplaceSchemaBase,
22
+ JsonRemoveSchema,
23
+ JsonRemoveSchemaBase,
18
24
  JsonContainsSchema,
19
25
  JsonContainsSchemaBase,
20
26
  JsonKeysSchema,
21
27
  JsonKeysSchemaBase,
28
+ JsonArrayAppendSchema,
29
+ JsonArrayAppendSchemaBase,
22
30
  } from "../../types.js";
23
- import { z } from "zod";
24
31
  import {
25
32
  validateIdentifier,
26
33
  validateQualifiedIdentifier,
@@ -136,27 +143,20 @@ export function createJsonSetTool(adapter: MySQLAdapter): ToolDefinition {
136
143
  }
137
144
 
138
145
  export function createJsonInsertTool(adapter: MySQLAdapter): ToolDefinition {
139
- const schema = z.object({
140
- table: z.string(),
141
- column: z.string(),
142
- path: z.string(),
143
- value: z.unknown(),
144
- where: z.string(),
145
- });
146
-
147
146
  return {
148
147
  name: "mysql_json_insert",
149
148
  title: "MySQL JSON Insert",
150
149
  description:
151
150
  "Insert values into JSON columns only if the path does not exist.",
152
151
  group: "json",
153
- inputSchema: schema,
152
+ inputSchema: JsonInsertSchemaBase,
154
153
  requiredScopes: ["write"],
155
154
  annotations: {
156
155
  readOnlyHint: false,
157
156
  },
158
157
  handler: async (params: unknown, _context: RequestContext) => {
159
- const { table, column, path, value, where } = schema.parse(params);
158
+ const { table, column, path, value, where } =
159
+ JsonInsertSchema.parse(params);
160
160
 
161
161
  // Validate inputs
162
162
  validateQualifiedIdentifier(table, "table");
@@ -197,26 +197,19 @@ export function createJsonInsertTool(adapter: MySQLAdapter): ToolDefinition {
197
197
  }
198
198
 
199
199
  export function createJsonReplaceTool(adapter: MySQLAdapter): ToolDefinition {
200
- const schema = z.object({
201
- table: z.string(),
202
- column: z.string(),
203
- path: z.string(),
204
- value: z.unknown(),
205
- where: z.string(),
206
- });
207
-
208
200
  return {
209
201
  name: "mysql_json_replace",
210
202
  title: "MySQL JSON Replace",
211
203
  description: "Replace values in JSON columns only if the path exists.",
212
204
  group: "json",
213
- inputSchema: schema,
205
+ inputSchema: JsonReplaceSchemaBase,
214
206
  requiredScopes: ["write"],
215
207
  annotations: {
216
208
  readOnlyHint: false,
217
209
  },
218
210
  handler: async (params: unknown, _context: RequestContext) => {
219
- const { table, column, path, value, where } = schema.parse(params);
211
+ const { table, column, path, value, where } =
212
+ JsonReplaceSchema.parse(params);
220
213
 
221
214
  // Validate inputs
222
215
  validateQualifiedIdentifier(table, "table");
@@ -242,25 +235,18 @@ export function createJsonReplaceTool(adapter: MySQLAdapter): ToolDefinition {
242
235
  }
243
236
 
244
237
  export function createJsonRemoveTool(adapter: MySQLAdapter): ToolDefinition {
245
- const schema = z.object({
246
- table: z.string(),
247
- column: z.string(),
248
- paths: z.array(z.string()),
249
- where: z.string(),
250
- });
251
-
252
238
  return {
253
239
  name: "mysql_json_remove",
254
240
  title: "MySQL JSON Remove",
255
241
  description: "Remove values from JSON columns at specified paths.",
256
242
  group: "json",
257
- inputSchema: schema,
243
+ inputSchema: JsonRemoveSchemaBase,
258
244
  requiredScopes: ["write"],
259
245
  annotations: {
260
246
  readOnlyHint: false,
261
247
  },
262
248
  handler: async (params: unknown, _context: RequestContext) => {
263
- const { table, column, paths, where } = schema.parse(params);
249
+ const { table, column, paths, where } = JsonRemoveSchema.parse(params);
264
250
 
265
251
  // Validate inputs
266
252
  validateQualifiedIdentifier(table, "table");
@@ -351,10 +337,10 @@ export function createJsonKeysTool(adapter: MySQLAdapter): ToolDefinition {
351
337
 
352
338
  try {
353
339
  const jsonPath = path ?? "$";
354
- const sql = `SELECT JSON_KEYS(\`${column}\`, ?) as json_keys FROM ${escapeQualifiedTable(table)}`;
340
+ const sql = `SELECT JSON_KEYS(\`${column}\`, ?) as json_keys FROM ${escapeQualifiedTable(table)} HAVING json_keys IS NOT NULL`;
355
341
 
356
342
  const result = await adapter.executeReadQuery(sql, [jsonPath]);
357
- return { rows: result.rows };
343
+ return { rows: result.rows, count: result.rows?.length ?? 0 };
358
344
  } catch (error) {
359
345
  const msg = error instanceof Error ? error.message : String(error);
360
346
  if (msg.includes("doesn't exist")) {
@@ -369,26 +355,19 @@ export function createJsonKeysTool(adapter: MySQLAdapter): ToolDefinition {
369
355
  export function createJsonArrayAppendTool(
370
356
  adapter: MySQLAdapter,
371
357
  ): ToolDefinition {
372
- const schema = z.object({
373
- table: z.string(),
374
- column: z.string(),
375
- path: z.string(),
376
- value: z.unknown(),
377
- where: z.string(),
378
- });
379
-
380
358
  return {
381
359
  name: "mysql_json_array_append",
382
360
  title: "MySQL JSON Array Append",
383
361
  description: "Append a value to a JSON array at the specified path.",
384
362
  group: "json",
385
- inputSchema: schema,
363
+ inputSchema: JsonArrayAppendSchemaBase,
386
364
  requiredScopes: ["write"],
387
365
  annotations: {
388
366
  readOnlyHint: false,
389
367
  },
390
368
  handler: async (params: unknown, _context: RequestContext) => {
391
- const { table, column, path, value, where } = schema.parse(params);
369
+ const { table, column, path, value, where } =
370
+ JsonArrayAppendSchema.parse(params);
392
371
 
393
372
  // Validate inputs
394
373
  validateQualifiedIdentifier(table, "table");
@@ -11,16 +11,21 @@ import type {
11
11
  RequestContext,
12
12
  } from "../../../../types/index.js";
13
13
  import { z } from "zod";
14
+ import {
15
+ JsonNormalizeSchema,
16
+ JsonNormalizeSchemaBase,
17
+ JsonStatsSchema,
18
+ JsonStatsSchemaBase,
19
+ JsonIndexSuggestSchema,
20
+ JsonIndexSuggestSchemaBase,
21
+ } from "../../types.js";
14
22
  import {
15
23
  validateQualifiedIdentifier,
16
24
  escapeQualifiedTable,
17
25
  validateIdentifier,
18
26
  } from "../../../../utils/validators.js";
19
27
 
20
- // =============================================================================
21
- // Schemas
22
- // =============================================================================
23
-
28
+ // Schemas for json_merge and json_diff (no table/column — no aliases needed)
24
29
  const JsonMergeSchema = z.object({
25
30
  json1: z.string().describe("First JSON document"),
26
31
  json2: z.string().describe("Second JSON document"),
@@ -35,26 +40,6 @@ const JsonDiffSchema = z.object({
35
40
  json2: z.string().describe("Second JSON document"),
36
41
  });
37
42
 
38
- const JsonNormalizeSchema = z.object({
39
- table: z.string().describe("Table name"),
40
- column: z.string().describe("JSON column name"),
41
- where: z.string().optional().describe("WHERE clause"),
42
- limit: z.number().default(100).describe("Maximum rows to process"),
43
- });
44
-
45
- const JsonStatsSchema = z.object({
46
- table: z.string().describe("Table name"),
47
- column: z.string().describe("JSON column name"),
48
- where: z.string().optional().describe("Optional WHERE clause"),
49
- sampleSize: z.number().default(1000).describe("Sample size for statistics"),
50
- });
51
-
52
- const JsonIndexSuggestSchema = z.object({
53
- table: z.string().describe("Table name"),
54
- column: z.string().describe("JSON column name"),
55
- sampleSize: z.number().default(100).describe("Sample size to analyze"),
56
- });
57
-
58
43
  // =============================================================================
59
44
  // Tool Creation Functions
60
45
  // =============================================================================
@@ -232,7 +217,7 @@ export function createJsonNormalizeTool(adapter: MySQLAdapter): ToolDefinition {
232
217
  description:
233
218
  "Normalize JSON column structure by extracting all unique keys across documents.",
234
219
  group: "json",
235
- inputSchema: JsonNormalizeSchema,
220
+ inputSchema: JsonNormalizeSchemaBase,
236
221
  requiredScopes: ["read"],
237
222
  annotations: {
238
223
  readOnlyHint: true,
@@ -306,7 +291,7 @@ export function createJsonStatsTool(adapter: MySQLAdapter): ToolDefinition {
306
291
  description:
307
292
  "Analyze statistics for a JSON column including depth, size, and key frequency.",
308
293
  group: "json",
309
- inputSchema: JsonStatsSchema,
294
+ inputSchema: JsonStatsSchemaBase,
310
295
  requiredScopes: ["read"],
311
296
  annotations: {
312
297
  readOnlyHint: true,
@@ -341,20 +326,20 @@ export function createJsonStatsTool(adapter: MySQLAdapter): ToolDefinition {
341
326
  const row = result.rows?.[0];
342
327
 
343
328
  return {
344
- totalSampled: row?.["total_rows"],
345
- nullCount: row?.["null_count"],
329
+ totalSampled: Number(row?.["total_rows"] ?? 0),
330
+ nullCount: Number(row?.["null_count"] ?? 0),
346
331
  length: {
347
- avg: row?.["avg_length"],
348
- max: row?.["max_length"],
349
- min: row?.["min_length"],
332
+ avg: Number(row?.["avg_length"] ?? 0),
333
+ max: Number(row?.["max_length"] ?? 0),
334
+ min: Number(row?.["min_length"] ?? 0),
350
335
  },
351
336
  depth: {
352
- avg: row?.["avg_depth"],
353
- max: row?.["max_depth"],
337
+ avg: Number(row?.["avg_depth"] ?? 0),
338
+ max: Number(row?.["max_depth"] ?? 0),
354
339
  },
355
340
  sizeBytes: {
356
- avg: row?.["avg_size_bytes"],
357
- max: row?.["max_size_bytes"],
341
+ avg: Number(row?.["avg_size_bytes"] ?? 0),
342
+ max: Number(row?.["max_size_bytes"] ?? 0),
358
343
  },
359
344
  sampleSize,
360
345
  };
@@ -378,7 +363,7 @@ export function createJsonIndexSuggestTool(
378
363
  description:
379
364
  "Suggest functional indexes for frequently accessed JSON paths.",
380
365
  group: "json",
381
- inputSchema: JsonIndexSuggestSchema,
366
+ inputSchema: JsonIndexSuggestSchemaBase,
382
367
  requiredScopes: ["read"],
383
368
  annotations: {
384
369
  readOnlyHint: true,
@@ -459,7 +444,7 @@ export function createJsonIndexSuggestTool(
459
444
  path: `$.${key}`,
460
445
  type: valueType ?? "UNKNOWN",
461
446
  cardinality,
462
- indexDdl: `ALTER TABLE \`${table}\` ADD INDEX idx_${table}_${key} ((CAST(JSON_EXTRACT(\`${column}\`, '$.${key}') AS ${dataType})));`,
447
+ indexDdl: `ALTER TABLE ${escapeQualifiedTable(table)} ADD INDEX idx_${table.split(".").pop()}_${key} ((CAST(JSON_EXTRACT(\`${column}\`, '$.${key}') AS ${dataType})));`,
463
448
  });
464
449
  }
465
450
  }
@@ -14,8 +14,11 @@ import {
14
14
  JsonSearchSchema,
15
15
  JsonSearchSchemaBase,
16
16
  JsonValidateSchema,
17
+ JsonGetSchema,
18
+ JsonGetSchemaBase,
19
+ JsonUpdateSchema,
20
+ JsonUpdateSchemaBase,
17
21
  } from "../../types.js";
18
- import { z } from "zod";
19
22
  import {
20
23
  validateQualifiedIdentifier,
21
24
  escapeQualifiedTable,
@@ -26,27 +29,19 @@ import {
26
29
  * Export all JSON helper tool creation functions
27
30
  */
28
31
  export function createJsonGetTool(adapter: MySQLAdapter): ToolDefinition {
29
- const schema = z.object({
30
- table: z.string(),
31
- column: z.string(),
32
- path: z.string(),
33
- id: z.union([z.string(), z.number()]),
34
- idColumn: z.string().default("id"),
35
- });
36
-
37
32
  return {
38
33
  name: "mysql_json_get",
39
34
  title: "MySQL JSON Get",
40
35
  description: "Simple JSON value extraction by row ID.",
41
36
  group: "json",
42
- inputSchema: schema,
37
+ inputSchema: JsonGetSchemaBase,
43
38
  requiredScopes: ["read"],
44
39
  annotations: {
45
40
  readOnlyHint: true,
46
41
  idempotentHint: true,
47
42
  },
48
43
  handler: async (params: unknown, _context: RequestContext) => {
49
- const { table, column, path, id, idColumn } = schema.parse(params);
44
+ const { table, column, path, id, idColumn } = JsonGetSchema.parse(params);
50
45
 
51
46
  validateQualifiedIdentifier(table, "table");
52
47
  validateIdentifier(column, "column");
@@ -56,6 +51,11 @@ export function createJsonGetTool(adapter: MySQLAdapter): ToolDefinition {
56
51
  const sql = `SELECT JSON_EXTRACT(\`${column}\`, ?) as value FROM ${escapeQualifiedTable(table)} WHERE \`${idColumn}\` = ?`;
57
52
  const result = await adapter.executeReadQuery(sql, [path, id]);
58
53
 
54
+ // No rows = row ID doesn't exist (distinct from null JSON path)
55
+ if (!result.rows || result.rows.length === 0) {
56
+ return { value: null, rowFound: false };
57
+ }
58
+
59
59
  const rawValue = result.rows?.[0]?.["value"];
60
60
  // Parse JSON value for consistency with mysql_json_extract
61
61
  // Return null for missing paths, parse objects/arrays, return primitives as-is
@@ -88,27 +88,19 @@ export function createJsonGetTool(adapter: MySQLAdapter): ToolDefinition {
88
88
  }
89
89
 
90
90
  export function createJsonUpdateTool(adapter: MySQLAdapter): ToolDefinition {
91
- const schema = z.object({
92
- table: z.string(),
93
- column: z.string(),
94
- path: z.string(),
95
- value: z.unknown(),
96
- id: z.union([z.string(), z.number()]),
97
- idColumn: z.string().default("id"),
98
- });
99
-
100
91
  return {
101
92
  name: "mysql_json_update",
102
93
  title: "MySQL JSON Update",
103
94
  description: "Simple JSON value update by row ID.",
104
95
  group: "json",
105
- inputSchema: schema,
96
+ inputSchema: JsonUpdateSchemaBase,
106
97
  requiredScopes: ["write"],
107
98
  annotations: {
108
99
  readOnlyHint: false,
109
100
  },
110
101
  handler: async (params: unknown, _context: RequestContext) => {
111
- const { table, column, path, value, id, idColumn } = schema.parse(params);
102
+ const { table, column, path, value, id, idColumn } =
103
+ JsonUpdateSchema.parse(params);
112
104
 
113
105
  validateQualifiedIdentifier(table, "table");
114
106
  validateIdentifier(column, "column");
@@ -140,7 +132,7 @@ export function createJsonUpdateTool(adapter: MySQLAdapter): ToolDefinition {
140
132
  if (result.rowsAffected === 0) {
141
133
  return {
142
134
  success: false,
143
- reason: `No row found with ${idColumn} = ${id}`,
135
+ error: `No row found with ${idColumn} = ${id}`,
144
136
  };
145
137
  }
146
138
  return { success: true };
@@ -176,7 +168,7 @@ export function createJsonSearchTool(adapter: MySQLAdapter): ToolDefinition {
176
168
  validateIdentifier(column, "column");
177
169
 
178
170
  try {
179
- const sql = `SELECT id, \`${column}\`, JSON_SEARCH(\`${column}\`, ?, ?) as match_path FROM ${escapeQualifiedTable(table)} WHERE JSON_SEARCH(\`${column}\`, ?, ?) IS NOT NULL`;
171
+ const sql = `SELECT id, JSON_SEARCH(\`${column}\`, ?, ?) as match_path FROM ${escapeQualifiedTable(table)} WHERE JSON_SEARCH(\`${column}\`, ?, ?) IS NOT NULL`;
180
172
 
181
173
  const result = await adapter.executeReadQuery(sql, [
182
174
  mode,
@@ -220,8 +212,12 @@ export function createJsonValidateTool(adapter: MySQLAdapter): ToolDefinition {
220
212
  } catch (error) {
221
213
  // MySQL may throw an error for severely malformed input
222
214
  // Return a structured error response instead of propagating
223
- const message =
215
+ let message =
224
216
  error instanceof Error ? error.message : "Unknown validation error";
217
+ message = message.replace(
218
+ /^(Query failed:\s*|Execute failed:\s*)+/i,
219
+ "",
220
+ );
225
221
  return { valid: false, error: message };
226
222
  }
227
223
  },
@@ -146,6 +146,7 @@ function createAddPartitionTool(adapter: MySQLAdapter): ToolDefinition {
146
146
 
147
147
  try {
148
148
  await adapter.executeQuery(sql);
149
+ adapter.clearSchemaCache();
149
150
  return { success: true, table, partitionName };
150
151
  } catch (error) {
151
152
  const msg = error instanceof Error ? error.message : String(error);
@@ -210,6 +211,7 @@ function createDropPartitionTool(adapter: MySQLAdapter): ToolDefinition {
210
211
  `ALTER TABLE \`${table}\` DROP PARTITION \`${partitionName}\``,
211
212
  );
212
213
 
214
+ adapter.clearSchemaCache();
213
215
  return {
214
216
  success: true,
215
217
  table,
@@ -296,6 +298,7 @@ function createReorganizePartitionTool(adapter: MySQLAdapter): ToolDefinition {
296
298
 
297
299
  try {
298
300
  await adapter.executeQuery(sql);
301
+ adapter.clearSchemaCache();
299
302
  return {
300
303
  success: true,
301
304
  table,