@confluentinc/mcp-confluent 1.2.2 → 1.4.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 (508) hide show
  1. package/README.md +299 -240
  2. package/assets/oauth-templates/callback-failure.html +22 -0
  3. package/assets/oauth-templates/callback-success.html +99 -0
  4. package/assets/oauth-templates/logo.html +91 -0
  5. package/assets/oauth-templates/styles.html +110 -0
  6. package/config.example.yaml +149 -0
  7. package/config.oauth.example.yaml +45 -0
  8. package/dist/cli.d.ts +59 -12
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +131 -61
  11. package/dist/cli.js.map +1 -1
  12. package/dist/config/env-config.d.ts +33 -0
  13. package/dist/config/env-config.d.ts.map +1 -0
  14. package/dist/config/env-config.js +478 -0
  15. package/dist/config/env-config.js.map +1 -0
  16. package/dist/config/index.d.ts +31 -0
  17. package/dist/config/index.d.ts.map +1 -0
  18. package/dist/config/index.js +76 -0
  19. package/dist/config/index.js.map +1 -0
  20. package/dist/config/interpolation.d.ts +9 -0
  21. package/dist/config/interpolation.d.ts.map +1 -0
  22. package/dist/config/interpolation.js +51 -0
  23. package/dist/config/interpolation.js.map +1 -0
  24. package/dist/config/models.d.ts +399 -0
  25. package/dist/config/models.d.ts.map +1 -0
  26. package/dist/config/models.js +406 -0
  27. package/dist/config/models.js.map +1 -0
  28. package/dist/config/validation.d.ts +9 -0
  29. package/dist/config/validation.d.ts.map +1 -0
  30. package/dist/config/validation.js +46 -0
  31. package/dist/config/validation.js.map +1 -0
  32. package/dist/confluent/base-client-manager.d.ts +133 -0
  33. package/dist/confluent/base-client-manager.d.ts.map +1 -0
  34. package/dist/confluent/base-client-manager.js +188 -0
  35. package/dist/confluent/base-client-manager.js.map +1 -0
  36. package/dist/confluent/client-manager.d.ts +42 -77
  37. package/dist/confluent/client-manager.d.ts.map +1 -1
  38. package/dist/confluent/client-manager.js +5 -213
  39. package/dist/confluent/client-manager.js.map +1 -1
  40. package/dist/confluent/config-telemetry.d.ts +41 -0
  41. package/dist/confluent/config-telemetry.d.ts.map +1 -0
  42. package/dist/confluent/config-telemetry.js +17 -0
  43. package/dist/confluent/config-telemetry.js.map +1 -0
  44. package/dist/confluent/direct-client-manager.d.ts +43 -0
  45. package/dist/confluent/direct-client-manager.d.ts.map +1 -0
  46. package/dist/confluent/direct-client-manager.js +154 -0
  47. package/dist/confluent/direct-client-manager.js.map +1 -0
  48. package/dist/confluent/middleware.d.ts +32 -4
  49. package/dist/confluent/middleware.d.ts.map +1 -1
  50. package/dist/confluent/middleware.js +46 -2
  51. package/dist/confluent/middleware.js.map +1 -1
  52. package/dist/confluent/node-deps.d.ts +33 -39
  53. package/dist/confluent/node-deps.d.ts.map +1 -1
  54. package/dist/confluent/node-deps.js +48 -7
  55. package/dist/confluent/node-deps.js.map +1 -1
  56. package/dist/confluent/oauth/auth-context.d.ts +94 -0
  57. package/dist/confluent/oauth/auth-context.d.ts.map +1 -0
  58. package/dist/confluent/oauth/auth-context.js +323 -0
  59. package/dist/confluent/oauth/auth-context.js.map +1 -0
  60. package/dist/confluent/oauth/auth0-config.d.ts +12 -0
  61. package/dist/confluent/oauth/auth0-config.d.ts.map +1 -0
  62. package/dist/confluent/oauth/auth0-config.js +43 -0
  63. package/dist/confluent/oauth/auth0-config.js.map +1 -0
  64. package/dist/confluent/oauth/callback-pages.d.ts +13 -0
  65. package/dist/confluent/oauth/callback-pages.d.ts.map +1 -0
  66. package/dist/confluent/oauth/callback-pages.js +47 -0
  67. package/dist/confluent/oauth/callback-pages.js.map +1 -0
  68. package/dist/confluent/oauth/crypto-utils.d.ts +16 -0
  69. package/dist/confluent/oauth/crypto-utils.d.ts.map +1 -0
  70. package/dist/confluent/oauth/crypto-utils.js +23 -0
  71. package/dist/confluent/oauth/crypto-utils.js.map +1 -0
  72. package/dist/confluent/oauth/errors.d.ts +27 -0
  73. package/dist/confluent/oauth/errors.d.ts.map +1 -0
  74. package/dist/confluent/oauth/errors.js +6 -0
  75. package/dist/confluent/oauth/errors.js.map +1 -0
  76. package/dist/confluent/oauth/oauth-holder.d.ts +34 -0
  77. package/dist/confluent/oauth/oauth-holder.d.ts.map +1 -0
  78. package/dist/confluent/oauth/oauth-holder.js +155 -0
  79. package/dist/confluent/oauth/oauth-holder.js.map +1 -0
  80. package/dist/confluent/oauth/pkce-login.d.ts +45 -0
  81. package/dist/confluent/oauth/pkce-login.d.ts.map +1 -0
  82. package/dist/confluent/oauth/pkce-login.js +270 -0
  83. package/dist/confluent/oauth/pkce-login.js.map +1 -0
  84. package/dist/confluent/oauth/token-chain.d.ts +53 -0
  85. package/dist/confluent/oauth/token-chain.d.ts.map +1 -0
  86. package/dist/confluent/oauth/token-chain.js +141 -0
  87. package/dist/confluent/oauth/token-chain.js.map +1 -0
  88. package/dist/confluent/oauth/token-lifetimes.d.ts +13 -0
  89. package/dist/confluent/oauth/token-lifetimes.d.ts.map +1 -0
  90. package/dist/confluent/oauth/token-lifetimes.js +13 -0
  91. package/dist/confluent/oauth/token-lifetimes.js.map +1 -0
  92. package/dist/confluent/oauth/types.d.ts +68 -0
  93. package/dist/confluent/oauth/types.d.ts.map +1 -0
  94. package/dist/confluent/oauth/types.js +2 -0
  95. package/dist/confluent/oauth/types.js.map +1 -0
  96. package/dist/confluent/oauth-client-manager.d.ts +78 -0
  97. package/dist/confluent/oauth-client-manager.d.ts.map +1 -0
  98. package/dist/confluent/oauth-client-manager.js +265 -0
  99. package/dist/confluent/oauth-client-manager.js.map +1 -0
  100. package/dist/confluent/oauth-resource-resolvers.d.ts +6 -0
  101. package/dist/confluent/oauth-resource-resolvers.d.ts.map +1 -0
  102. package/dist/confluent/oauth-resource-resolvers.js +65 -0
  103. package/dist/confluent/oauth-resource-resolvers.js.map +1 -0
  104. package/dist/confluent/schema-registry-helper.d.ts +5 -9
  105. package/dist/confluent/schema-registry-helper.d.ts.map +1 -1
  106. package/dist/confluent/schema-registry-helper.js +1 -9
  107. package/dist/confluent/schema-registry-helper.js.map +1 -1
  108. package/dist/confluent/telemetry.d.ts +38 -1
  109. package/dist/confluent/telemetry.d.ts.map +1 -1
  110. package/dist/confluent/telemetry.js +37 -8
  111. package/dist/confluent/telemetry.js.map +1 -1
  112. package/dist/confluent/tools/base-tools.d.ts +140 -23
  113. package/dist/confluent/tools/base-tools.d.ts.map +1 -1
  114. package/dist/confluent/tools/base-tools.js +98 -4
  115. package/dist/confluent/tools/base-tools.js.map +1 -1
  116. package/dist/confluent/tools/cluster-arg-resolvers.d.ts +75 -0
  117. package/dist/confluent/tools/cluster-arg-resolvers.d.ts.map +1 -0
  118. package/dist/confluent/tools/cluster-arg-resolvers.js +127 -0
  119. package/dist/confluent/tools/cluster-arg-resolvers.js.map +1 -0
  120. package/dist/confluent/tools/connection-predicates.d.ts +176 -0
  121. package/dist/confluent/tools/connection-predicates.d.ts.map +1 -0
  122. package/dist/confluent/tools/connection-predicates.js +284 -0
  123. package/dist/confluent/tools/connection-predicates.js.map +1 -0
  124. package/dist/confluent/tools/handlers/billing/list-billing-costs-handler.d.ts +5 -6
  125. package/dist/confluent/tools/handlers/billing/list-billing-costs-handler.d.ts.map +1 -1
  126. package/dist/confluent/tools/handlers/billing/list-billing-costs-handler.js +40 -11
  127. package/dist/confluent/tools/handlers/billing/list-billing-costs-handler.js.map +1 -1
  128. package/dist/confluent/tools/handlers/catalog/add-tags-to-topic.d.ts +6 -6
  129. package/dist/confluent/tools/handlers/catalog/add-tags-to-topic.d.ts.map +1 -1
  130. package/dist/confluent/tools/handlers/catalog/add-tags-to-topic.js +6 -9
  131. package/dist/confluent/tools/handlers/catalog/add-tags-to-topic.js.map +1 -1
  132. package/dist/confluent/tools/handlers/catalog/create-topic-tags.d.ts +6 -6
  133. package/dist/confluent/tools/handlers/catalog/create-topic-tags.d.ts.map +1 -1
  134. package/dist/confluent/tools/handlers/catalog/create-topic-tags.js +6 -9
  135. package/dist/confluent/tools/handlers/catalog/create-topic-tags.js.map +1 -1
  136. package/dist/confluent/tools/handlers/catalog/delete-tag.d.ts +6 -6
  137. package/dist/confluent/tools/handlers/catalog/delete-tag.d.ts.map +1 -1
  138. package/dist/confluent/tools/handlers/catalog/delete-tag.js +6 -9
  139. package/dist/confluent/tools/handlers/catalog/delete-tag.js.map +1 -1
  140. package/dist/confluent/tools/handlers/catalog/list-tags.d.ts +6 -6
  141. package/dist/confluent/tools/handlers/catalog/list-tags.d.ts.map +1 -1
  142. package/dist/confluent/tools/handlers/catalog/list-tags.js +6 -9
  143. package/dist/confluent/tools/handlers/catalog/list-tags.js.map +1 -1
  144. package/dist/confluent/tools/handlers/catalog/remove-tag-from-entity.d.ts +6 -6
  145. package/dist/confluent/tools/handlers/catalog/remove-tag-from-entity.d.ts.map +1 -1
  146. package/dist/confluent/tools/handlers/catalog/remove-tag-from-entity.js +6 -9
  147. package/dist/confluent/tools/handlers/catalog/remove-tag-from-entity.js.map +1 -1
  148. package/dist/confluent/tools/handlers/clusters/list-clusters-handler.d.ts +5 -6
  149. package/dist/confluent/tools/handlers/clusters/list-clusters-handler.d.ts.map +1 -1
  150. package/dist/confluent/tools/handlers/clusters/list-clusters-handler.js +11 -13
  151. package/dist/confluent/tools/handlers/clusters/list-clusters-handler.js.map +1 -1
  152. package/dist/confluent/tools/handlers/connect/connect-tool-handler.d.ts +34 -0
  153. package/dist/confluent/tools/handlers/connect/connect-tool-handler.d.ts.map +1 -0
  154. package/dist/confluent/tools/handlers/connect/connect-tool-handler.js +47 -0
  155. package/dist/confluent/tools/handlers/connect/connect-tool-handler.js.map +1 -0
  156. package/dist/confluent/tools/handlers/connect/create-connector-handler.d.ts +11 -7
  157. package/dist/confluent/tools/handlers/connect/create-connector-handler.d.ts.map +1 -1
  158. package/dist/confluent/tools/handlers/connect/create-connector-handler.js +21 -21
  159. package/dist/confluent/tools/handlers/connect/create-connector-handler.js.map +1 -1
  160. package/dist/confluent/tools/handlers/connect/delete-connector-handler.d.ts +6 -7
  161. package/dist/confluent/tools/handlers/connect/delete-connector-handler.d.ts.map +1 -1
  162. package/dist/confluent/tools/handlers/connect/delete-connector-handler.js +10 -15
  163. package/dist/confluent/tools/handlers/connect/delete-connector-handler.js.map +1 -1
  164. package/dist/confluent/tools/handlers/connect/get-connector-config-handler.d.ts +9 -0
  165. package/dist/confluent/tools/handlers/connect/get-connector-config-handler.d.ts.map +1 -0
  166. package/dist/confluent/tools/handlers/connect/get-connector-config-handler.js +35 -0
  167. package/dist/confluent/tools/handlers/connect/get-connector-config-handler.js.map +1 -0
  168. package/dist/confluent/tools/handlers/connect/get-connector-error-recommendations-handler.d.ts +9 -0
  169. package/dist/confluent/tools/handlers/connect/get-connector-error-recommendations-handler.d.ts.map +1 -0
  170. package/dist/confluent/tools/handlers/connect/get-connector-error-recommendations-handler.js +66 -0
  171. package/dist/confluent/tools/handlers/connect/get-connector-error-recommendations-handler.js.map +1 -0
  172. package/dist/confluent/tools/handlers/connect/get-connector-error-summary-handler.d.ts +9 -0
  173. package/dist/confluent/tools/handlers/connect/get-connector-error-summary-handler.d.ts.map +1 -0
  174. package/dist/confluent/tools/handlers/connect/get-connector-error-summary-handler.js +131 -0
  175. package/dist/confluent/tools/handlers/connect/get-connector-error-summary-handler.js.map +1 -0
  176. package/dist/confluent/tools/handlers/connect/get-connector-logs-handler.d.ts +9 -0
  177. package/dist/confluent/tools/handlers/connect/get-connector-logs-handler.d.ts.map +1 -0
  178. package/dist/confluent/tools/handlers/connect/get-connector-logs-handler.js +244 -0
  179. package/dist/confluent/tools/handlers/connect/get-connector-logs-handler.js.map +1 -0
  180. package/dist/confluent/tools/handlers/connect/get-connector-offsets-handler.d.ts +9 -0
  181. package/dist/confluent/tools/handlers/connect/get-connector-offsets-handler.d.ts.map +1 -0
  182. package/dist/confluent/tools/handlers/connect/get-connector-offsets-handler.js +35 -0
  183. package/dist/confluent/tools/handlers/connect/get-connector-offsets-handler.js.map +1 -0
  184. package/dist/confluent/tools/handlers/connect/get-connector-status-handler.d.ts +9 -0
  185. package/dist/confluent/tools/handlers/connect/get-connector-status-handler.d.ts.map +1 -0
  186. package/dist/confluent/tools/handlers/connect/get-connector-status-handler.js +44 -0
  187. package/dist/confluent/tools/handlers/connect/get-connector-status-handler.js.map +1 -0
  188. package/dist/confluent/tools/handlers/connect/get-connector-tasks-handler.d.ts +9 -0
  189. package/dist/confluent/tools/handlers/connect/get-connector-tasks-handler.d.ts.map +1 -0
  190. package/dist/confluent/tools/handlers/connect/get-connector-tasks-handler.js +35 -0
  191. package/dist/confluent/tools/handlers/connect/get-connector-tasks-handler.js.map +1 -0
  192. package/dist/confluent/tools/handlers/connect/list-connectors-handler.d.ts +6 -7
  193. package/dist/confluent/tools/handlers/connect/list-connectors-handler.d.ts.map +1 -1
  194. package/dist/confluent/tools/handlers/connect/list-connectors-handler.js +15 -17
  195. package/dist/confluent/tools/handlers/connect/list-connectors-handler.js.map +1 -1
  196. package/dist/confluent/tools/handlers/connect/pause-connector-handler.d.ts +9 -0
  197. package/dist/confluent/tools/handlers/connect/pause-connector-handler.d.ts.map +1 -0
  198. package/dist/confluent/tools/handlers/connect/pause-connector-handler.js +35 -0
  199. package/dist/confluent/tools/handlers/connect/pause-connector-handler.js.map +1 -0
  200. package/dist/confluent/tools/handlers/connect/restart-connector-handler.d.ts +9 -0
  201. package/dist/confluent/tools/handlers/connect/restart-connector-handler.d.ts.map +1 -0
  202. package/dist/confluent/tools/handlers/connect/restart-connector-handler.js +35 -0
  203. package/dist/confluent/tools/handlers/connect/restart-connector-handler.js.map +1 -0
  204. package/dist/confluent/tools/handlers/connect/resume-connector-handler.d.ts +9 -0
  205. package/dist/confluent/tools/handlers/connect/resume-connector-handler.d.ts.map +1 -0
  206. package/dist/confluent/tools/handlers/connect/resume-connector-handler.js +35 -0
  207. package/dist/confluent/tools/handlers/connect/resume-connector-handler.js.map +1 -0
  208. package/dist/confluent/tools/handlers/connect/update-connector-config-handler.d.ts +9 -0
  209. package/dist/confluent/tools/handlers/connect/update-connector-config-handler.d.ts.map +1 -0
  210. package/dist/confluent/tools/handlers/connect/update-connector-config-handler.js +44 -0
  211. package/dist/confluent/tools/handlers/connect/update-connector-config-handler.js.map +1 -0
  212. package/dist/confluent/tools/handlers/diagnostics/explain-disabled-tools-handler.d.ts +58 -0
  213. package/dist/confluent/tools/handlers/diagnostics/explain-disabled-tools-handler.d.ts.map +1 -0
  214. package/dist/confluent/tools/handlers/diagnostics/explain-disabled-tools-handler.js +135 -0
  215. package/dist/confluent/tools/handlers/diagnostics/explain-disabled-tools-handler.js.map +1 -0
  216. package/dist/confluent/tools/handlers/docs/get-product-doc-page-handler.d.ts +18 -0
  217. package/dist/confluent/tools/handlers/docs/get-product-doc-page-handler.d.ts.map +1 -0
  218. package/dist/confluent/tools/handlers/docs/get-product-doc-page-handler.js +235 -0
  219. package/dist/confluent/tools/handlers/docs/get-product-doc-page-handler.js.map +1 -0
  220. package/dist/confluent/tools/handlers/docs/search-product-docs-handler.d.ts +14 -0
  221. package/dist/confluent/tools/handlers/docs/search-product-docs-handler.d.ts.map +1 -0
  222. package/dist/confluent/tools/handlers/docs/search-product-docs-handler.js +286 -0
  223. package/dist/confluent/tools/handlers/docs/search-product-docs-handler.js.map +1 -0
  224. package/dist/confluent/tools/handlers/environments/list-environments-handler.d.ts +11 -12
  225. package/dist/confluent/tools/handlers/environments/list-environments-handler.d.ts.map +1 -1
  226. package/dist/confluent/tools/handlers/environments/list-environments-handler.js +11 -14
  227. package/dist/confluent/tools/handlers/environments/list-environments-handler.js.map +1 -1
  228. package/dist/confluent/tools/handlers/environments/read-environment-handler.d.ts +5 -6
  229. package/dist/confluent/tools/handlers/environments/read-environment-handler.d.ts.map +1 -1
  230. package/dist/confluent/tools/handlers/environments/read-environment-handler.js +6 -9
  231. package/dist/confluent/tools/handlers/environments/read-environment-handler.js.map +1 -1
  232. package/dist/confluent/tools/handlers/flink/catalog/catalog-resolver.d.ts +32 -11
  233. package/dist/confluent/tools/handlers/flink/catalog/catalog-resolver.d.ts.map +1 -1
  234. package/dist/confluent/tools/handlers/flink/catalog/catalog-resolver.js +22 -16
  235. package/dist/confluent/tools/handlers/flink/catalog/catalog-resolver.js.map +1 -1
  236. package/dist/confluent/tools/handlers/flink/catalog/describe-table-handler.d.ts +5 -7
  237. package/dist/confluent/tools/handlers/flink/catalog/describe-table-handler.d.ts.map +1 -1
  238. package/dist/confluent/tools/handlers/flink/catalog/describe-table-handler.js +34 -30
  239. package/dist/confluent/tools/handlers/flink/catalog/describe-table-handler.js.map +1 -1
  240. package/dist/confluent/tools/handlers/flink/catalog/flink-catalog-tool-handler.d.ts +14 -0
  241. package/dist/confluent/tools/handlers/flink/catalog/flink-catalog-tool-handler.d.ts.map +1 -0
  242. package/dist/confluent/tools/handlers/flink/catalog/flink-catalog-tool-handler.js +15 -0
  243. package/dist/confluent/tools/handlers/flink/catalog/flink-catalog-tool-handler.js.map +1 -0
  244. package/dist/confluent/tools/handlers/flink/catalog/get-table-info-handler.d.ts +5 -7
  245. package/dist/confluent/tools/handlers/flink/catalog/get-table-info-handler.d.ts.map +1 -1
  246. package/dist/confluent/tools/handlers/flink/catalog/get-table-info-handler.js +34 -30
  247. package/dist/confluent/tools/handlers/flink/catalog/get-table-info-handler.js.map +1 -1
  248. package/dist/confluent/tools/handlers/flink/catalog/list-catalogs-handler.d.ts +5 -7
  249. package/dist/confluent/tools/handlers/flink/catalog/list-catalogs-handler.d.ts.map +1 -1
  250. package/dist/confluent/tools/handlers/flink/catalog/list-catalogs-handler.js +21 -24
  251. package/dist/confluent/tools/handlers/flink/catalog/list-catalogs-handler.js.map +1 -1
  252. package/dist/confluent/tools/handlers/flink/catalog/list-databases-handler.d.ts +5 -7
  253. package/dist/confluent/tools/handlers/flink/catalog/list-databases-handler.d.ts.map +1 -1
  254. package/dist/confluent/tools/handlers/flink/catalog/list-databases-handler.js +21 -24
  255. package/dist/confluent/tools/handlers/flink/catalog/list-databases-handler.js.map +1 -1
  256. package/dist/confluent/tools/handlers/flink/catalog/list-tables-handler.d.ts +5 -7
  257. package/dist/confluent/tools/handlers/flink/catalog/list-tables-handler.d.ts.map +1 -1
  258. package/dist/confluent/tools/handlers/flink/catalog/list-tables-handler.js +22 -33
  259. package/dist/confluent/tools/handlers/flink/catalog/list-tables-handler.js.map +1 -1
  260. package/dist/confluent/tools/handlers/flink/create-flink-statement-handler.d.ts +5 -7
  261. package/dist/confluent/tools/handlers/flink/create-flink-statement-handler.d.ts.map +1 -1
  262. package/dist/confluent/tools/handlers/flink/create-flink-statement-handler.js +18 -23
  263. package/dist/confluent/tools/handlers/flink/create-flink-statement-handler.js.map +1 -1
  264. package/dist/confluent/tools/handlers/flink/delete-flink-statement-handler.d.ts +5 -7
  265. package/dist/confluent/tools/handlers/flink/delete-flink-statement-handler.d.ts.map +1 -1
  266. package/dist/confluent/tools/handlers/flink/delete-flink-statement-handler.js +7 -13
  267. package/dist/confluent/tools/handlers/flink/delete-flink-statement-handler.js.map +1 -1
  268. package/dist/confluent/tools/handlers/flink/diagnostics/check-health-handler.d.ts +5 -7
  269. package/dist/confluent/tools/handlers/flink/diagnostics/check-health-handler.d.ts.map +1 -1
  270. package/dist/confluent/tools/handlers/flink/diagnostics/check-health-handler.js +7 -13
  271. package/dist/confluent/tools/handlers/flink/diagnostics/check-health-handler.js.map +1 -1
  272. package/dist/confluent/tools/handlers/flink/diagnostics/detect-issues-handler.d.ts +5 -7
  273. package/dist/confluent/tools/handlers/flink/diagnostics/detect-issues-handler.d.ts.map +1 -1
  274. package/dist/confluent/tools/handlers/flink/diagnostics/detect-issues-handler.js +8 -15
  275. package/dist/confluent/tools/handlers/flink/diagnostics/detect-issues-handler.js.map +1 -1
  276. package/dist/confluent/tools/handlers/flink/diagnostics/metrics-helper.d.ts +2 -2
  277. package/dist/confluent/tools/handlers/flink/diagnostics/metrics-helper.d.ts.map +1 -1
  278. package/dist/confluent/tools/handlers/flink/diagnostics/metrics-helper.js.map +1 -1
  279. package/dist/confluent/tools/handlers/flink/diagnostics/query-profiler-handler.d.ts +7 -7
  280. package/dist/confluent/tools/handlers/flink/diagnostics/query-profiler-handler.d.ts.map +1 -1
  281. package/dist/confluent/tools/handlers/flink/diagnostics/query-profiler-handler.js +11 -17
  282. package/dist/confluent/tools/handlers/flink/diagnostics/query-profiler-handler.js.map +1 -1
  283. package/dist/confluent/tools/handlers/flink/flink-sql-helper.d.ts +15 -2
  284. package/dist/confluent/tools/handlers/flink/flink-sql-helper.d.ts.map +1 -1
  285. package/dist/confluent/tools/handlers/flink/flink-sql-helper.js.map +1 -1
  286. package/dist/confluent/tools/handlers/flink/flink-tool-handler.d.ts +22 -0
  287. package/dist/confluent/tools/handlers/flink/flink-tool-handler.d.ts.map +1 -0
  288. package/dist/confluent/tools/handlers/flink/flink-tool-handler.js +32 -0
  289. package/dist/confluent/tools/handlers/flink/flink-tool-handler.js.map +1 -0
  290. package/dist/confluent/tools/handlers/flink/get-flink-exceptions-handler.d.ts +5 -7
  291. package/dist/confluent/tools/handlers/flink/get-flink-exceptions-handler.d.ts.map +1 -1
  292. package/dist/confluent/tools/handlers/flink/get-flink-exceptions-handler.js +7 -13
  293. package/dist/confluent/tools/handlers/flink/get-flink-exceptions-handler.js.map +1 -1
  294. package/dist/confluent/tools/handlers/flink/list-flink-statements-handler.d.ts +5 -7
  295. package/dist/confluent/tools/handlers/flink/list-flink-statements-handler.d.ts.map +1 -1
  296. package/dist/confluent/tools/handlers/flink/list-flink-statements-handler.js +9 -17
  297. package/dist/confluent/tools/handlers/flink/list-flink-statements-handler.js.map +1 -1
  298. package/dist/confluent/tools/handlers/flink/read-flink-statement-handler.d.ts +5 -7
  299. package/dist/confluent/tools/handlers/flink/read-flink-statement-handler.d.ts.map +1 -1
  300. package/dist/confluent/tools/handlers/flink/read-flink-statement-handler.js +7 -13
  301. package/dist/confluent/tools/handlers/flink/read-flink-statement-handler.js.map +1 -1
  302. package/dist/confluent/tools/handlers/kafka/alter-topic-config.d.ts +5 -6
  303. package/dist/confluent/tools/handlers/kafka/alter-topic-config.d.ts.map +1 -1
  304. package/dist/confluent/tools/handlers/kafka/alter-topic-config.js +22 -20
  305. package/dist/confluent/tools/handlers/kafka/alter-topic-config.js.map +1 -1
  306. package/dist/confluent/tools/handlers/kafka/consume-kafka-messages-handler.d.ts +216 -30
  307. package/dist/confluent/tools/handlers/kafka/consume-kafka-messages-handler.d.ts.map +1 -1
  308. package/dist/confluent/tools/handlers/kafka/consume-kafka-messages-handler.js +797 -70
  309. package/dist/confluent/tools/handlers/kafka/consume-kafka-messages-handler.js.map +1 -1
  310. package/dist/confluent/tools/handlers/kafka/consumer-group-enums.d.ts +48 -0
  311. package/dist/confluent/tools/handlers/kafka/consumer-group-enums.d.ts.map +1 -0
  312. package/dist/confluent/tools/handlers/kafka/consumer-group-enums.js +84 -0
  313. package/dist/confluent/tools/handlers/kafka/consumer-group-enums.js.map +1 -0
  314. package/dist/confluent/tools/handlers/kafka/consumer-group-helpers.d.ts +54 -0
  315. package/dist/confluent/tools/handlers/kafka/consumer-group-helpers.d.ts.map +1 -0
  316. package/dist/confluent/tools/handlers/kafka/consumer-group-helpers.js +89 -0
  317. package/dist/confluent/tools/handlers/kafka/consumer-group-helpers.js.map +1 -0
  318. package/dist/confluent/tools/handlers/kafka/create-topics-handler.d.ts +5 -5
  319. package/dist/confluent/tools/handlers/kafka/create-topics-handler.d.ts.map +1 -1
  320. package/dist/confluent/tools/handlers/kafka/create-topics-handler.js +52 -15
  321. package/dist/confluent/tools/handlers/kafka/create-topics-handler.js.map +1 -1
  322. package/dist/confluent/tools/handlers/kafka/delete-topics-handler.d.ts +5 -5
  323. package/dist/confluent/tools/handlers/kafka/delete-topics-handler.d.ts.map +1 -1
  324. package/dist/confluent/tools/handlers/kafka/delete-topics-handler.js +26 -8
  325. package/dist/confluent/tools/handlers/kafka/delete-topics-handler.js.map +1 -1
  326. package/dist/confluent/tools/handlers/kafka/describe-consumer-group-handler.d.ts +64 -0
  327. package/dist/confluent/tools/handlers/kafka/describe-consumer-group-handler.d.ts.map +1 -0
  328. package/dist/confluent/tools/handlers/kafka/describe-consumer-group-handler.js +140 -0
  329. package/dist/confluent/tools/handlers/kafka/describe-consumer-group-handler.js.map +1 -0
  330. package/dist/confluent/tools/handlers/kafka/get-consumer-group-lag-handler.d.ts +73 -0
  331. package/dist/confluent/tools/handlers/kafka/get-consumer-group-lag-handler.d.ts.map +1 -0
  332. package/dist/confluent/tools/handlers/kafka/get-consumer-group-lag-handler.js +337 -0
  333. package/dist/confluent/tools/handlers/kafka/get-consumer-group-lag-handler.js.map +1 -0
  334. package/dist/confluent/tools/handlers/kafka/get-partition-offsets-handler.d.ts +43 -0
  335. package/dist/confluent/tools/handlers/kafka/get-partition-offsets-handler.d.ts.map +1 -0
  336. package/dist/confluent/tools/handlers/kafka/get-partition-offsets-handler.js +123 -0
  337. package/dist/confluent/tools/handlers/kafka/get-partition-offsets-handler.js.map +1 -0
  338. package/dist/confluent/tools/handlers/kafka/get-topic-config.d.ts +5 -6
  339. package/dist/confluent/tools/handlers/kafka/get-topic-config.d.ts.map +1 -1
  340. package/dist/confluent/tools/handlers/kafka/get-topic-config.js +22 -20
  341. package/dist/confluent/tools/handlers/kafka/get-topic-config.js.map +1 -1
  342. package/dist/confluent/tools/handlers/kafka/list-consumer-groups-handler.d.ts +45 -0
  343. package/dist/confluent/tools/handlers/kafka/list-consumer-groups-handler.d.ts.map +1 -0
  344. package/dist/confluent/tools/handlers/kafka/list-consumer-groups-handler.js +86 -0
  345. package/dist/confluent/tools/handlers/kafka/list-consumer-groups-handler.js.map +1 -0
  346. package/dist/confluent/tools/handlers/kafka/list-topics-handler.d.ts +5 -5
  347. package/dist/confluent/tools/handlers/kafka/list-topics-handler.d.ts.map +1 -1
  348. package/dist/confluent/tools/handlers/kafka/list-topics-handler.js +25 -10
  349. package/dist/confluent/tools/handlers/kafka/list-topics-handler.js.map +1 -1
  350. package/dist/confluent/tools/handlers/kafka/partition-watermarks.d.ts +54 -0
  351. package/dist/confluent/tools/handlers/kafka/partition-watermarks.d.ts.map +1 -0
  352. package/dist/confluent/tools/handlers/kafka/partition-watermarks.js +56 -0
  353. package/dist/confluent/tools/handlers/kafka/partition-watermarks.js.map +1 -0
  354. package/dist/confluent/tools/handlers/kafka/produce-kafka-message-handler.d.ts +8 -8
  355. package/dist/confluent/tools/handlers/kafka/produce-kafka-message-handler.d.ts.map +1 -1
  356. package/dist/confluent/tools/handlers/kafka/produce-kafka-message-handler.js +57 -46
  357. package/dist/confluent/tools/handlers/kafka/produce-kafka-message-handler.js.map +1 -1
  358. package/dist/confluent/tools/handlers/kafka/topic-metadata.d.ts +18 -0
  359. package/dist/confluent/tools/handlers/kafka/topic-metadata.d.ts.map +1 -0
  360. package/dist/confluent/tools/handlers/kafka/topic-metadata.js +18 -0
  361. package/dist/confluent/tools/handlers/kafka/topic-metadata.js.map +1 -0
  362. package/dist/confluent/tools/handlers/metrics/list-metrics-handler.d.ts +6 -6
  363. package/dist/confluent/tools/handlers/metrics/list-metrics-handler.d.ts.map +1 -1
  364. package/dist/confluent/tools/handlers/metrics/list-metrics-handler.js +6 -9
  365. package/dist/confluent/tools/handlers/metrics/list-metrics-handler.js.map +1 -1
  366. package/dist/confluent/tools/handlers/metrics/query-metrics-handler.d.ts +24 -6
  367. package/dist/confluent/tools/handlers/metrics/query-metrics-handler.d.ts.map +1 -1
  368. package/dist/confluent/tools/handlers/metrics/query-metrics-handler.js +88 -53
  369. package/dist/confluent/tools/handlers/metrics/query-metrics-handler.js.map +1 -1
  370. package/dist/confluent/tools/handlers/organizations/list-organizations-handler.d.ts +50 -0
  371. package/dist/confluent/tools/handlers/organizations/list-organizations-handler.d.ts.map +1 -0
  372. package/dist/confluent/tools/handlers/organizations/list-organizations-handler.js +116 -0
  373. package/dist/confluent/tools/handlers/organizations/list-organizations-handler.js.map +1 -0
  374. package/dist/confluent/tools/handlers/schema/delete-schema-handler.d.ts +5 -5
  375. package/dist/confluent/tools/handlers/schema/delete-schema-handler.d.ts.map +1 -1
  376. package/dist/confluent/tools/handlers/schema/delete-schema-handler.js +13 -8
  377. package/dist/confluent/tools/handlers/schema/delete-schema-handler.js.map +1 -1
  378. package/dist/confluent/tools/handlers/schema/list-schemas-handler.d.ts +5 -5
  379. package/dist/confluent/tools/handlers/schema/list-schemas-handler.d.ts.map +1 -1
  380. package/dist/confluent/tools/handlers/schema/list-schemas-handler.js +13 -7
  381. package/dist/confluent/tools/handlers/schema/list-schemas-handler.js.map +1 -1
  382. package/dist/confluent/tools/handlers/search/search-topic-by-tag-handler.d.ts +6 -6
  383. package/dist/confluent/tools/handlers/search/search-topic-by-tag-handler.d.ts.map +1 -1
  384. package/dist/confluent/tools/handlers/search/search-topic-by-tag-handler.js +6 -9
  385. package/dist/confluent/tools/handlers/search/search-topic-by-tag-handler.js.map +1 -1
  386. package/dist/confluent/tools/handlers/search/search-topics-by-name-handler.d.ts +6 -6
  387. package/dist/confluent/tools/handlers/search/search-topics-by-name-handler.d.ts.map +1 -1
  388. package/dist/confluent/tools/handlers/search/search-topics-by-name-handler.js +6 -9
  389. package/dist/confluent/tools/handlers/search/search-topics-by-name-handler.js.map +1 -1
  390. package/dist/confluent/tools/handlers/tableflow/catalog/create-tableflow-catalog-integration-handler.d.ts +5 -7
  391. package/dist/confluent/tools/handlers/tableflow/catalog/create-tableflow-catalog-integration-handler.d.ts.map +1 -1
  392. package/dist/confluent/tools/handlers/tableflow/catalog/create-tableflow-catalog-integration-handler.js +17 -13
  393. package/dist/confluent/tools/handlers/tableflow/catalog/create-tableflow-catalog-integration-handler.js.map +1 -1
  394. package/dist/confluent/tools/handlers/tableflow/catalog/delete-tableflow-catalog-integration-handler.d.ts +5 -7
  395. package/dist/confluent/tools/handlers/tableflow/catalog/delete-tableflow-catalog-integration-handler.d.ts.map +1 -1
  396. package/dist/confluent/tools/handlers/tableflow/catalog/delete-tableflow-catalog-integration-handler.js +6 -12
  397. package/dist/confluent/tools/handlers/tableflow/catalog/delete-tableflow-catalog-integration-handler.js.map +1 -1
  398. package/dist/confluent/tools/handlers/tableflow/catalog/list-tableflow-catalog-integrations-handler.d.ts +5 -7
  399. package/dist/confluent/tools/handlers/tableflow/catalog/list-tableflow-catalog-integrations-handler.d.ts.map +1 -1
  400. package/dist/confluent/tools/handlers/tableflow/catalog/list-tableflow-catalog-integrations-handler.js +7 -13
  401. package/dist/confluent/tools/handlers/tableflow/catalog/list-tableflow-catalog-integrations-handler.js.map +1 -1
  402. package/dist/confluent/tools/handlers/tableflow/catalog/read-tableflow-catalog-integration-handler.d.ts +5 -7
  403. package/dist/confluent/tools/handlers/tableflow/catalog/read-tableflow-catalog-integration-handler.d.ts.map +1 -1
  404. package/dist/confluent/tools/handlers/tableflow/catalog/read-tableflow-catalog-integration-handler.js +6 -12
  405. package/dist/confluent/tools/handlers/tableflow/catalog/read-tableflow-catalog-integration-handler.js.map +1 -1
  406. package/dist/confluent/tools/handlers/tableflow/catalog/update-tableflow-catalog-integration-handler.d.ts +5 -7
  407. package/dist/confluent/tools/handlers/tableflow/catalog/update-tableflow-catalog-integration-handler.d.ts.map +1 -1
  408. package/dist/confluent/tools/handlers/tableflow/catalog/update-tableflow-catalog-integration-handler.js +5 -9
  409. package/dist/confluent/tools/handlers/tableflow/catalog/update-tableflow-catalog-integration-handler.js.map +1 -1
  410. package/dist/confluent/tools/handlers/tableflow/list-tableflow-regions-handler.d.ts +5 -7
  411. package/dist/confluent/tools/handlers/tableflow/list-tableflow-regions-handler.d.ts.map +1 -1
  412. package/dist/confluent/tools/handlers/tableflow/list-tableflow-regions-handler.js +18 -21
  413. package/dist/confluent/tools/handlers/tableflow/list-tableflow-regions-handler.js.map +1 -1
  414. package/dist/confluent/tools/handlers/tableflow/tableflow-tool-handler.d.ts +26 -0
  415. package/dist/confluent/tools/handlers/tableflow/tableflow-tool-handler.d.ts.map +1 -0
  416. package/dist/confluent/tools/handlers/tableflow/tableflow-tool-handler.js +28 -0
  417. package/dist/confluent/tools/handlers/tableflow/tableflow-tool-handler.js.map +1 -0
  418. package/dist/confluent/tools/handlers/tableflow/topic/create-tableflow-topic-handler.d.ts +5 -7
  419. package/dist/confluent/tools/handlers/tableflow/topic/create-tableflow-topic-handler.d.ts.map +1 -1
  420. package/dist/confluent/tools/handlers/tableflow/topic/create-tableflow-topic-handler.js +17 -13
  421. package/dist/confluent/tools/handlers/tableflow/topic/create-tableflow-topic-handler.js.map +1 -1
  422. package/dist/confluent/tools/handlers/tableflow/topic/delete-tableflow-topic-handler.d.ts +5 -7
  423. package/dist/confluent/tools/handlers/tableflow/topic/delete-tableflow-topic-handler.d.ts.map +1 -1
  424. package/dist/confluent/tools/handlers/tableflow/topic/delete-tableflow-topic-handler.js +6 -12
  425. package/dist/confluent/tools/handlers/tableflow/topic/delete-tableflow-topic-handler.js.map +1 -1
  426. package/dist/confluent/tools/handlers/tableflow/topic/list-tableflow-topics-handler.d.ts +5 -7
  427. package/dist/confluent/tools/handlers/tableflow/topic/list-tableflow-topics-handler.d.ts.map +1 -1
  428. package/dist/confluent/tools/handlers/tableflow/topic/list-tableflow-topics-handler.js +7 -13
  429. package/dist/confluent/tools/handlers/tableflow/topic/list-tableflow-topics-handler.js.map +1 -1
  430. package/dist/confluent/tools/handlers/tableflow/topic/read-tableflow-topic-handler.d.ts +5 -7
  431. package/dist/confluent/tools/handlers/tableflow/topic/read-tableflow-topic-handler.d.ts.map +1 -1
  432. package/dist/confluent/tools/handlers/tableflow/topic/read-tableflow-topic-handler.js +6 -12
  433. package/dist/confluent/tools/handlers/tableflow/topic/read-tableflow-topic-handler.js.map +1 -1
  434. package/dist/confluent/tools/handlers/tableflow/topic/update-tableflow-topic-handler.d.ts +5 -7
  435. package/dist/confluent/tools/handlers/tableflow/topic/update-tableflow-topic-handler.d.ts.map +1 -1
  436. package/dist/confluent/tools/handlers/tableflow/topic/update-tableflow-topic-handler.js +5 -9
  437. package/dist/confluent/tools/handlers/tableflow/topic/update-tableflow-topic-handler.js.map +1 -1
  438. package/dist/confluent/tools/tool-availability.d.ts +91 -0
  439. package/dist/confluent/tools/tool-availability.d.ts.map +1 -0
  440. package/dist/confluent/tools/tool-availability.js +130 -0
  441. package/dist/confluent/tools/tool-availability.js.map +1 -0
  442. package/dist/confluent/tools/tool-name.d.ts +20 -2
  443. package/dist/confluent/tools/tool-name.d.ts.map +1 -1
  444. package/dist/confluent/tools/tool-name.js +19 -1
  445. package/dist/confluent/tools/tool-name.js.map +1 -1
  446. package/dist/confluent/tools/tool-registry.d.ts +17 -0
  447. package/dist/confluent/tools/tool-registry.d.ts.map +1 -0
  448. package/dist/confluent/tools/{tool-factory.js → tool-registry.js} +66 -22
  449. package/dist/confluent/tools/tool-registry.js.map +1 -0
  450. package/dist/env-schema.d.ts +6 -7
  451. package/dist/env-schema.d.ts.map +1 -1
  452. package/dist/env-schema.js +30 -44
  453. package/dist/env-schema.js.map +1 -1
  454. package/dist/env.d.ts +17 -7
  455. package/dist/env.d.ts.map +1 -1
  456. package/dist/env.js +16 -6
  457. package/dist/env.js.map +1 -1
  458. package/dist/index.d.ts +74 -1
  459. package/dist/index.d.ts.map +1 -1
  460. package/dist/index.js +302 -166
  461. package/dist/index.js.map +1 -1
  462. package/dist/logger.d.ts.map +1 -1
  463. package/dist/logger.js +21 -20
  464. package/dist/logger.js.map +1 -1
  465. package/dist/mcp/server.d.ts +29 -0
  466. package/dist/mcp/server.d.ts.map +1 -0
  467. package/dist/mcp/server.js +53 -0
  468. package/dist/mcp/server.js.map +1 -0
  469. package/dist/mcp/transports/auth.d.ts +20 -4
  470. package/dist/mcp/transports/auth.d.ts.map +1 -1
  471. package/dist/mcp/transports/auth.js +27 -7
  472. package/dist/mcp/transports/auth.js.map +1 -1
  473. package/dist/mcp/transports/http.d.ts +8 -2
  474. package/dist/mcp/transports/http.d.ts.map +1 -1
  475. package/dist/mcp/transports/http.js +57 -42
  476. package/dist/mcp/transports/http.js.map +1 -1
  477. package/dist/mcp/transports/manager.d.ts +23 -9
  478. package/dist/mcp/transports/manager.d.ts.map +1 -1
  479. package/dist/mcp/transports/manager.js +27 -24
  480. package/dist/mcp/transports/manager.js.map +1 -1
  481. package/dist/mcp/transports/server.d.ts +1 -1
  482. package/dist/mcp/transports/server.d.ts.map +1 -1
  483. package/dist/mcp/transports/server.js +17 -5
  484. package/dist/mcp/transports/server.js.map +1 -1
  485. package/dist/mcp/transports/session-registry.d.ts +33 -0
  486. package/dist/mcp/transports/session-registry.d.ts.map +1 -0
  487. package/dist/mcp/transports/session-registry.js +65 -0
  488. package/dist/mcp/transports/session-registry.js.map +1 -0
  489. package/dist/mcp/transports/sse.d.ts +13 -2
  490. package/dist/mcp/transports/sse.d.ts.map +1 -1
  491. package/dist/mcp/transports/sse.js +58 -46
  492. package/dist/mcp/transports/sse.js.map +1 -1
  493. package/dist/server-runtime.d.ts +28 -0
  494. package/dist/server-runtime.d.ts.map +1 -0
  495. package/dist/server-runtime.js +73 -0
  496. package/dist/server-runtime.js.map +1 -0
  497. package/package.json +26 -9
  498. package/dist/confluent/helpers.d.ts +0 -11
  499. package/dist/confluent/helpers.d.ts.map +0 -1
  500. package/dist/confluent/helpers.js +0 -17
  501. package/dist/confluent/helpers.js.map +0 -1
  502. package/dist/confluent/tools/handlers/connect/read-connectors-handler.d.ts +0 -11
  503. package/dist/confluent/tools/handlers/connect/read-connectors-handler.d.ts.map +0 -1
  504. package/dist/confluent/tools/handlers/connect/read-connectors-handler.js +0 -59
  505. package/dist/confluent/tools/handlers/connect/read-connectors-handler.js.map +0 -1
  506. package/dist/confluent/tools/tool-factory.d.ts +0 -9
  507. package/dist/confluent/tools/tool-factory.d.ts.map +0 -1
  508. package/dist/confluent/tools/tool-factory.js.map +0 -1
@@ -1,28 +1,127 @@
1
- import { KafkaJS } from "@confluentinc/kafka-javascript";
2
1
  import { SerdeType } from "@confluentinc/schemaregistry";
3
- import { deserializeMessage, getLatestSchemaIfExists, } from "../../../../confluent/schema-registry-helper.js";
4
- import { BaseToolHandler, READ_ONLY, } from "../../../../confluent/tools/base-tools.js";
2
+ import { nodeCrypto } from "../../../../confluent/node-deps.js";
3
+ import * as schemaRegistryHelper from "../../../../confluent/schema-registry-helper.js";
4
+ import { BaseToolHandler, READ_ONLY, ToolCategory, } from "../../../../confluent/tools/base-tools.js";
5
+ import { disposeIfOAuth, formatKafkaError, resolveKafkaClusterArgs, } from "../../../../confluent/tools/cluster-arg-resolvers.js";
6
+ import { hasSchemaRegistryOrOAuth, kafkaBootstrapOrOAuth, } from "../../../../confluent/tools/connection-predicates.js";
7
+ import { createWatermarkCache, } from "../../../../confluent/tools/handlers/kafka/partition-watermarks.js";
8
+ import { normalizeFetchTopicMetadataResponse } from "../../../../confluent/tools/handlers/kafka/topic-metadata.js";
5
9
  import { ToolName } from "../../../../confluent/tools/tool-name.js";
6
10
  import { logger } from "../../../../logger.js";
7
11
  import { z } from "zod";
8
- const messageOptions = z.object({
9
- useSchemaRegistry: z
12
+ const schemaRegistryOptions = z
13
+ .object({
14
+ disableSchemaRegistry: z
10
15
  .boolean()
11
16
  .optional()
12
17
  .default(false)
13
- .describe("Whether to use schema registry for deserialization. If false, messages will be returned as raw."),
18
+ .describe("Set to true to skip Schema Registry decoding and return raw UTF-8 bytes. " +
19
+ "When false (the default), messages are auto-decoded via the registered " +
20
+ "AVRO / JSON / PROTOBUF schema if the connection has Schema Registry " +
21
+ "configured and a schema exists for the subject; otherwise left as raw bytes."),
14
22
  subject: z
15
23
  .string()
16
24
  .optional()
17
- .describe("Schema registry subject. Defaults to 'topicName-value' or 'topicName-key'."),
25
+ .describe("Schema registry subject. Defaults to '<topic>-value' or '<topic>-key'."),
26
+ })
27
+ // The optional() + default() wrapping lives here on the shared
28
+ // schema so `valueFormat` and `keyFormat` declarations downstream
29
+ // are bare references — one place to change if the omit-by-default
30
+ // contract ever evolves.
31
+ .optional()
32
+ .default({ disableSchemaRegistry: false });
33
+ /**
34
+ * Per-entry "where to start consuming" tagged union. Collapses the prior
35
+ * `offset` and `timestamp` peer fields plus the top-level `offsetReset`
36
+ * knob into a single per-topic position control with five arms:
37
+ *
38
+ * - `"earliest"` — begin at the partition low watermark (entire retained
39
+ * history). This is the default when `start` is omitted.
40
+ * - `"latest"` — begin at the partition high watermark (only
41
+ * newly-produced messages).
42
+ * - `{ offset: "..." }` — begin at an absolute partition offset
43
+ * (digit-only string; requires `partition`).
44
+ * - `{ timestamp: ... }` — begin at the broker-resolved offset for the
45
+ * supplied time (ISO 8601 preferred; ms-since-epoch also accepted).
46
+ * - `{ tail: N }` — begin at `max(low, high - N)` on the partition, so
47
+ * the consumer returns up to the last N already-written messages
48
+ * without waiting for new traffic (requires `partition`).
49
+ *
50
+ * The object arms are `strictObject` so `{offset, timestamp}`,
51
+ * `{tail, offset}`, etc. together are a union miss rather than a silent
52
+ * strip of one key.
53
+ */
54
+ const startOption = z
55
+ .union([
56
+ z.literal("earliest"),
57
+ z.literal("latest"),
58
+ z.strictObject({
59
+ offset: z
60
+ .string()
61
+ .regex(/^\d+$/, "offset must be a non-negative integer (digit-only string)")
62
+ .describe("Absolute starting offset within the partition, as a digit-only string."),
63
+ }),
64
+ z.strictObject({
65
+ timestamp: z
66
+ .union([
67
+ z.iso.datetime({ offset: true }),
68
+ z.number().int().nonnegative(),
69
+ ])
70
+ .describe('ISO 8601 timestamp (e.g. "2026-05-14T17:00:00Z" or ' +
71
+ '"2026-05-14T13:00:00-04:00") or ms-since-epoch number. The ' +
72
+ "broker resolves this to a per-partition offset."),
73
+ }),
74
+ z.strictObject({
75
+ tail: z
76
+ .number()
77
+ .int()
78
+ .positive()
79
+ .describe("Consume the most recent N already-written messages from this partition. " +
80
+ "REQUIRES `partition` to be set on the same topic entry — there " +
81
+ "is no implicit partition default; consumption is " +
82
+ "single-partition only. N must be a positive integer. The " +
83
+ "consumer seeks to max(lowWatermark, highWatermark - N) and " +
84
+ "returns immediately with whatever is already there — it does " +
85
+ "not block waiting for new writes."),
86
+ }),
87
+ ])
88
+ .describe("Where to begin consuming this topic. Use 'earliest' for the entire " +
89
+ "retained history; 'latest' for " +
90
+ "newly-produced messages only; {offset: 'N'} for an absolute " +
91
+ "partition offset (requires `partition`); {timestamp: '...'} " +
92
+ "to seek to the broker-resolved offset for a point in time; or " +
93
+ "{tail: N} for the last N already-written messages on the " +
94
+ "partition (requires `partition`, returns without waiting for new " +
95
+ "traffic).");
96
+ /**
97
+ * Per-topic consume options. `name` is the only required field. `partition`
98
+ * optionally restricts to one partition; `start` optionally picks the
99
+ * starting position. Both are independent — `partition` answers WHICH
100
+ * partition(s), `start` answers WHERE in them to begin.
101
+ */
102
+ const topicConsumeOptions = z.object({
103
+ name: z.string().min(1).describe("Kafka topic name to consume from."),
104
+ partition: z
105
+ .number()
106
+ .int()
107
+ .nonnegative()
108
+ .optional()
109
+ .describe("Optional. Restrict consumption to this partition (0-indexed). " +
110
+ "Other partitions in the topic are paused after assignment. " +
111
+ "Omit to consume all partitions of the topic."),
112
+ start: startOption.optional().default("earliest"),
18
113
  });
19
- const valueOptions = z.object({}).extend(messageOptions.shape);
20
- const keyOptions = z.object({}).extend(messageOptions.shape);
21
114
  export const consumeKafkaMessagesArgs = z.object({
22
- topicNames: z
23
- .array(z.string())
115
+ topics: z
116
+ .array(topicConsumeOptions)
24
117
  .nonempty()
25
- .describe("Names of the Kafka topics to consume from."),
118
+ .describe("Topics to consume from. Each entry is an object with at least " +
119
+ "`name` (the Kafka topic name). Example simple call: " +
120
+ '[{name: "orders"}]. The `partition` and `start` fields let ' +
121
+ "callers restrict to a specific partition and/or pick where in " +
122
+ "the topic to begin consuming (e.g. " +
123
+ '[{name: "orders", partition: 0, start: {offset: "42"}}], ' +
124
+ '[{name: "orders", start: {timestamp: "2026-05-14T17:00:00Z"}}]).'),
26
125
  maxMessages: z
27
126
  .number()
28
127
  .int()
@@ -37,9 +136,504 @@ export const consumeKafkaMessagesArgs = z.object({
37
136
  .optional()
38
137
  .default(10000)
39
138
  .describe("Maximum time in milliseconds to wait for messages before stopping."),
40
- value: valueOptions,
41
- key: keyOptions.optional(),
139
+ valueFormat: schemaRegistryOptions.describe("VALUE format. Default: auto-decode via Schema Registry when configured. " +
140
+ "Set `disableSchemaRegistry: true` for raw UTF-8."),
141
+ keyFormat: schemaRegistryOptions.describe("KEY format. Default: auto-decode via Schema Registry when configured. " +
142
+ "Set `disableSchemaRegistry: true` for raw UTF-8."),
143
+ cluster_id: z
144
+ .string()
145
+ .optional()
146
+ .describe("Confluent Cloud logical Kafka cluster ID (lkc-...). Discover via list-clusters."),
147
+ environment_id: z
148
+ .string()
149
+ .optional()
150
+ .describe("Confluent Cloud environment ID (env-...) that owns the cluster. Discover via list-environments."),
42
151
  });
152
+ /**
153
+ * Format a Kafka message's `message.timestamp` (a string of ms-since-epoch
154
+ * per kafkajs) into an ISO 8601 UTC string. Returns `"(no timestamp)"` for
155
+ * undefined or Kafka's `-1` sentinel (message format pre-0.10.0 or
156
+ * timestamp unset by the producer). Exported for direct unit-test coverage
157
+ * of the four branches plus the empty-string edge case (`Number("")` is
158
+ * `0`, which is finite, so an empty timestamp string formats as epoch).
159
+ */
160
+ export function formatMessageTimestamp(ts) {
161
+ if (ts === undefined || ts === "-1")
162
+ return "(no timestamp)";
163
+ const ms = Number(ts);
164
+ if (!Number.isFinite(ms))
165
+ return ts;
166
+ return new Date(ms).toISOString();
167
+ }
168
+ /**
169
+ * Collapse the parsed `start` union into the internal tagged form.
170
+ * ISO 8601 timestamps normalize to ms-since-epoch at this boundary so
171
+ * downstream code only sees numbers. Exported so the timestamp-arm's
172
+ * string-vs-number branch can be unit-tested directly (the handler-level
173
+ * tests only exercise the string path).
174
+ */
175
+ export function normalizeStart(start) {
176
+ if (start === "earliest")
177
+ return { kind: "earliest" };
178
+ if (start === "latest")
179
+ return { kind: "latest" };
180
+ if ("offset" in start)
181
+ return { kind: "offset", value: start.offset };
182
+ if ("tail" in start)
183
+ return { kind: "tail", count: start.tail };
184
+ return {
185
+ kind: "timestamp",
186
+ ms: typeof start.timestamp === "number"
187
+ ? start.timestamp
188
+ : Date.parse(start.timestamp),
189
+ };
190
+ }
191
+ /**
192
+ * Normalize the parsed tool args into a uniform list of per-topic targets.
193
+ */
194
+ function normalizeTopicTargets(parsed) {
195
+ return parsed.topics.map((entry) => ({
196
+ name: entry.name,
197
+ partition: entry.partition,
198
+ start: normalizeStart(entry.start),
199
+ }));
200
+ }
201
+ /**
202
+ * Pick the consumer's `auto.offset.reset` value from the call. The
203
+ * consumer-wide setting governs any partition that doesn't get an
204
+ * explicit seek — so we want to align it with the call's intent and
205
+ * avoid emitting watermark seeks unnecessarily.
206
+ *
207
+ * Rule: if every direction-only entry (`start: "earliest"` or
208
+ * `start: "latest"`) agrees on `"earliest"`, use `"earliest"`; otherwise
209
+ * use `"latest"`. The choice of `"latest"` as the mixed-direction
210
+ * tiebreaker matches librdkafka's own `auto.offset.reset` default and
211
+ * keeps the explicit-seek work localized to the `"earliest"` minority
212
+ * (which gets per-partition low-watermark seeks during preflight); the
213
+ * `"latest"` majority inherits the consumer-wide default and needs no
214
+ * extra admin round-trips.
215
+ */
216
+ function deriveConsumerOffsetReset(targets) {
217
+ const directions = targets
218
+ .map((t) => t.start.kind === "earliest" || t.start.kind === "latest"
219
+ ? t.start.kind
220
+ : null)
221
+ .filter((d) => d !== null);
222
+ if (directions.length > 0 && directions.every((d) => d === "earliest")) {
223
+ return "earliest";
224
+ }
225
+ return "latest";
226
+ }
227
+ /**
228
+ * Returns true when any target requires the admin pre-flight + seek/pause
229
+ * dance. Bare-name-only calls (no partition restrictions, no explicit
230
+ * offset/timestamp/tail seeks, and a `start` whose direction matches the
231
+ * consumer's chosen reset) skip the whole dance — the consumer's
232
+ * `auto.offset.reset` handles them naturally.
233
+ */
234
+ function planNeedsPreflight(targets, consumerOffsetReset) {
235
+ return targets.some((t) => t.partition !== undefined ||
236
+ t.start.kind === "offset" ||
237
+ t.start.kind === "timestamp" ||
238
+ t.start.kind === "tail" ||
239
+ (t.start.kind === "earliest" && consumerOffsetReset === "latest"));
240
+ }
241
+ /**
242
+ * Reject any target whose `start` arm is partition-scoped but supplies
243
+ * no `partition`. Both `{offset}` and `{tail}` need partition context
244
+ * (different partitions have different offset spaces and different
245
+ * message counts), so picking a default is footgun-prone; rejecting at
246
+ * the boundary is louder.
247
+ */
248
+ function guardScopedStartRequiresPartition(targets) {
249
+ for (const t of targets) {
250
+ if (t.start.kind === "offset" && t.partition === undefined) {
251
+ throw new Error(`Topic "${t.name}" has an explicit offset (${t.start.value}) but no partition. ` +
252
+ `Absolute offsets are partition-scoped — different partitions have different offset spaces. ` +
253
+ `Either also supply a partition for this entry, or use a timestamp (which resolves per-partition).`);
254
+ }
255
+ if (t.start.kind === "tail" && t.partition === undefined) {
256
+ throw new Error(`Topic "${t.name}" requested tail of ${t.start.count} messages but no partition. ` +
257
+ `Tail is partition-scoped — different partitions have different message counts, and ` +
258
+ `cross-partition freshness ordering is not defined for this tool. ` +
259
+ `Supply a partition for this entry.`);
260
+ }
261
+ }
262
+ }
263
+ /**
264
+ * Group targets by topic name preserving entry order. Used downstream
265
+ * for both the all-or-nothing partition-mode check and the keep-set
266
+ * derivation; computing it once means subsequent iterations stay O(N).
267
+ */
268
+ /**
269
+ * Fetch partition counts for the supplied topics via
270
+ * `admin.fetchTopicMetadata`. Throws if any requested topic returned no
271
+ * metadata (typically: the topic doesn't exist on this cluster). The
272
+ * upstream type/runtime mismatch on the response shape is handled by
273
+ * {@link normalizeFetchTopicMetadataResponse}.
274
+ */
275
+ async function fetchPartitionCounts(admin, topicNames) {
276
+ const topicMetadata = normalizeFetchTopicMetadataResponse(await admin.fetchTopicMetadata({ topics: topicNames }));
277
+ const counts = new Map();
278
+ for (const t of topicMetadata) {
279
+ counts.set(t.name, t.partitions.length);
280
+ }
281
+ for (const name of topicNames) {
282
+ if (!counts.has(name)) {
283
+ throw new Error(`Topic "${name}" returned no partition metadata (does it exist on this cluster?).`);
284
+ }
285
+ }
286
+ return counts;
287
+ }
288
+ /**
289
+ * Reject any target whose `partition` index is out of range for its
290
+ * topic. The error message cites the actual partition count so the
291
+ * caller can correct without guessing.
292
+ */
293
+ function validateRequestedPartitions(targets, numPartitionsByTopic) {
294
+ for (const t of targets) {
295
+ if (t.partition !== undefined) {
296
+ const numParts = numPartitionsByTopic.get(t.name);
297
+ if (t.partition >= numParts) {
298
+ throw new Error(`Topic "${t.name}" has ${numParts} partition(s) (0..${numParts - 1}); ` +
299
+ `requested partition ${t.partition} is out of range.`);
300
+ }
301
+ }
302
+ }
303
+ }
304
+ /**
305
+ * Validate per-topic consistency and derive the keep-partitions map in
306
+ * a single pass over `byTopic`. Three rejections fire here, each a
307
+ * shape of "starting position is ambiguous" the consumer can't honor:
308
+ *
309
+ * - **Mixed mode**: a topic with some entries restricting to a partition
310
+ * and others not — does the bare entry coexist with or override the
311
+ * partitioned one? Reject loudly.
312
+ * - **Duplicate unrestricted**: a topic with multiple entries that all
313
+ * omit `partition`. Two "every partition" entries with conflicting
314
+ * `start` directions silently let one win the seek/reset race; reject.
315
+ * - **Duplicate (topic, partition)**: the same partition index referenced
316
+ * twice within one topic — same ambiguity at finer granularity.
317
+ *
318
+ * Topics whose entries are all unrestricted are omitted from the
319
+ * returned map (downstream: "keep every assigned partition for that
320
+ * topic"). For topics that restrict, the keep-set is exactly the
321
+ * requested partition indices.
322
+ */
323
+ function validateAndBuildKeepPartitions(byTopic) {
324
+ const keepPartitions = new Map();
325
+ for (const [topic, list] of byTopic) {
326
+ const explicit = list
327
+ .map((t) => t.partition)
328
+ .filter((p) => p !== undefined);
329
+ const allPartitioned = explicit.length === list.length;
330
+ const nonePartitioned = explicit.length === 0;
331
+ if (!allPartitioned && !nonePartitioned) {
332
+ throw new Error(`Topic "${topic}" mixes entries with explicit partitions and entries without one. ` +
333
+ `Pick one mode per topic: either every entry restricts to a partition, or none do.`);
334
+ }
335
+ if (nonePartitioned) {
336
+ if (list.length > 1) {
337
+ throw new Error(`Topic "${topic}" has ${list.length} entries without partition restrictions; ` +
338
+ `specify each topic at most once at the unrestricted level (or restrict each entry to a distinct partition).`);
339
+ }
340
+ continue;
341
+ }
342
+ const seen = new Set();
343
+ for (const p of explicit) {
344
+ if (seen.has(p)) {
345
+ throw new Error(`Topic "${topic}" has multiple entries for partition ${p}; ` +
346
+ `specify each (topic, partition) pair at most once.`);
347
+ }
348
+ seen.add(p);
349
+ }
350
+ keepPartitions.set(topic, seen);
351
+ }
352
+ return keepPartitions;
353
+ }
354
+ /**
355
+ * Validate an explicit `start: {offset}` against the partition's
356
+ * `[low, high)` watermarks and return the seek target. Throws if the
357
+ * partition has no offset metadata or the requested offset is out of
358
+ * range.
359
+ */
360
+ async function resolveExplicitOffsetSeek(topic, partition, offset, getWatermarks) {
361
+ const offsets = await getWatermarks(topic);
362
+ const partOffsets = offsets.find((o) => o.partition === partition);
363
+ if (!partOffsets) {
364
+ throw new Error(`Topic "${topic}" partition ${partition} returned no offset metadata.`);
365
+ }
366
+ const low = BigInt(partOffsets.low);
367
+ const high = BigInt(partOffsets.high);
368
+ const target = BigInt(offset);
369
+ if (target < low || target >= high) {
370
+ throw new Error(`Topic "${topic}" partition ${partition} offset ${offset} is out of range ` +
371
+ `[low=${partOffsets.low}, high=${partOffsets.high}). ` +
372
+ `An empty partition has low === high; pick an offset already on the partition.`);
373
+ }
374
+ return { topic, partition, offset };
375
+ }
376
+ /**
377
+ * Resolve a `start: {tail: N}` to a single seek target on the requested
378
+ * partition. Computes `target = max(low, high - N)` using `BigInt`
379
+ * (Kafka offsets are int64; `N` may legitimately be large).
380
+ *
381
+ * Empty-partition contract (`low === high`): the seek target collapses
382
+ * to `high` (`max(high, high - N) === high`), which parks the consumer
383
+ * at `OFFSET_END`. No records flow, the orchestrator's `timeoutMs`
384
+ * budget fires, and the call returns an empty success response — the
385
+ * issue's "tail on empty partition returns zero, no error" path. The
386
+ * `BigInt` subtraction stays well-defined for huge `N` because the
387
+ * arithmetic compares signed values and `max` clamps back into the
388
+ * `[low, high)` range before serializing.
389
+ */
390
+ async function resolveTailSeek(topic, partition, count, getWatermarks) {
391
+ const offsets = await getWatermarks(topic);
392
+ const partOffsets = offsets.find((o) => o.partition === partition);
393
+ if (!partOffsets) {
394
+ throw new Error(`Topic "${topic}" partition ${partition} returned no offset metadata.`);
395
+ }
396
+ const low = BigInt(partOffsets.low);
397
+ const high = BigInt(partOffsets.high);
398
+ const candidate = high - BigInt(count);
399
+ // Manual clamp instead of Math.max: Math.max rejects BigInt operands
400
+ // (TypeError: Cannot convert a BigInt value to a number), and the
401
+ // BigInt path is load-bearing because Kafka offsets are int64.
402
+ const target = candidate < low ? low : candidate;
403
+ return { topic, partition, offset: target.toString() };
404
+ }
405
+ /**
406
+ * Resolve a `start: {timestamp}` to per-partition offsets via
407
+ * `admin.fetchTopicOffsetsByTimestamp` AND filter out the binding's
408
+ * silent high-watermark substitutions.
409
+ *
410
+ * `@confluentinc/kafka-javascript`'s `fetchTopicOffsetsByTimestamp`
411
+ * silently substitutes the partition's high watermark when no message
412
+ * exists at or after the requested timestamp (see the method's
413
+ * docstring in node_modules/.../kafkajs/_admin.js). Seeking to a
414
+ * position == high watermark parks the consumer at OFFSET_END and we'd
415
+ * time out with zero messages with no signal as to why. The defense:
416
+ * cross-check each resolved offset against the partition's actual
417
+ * watermarks, skip silent partitions, and emit a diagnostic log so
418
+ * operators can distinguish the three resolution modes (silent /
419
+ * broker-low-fallback / real-index-hit).
420
+ */
421
+ async function resolveTimestampSeeks(admin, topic, restrictToPartition, timestampMs, getWatermarks) {
422
+ const resolved = await admin.fetchTopicOffsetsByTimestamp(topic, timestampMs);
423
+ const watermarks = await getWatermarks(topic);
424
+ const watermarkByPartition = new Map();
425
+ for (const w of watermarks) {
426
+ watermarkByPartition.set(w.partition, { low: w.low, high: w.high });
427
+ }
428
+ const candidates = restrictToPartition === undefined
429
+ ? resolved
430
+ : resolved.filter((r) => r.partition === restrictToPartition);
431
+ const active = [];
432
+ const silent = [];
433
+ for (const r of candidates) {
434
+ const wm = watermarkByPartition.get(r.partition);
435
+ // Diagnostic log so debugging timestamp-to-offset resolution
436
+ // doesn't require adding instrumentation later. Lets a reader
437
+ // distinguish three failure modes from one log inspection:
438
+ // - resolvedOffset == high → binding's silent substitution
439
+ // (already filtered below; the warn-level log fires too).
440
+ // - resolvedOffset == low → broker fell back to the earliest
441
+ // offset (e.g. requested timestamp is older than every
442
+ // indexed message, or tiered-storage index quirk).
443
+ // - resolvedOffset in (low, high) → real timestamp resolution.
444
+ logger.info({
445
+ topic,
446
+ partition: r.partition,
447
+ resolvedOffset: r.offset,
448
+ low: wm?.low,
449
+ high: wm?.high,
450
+ requestedMs: timestampMs,
451
+ requestedIso: new Date(timestampMs).toISOString(),
452
+ }, `Timestamp → offset resolution for ${topic} partition ${r.partition}`);
453
+ if (wm !== undefined && BigInt(r.offset) >= BigInt(wm.high)) {
454
+ silent.push(r.partition);
455
+ }
456
+ else {
457
+ active.push(r);
458
+ }
459
+ }
460
+ if (active.length === 0) {
461
+ const scopePhrase = restrictToPartition === undefined
462
+ ? "every partition"
463
+ : `partition ${restrictToPartition}`;
464
+ throw new Error(`Topic "${topic}" has no messages at or after timestamp ` +
465
+ `${new Date(timestampMs).toISOString()} ` +
466
+ `(${scopePhrase} has no record produced past that point). ` +
467
+ `Try an earlier timestamp, or use \`start: "latest"\` to consume ` +
468
+ `from the live position instead.`);
469
+ }
470
+ if (silent.length > 0) {
471
+ logger.warn({ topic, timestampMs, silentPartitions: silent }, `Skipping seek for partitions of "${topic}" with no record at or after the requested timestamp; they will idle at OFFSET_END.`);
472
+ }
473
+ return active.map((r) => ({
474
+ topic,
475
+ partition: r.partition,
476
+ offset: r.offset,
477
+ }));
478
+ }
479
+ /**
480
+ * Resolve a `start: "earliest"` entry that lost the direction-derivation
481
+ * race — i.e. another entry pushed the consumer-wide
482
+ * `auto.offset.reset` to `"latest"`. Returns explicit low-watermark
483
+ * seeks for every partition (or the single restricted partition) so
484
+ * this topic replays its history instead of inheriting the
485
+ * consumer-wide "latest" default.
486
+ */
487
+ async function resolveEarliestMinoritySeeks(topic, restrictToPartition, getWatermarks) {
488
+ const offsets = await getWatermarks(topic);
489
+ const partitionsToSeek = restrictToPartition === undefined
490
+ ? offsets
491
+ : offsets.filter((o) => o.partition === restrictToPartition);
492
+ return partitionsToSeek.map((p) => ({
493
+ topic,
494
+ partition: p.partition,
495
+ offset: p.low,
496
+ }));
497
+ }
498
+ async function buildPreflightPlan(admin, targets, consumerOffsetReset) {
499
+ guardScopedStartRequiresPartition(targets);
500
+ const byTopic = new Map();
501
+ for (const t of targets) {
502
+ const list = byTopic.get(t.name);
503
+ if (list)
504
+ list.push(t);
505
+ else
506
+ byTopic.set(t.name, [t]);
507
+ }
508
+ const topicNames = [...byTopic.keys()];
509
+ const numPartitionsByTopic = await fetchPartitionCounts(admin, topicNames);
510
+ validateRequestedPartitions(targets, numPartitionsByTopic);
511
+ const keepPartitions = validateAndBuildKeepPartitions(byTopic);
512
+ const getWatermarks = createWatermarkCache(admin);
513
+ const seeks = [];
514
+ for (const t of targets) {
515
+ if (t.start.kind === "offset" && t.partition !== undefined) {
516
+ seeks.push(await resolveExplicitOffsetSeek(t.name, t.partition, t.start.value, getWatermarks));
517
+ }
518
+ else if (t.start.kind === "timestamp") {
519
+ seeks.push(...(await resolveTimestampSeeks(admin, t.name, t.partition, t.start.ms, getWatermarks)));
520
+ }
521
+ else if (t.start.kind === "tail" && t.partition !== undefined) {
522
+ seeks.push(await resolveTailSeek(t.name, t.partition, t.start.count, getWatermarks));
523
+ }
524
+ else if (t.start.kind === "earliest" &&
525
+ consumerOffsetReset === "latest") {
526
+ seeks.push(...(await resolveEarliestMinoritySeeks(t.name, t.partition, getWatermarks)));
527
+ }
528
+ }
529
+ return { topicNames, keepPartitions, seeks };
530
+ }
531
+ /**
532
+ * Poll `consumer.assignment()` until it returns a non-empty array or the
533
+ * supplied deadline passes. Returns the assignment, or `null` if the
534
+ * deadline was hit first. The kafkajs-compat consumer only populates its
535
+ * assignment after `consumer.run()` triggers the first poll, so this is
536
+ * the well-defined seam to wait on before issuing per-partition seeks.
537
+ * Exported so the three branches (immediate-return, polled-populate,
538
+ * polled-timeout) can be exercised directly under fake timers.
539
+ */
540
+ export async function waitForAssignment(consumer, deadline) {
541
+ for (;;) {
542
+ const assignment = consumer.assignment();
543
+ if (assignment.length > 0) {
544
+ return assignment;
545
+ }
546
+ if (Date.now() >= deadline) {
547
+ return null;
548
+ }
549
+ await new Promise((r) => setTimeout(r, 50));
550
+ }
551
+ }
552
+ /**
553
+ * After the consumer assignment lands, pause any assigned partition that
554
+ * isn't in the keep-set. Seeks were stashed before `consumer.run()` (see
555
+ * the inline comment in the orchestrator) so the per-partition seek
556
+ * targets are already baked into the assignment by the time this runs.
557
+ */
558
+ async function applyPauseAfterAssignment(consumer, plan, assignment) {
559
+ const toPause = [];
560
+ for (const [topic, keepSet] of plan.keepPartitions) {
561
+ const pauseForTopic = assignment
562
+ .filter((a) => a.topic === topic && !keepSet.has(a.partition))
563
+ .map((a) => a.partition);
564
+ if (pauseForTopic.length > 0) {
565
+ toPause.push({ topic, partitions: pauseForTopic });
566
+ }
567
+ }
568
+ if (toPause.length > 0) {
569
+ consumer.pause(toPause);
570
+ }
571
+ }
572
+ /**
573
+ * Wrap a promise so its successful resolution is ignored (never settles
574
+ * downstream) while its rejection still propagates. Used in the
575
+ * orchestrator's `Promise.race` to let "engine still running" branches
576
+ * (`consumer.run`, `applyPostAssignmentHook`) participate only on
577
+ * failure — successful completion of those promises shouldn't end the
578
+ * consume loop, but their errors must surface as the race's rejection.
579
+ */
580
+ function rejectOnly(p) {
581
+ return p.then(() => new Promise(() => { }));
582
+ }
583
+ /**
584
+ * Drive the post-`consumer.run()` pause step: poll for an assignment up
585
+ * to `deadlineMs`, then pause partitions outside the keep-set. Signals
586
+ * completion via callbacks rather than its return value because the
587
+ * orchestrator's `Promise.race` only cares about success (`onApplied`)
588
+ * vs. assignment-deadline-elapsed (`onAssignmentTimedOut`); internal
589
+ * pause failures propagate as a rejection so the race can surface them
590
+ * via `rejectOnly`.
591
+ */
592
+ export async function applyPostAssignmentHook(opts) {
593
+ const assignment = await waitForAssignment(opts.consumer, opts.deadlineMs);
594
+ if (!assignment) {
595
+ opts.onAssignmentTimedOut();
596
+ return;
597
+ }
598
+ await applyPauseAfterAssignment(opts.consumer, opts.plan, assignment);
599
+ opts.onApplied();
600
+ }
601
+ /**
602
+ * Build the `eachMessage` callback `consumer.run` invokes per record.
603
+ * Pulled out of the orchestrator so the synchronous gates and the
604
+ * "did we hit `maxMessages`?" signal are individually testable.
605
+ *
606
+ * The synchronous boolean/predicate getters (`isAccepting`,
607
+ * `isPreflightApplied`, `shouldKeepDuringPrePause`) intentionally stay
608
+ * synchronous — `await`ing a Deferred in their place would change
609
+ * behavior, because pre-pause deliveries from librdkafka's fetch buffer
610
+ * must be filtered on arrival rather than queued through.
611
+ *
612
+ * Pre-pause gate semantics: before the post-assignment pause step has
613
+ * run, drop a delivery **only** when its `(topic, partition)` is one
614
+ * we'd pause anyway (i.e. outside the topic's keep-set). Keep-set
615
+ * deliveries arriving during the brief window between assignment-landing
616
+ * and pause-being-applied are real records the caller asked for; the
617
+ * pre-run-stashed seeks have already positioned the consumer, so
618
+ * librdkafka can hand them to `eachMessage` immediately. Dropping them
619
+ * would be silent data loss. After `preflightApplied` flips, the gate
620
+ * doesn't fire (pause has already kept the unwanted partitions silent).
621
+ */
622
+ export function createEachMessageHandler(opts) {
623
+ return async ({ topic, partition, message }) => {
624
+ if (!opts.state.isAccepting())
625
+ return;
626
+ if (!opts.state.isPreflightApplied() &&
627
+ !opts.state.shouldKeepDuringPrePause(topic, partition)) {
628
+ return;
629
+ }
630
+ const processed = await opts.processMessage(topic, partition, message);
631
+ opts.state.consumedMessages.push(processed);
632
+ if (opts.state.consumedMessages.length >= opts.maxMessages) {
633
+ opts.onMaxReached();
634
+ }
635
+ };
636
+ }
43
637
  /**
44
638
  * Handler for consuming messages from Kafka topics with support for Schema Registry deserialization.
45
639
  * This handler allows consuming messages from one or more topics with configurable message limits and timeouts.
@@ -52,25 +646,25 @@ export class ConsumeKafkaMessagesHandler extends BaseToolHandler {
52
646
  * @param partition - The partition the message was consumed from
53
647
  * @param message - The raw Kafka message
54
648
  * @param registry - Optional Schema Registry client for deserialization
55
- * @param valueOptions - Options for value deserialization
56
- * @param keyOptions - Optional options for key deserialization
649
+ * @param valueOptions - Options for value-side deserialization
650
+ * @param keyOptions - Options for key-side deserialization
57
651
  * @returns A processed message with deserialized key and value
58
652
  */
59
653
  async processMessage(topic, partition, message, registry, valueOptions, keyOptions) {
60
654
  let processedKey = message.key?.toString();
61
655
  let processedValue = message.value?.toString();
62
656
  const deserializeWithOptions = async (buffer, options, serdeType) => {
63
- if (!options.useSchemaRegistry || !registry) {
657
+ if (options.disableSchemaRegistry || !registry) {
64
658
  return buffer?.toString();
65
659
  }
66
660
  const subject = options.subject ||
67
661
  `${topic}-${serdeType === SerdeType.KEY ? "key" : "value"}`;
68
- const schema = await getLatestSchemaIfExists(registry, subject);
662
+ const schema = await schemaRegistryHelper.getLatestSchemaIfExists(registry, subject);
69
663
  if (!schema || !schema.schemaType) {
70
664
  return buffer?.toString();
71
665
  }
72
666
  try {
73
- return await deserializeMessage(topic, buffer, schema.schemaType, registry, serdeType);
667
+ return await schemaRegistryHelper.deserializeMessage(topic, buffer, schema.schemaType, registry, serdeType);
74
668
  }
75
669
  catch (err) {
76
670
  logger.error({ error: err, topic, schemaType: schema.schemaType, serdeType }, `Error deserializing message ${serdeType} for topic ${topic}`);
@@ -78,13 +672,13 @@ export class ConsumeKafkaMessagesHandler extends BaseToolHandler {
78
672
  }
79
673
  };
80
674
  processedValue = await deserializeWithOptions(message.value, valueOptions, SerdeType.VALUE);
81
- if (message.key && keyOptions) {
675
+ if (message.key) {
82
676
  processedKey = await deserializeWithOptions(message.key, keyOptions, SerdeType.KEY);
83
677
  }
84
678
  return {
85
679
  key: processedKey,
86
680
  value: processedValue,
87
- timestamp: message.timestamp,
681
+ timestamp: formatMessageTimestamp(message.timestamp),
88
682
  offset: message.offset,
89
683
  headers: message.headers
90
684
  ? Object.fromEntries(Object.entries(message.headers).map(([key, value]) => [
@@ -97,60 +691,193 @@ export class ConsumeKafkaMessagesHandler extends BaseToolHandler {
97
691
  };
98
692
  }
99
693
  /**
100
- * Main handler for consuming messages from Kafka topics.
101
- * @param clientManager - The client manager for Kafka and registry clients
102
- * @param toolArguments - The arguments for the tool, including topics, message limits, and deserialization options
103
- * @param sessionId - Optional session ID for Kafka consumer
104
- * @returns A CallToolResult containing the consumed messages or error information
694
+ * Consume messages from one or more Kafka topics, honoring per-topic
695
+ * `partition` and `start` controls. Resolves when one of four exit
696
+ * conditions wins a `Promise.race`: `maxMessages` records have been
697
+ * collected, the `timeoutMs` budget elapses, `consumer.run()` rejects,
698
+ * or the post-assignment hook rejects. On the timeout path the
699
+ * partial set collected so far is returned (success-shaped response,
700
+ * not an error).
701
+ *
702
+ * @param runtime - The {@link ServerRuntime} (config + active client
703
+ * manager + OAuth holder). Supplied by the MCP server dispatcher;
704
+ * the handler resolves cluster/env/registry clients off of it.
705
+ * @param toolArguments - Parsed args matching `consumeKafkaMessagesArgs`.
706
+ * The handler re-parses internally to apply defaults at the
707
+ * boundary.
708
+ * @returns A {@link CallToolResult}. Success path emits a text block
709
+ * summarizing the consumed messages; failures (build/preflight/run
710
+ * errors) surface via `createResponse(text, true)` with the
711
+ * formatted Kafka error.
105
712
  */
106
- async handle(clientManager, toolArguments, sessionId) {
107
- const { topicNames, maxMessages, timeoutMs, value, key } = consumeKafkaMessagesArgs.parse(toolArguments);
713
+ async handle(runtime, toolArguments) {
714
+ const parsed = consumeKafkaMessagesArgs.parse(toolArguments);
715
+ const { maxMessages, timeoutMs, valueFormat, keyFormat } = parsed;
716
+ const { connId, conn, clientManager } = this.resolveSoleConnection(runtime);
717
+ const resolved = resolveKafkaClusterArgs(parsed, runtime, connId);
718
+ // Auto-decode when SR is reachable on this connection (OAuth always; direct
719
+ // requires a `schema_registry` block — single source of truth lives in the
720
+ // `hasSchemaRegistryOrOAuth` predicate) and the caller hasn't opted out on
721
+ // BOTH sides. Either side wanting decode triggers the SR fetch.
722
+ const userDisabled = valueFormat.disableSchemaRegistry && keyFormat.disableSchemaRegistry;
723
+ const srReachable = hasSchemaRegistryOrOAuth(conn).enabled;
724
+ let registry;
725
+ if (!userDisabled && srReachable) {
726
+ try {
727
+ registry = await clientManager.getSchemaRegistrySdkClient(resolved.envId);
728
+ }
729
+ catch (error) {
730
+ // Graceful fallback: user didn't explicitly opt in, so an SR-transport
731
+ // failure shouldn't fail an otherwise-satisfiable consume. Per-message
732
+ // decode errors already fall back to raw inside processMessage.
733
+ logger.warn({ error, connId }, "Schema Registry client unavailable; consuming as raw bytes.");
734
+ }
735
+ }
736
+ const targets = normalizeTopicTargets(parsed);
737
+ const offsetReset = deriveConsumerOffsetReset(targets);
738
+ const needsPreflight = planNeedsPreflight(targets, offsetReset);
739
+ let plan;
740
+ if (needsPreflight) {
741
+ // `admin` is acquired INSIDE the try so a failed
742
+ // getKafkaAdminClient() (auth/network) becomes a tool-error
743
+ // response rather than propagating up unhandled. The finally
744
+ // guards against running disposeIfOAuth on an undefined admin
745
+ // (which would happen if the acquisition itself threw).
746
+ let admin;
747
+ try {
748
+ admin = await clientManager.getKafkaAdminClient(resolved.clusterId, resolved.envId);
749
+ plan = await buildPreflightPlan(admin, targets, offsetReset);
750
+ }
751
+ catch (error) {
752
+ return this.createResponse(`Failed to consume messages: ${formatKafkaError(error)}`, true);
753
+ }
754
+ finally {
755
+ if (admin !== undefined) {
756
+ await disposeIfOAuth(runtime, connId, admin);
757
+ }
758
+ }
759
+ }
760
+ else {
761
+ plan = {
762
+ topicNames: [...new Set(targets.map((t) => t.name))],
763
+ keepPartitions: new Map(),
764
+ seeks: [],
765
+ };
766
+ }
108
767
  const consumedMessages = [];
109
- let timeoutReached = false;
768
+ // `accepting` is the synchronous gate that suppresses further
769
+ // processing once any terminal condition fires. `preflightApplied`
770
+ // is the synchronous gate that drops pre-pause fetch-buffer
771
+ // deliveries. Both stay booleans because eachMessage needs to check
772
+ // them on arrival — a `Promise` would require `await`, which would
773
+ // queue rather than drop the message.
774
+ let accepting = true;
775
+ let preflightApplied = !needsPreflight;
110
776
  let consumer;
111
- const registry = value.useSchemaRegistry || (key && key.useSchemaRegistry)
112
- ? clientManager.getSchemaRegistryClient()
113
- : undefined;
114
777
  try {
115
- consumer = await clientManager.getConsumer(sessionId);
778
+ consumer = await clientManager.buildKafkaConsumer({
779
+ clusterId: resolved.clusterId,
780
+ envId: resolved.envId,
781
+ // Per-invocation unique group id: each consume call becomes
782
+ // the sole member of its own Kafka consumer group, so two
783
+ // concurrent calls can't race for the same partition
784
+ // assignment via rebalance. (How the value reaches `group.id`
785
+ // depends on the manager: `DirectClientManager` appends it as
786
+ // a suffix to its base `mcp-confluent` group; `OAuthClientManager`
787
+ // uses it as the literal group id. Both yield a unique-per-call
788
+ // group, which is what the no-contention contract requires.)
789
+ groupId: nodeCrypto.randomUUID(),
790
+ offsetReset,
791
+ });
116
792
  await consumer.connect();
117
- await consumer.subscribe({ topics: topicNames });
118
- const consumePromise = new Promise((resolve, reject) => {
119
- if (!consumer) {
120
- reject(new Error("Consumer was unexpectedly undefined"));
121
- return;
122
- }
123
- consumer
124
- .run({
125
- eachMessage: async ({ topic, partition, message }) => {
126
- if (timeoutReached)
127
- return;
128
- const processed = await this.processMessage(topic, partition, message, registry, value, key);
129
- consumedMessages.push(processed);
130
- if (consumedMessages.length >= maxMessages) {
131
- timeoutReached = true;
132
- resolve();
133
- }
134
- },
135
- })
136
- .catch((error) => {
137
- reject(error);
793
+ await consumer.subscribe({ topics: plan.topicNames });
794
+ // Stash per-partition seeks on the consumer BEFORE `consumer.run()`
795
+ // is invoked. The kafkajs-compat library queues these as "pending
796
+ // seeks" via its `#addPendingOperation` → `#seekInternal` path; when
797
+ // the first rebalance fires inside `run()`, the assignment handler
798
+ // calls `#assignAsPerSeekedOffsets` and modifies the assignment to
799
+ // include the seeked offsets BEFORE calling `assignmentFn`, so the
800
+ // partition is assigned at the seek target atomically.
801
+ //
802
+ // This avoids the `ERR__STATE` race that the post-assignment seek
803
+ // path trips: even after `consumer.assignment()` returns the
804
+ // partition, the native librdkafka client can briefly reject seeks
805
+ // because its internal state hasn't fully transitioned from
806
+ // "rebalancing" to "ready." The pre-run path bypasses native seek
807
+ // calls entirely.
808
+ for (const s of plan.seeks) {
809
+ consumer.seek({
810
+ topic: s.topic,
811
+ partition: s.partition,
812
+ offset: s.offset,
138
813
  });
139
- setTimeout(() => {
140
- timeoutReached = true;
141
- resolve();
142
- }, timeoutMs);
814
+ }
815
+ // Named exit conditions. Each Deferred resolves only its own
816
+ // promise — the prior shared `timeoutReached` boolean was written
817
+ // by three sites with overlapping semantics; this splits them into
818
+ // independent signals the race observes.
819
+ const maxReached = Promise.withResolvers();
820
+ const timedOut = Promise.withResolvers();
821
+ const consumerActive = consumer;
822
+ const eachMessage = createEachMessageHandler({
823
+ state: {
824
+ consumedMessages,
825
+ isAccepting: () => accepting,
826
+ isPreflightApplied: () => preflightApplied,
827
+ // Pre-pause gate predicate: a (topic, partition) is "keep" if
828
+ // the topic has no partition restriction (keepPartitions omits
829
+ // it) or the partition is in the topic's keep-set. The
830
+ // orchestrator's `plan.keepPartitions` is built so absence of
831
+ // an entry means "no restriction"; we honor that contract here.
832
+ shouldKeepDuringPrePause: (topic, partition) => {
833
+ const keepSet = plan.keepPartitions.get(topic);
834
+ return keepSet === undefined || keepSet.has(partition);
835
+ },
836
+ },
837
+ maxMessages,
838
+ onMaxReached: () => {
839
+ accepting = false;
840
+ maxReached.resolve();
841
+ },
842
+ processMessage: (topic, partition, message) => this.processMessage(topic, partition, message, registry, valueFormat, keyFormat),
143
843
  });
144
- await consumePromise;
145
- return this.createResponse(`Consumed ${consumedMessages.length} messages from topics ${topicNames.join(", ")}.\nConsumed messages: ${JSON.stringify(consumedMessages, null, 2)}`, false);
844
+ const timer = setTimeout(() => {
845
+ accepting = false;
846
+ timedOut.resolve();
847
+ }, timeoutMs);
848
+ const preflightHook = needsPreflight
849
+ ? applyPostAssignmentHook({
850
+ consumer: consumerActive,
851
+ plan,
852
+ deadlineMs: Date.now() + timeoutMs,
853
+ onApplied: () => {
854
+ preflightApplied = true;
855
+ },
856
+ onAssignmentTimedOut: () => {
857
+ accepting = false;
858
+ timedOut.resolve();
859
+ },
860
+ })
861
+ : Promise.resolve();
862
+ const runPromise = consumerActive.run({ eachMessage });
863
+ try {
864
+ await Promise.race([
865
+ maxReached.promise,
866
+ timedOut.promise,
867
+ // Success of either branch means "engine still running" — only
868
+ // their rejection is a terminal condition for the race.
869
+ rejectOnly(runPromise),
870
+ rejectOnly(preflightHook),
871
+ ]);
872
+ }
873
+ finally {
874
+ clearTimeout(timer);
875
+ accepting = false;
876
+ }
877
+ return this.createResponse(`Consumed ${consumedMessages.length} messages from topics ${plan.topicNames.join(", ")}.\nConsumed messages: ${JSON.stringify(consumedMessages, null, 2)}`, false);
146
878
  }
147
879
  catch (error) {
148
- const errorMessage = error instanceof Error
149
- ? error.message
150
- : error instanceof KafkaJS.KafkaJSError
151
- ? `Kafka error (${error.code}): ${error.message}`
152
- : String(error);
153
- return this.createResponse(`Failed to consume messages: ${errorMessage}`, true);
880
+ return this.createResponse(`Failed to consume messages: ${formatKafkaError(error)}`, true);
154
881
  }
155
882
  finally {
156
883
  if (consumer) {
@@ -166,13 +893,13 @@ export class ConsumeKafkaMessagesHandler extends BaseToolHandler {
166
893
  getToolConfig() {
167
894
  return {
168
895
  name: ToolName.CONSUME_MESSAGES,
169
- description: "Consumes messages from one or more Kafka topics. Supports automatic deserialization of Schema Registry encoded messages (AVRO, JSON, PROTOBUF).",
896
+ description: "Consume messages from Kafka topics. Optionally restrict to a partition, start from an offset, timestamp, earliest, latest, or tailmost pre-existing messages." +
897
+ " Auto-deserializes Schema Registry messages (AVRO/JSON/PROTOBUF) when SR is configured on the connection; pass `valueFormat: {disableSchemaRegistry: true}` (or `keyFormat`) to skip decoding per side.",
170
898
  inputSchema: consumeKafkaMessagesArgs.shape,
171
899
  annotations: READ_ONLY,
172
900
  };
173
901
  }
174
- getRequiredEnvVars() {
175
- return ["BOOTSTRAP_SERVERS"];
176
- }
902
+ category = ToolCategory.Kafka;
903
+ predicate = kafkaBootstrapOrOAuth;
177
904
  }
178
905
  //# sourceMappingURL=consume-kafka-messages-handler.js.map