@tambo-ai/react 0.68.0 → 0.69.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 (326) hide show
  1. package/README.md +1 -1
  2. package/dist/context-helpers/context-helpers.test.js +16 -4
  3. package/dist/context-helpers/context-helpers.test.js.map +1 -1
  4. package/dist/context-helpers/current-interactables-context-helper.d.ts +2 -2
  5. package/dist/context-helpers/current-interactables-context-helper.d.ts.map +1 -1
  6. package/dist/context-helpers/current-interactables-context-helper.js +31 -15
  7. package/dist/context-helpers/current-interactables-context-helper.js.map +1 -1
  8. package/dist/context-helpers/registry.d.ts +2 -2
  9. package/dist/context-helpers/registry.d.ts.map +1 -1
  10. package/dist/context-helpers/registry.js.map +1 -1
  11. package/dist/context-helpers/types.d.ts +2 -2
  12. package/dist/context-helpers/types.d.ts.map +1 -1
  13. package/dist/context-helpers/types.js.map +1 -1
  14. package/dist/hooks/use-message-images.test.js +174 -37
  15. package/dist/hooks/use-message-images.test.js.map +1 -1
  16. package/dist/hooks/use-tambo-voice.d.ts +1 -1
  17. package/dist/hooks/use-tambo-voice.js +1 -1
  18. package/dist/hooks/use-tambo-voice.js.map +1 -1
  19. package/dist/hooks/use-tambo-voice.test.d.ts +2 -0
  20. package/dist/hooks/use-tambo-voice.test.d.ts.map +1 -0
  21. package/dist/hooks/use-tambo-voice.test.js +239 -0
  22. package/dist/hooks/use-tambo-voice.test.js.map +1 -0
  23. package/dist/index.d.ts +2 -2
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/mcp/elicitation.d.ts.map +1 -1
  27. package/dist/mcp/elicitation.js +12 -0
  28. package/dist/mcp/elicitation.js.map +1 -1
  29. package/dist/mcp/elicitation.test.js +8 -1
  30. package/dist/mcp/elicitation.test.js.map +1 -1
  31. package/dist/mcp/mcp-client.d.ts +6 -10
  32. package/dist/mcp/mcp-client.d.ts.map +1 -1
  33. package/dist/mcp/mcp-client.js.map +1 -1
  34. package/dist/mcp/mcp-hooks.d.ts +12 -60
  35. package/dist/mcp/mcp-hooks.d.ts.map +1 -1
  36. package/dist/mcp/mcp-hooks.js +90 -10
  37. package/dist/mcp/mcp-hooks.js.map +1 -1
  38. package/dist/mcp/mcp-hooks.test.js +423 -0
  39. package/dist/mcp/mcp-hooks.test.js.map +1 -1
  40. package/dist/mcp/tambo-mcp-provider.d.ts.map +1 -1
  41. package/dist/mcp/tambo-mcp-provider.js +3 -0
  42. package/dist/mcp/tambo-mcp-provider.js.map +1 -1
  43. package/dist/mcp/tambo-mcp-provider.test.js +37 -0
  44. package/dist/mcp/tambo-mcp-provider.test.js.map +1 -1
  45. package/dist/model/component-metadata.d.ts +53 -20
  46. package/dist/model/component-metadata.d.ts.map +1 -1
  47. package/dist/model/component-metadata.js.map +1 -1
  48. package/dist/model/tambo-interactable.d.ts +6 -0
  49. package/dist/model/tambo-interactable.d.ts.map +1 -1
  50. package/dist/model/tambo-interactable.js.map +1 -1
  51. package/dist/providers/index.d.ts +1 -1
  52. package/dist/providers/index.d.ts.map +1 -1
  53. package/dist/providers/index.js.map +1 -1
  54. package/dist/providers/tambo-client-provider.d.ts +8 -0
  55. package/dist/providers/tambo-client-provider.d.ts.map +1 -1
  56. package/dist/providers/tambo-client-provider.js +10 -11
  57. package/dist/providers/tambo-client-provider.js.map +1 -1
  58. package/dist/providers/tambo-client-provider.test.d.ts +2 -0
  59. package/dist/providers/tambo-client-provider.test.d.ts.map +1 -0
  60. package/dist/providers/tambo-client-provider.test.js +208 -0
  61. package/dist/providers/tambo-client-provider.test.js.map +1 -0
  62. package/dist/providers/tambo-context-attachment-provider.d.ts +34 -92
  63. package/dist/providers/tambo-context-attachment-provider.d.ts.map +1 -1
  64. package/dist/providers/tambo-context-attachment-provider.js +62 -105
  65. package/dist/providers/tambo-context-attachment-provider.js.map +1 -1
  66. package/dist/providers/tambo-context-attachment-provider.test.js +229 -463
  67. package/dist/providers/tambo-context-attachment-provider.test.js.map +1 -1
  68. package/dist/providers/tambo-interactable-provider.d.ts +2 -0
  69. package/dist/providers/tambo-interactable-provider.d.ts.map +1 -1
  70. package/dist/providers/tambo-interactable-provider.js +29 -4
  71. package/dist/providers/tambo-interactable-provider.js.map +1 -1
  72. package/dist/providers/tambo-interactable-provider.test.js +1 -1
  73. package/dist/providers/tambo-interactable-provider.test.js.map +1 -1
  74. package/dist/providers/tambo-interactables-additional-context.test.js +2 -5
  75. package/dist/providers/tambo-interactables-additional-context.test.js.map +1 -1
  76. package/dist/providers/tambo-provider.d.ts +2 -3
  77. package/dist/providers/tambo-provider.d.ts.map +1 -1
  78. package/dist/providers/tambo-provider.js +5 -6
  79. package/dist/providers/tambo-provider.js.map +1 -1
  80. package/dist/providers/tambo-registry-provider.test.js +16 -0
  81. package/dist/providers/tambo-registry-provider.test.js.map +1 -1
  82. package/dist/providers/tambo-registry-schema-compat.test.js +31 -0
  83. package/dist/providers/tambo-registry-schema-compat.test.js.map +1 -1
  84. package/dist/providers/tambo-thread-input-provider.d.ts +1 -1
  85. package/dist/providers/tambo-thread-input-provider.d.ts.map +1 -1
  86. package/dist/providers/tambo-thread-input-provider.js +5 -1
  87. package/dist/providers/tambo-thread-input-provider.js.map +1 -1
  88. package/dist/providers/tambo-thread-provider-initial-messages.test.js +84 -2
  89. package/dist/providers/tambo-thread-provider-initial-messages.test.js.map +1 -1
  90. package/dist/providers/tambo-thread-provider.d.ts.map +1 -1
  91. package/dist/providers/tambo-thread-provider.js +53 -42
  92. package/dist/providers/tambo-thread-provider.js.map +1 -1
  93. package/dist/providers/tambo-thread-provider.test.js +368 -262
  94. package/dist/providers/tambo-thread-provider.test.js.map +1 -1
  95. package/dist/schema/json-schema.js +29 -29
  96. package/dist/schema/json-schema.js.map +1 -1
  97. package/dist/schema/schema.test.js +237 -0
  98. package/dist/schema/schema.test.js.map +1 -1
  99. package/dist/schema/standard-schema.d.ts +1 -0
  100. package/dist/schema/standard-schema.d.ts.map +1 -1
  101. package/dist/schema/standard-schema.js +18 -13
  102. package/dist/schema/standard-schema.js.map +1 -1
  103. package/dist/schema/standard-schema.test.d.ts +2 -0
  104. package/dist/schema/standard-schema.test.d.ts.map +1 -0
  105. package/dist/schema/standard-schema.test.js +165 -0
  106. package/dist/schema/standard-schema.test.js.map +1 -0
  107. package/dist/schema/validate.test.js +149 -0
  108. package/dist/schema/validate.test.js.map +1 -1
  109. package/dist/schema/zod.d.ts +7 -4
  110. package/dist/schema/zod.d.ts.map +1 -1
  111. package/dist/schema/zod.js +65 -22
  112. package/dist/schema/zod.js.map +1 -1
  113. package/dist/schema/zod.test.js +112 -0
  114. package/dist/schema/zod.test.js.map +1 -1
  115. package/dist/testing/tools.d.ts +4 -1
  116. package/dist/testing/tools.d.ts.map +1 -1
  117. package/dist/testing/tools.js +6 -1
  118. package/dist/testing/tools.js.map +1 -1
  119. package/dist/util/generate-component.d.ts.map +1 -1
  120. package/dist/util/generate-component.js +18 -3
  121. package/dist/util/generate-component.js.map +1 -1
  122. package/dist/util/generate-component.test.d.ts +2 -0
  123. package/dist/util/generate-component.test.d.ts.map +1 -0
  124. package/dist/util/generate-component.test.js +340 -0
  125. package/dist/util/generate-component.test.js.map +1 -0
  126. package/dist/util/is-promise.d.ts +9 -0
  127. package/dist/util/is-promise.d.ts.map +1 -0
  128. package/dist/util/is-promise.js +20 -0
  129. package/dist/util/is-promise.js.map +1 -0
  130. package/dist/util/is-promise.test.d.ts +2 -0
  131. package/dist/util/is-promise.test.d.ts.map +1 -0
  132. package/dist/util/is-promise.test.js +48 -0
  133. package/dist/util/is-promise.test.js.map +1 -0
  134. package/dist/util/query-utils.test.d.ts +2 -0
  135. package/dist/util/query-utils.test.d.ts.map +1 -0
  136. package/dist/util/query-utils.test.js +382 -0
  137. package/dist/util/query-utils.test.js.map +1 -0
  138. package/dist/util/registry-validators.d.ts.map +1 -1
  139. package/dist/util/registry-validators.js +7 -0
  140. package/dist/util/registry-validators.js.map +1 -1
  141. package/dist/util/registry-validators.test.js +57 -0
  142. package/dist/util/registry-validators.test.js.map +1 -1
  143. package/dist/util/registry.d.ts.map +1 -1
  144. package/dist/util/registry.js +9 -0
  145. package/dist/util/registry.js.map +1 -1
  146. package/dist/util/registry.test.js +323 -1
  147. package/dist/util/registry.test.js.map +1 -1
  148. package/dist/util/resource-validators.test.d.ts +2 -0
  149. package/dist/util/resource-validators.test.d.ts.map +1 -0
  150. package/dist/util/resource-validators.test.js +90 -0
  151. package/dist/util/resource-validators.test.js.map +1 -0
  152. package/dist/util/tool-caller.d.ts +2 -2
  153. package/dist/util/tool-caller.d.ts.map +1 -1
  154. package/dist/util/tool-caller.js +8 -8
  155. package/dist/util/tool-caller.js.map +1 -1
  156. package/dist/util/validate-component-name.test.d.ts +2 -0
  157. package/dist/util/validate-component-name.test.d.ts.map +1 -0
  158. package/dist/util/validate-component-name.test.js +35 -0
  159. package/dist/util/validate-component-name.test.js.map +1 -0
  160. package/esm/context-helpers/context-helpers.test.js +16 -4
  161. package/esm/context-helpers/context-helpers.test.js.map +1 -1
  162. package/esm/context-helpers/current-interactables-context-helper.d.ts +2 -2
  163. package/esm/context-helpers/current-interactables-context-helper.d.ts.map +1 -1
  164. package/esm/context-helpers/current-interactables-context-helper.js +31 -15
  165. package/esm/context-helpers/current-interactables-context-helper.js.map +1 -1
  166. package/esm/context-helpers/registry.d.ts +2 -2
  167. package/esm/context-helpers/registry.d.ts.map +1 -1
  168. package/esm/context-helpers/registry.js.map +1 -1
  169. package/esm/context-helpers/types.d.ts +2 -2
  170. package/esm/context-helpers/types.d.ts.map +1 -1
  171. package/esm/context-helpers/types.js.map +1 -1
  172. package/esm/hooks/use-message-images.test.js +174 -37
  173. package/esm/hooks/use-message-images.test.js.map +1 -1
  174. package/esm/hooks/use-tambo-voice.d.ts +1 -1
  175. package/esm/hooks/use-tambo-voice.js +1 -1
  176. package/esm/hooks/use-tambo-voice.js.map +1 -1
  177. package/esm/hooks/use-tambo-voice.test.d.ts +2 -0
  178. package/esm/hooks/use-tambo-voice.test.d.ts.map +1 -0
  179. package/esm/hooks/use-tambo-voice.test.js +234 -0
  180. package/esm/hooks/use-tambo-voice.test.js.map +1 -0
  181. package/esm/index.d.ts +2 -2
  182. package/esm/index.d.ts.map +1 -1
  183. package/esm/index.js.map +1 -1
  184. package/esm/mcp/elicitation.d.ts.map +1 -1
  185. package/esm/mcp/elicitation.js +12 -0
  186. package/esm/mcp/elicitation.js.map +1 -1
  187. package/esm/mcp/elicitation.test.js +8 -1
  188. package/esm/mcp/elicitation.test.js.map +1 -1
  189. package/esm/mcp/mcp-client.d.ts +6 -10
  190. package/esm/mcp/mcp-client.d.ts.map +1 -1
  191. package/esm/mcp/mcp-client.js.map +1 -1
  192. package/esm/mcp/mcp-hooks.d.ts +12 -60
  193. package/esm/mcp/mcp-hooks.d.ts.map +1 -1
  194. package/esm/mcp/mcp-hooks.js +57 -10
  195. package/esm/mcp/mcp-hooks.js.map +1 -1
  196. package/esm/mcp/mcp-hooks.test.js +423 -0
  197. package/esm/mcp/mcp-hooks.test.js.map +1 -1
  198. package/esm/mcp/tambo-mcp-provider.d.ts.map +1 -1
  199. package/esm/mcp/tambo-mcp-provider.js +3 -0
  200. package/esm/mcp/tambo-mcp-provider.js.map +1 -1
  201. package/esm/mcp/tambo-mcp-provider.test.js +37 -0
  202. package/esm/mcp/tambo-mcp-provider.test.js.map +1 -1
  203. package/esm/model/component-metadata.d.ts +53 -20
  204. package/esm/model/component-metadata.d.ts.map +1 -1
  205. package/esm/model/component-metadata.js.map +1 -1
  206. package/esm/model/tambo-interactable.d.ts +6 -0
  207. package/esm/model/tambo-interactable.d.ts.map +1 -1
  208. package/esm/model/tambo-interactable.js.map +1 -1
  209. package/esm/providers/index.d.ts +1 -1
  210. package/esm/providers/index.d.ts.map +1 -1
  211. package/esm/providers/index.js.map +1 -1
  212. package/esm/providers/tambo-client-provider.d.ts +8 -0
  213. package/esm/providers/tambo-client-provider.d.ts.map +1 -1
  214. package/esm/providers/tambo-client-provider.js +11 -12
  215. package/esm/providers/tambo-client-provider.js.map +1 -1
  216. package/esm/providers/tambo-client-provider.test.d.ts +2 -0
  217. package/esm/providers/tambo-client-provider.test.d.ts.map +1 -0
  218. package/esm/providers/tambo-client-provider.test.js +203 -0
  219. package/esm/providers/tambo-client-provider.test.js.map +1 -0
  220. package/esm/providers/tambo-context-attachment-provider.d.ts +34 -92
  221. package/esm/providers/tambo-context-attachment-provider.d.ts.map +1 -1
  222. package/esm/providers/tambo-context-attachment-provider.js +63 -106
  223. package/esm/providers/tambo-context-attachment-provider.js.map +1 -1
  224. package/esm/providers/tambo-context-attachment-provider.test.js +230 -464
  225. package/esm/providers/tambo-context-attachment-provider.test.js.map +1 -1
  226. package/esm/providers/tambo-interactable-provider.d.ts +2 -0
  227. package/esm/providers/tambo-interactable-provider.d.ts.map +1 -1
  228. package/esm/providers/tambo-interactable-provider.js +29 -4
  229. package/esm/providers/tambo-interactable-provider.js.map +1 -1
  230. package/esm/providers/tambo-interactable-provider.test.js +1 -1
  231. package/esm/providers/tambo-interactable-provider.test.js.map +1 -1
  232. package/esm/providers/tambo-interactables-additional-context.test.js +2 -5
  233. package/esm/providers/tambo-interactables-additional-context.test.js.map +1 -1
  234. package/esm/providers/tambo-provider.d.ts +2 -3
  235. package/esm/providers/tambo-provider.d.ts.map +1 -1
  236. package/esm/providers/tambo-provider.js +5 -6
  237. package/esm/providers/tambo-provider.js.map +1 -1
  238. package/esm/providers/tambo-registry-provider.test.js +16 -0
  239. package/esm/providers/tambo-registry-provider.test.js.map +1 -1
  240. package/esm/providers/tambo-registry-schema-compat.test.js +31 -0
  241. package/esm/providers/tambo-registry-schema-compat.test.js.map +1 -1
  242. package/esm/providers/tambo-thread-input-provider.d.ts +1 -1
  243. package/esm/providers/tambo-thread-input-provider.d.ts.map +1 -1
  244. package/esm/providers/tambo-thread-input-provider.js +5 -1
  245. package/esm/providers/tambo-thread-input-provider.js.map +1 -1
  246. package/esm/providers/tambo-thread-provider-initial-messages.test.js +84 -2
  247. package/esm/providers/tambo-thread-provider-initial-messages.test.js.map +1 -1
  248. package/esm/providers/tambo-thread-provider.d.ts.map +1 -1
  249. package/esm/providers/tambo-thread-provider.js +53 -42
  250. package/esm/providers/tambo-thread-provider.js.map +1 -1
  251. package/esm/providers/tambo-thread-provider.test.js +368 -262
  252. package/esm/providers/tambo-thread-provider.test.js.map +1 -1
  253. package/esm/schema/json-schema.js +1 -1
  254. package/esm/schema/json-schema.js.map +1 -1
  255. package/esm/schema/schema.test.js +238 -1
  256. package/esm/schema/schema.test.js.map +1 -1
  257. package/esm/schema/standard-schema.d.ts +1 -0
  258. package/esm/schema/standard-schema.d.ts.map +1 -1
  259. package/esm/schema/standard-schema.js +18 -13
  260. package/esm/schema/standard-schema.js.map +1 -1
  261. package/esm/schema/standard-schema.test.d.ts +2 -0
  262. package/esm/schema/standard-schema.test.d.ts.map +1 -0
  263. package/esm/schema/standard-schema.test.js +130 -0
  264. package/esm/schema/standard-schema.test.js.map +1 -0
  265. package/esm/schema/validate.test.js +149 -0
  266. package/esm/schema/validate.test.js.map +1 -1
  267. package/esm/schema/zod.d.ts +7 -4
  268. package/esm/schema/zod.d.ts.map +1 -1
  269. package/esm/schema/zod.js +65 -22
  270. package/esm/schema/zod.js.map +1 -1
  271. package/esm/schema/zod.test.js +113 -1
  272. package/esm/schema/zod.test.js.map +1 -1
  273. package/esm/testing/tools.d.ts +4 -1
  274. package/esm/testing/tools.d.ts.map +1 -1
  275. package/esm/testing/tools.js +6 -1
  276. package/esm/testing/tools.js.map +1 -1
  277. package/esm/util/generate-component.d.ts.map +1 -1
  278. package/esm/util/generate-component.js +18 -3
  279. package/esm/util/generate-component.js.map +1 -1
  280. package/esm/util/generate-component.test.d.ts +2 -0
  281. package/esm/util/generate-component.test.d.ts.map +1 -0
  282. package/esm/util/generate-component.test.js +302 -0
  283. package/esm/util/generate-component.test.js.map +1 -0
  284. package/esm/util/is-promise.d.ts +9 -0
  285. package/esm/util/is-promise.d.ts.map +1 -0
  286. package/esm/util/is-promise.js +17 -0
  287. package/esm/util/is-promise.js.map +1 -0
  288. package/esm/util/is-promise.test.d.ts +2 -0
  289. package/esm/util/is-promise.test.d.ts.map +1 -0
  290. package/esm/util/is-promise.test.js +46 -0
  291. package/esm/util/is-promise.test.js.map +1 -0
  292. package/esm/util/query-utils.test.d.ts +2 -0
  293. package/esm/util/query-utils.test.d.ts.map +1 -0
  294. package/esm/util/query-utils.test.js +380 -0
  295. package/esm/util/query-utils.test.js.map +1 -0
  296. package/esm/util/registry-validators.d.ts.map +1 -1
  297. package/esm/util/registry-validators.js +7 -0
  298. package/esm/util/registry-validators.js.map +1 -1
  299. package/esm/util/registry-validators.test.js +57 -0
  300. package/esm/util/registry-validators.test.js.map +1 -1
  301. package/esm/util/registry.d.ts.map +1 -1
  302. package/esm/util/registry.js +9 -0
  303. package/esm/util/registry.js.map +1 -1
  304. package/esm/util/registry.test.js +324 -2
  305. package/esm/util/registry.test.js.map +1 -1
  306. package/esm/util/resource-validators.test.d.ts +2 -0
  307. package/esm/util/resource-validators.test.d.ts.map +1 -0
  308. package/esm/util/resource-validators.test.js +88 -0
  309. package/esm/util/resource-validators.test.js.map +1 -0
  310. package/esm/util/tool-caller.d.ts +2 -2
  311. package/esm/util/tool-caller.d.ts.map +1 -1
  312. package/esm/util/tool-caller.js +8 -8
  313. package/esm/util/tool-caller.js.map +1 -1
  314. package/esm/util/validate-component-name.test.d.ts +2 -0
  315. package/esm/util/validate-component-name.test.d.ts.map +1 -0
  316. package/esm/util/validate-component-name.test.js +33 -0
  317. package/esm/util/validate-component-name.test.js.map +1 -0
  318. package/package.json +15 -23
  319. package/dist/schema/alias.d.ts +0 -3
  320. package/dist/schema/alias.d.ts.map +0 -1
  321. package/dist/schema/alias.js +0 -6
  322. package/dist/schema/alias.js.map +0 -1
  323. package/esm/schema/alias.d.ts +0 -3
  324. package/esm/schema/alias.d.ts.map +0 -1
  325. package/esm/schema/alias.js +0 -13
  326. package/esm/schema/alias.js.map +0 -1
@@ -469,6 +469,142 @@ describe("useTamboMcpPromptList - individual server caching", () => {
469
469
  expect(promptNames).toContain("server-b:prompt-b");
470
470
  });
471
471
  });
472
+ describe("useTamboMcpPromptList - search filtering", () => {
473
+ let queryClient;
474
+ beforeEach(() => {
475
+ createImpl = jest.fn();
476
+ queryClient = new QueryClient({
477
+ defaultOptions: {
478
+ queries: {
479
+ retry: false,
480
+ },
481
+ },
482
+ });
483
+ });
484
+ afterEach(() => {
485
+ queryClient.clear();
486
+ });
487
+ it("should filter MCP prompts locally by search string", async () => {
488
+ const serverAPrompts = {
489
+ prompts: [
490
+ { name: "create-issue", description: "Create a new issue" },
491
+ { name: "list-tasks", description: "List all tasks" },
492
+ { name: "search-docs", description: "Search documentation" },
493
+ ],
494
+ };
495
+ const mockClientA = {
496
+ listTools: jest.fn().mockResolvedValue([]),
497
+ listPrompts: jest.fn().mockResolvedValue(serverAPrompts),
498
+ listResources: jest.fn().mockResolvedValue({ resources: [] }),
499
+ close: jest.fn(),
500
+ };
501
+ const clientA = {
502
+ client: mockClientA,
503
+ listTools: jest.fn().mockResolvedValue([]),
504
+ close: jest.fn(),
505
+ };
506
+ createImpl.mockImplementation(async () => clientA);
507
+ let capturedPrompts = [];
508
+ const Capture = ({ search }) => {
509
+ const { data: prompts } = useTamboMcpPromptList(search);
510
+ useEffect(() => {
511
+ if (prompts) {
512
+ capturedPrompts = prompts;
513
+ }
514
+ }, [prompts]);
515
+ return null;
516
+ };
517
+ const { rerender } = render(React.createElement(TamboClientContext.Provider, { value: {
518
+ client: { baseURL: "https://api.tambo.co" },
519
+ queryClient,
520
+ isUpdatingToken: false,
521
+ } },
522
+ React.createElement(TamboRegistryProvider, { mcpServers: [
523
+ {
524
+ url: "https://server-a.example",
525
+ transport: MCPTransport.SSE,
526
+ },
527
+ ] },
528
+ React.createElement(TamboMcpTokenProvider, null,
529
+ React.createElement(TamboMcpProvider, null,
530
+ React.createElement(Capture, null))))));
531
+ // Wait for all prompts to be loaded (no search)
532
+ await waitFor(() => {
533
+ expect(capturedPrompts.length).toBe(3);
534
+ });
535
+ // Now search for "issue"
536
+ rerender(React.createElement(TamboClientContext.Provider, { value: {
537
+ client: { baseURL: "https://api.tambo.co" },
538
+ queryClient,
539
+ isUpdatingToken: false,
540
+ } },
541
+ React.createElement(TamboRegistryProvider, { mcpServers: [
542
+ {
543
+ url: "https://server-a.example",
544
+ transport: MCPTransport.SSE,
545
+ },
546
+ ] },
547
+ React.createElement(TamboMcpTokenProvider, null,
548
+ React.createElement(TamboMcpProvider, null,
549
+ React.createElement(Capture, { search: "issue" }))))));
550
+ // Should only have the create-issue prompt
551
+ await waitFor(() => {
552
+ expect(capturedPrompts.length).toBe(1);
553
+ });
554
+ expect(capturedPrompts[0].prompt.name).toBe("server-a:create-issue");
555
+ // MCP listPrompts should only be called once (not re-fetched on search change)
556
+ expect(mockClientA.listPrompts).toHaveBeenCalledTimes(1);
557
+ });
558
+ it("should filter prompts case-insensitively", async () => {
559
+ const serverAPrompts = {
560
+ prompts: [
561
+ { name: "Create-Issue", description: "Create a new issue" },
562
+ { name: "list-tasks", description: "List all tasks" },
563
+ ],
564
+ };
565
+ const mockClientA = {
566
+ listTools: jest.fn().mockResolvedValue([]),
567
+ listPrompts: jest.fn().mockResolvedValue(serverAPrompts),
568
+ listResources: jest.fn().mockResolvedValue({ resources: [] }),
569
+ close: jest.fn(),
570
+ };
571
+ const clientA = {
572
+ client: mockClientA,
573
+ listTools: jest.fn().mockResolvedValue([]),
574
+ close: jest.fn(),
575
+ };
576
+ createImpl.mockImplementation(async () => clientA);
577
+ let capturedPrompts = [];
578
+ const Capture = ({ search }) => {
579
+ const { data: prompts } = useTamboMcpPromptList(search);
580
+ useEffect(() => {
581
+ if (prompts) {
582
+ capturedPrompts = prompts;
583
+ }
584
+ }, [prompts]);
585
+ return null;
586
+ };
587
+ render(React.createElement(TamboClientContext.Provider, { value: {
588
+ client: { baseURL: "https://api.tambo.co" },
589
+ queryClient,
590
+ isUpdatingToken: false,
591
+ } },
592
+ React.createElement(TamboRegistryProvider, { mcpServers: [
593
+ {
594
+ url: "https://server-a.example",
595
+ transport: MCPTransport.SSE,
596
+ },
597
+ ] },
598
+ React.createElement(TamboMcpTokenProvider, null,
599
+ React.createElement(TamboMcpProvider, null,
600
+ React.createElement(Capture, { search: "CREATE" }))))));
601
+ // Should find "Create-Issue" even though search is uppercase
602
+ await waitFor(() => {
603
+ expect(capturedPrompts.length).toBe(1);
604
+ });
605
+ expect(capturedPrompts[0].prompt.name).toBe("server-a:Create-Issue");
606
+ });
607
+ });
472
608
  describe("useTamboMcpResourceList - resource management", () => {
473
609
  let queryClient;
474
610
  beforeEach(() => {
@@ -780,6 +916,293 @@ describe("useTamboMcpResourceList - resource management", () => {
780
916
  expect(updatedUris).not.toContain("server-b:file:///workspace/code.js"); // Server B removed
781
917
  });
782
918
  });
919
+ describe("useTamboMcpResourceList - search filtering", () => {
920
+ let queryClient;
921
+ beforeEach(() => {
922
+ createImpl = jest.fn();
923
+ queryClient = new QueryClient({
924
+ defaultOptions: {
925
+ queries: {
926
+ retry: false,
927
+ },
928
+ },
929
+ });
930
+ });
931
+ afterEach(() => {
932
+ queryClient.clear();
933
+ });
934
+ it("should filter MCP resources locally by search string", async () => {
935
+ const serverAResources = {
936
+ resources: [
937
+ {
938
+ uri: "file:///home/user/document.txt",
939
+ name: "My Document",
940
+ mimeType: "text/plain",
941
+ },
942
+ {
943
+ uri: "file:///home/user/image.png",
944
+ name: "My Image",
945
+ mimeType: "image/png",
946
+ },
947
+ {
948
+ uri: "file:///home/user/notes.txt",
949
+ name: "Notes",
950
+ mimeType: "text/plain",
951
+ },
952
+ ],
953
+ };
954
+ const mockClientA = {
955
+ listTools: jest.fn().mockResolvedValue([]),
956
+ listPrompts: jest.fn().mockResolvedValue({ prompts: [] }),
957
+ listResources: jest.fn().mockResolvedValue(serverAResources),
958
+ close: jest.fn(),
959
+ };
960
+ const clientA = {
961
+ client: mockClientA,
962
+ listTools: jest.fn().mockResolvedValue([]),
963
+ close: jest.fn(),
964
+ };
965
+ createImpl.mockImplementation(async () => clientA);
966
+ let capturedResources = [];
967
+ const Capture = ({ search }) => {
968
+ const { data: resources } = useTamboMcpResourceList(search);
969
+ useEffect(() => {
970
+ if (resources) {
971
+ capturedResources = resources;
972
+ }
973
+ }, [resources]);
974
+ return null;
975
+ };
976
+ const { rerender } = render(React.createElement(TamboClientContext.Provider, { value: {
977
+ client: { baseURL: "https://api.tambo.co" },
978
+ queryClient,
979
+ isUpdatingToken: false,
980
+ } },
981
+ React.createElement(TamboRegistryProvider, { mcpServers: [
982
+ {
983
+ url: "https://server-a.example",
984
+ transport: MCPTransport.SSE,
985
+ },
986
+ ] },
987
+ React.createElement(TamboMcpTokenProvider, null,
988
+ React.createElement(TamboMcpProvider, null,
989
+ React.createElement(Capture, null))))));
990
+ // Wait for all resources to be loaded (no search)
991
+ await waitFor(() => {
992
+ expect(capturedResources.length).toBe(3);
993
+ });
994
+ // Now search for "document"
995
+ rerender(React.createElement(TamboClientContext.Provider, { value: {
996
+ client: { baseURL: "https://api.tambo.co" },
997
+ queryClient,
998
+ isUpdatingToken: false,
999
+ } },
1000
+ React.createElement(TamboRegistryProvider, { mcpServers: [
1001
+ {
1002
+ url: "https://server-a.example",
1003
+ transport: MCPTransport.SSE,
1004
+ },
1005
+ ] },
1006
+ React.createElement(TamboMcpTokenProvider, null,
1007
+ React.createElement(TamboMcpProvider, null,
1008
+ React.createElement(Capture, { search: "document" }))))));
1009
+ // Should only have the document resource
1010
+ await waitFor(() => {
1011
+ expect(capturedResources.length).toBe(1);
1012
+ });
1013
+ expect(capturedResources[0].resource.name).toBe("My Document");
1014
+ // MCP listResources should only be called once (not re-fetched on search change)
1015
+ expect(mockClientA.listResources).toHaveBeenCalledTimes(1);
1016
+ });
1017
+ it("should pass search string to registry listResources for dynamic generation", async () => {
1018
+ const listResources = jest
1019
+ .fn()
1020
+ .mockImplementation(async (search) => {
1021
+ // Dynamically generate resources based on search
1022
+ if (!search)
1023
+ return [];
1024
+ return [
1025
+ {
1026
+ uri: `dynamic://${search}`,
1027
+ name: `Dynamic Resource for ${search}`,
1028
+ mimeType: "text/plain",
1029
+ },
1030
+ ];
1031
+ });
1032
+ const getResource = jest.fn().mockResolvedValue({
1033
+ contents: [{ uri: "test", text: "test content", mimeType: "text/plain" }],
1034
+ });
1035
+ let capturedResources = [];
1036
+ const Capture = ({ search }) => {
1037
+ const { data: resources } = useTamboMcpResourceList(search);
1038
+ useEffect(() => {
1039
+ if (resources) {
1040
+ capturedResources = resources;
1041
+ }
1042
+ }, [resources]);
1043
+ return null;
1044
+ };
1045
+ const { rerender } = render(React.createElement(TamboClientContext.Provider, { value: {
1046
+ client: { baseURL: "https://api.tambo.co" },
1047
+ queryClient,
1048
+ isUpdatingToken: false,
1049
+ } },
1050
+ React.createElement(TamboRegistryProvider, { listResources: listResources, getResource: getResource },
1051
+ React.createElement(TamboMcpTokenProvider, null,
1052
+ React.createElement(TamboMcpProvider, null,
1053
+ React.createElement(Capture, { search: "foo" }))))));
1054
+ // Wait for dynamic resource to be generated
1055
+ await waitFor(() => {
1056
+ expect(capturedResources.length).toBe(1);
1057
+ });
1058
+ // Verify listResources was called with the search string
1059
+ expect(listResources).toHaveBeenCalledWith("foo");
1060
+ expect(capturedResources[0].resource.name).toBe("Dynamic Resource for foo");
1061
+ // Registry resources get the "registry:" prefix
1062
+ expect(capturedResources[0].resource.uri).toBe("registry:dynamic://foo");
1063
+ // Now search for "bar"
1064
+ rerender(React.createElement(TamboClientContext.Provider, { value: {
1065
+ client: { baseURL: "https://api.tambo.co" },
1066
+ queryClient,
1067
+ isUpdatingToken: false,
1068
+ } },
1069
+ React.createElement(TamboRegistryProvider, { listResources: listResources, getResource: getResource },
1070
+ React.createElement(TamboMcpTokenProvider, null,
1071
+ React.createElement(TamboMcpProvider, null,
1072
+ React.createElement(Capture, { search: "bar" }))))));
1073
+ // Wait for new dynamic resource
1074
+ await waitFor(() => {
1075
+ expect(capturedResources[0].resource.uri).toBe("registry:dynamic://bar");
1076
+ });
1077
+ // listResources should be called again with new search
1078
+ expect(listResources).toHaveBeenCalledWith("bar");
1079
+ expect(capturedResources[0].resource.name).toBe("Dynamic Resource for bar");
1080
+ });
1081
+ it("should not locally substring-filter dynamic registry resources", async () => {
1082
+ const listResources = jest
1083
+ .fn()
1084
+ .mockImplementation(async (search) => {
1085
+ if (!search)
1086
+ return [];
1087
+ // Simulate a provider that matches resources using non-substring logic.
1088
+ return [
1089
+ {
1090
+ uri: "dynamic://matched-by-provider",
1091
+ name: "Smart Match",
1092
+ mimeType: "text/plain",
1093
+ },
1094
+ ];
1095
+ });
1096
+ const getResource = jest.fn().mockResolvedValue({
1097
+ contents: [{ uri: "test", text: "test content", mimeType: "text/plain" }],
1098
+ });
1099
+ let capturedResources = [];
1100
+ const Capture = ({ search }) => {
1101
+ const { data: resources } = useTamboMcpResourceList(search);
1102
+ useEffect(() => {
1103
+ if (resources) {
1104
+ capturedResources = resources;
1105
+ }
1106
+ }, [resources]);
1107
+ return null;
1108
+ };
1109
+ render(React.createElement(TamboClientContext.Provider, { value: {
1110
+ client: { baseURL: "https://api.tambo.co" },
1111
+ queryClient,
1112
+ isUpdatingToken: false,
1113
+ } },
1114
+ React.createElement(TamboRegistryProvider, { listResources: listResources, getResource: getResource },
1115
+ React.createElement(TamboMcpTokenProvider, null,
1116
+ React.createElement(TamboMcpProvider, null,
1117
+ React.createElement(Capture, { search: "foo" }))))));
1118
+ await waitFor(() => {
1119
+ expect(capturedResources.length).toBe(1);
1120
+ });
1121
+ expect(listResources).toHaveBeenCalledWith("foo");
1122
+ expect(capturedResources[0].server).toBeNull();
1123
+ expect(capturedResources[0].resource.name).toBe("Smart Match");
1124
+ expect(capturedResources[0].resource.uri).toBe("registry:dynamic://matched-by-provider");
1125
+ });
1126
+ it("should combine MCP filtered resources with dynamically generated registry resources", async () => {
1127
+ const serverAResources = {
1128
+ resources: [
1129
+ {
1130
+ uri: "file:///apple.txt",
1131
+ name: "Apple",
1132
+ mimeType: "text/plain",
1133
+ },
1134
+ {
1135
+ uri: "file:///banana.txt",
1136
+ name: "Banana",
1137
+ mimeType: "text/plain",
1138
+ },
1139
+ ],
1140
+ };
1141
+ const mockClientA = {
1142
+ listTools: jest.fn().mockResolvedValue([]),
1143
+ listPrompts: jest.fn().mockResolvedValue({ prompts: [] }),
1144
+ listResources: jest.fn().mockResolvedValue(serverAResources),
1145
+ close: jest.fn(),
1146
+ };
1147
+ const clientA = {
1148
+ client: mockClientA,
1149
+ listTools: jest.fn().mockResolvedValue([]),
1150
+ close: jest.fn(),
1151
+ };
1152
+ createImpl.mockImplementation(async () => clientA);
1153
+ const listResources = jest
1154
+ .fn()
1155
+ .mockImplementation(async (search) => {
1156
+ // Always return a resource that includes the search term
1157
+ return [
1158
+ {
1159
+ uri: `registry://${search ?? "all"}`,
1160
+ name: `Registry ${search ?? "all"}`,
1161
+ mimeType: "text/plain",
1162
+ },
1163
+ ];
1164
+ });
1165
+ const getResource = jest.fn().mockResolvedValue({
1166
+ contents: [{ uri: "test", text: "test", mimeType: "text/plain" }],
1167
+ });
1168
+ let capturedResources = [];
1169
+ const Capture = ({ search }) => {
1170
+ const { data: resources } = useTamboMcpResourceList(search);
1171
+ useEffect(() => {
1172
+ if (resources) {
1173
+ capturedResources = resources;
1174
+ }
1175
+ }, [resources]);
1176
+ return null;
1177
+ };
1178
+ render(React.createElement(TamboClientContext.Provider, { value: {
1179
+ client: { baseURL: "https://api.tambo.co" },
1180
+ queryClient,
1181
+ isUpdatingToken: false,
1182
+ } },
1183
+ React.createElement(TamboRegistryProvider, { mcpServers: [
1184
+ {
1185
+ url: "https://server-a.example",
1186
+ transport: MCPTransport.SSE,
1187
+ },
1188
+ ], listResources: listResources, getResource: getResource },
1189
+ React.createElement(TamboMcpTokenProvider, null,
1190
+ React.createElement(TamboMcpProvider, null,
1191
+ React.createElement(Capture, { search: "apple" }))))));
1192
+ // Wait for resources
1193
+ await waitFor(() => {
1194
+ // Should have: 1 MCP resource (Apple filtered) + 1 registry resource (dynamic)
1195
+ expect(capturedResources.length).toBe(2);
1196
+ });
1197
+ const uris = capturedResources.map((r) => r.resource.uri);
1198
+ // MCP "Apple" should match (filtered locally)
1199
+ expect(uris).toContain("server-a:file:///apple.txt");
1200
+ // Registry dynamic resource
1201
+ expect(uris).toContain("registry:registry://apple");
1202
+ // MCP "Banana" should NOT be included (filtered out)
1203
+ expect(uris).not.toContain("server-a:file:///banana.txt");
1204
+ });
1205
+ });
783
1206
  describe("useTamboMcpResource - read individual resource", () => {
784
1207
  let queryClient;
785
1208
  beforeEach(() => {