@tambo-ai/react 0.58.1 → 0.59.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 (77) hide show
  1. package/dist/hooks/use-tambo-stream-status.js +1 -1
  2. package/dist/hooks/use-tambo-stream-status.js.map +1 -1
  3. package/dist/mcp/__tests__/mcp-client.test.js +0 -266
  4. package/dist/mcp/__tests__/mcp-client.test.js.map +1 -1
  5. package/dist/mcp/__tests__/tambo-mcp-provider.test.js +218 -12
  6. package/dist/mcp/__tests__/tambo-mcp-provider.test.js.map +1 -1
  7. package/dist/mcp/__tests__/use-mcp-servers.test.js +34 -9
  8. package/dist/mcp/__tests__/use-mcp-servers.test.js.map +1 -1
  9. package/dist/mcp/index.d.ts +3 -1
  10. package/dist/mcp/index.d.ts.map +1 -1
  11. package/dist/mcp/index.js +4 -1
  12. package/dist/mcp/index.js.map +1 -1
  13. package/dist/mcp/mcp-client.d.ts +12 -79
  14. package/dist/mcp/mcp-client.d.ts.map +1 -1
  15. package/dist/mcp/mcp-client.js +22 -159
  16. package/dist/mcp/mcp-client.js.map +1 -1
  17. package/dist/mcp/mcp-hooks.d.ts +93 -0
  18. package/dist/mcp/mcp-hooks.d.ts.map +1 -0
  19. package/dist/mcp/mcp-hooks.js +56 -0
  20. package/dist/mcp/mcp-hooks.js.map +1 -0
  21. package/dist/mcp/tambo-mcp-provider.d.ts +30 -2
  22. package/dist/mcp/tambo-mcp-provider.d.ts.map +1 -1
  23. package/dist/mcp/tambo-mcp-provider.js +126 -16
  24. package/dist/mcp/tambo-mcp-provider.js.map +1 -1
  25. package/dist/providers/__tests__/tambo-thread-provider-initial-messages.test.js +3 -1
  26. package/dist/providers/__tests__/tambo-thread-provider-initial-messages.test.js.map +1 -1
  27. package/dist/providers/__tests__/tambo-thread-provider.test.js +25 -12
  28. package/dist/providers/__tests__/tambo-thread-provider.test.js.map +1 -1
  29. package/dist/providers/tambo-mcp-token-provider.d.ts +34 -0
  30. package/dist/providers/tambo-mcp-token-provider.d.ts.map +1 -0
  31. package/dist/providers/tambo-mcp-token-provider.js +69 -0
  32. package/dist/providers/tambo-mcp-token-provider.js.map +1 -0
  33. package/dist/providers/tambo-provider.d.ts.map +1 -1
  34. package/dist/providers/tambo-provider.js +7 -5
  35. package/dist/providers/tambo-provider.js.map +1 -1
  36. package/dist/providers/tambo-thread-provider.d.ts.map +1 -1
  37. package/dist/providers/tambo-thread-provider.js +14 -0
  38. package/dist/providers/tambo-thread-provider.js.map +1 -1
  39. package/esm/hooks/use-tambo-stream-status.js +1 -1
  40. package/esm/hooks/use-tambo-stream-status.js.map +1 -1
  41. package/esm/mcp/__tests__/mcp-client.test.js +0 -266
  42. package/esm/mcp/__tests__/mcp-client.test.js.map +1 -1
  43. package/esm/mcp/__tests__/tambo-mcp-provider.test.js +218 -12
  44. package/esm/mcp/__tests__/tambo-mcp-provider.test.js.map +1 -1
  45. package/esm/mcp/__tests__/use-mcp-servers.test.js +34 -9
  46. package/esm/mcp/__tests__/use-mcp-servers.test.js.map +1 -1
  47. package/esm/mcp/index.d.ts +3 -1
  48. package/esm/mcp/index.d.ts.map +1 -1
  49. package/esm/mcp/index.js +1 -0
  50. package/esm/mcp/index.js.map +1 -1
  51. package/esm/mcp/mcp-client.d.ts +12 -79
  52. package/esm/mcp/mcp-client.d.ts.map +1 -1
  53. package/esm/mcp/mcp-client.js +22 -159
  54. package/esm/mcp/mcp-client.js.map +1 -1
  55. package/esm/mcp/mcp-hooks.d.ts +93 -0
  56. package/esm/mcp/mcp-hooks.d.ts.map +1 -0
  57. package/esm/mcp/mcp-hooks.js +52 -0
  58. package/esm/mcp/mcp-hooks.js.map +1 -0
  59. package/esm/mcp/tambo-mcp-provider.d.ts +30 -2
  60. package/esm/mcp/tambo-mcp-provider.d.ts.map +1 -1
  61. package/esm/mcp/tambo-mcp-provider.js +127 -17
  62. package/esm/mcp/tambo-mcp-provider.js.map +1 -1
  63. package/esm/providers/__tests__/tambo-thread-provider-initial-messages.test.js +3 -1
  64. package/esm/providers/__tests__/tambo-thread-provider-initial-messages.test.js.map +1 -1
  65. package/esm/providers/__tests__/tambo-thread-provider.test.js +25 -12
  66. package/esm/providers/__tests__/tambo-thread-provider.test.js.map +1 -1
  67. package/esm/providers/tambo-mcp-token-provider.d.ts +34 -0
  68. package/esm/providers/tambo-mcp-token-provider.d.ts.map +1 -0
  69. package/esm/providers/tambo-mcp-token-provider.js +31 -0
  70. package/esm/providers/tambo-mcp-token-provider.js.map +1 -0
  71. package/esm/providers/tambo-provider.d.ts.map +1 -1
  72. package/esm/providers/tambo-provider.js +7 -5
  73. package/esm/providers/tambo-provider.js.map +1 -1
  74. package/esm/providers/tambo-thread-provider.d.ts.map +1 -1
  75. package/esm/providers/tambo-thread-provider.js +14 -0
  76. package/esm/providers/tambo-thread-provider.js.map +1 -1
  77. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import React, { FC } from "react";
2
- import { MCPClient, MCPTransport } from "./mcp-client";
2
+ import { MCPClient, MCPHandlers, MCPTransport } from "./mcp-client";
3
3
  /**
4
4
  * Extracts error message from MCP tool result content.
5
5
  * Handles both array and string content formats.
@@ -7,12 +7,26 @@ import { MCPClient, MCPTransport } from "./mcp-client";
7
7
  * @returns The extracted error message as a string
8
8
  */
9
9
  export declare function extractErrorMessage(content: unknown): string;
10
+ /**
11
+ * Configuration for connecting to an MCP server.
12
+ */
10
13
  export interface McpServerInfo {
14
+ /** Optional name for the MCP server */
11
15
  name?: string;
16
+ /** The URL of the MCP server to connect to */
12
17
  url: string;
18
+ /** Optional description of the MCP server */
13
19
  description?: string;
20
+ /** The transport type to use (SSE or HTTP). Defaults to SSE for string URLs */
14
21
  transport?: MCPTransport;
22
+ /** Optional custom headers to include in requests */
15
23
  customHeaders?: Record<string, string>;
24
+ /**
25
+ * Optional handlers for elicitation and sampling requests from the server.
26
+ * Note: These callbacks should be stable (e.g., wrapped in useCallback or defined outside the component)
27
+ * to avoid constant re-registration of the MCP server on every render.
28
+ */
29
+ handlers?: Partial<MCPHandlers>;
16
30
  }
17
31
  export interface ConnectedMcpServer extends McpServerInfo {
18
32
  client: MCPClient;
@@ -22,12 +36,26 @@ export interface FailedMcpServer extends McpServerInfo {
22
36
  connectionError: Error;
23
37
  }
24
38
  export type McpServer = ConnectedMcpServer | FailedMcpServer;
39
+ /**
40
+ * Provider-level MCP handlers that receive the McpServerInfo as context in addition to the request.
41
+ * These handlers are applied to all MCP servers unless overridden by per-server handlers.
42
+ */
43
+ export interface ProviderMCPHandlers {
44
+ elicitation?: (request: Parameters<MCPHandlers["elicitation"]>[0], serverInfo: McpServerInfo) => ReturnType<MCPHandlers["elicitation"]>;
45
+ sampling?: (request: Parameters<MCPHandlers["sampling"]>[0], serverInfo: McpServerInfo) => ReturnType<MCPHandlers["sampling"]>;
46
+ }
25
47
  /**
26
48
  * This provider is used to register tools from MCP servers.
27
- * @returns the wrapped children
49
+ * It automatically includes an internal Tambo MCP server when an MCP access token is available.
50
+ * @param props - The provider props
51
+ * @param props.mcpServers - Array of MCP server configurations
52
+ * @param props.handlers - Optional handlers applied to all MCP servers unless overridden per-server
53
+ * @param props.children - The children to wrap
54
+ * @returns The TamboMcpProvider component
28
55
  */
29
56
  export declare const TamboMcpProvider: FC<{
30
57
  mcpServers: (McpServerInfo | string)[];
58
+ handlers?: ProviderMCPHandlers;
31
59
  children: React.ReactNode;
32
60
  }>;
33
61
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"tambo-mcp-provider.d.ts","sourceRoot":"","sources":["../../src/mcp/tambo-mcp-provider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAEZ,EAAE,EAIH,MAAM,OAAO,CAAC;AAIf,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEvD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAsB5D;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD,MAAM,EAAE,SAAS,CAAC;CACnB;AAED,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,eAAe,EAAE,KAAK,CAAC;CACxB;AAED,MAAM,MAAM,SAAS,GAAG,kBAAkB,GAAG,eAAe,CAAC;AAG7D;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC;IAChC,UAAU,EAAE,CAAC,aAAa,GAAG,MAAM,CAAC,EAAE,CAAC;IACvC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAgJA,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,kBAAkB,mBAE9B,CAAC"}
1
+ {"version":3,"file":"tambo-mcp-provider.d.ts","sourceRoot":"","sources":["../../src/mcp/tambo-mcp-provider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAEZ,EAAE,EAKH,MAAM,OAAO,CAAC;AAKf,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEpE;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAsB5D;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD,MAAM,EAAE,SAAS,CAAC;CACnB;AAED,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,eAAe,EAAE,KAAK,CAAC;CACxB;AAED,MAAM,MAAM,SAAS,GAAG,kBAAkB,GAAG,eAAe,CAAC;AAE7D;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,CACZ,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,EAClD,UAAU,EAAE,aAAa,KACtB,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC;IAC5C,QAAQ,CAAC,EAAE,CACT,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,EAC/C,UAAU,EAAE,aAAa,KACtB,UAAU,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC;CAC1C;AAOD;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC;IAChC,UAAU,EAAE,CAAC,aAAa,GAAG,MAAM,CAAC,EAAE,CAAC;IACvC,QAAQ,CAAC,EAAE,mBAAmB,CAAC;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CA8QA,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,kBAAkB,mBAE9B,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { deepEqual } from "fast-equals";
2
- import React, { createContext, useContext, useEffect, useState, } from "react";
2
+ import React, { createContext, useContext, useEffect, useMemo, useState, } from "react";
3
+ import { useTamboMcpToken } from "../providers/tambo-mcp-token-provider";
3
4
  import { useTamboRegistry } from "../providers/tambo-registry-provider";
4
5
  import { isContentPartArray, toText } from "../util/content-parts";
5
6
  import { MCPClient, MCPTransport } from "./mcp-client";
@@ -27,15 +28,45 @@ export function extractErrorMessage(content) {
27
28
  return `${content}`;
28
29
  }
29
30
  const McpProviderContext = createContext([]);
31
+ // Constant for the internal Tambo MCP server name
32
+ const TAMBO_INTERNAL_MCP_SERVER_NAME = "__tambo_internal_mcp_server__";
30
33
  /**
31
34
  * This provider is used to register tools from MCP servers.
32
- * @returns the wrapped children
35
+ * It automatically includes an internal Tambo MCP server when an MCP access token is available.
36
+ * @param props - The provider props
37
+ * @param props.mcpServers - Array of MCP server configurations
38
+ * @param props.handlers - Optional handlers applied to all MCP servers unless overridden per-server
39
+ * @param props.children - The children to wrap
40
+ * @returns The TamboMcpProvider component
33
41
  */
34
- export const TamboMcpProvider = ({ mcpServers, children }) => {
42
+ export const TamboMcpProvider = ({ mcpServers, handlers, children }) => {
35
43
  const { registerTool } = useTamboRegistry();
44
+ const { mcpAccessToken, tamboBaseUrl } = useTamboMcpToken();
45
+ const providerElicitationHandler = handlers?.elicitation;
46
+ const providerSamplingHandler = handlers?.sampling;
36
47
  const [connectedMcpServers, setConnectedMcpServers] = useState([]);
48
+ // Combine user-provided MCP servers with the internal Tambo MCP server
49
+ const allMcpServers = useMemo(() => {
50
+ const servers = [...mcpServers];
51
+ // Add internal Tambo MCP server if we have an access token and a base URL
52
+ if (mcpAccessToken && tamboBaseUrl) {
53
+ // Build the internal MCP URL robustly, preserving any existing base path
54
+ const base = new URL(tamboBaseUrl);
55
+ base.pathname = `${base.pathname.replace(/\/+$/, "")}/mcp`;
56
+ const tamboMcpUrl = base.toString();
57
+ servers.push({
58
+ name: TAMBO_INTERNAL_MCP_SERVER_NAME,
59
+ url: tamboMcpUrl,
60
+ transport: MCPTransport.HTTP,
61
+ customHeaders: {
62
+ Authorization: `Bearer ${mcpAccessToken}`,
63
+ },
64
+ });
65
+ }
66
+ return servers;
67
+ }, [mcpServers, mcpAccessToken, tamboBaseUrl]);
37
68
  useEffect(() => {
38
- if (!mcpServers) {
69
+ if (!allMcpServers.length) {
39
70
  return;
40
71
  }
41
72
  async function registerMcpServers(mcpServerInfos) {
@@ -47,19 +78,48 @@ export const TamboMcpProvider = ({ mcpServers, children }) => {
47
78
  // initialize the MCP clients, converting McpServerInfo -> McpServer
48
79
  const mcpServers = await Promise.allSettled(mcpServerInfos.map(async (mcpServerInfo) => {
49
80
  try {
81
+ // Merge provider handlers with per-server handlers (per-server takes precedence)
82
+ const effectiveHandlers = {};
83
+ // Apply provider elicitation handler if present and not overridden
84
+ if (mcpServerInfo.handlers?.elicitation) {
85
+ effectiveHandlers.elicitation =
86
+ mcpServerInfo.handlers.elicitation;
87
+ }
88
+ else if (providerElicitationHandler) {
89
+ const elicitationHandler = providerElicitationHandler;
90
+ effectiveHandlers.elicitation = async (request) => await elicitationHandler(request, mcpServerInfo);
91
+ }
92
+ // Apply provider sampling handler if present and not overridden
93
+ if (mcpServerInfo.handlers?.sampling) {
94
+ effectiveHandlers.sampling = mcpServerInfo.handlers.sampling;
95
+ }
96
+ else if (providerSamplingHandler) {
97
+ const samplingHandler = providerSamplingHandler;
98
+ effectiveHandlers.sampling = async (request) => await samplingHandler(request, mcpServerInfo);
99
+ }
50
100
  const client = await MCPClient.create(mcpServerInfo.url, mcpServerInfo.transport, mcpServerInfo.customHeaders, undefined, // no oauth support yet
51
- undefined);
101
+ undefined, // starting with no session id at first.
102
+ effectiveHandlers);
52
103
  const connectedMcpServer = {
53
104
  ...mcpServerInfo,
54
105
  client: client,
55
106
  };
56
107
  // note because the promises may resolve in any order, the resulting
57
108
  // array may not be in the same order as the input array
58
- setConnectedMcpServers((prev) => [
59
- // replace the server if it already exists
60
- ...prev.filter((s) => !equalsMcpServer(s, mcpServerInfo)),
61
- connectedMcpServer,
62
- ]);
109
+ setConnectedMcpServers((prev) => {
110
+ const existing = prev.find((s) => equalsMcpServer(s, mcpServerInfo));
111
+ try {
112
+ existing?.client?.close();
113
+ }
114
+ catch {
115
+ // best-effort cleanup
116
+ }
117
+ return [
118
+ // replace the server if it already exists
119
+ ...prev.filter((s) => !equalsMcpServer(s, mcpServerInfo)),
120
+ connectedMcpServer,
121
+ ];
122
+ });
63
123
  return connectedMcpServer;
64
124
  }
65
125
  catch (error) {
@@ -69,11 +129,20 @@ export const TamboMcpProvider = ({ mcpServers, children }) => {
69
129
  };
70
130
  // note because the promises may resolve in any order, the resulting
71
131
  // array may not be in the same order as the input array
72
- setConnectedMcpServers((prev) => [
73
- // replace the server if it already exists
74
- ...prev.filter((s) => !equalsMcpServer(s, mcpServerInfo)),
75
- failedMcpServer,
76
- ]);
132
+ setConnectedMcpServers((prev) => {
133
+ const existing = prev.find((s) => equalsMcpServer(s, mcpServerInfo));
134
+ try {
135
+ existing?.client?.close();
136
+ }
137
+ catch {
138
+ // best-effort cleanup
139
+ }
140
+ return [
141
+ // replace the server if it already exists
142
+ ...prev.filter((s) => !equalsMcpServer(s, mcpServerInfo)),
143
+ failedMcpServer,
144
+ ];
145
+ });
77
146
  return failedMcpServer;
78
147
  }
79
148
  }));
@@ -134,11 +203,52 @@ export const TamboMcpProvider = ({ mcpServers, children }) => {
134
203
  });
135
204
  }
136
205
  // normalize the server infos
137
- const mcpServerInfos = mcpServers.map((mcpServer) => typeof mcpServer === "string"
206
+ const mcpServerInfos = allMcpServers.map((mcpServer) => typeof mcpServer === "string"
138
207
  ? { url: mcpServer, transport: MCPTransport.SSE }
139
208
  : mcpServer);
140
209
  registerMcpServers(mcpServerInfos);
141
- }, [mcpServers, registerTool]);
210
+ // eslint-disable-next-line react-hooks/exhaustive-deps
211
+ }, [allMcpServers, registerTool]);
212
+ // Update handlers when they change
213
+ // We depend only on the handler refs and server identities. The linter cannot
214
+ // infer this shape with optional chaining and derived wrapper functions.
215
+ useEffect(() => {
216
+ const mcpServerInfos = allMcpServers.map((mcpServer) => typeof mcpServer === "string"
217
+ ? { url: mcpServer, transport: MCPTransport.SSE }
218
+ : mcpServer);
219
+ connectedMcpServers.forEach((connectedServer) => {
220
+ if (!connectedServer.client) {
221
+ // Skip failed servers
222
+ return;
223
+ }
224
+ // Find the matching server info to get the current handlers
225
+ const serverInfo = mcpServerInfos.find((info) => equalsMcpServer(connectedServer, info));
226
+ if (!serverInfo) {
227
+ // Server was removed, will be handled by the main effect
228
+ return;
229
+ }
230
+ // Determine effective elicitation handler (per-server overrides provider)
231
+ const defaultElicitationHandler = providerElicitationHandler;
232
+ const effectiveElicitationHandler = serverInfo.handlers?.elicitation ??
233
+ (defaultElicitationHandler
234
+ ? async (request) => await defaultElicitationHandler(request, serverInfo)
235
+ : undefined);
236
+ // Determine effective sampling handler (per-server overrides provider)
237
+ const defaultSamplingHandler = providerSamplingHandler;
238
+ const effectiveSamplingHandler = serverInfo.handlers?.sampling ??
239
+ (defaultSamplingHandler
240
+ ? async (request) => await defaultSamplingHandler(request, serverInfo)
241
+ : undefined);
242
+ // Apply handler updates unconditionally so removals propagate
243
+ connectedServer.client.updateElicitationHandler?.(effectiveElicitationHandler);
244
+ connectedServer.client.updateSamplingHandler?.(effectiveSamplingHandler);
245
+ });
246
+ }, [
247
+ allMcpServers,
248
+ connectedMcpServers,
249
+ providerElicitationHandler,
250
+ providerSamplingHandler,
251
+ ]);
142
252
  return (React.createElement(McpProviderContext.Provider, { value: connectedMcpServers }, children));
143
253
  };
144
254
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"tambo-mcp-provider.js","sourceRoot":"","sources":["../../src/mcp/tambo-mcp-provider.tsx"],"names":[],"mappings":"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","sourcesContent":["import { deepEqual } from \"fast-equals\";\nimport React, {\n createContext,\n FC,\n useContext,\n useEffect,\n useState,\n} from \"react\";\nimport { TamboTool } from \"../model/component-metadata\";\nimport { useTamboRegistry } from \"../providers/tambo-registry-provider\";\nimport { isContentPartArray, toText } from \"../util/content-parts\";\nimport { MCPClient, MCPTransport } from \"./mcp-client\";\n\n/**\n * Extracts error message from MCP tool result content.\n * Handles both array and string content formats.\n * Always returns a string, even for invalid/null inputs.\n * @returns The extracted error message as a string\n */\nexport function extractErrorMessage(content: unknown): string {\n if (content === undefined || content === null) {\n return \"Unknown error occurred\";\n }\n\n if (Array.isArray(content)) {\n const textItems = content\n .filter(\n (item) => item && item.type === \"text\" && typeof item.text === \"string\",\n )\n .map((item) => item.text);\n\n return textItems.length > 0\n ? textItems.join(\" \")\n : \"Error occurred but no details provided\";\n }\n\n if (typeof content === \"object\") {\n return JSON.stringify(content);\n }\n\n return `${content}`;\n}\n\nexport interface McpServerInfo {\n name?: string;\n url: string;\n description?: string;\n transport?: MCPTransport;\n customHeaders?: Record<string, string>;\n}\n\nexport interface ConnectedMcpServer extends McpServerInfo {\n client: MCPClient;\n}\n\nexport interface FailedMcpServer extends McpServerInfo {\n client?: never;\n connectionError: Error;\n}\n\nexport type McpServer = ConnectedMcpServer | FailedMcpServer;\n\nconst McpProviderContext = createContext<McpServer[]>([]);\n/**\n * This provider is used to register tools from MCP servers.\n * @returns the wrapped children\n */\nexport const TamboMcpProvider: FC<{\n mcpServers: (McpServerInfo | string)[];\n children: React.ReactNode;\n}> = ({ mcpServers, children }) => {\n const { registerTool } = useTamboRegistry();\n const [connectedMcpServers, setConnectedMcpServers] = useState<McpServer[]>(\n [],\n );\n\n useEffect(() => {\n if (!mcpServers) {\n return;\n }\n async function registerMcpServers(mcpServerInfos: McpServerInfo[]) {\n // Maps tool names to the MCP client that registered them\n const mcpServerMap = new Map<string, McpServer>();\n setConnectedMcpServers((prev) =>\n // remove any servers that are not in the new list\n prev.filter((s) =>\n mcpServerInfos.some((mcpServerInfo) =>\n equalsMcpServer(s, mcpServerInfo),\n ),\n ),\n );\n\n // initialize the MCP clients, converting McpServerInfo -> McpServer\n const mcpServers = await Promise.allSettled(\n mcpServerInfos.map(async (mcpServerInfo): Promise<McpServer> => {\n try {\n const client = await MCPClient.create(\n mcpServerInfo.url,\n mcpServerInfo.transport,\n mcpServerInfo.customHeaders,\n undefined, // no oauth support yet\n undefined, // starting with no session id at first.\n );\n const connectedMcpServer = {\n ...mcpServerInfo,\n client: client,\n };\n // note because the promises may resolve in any order, the resulting\n // array may not be in the same order as the input array\n setConnectedMcpServers((prev) => [\n // replace the server if it already exists\n ...prev.filter((s) => !equalsMcpServer(s, mcpServerInfo)),\n connectedMcpServer,\n ]);\n return connectedMcpServer;\n } catch (error) {\n const failedMcpServer = {\n ...mcpServerInfo,\n connectionError: error as Error,\n };\n // note because the promises may resolve in any order, the resulting\n // array may not be in the same order as the input array\n setConnectedMcpServers((prev) => [\n // replace the server if it already exists\n ...prev.filter((s) => !equalsMcpServer(s, mcpServerInfo)),\n failedMcpServer,\n ]);\n return failedMcpServer;\n }\n }),\n );\n\n // note do not rely on the state\n const connectedMcpServers = mcpServers\n .filter((result) => result.status === \"fulfilled\")\n .map((result) => result.value);\n\n // Now create a map of tool name to MCP client\n const serverToolLists = connectedMcpServers.map(async (mcpServer) => {\n const tools = (await mcpServer.client?.listTools()) ?? [];\n tools.forEach((tool) => {\n mcpServerMap.set(tool.name, mcpServer);\n });\n return tools;\n });\n const toolResults = await Promise.allSettled(serverToolLists);\n\n // Just log the failed tools, we can't do anything about them\n const failedTools = toolResults.filter(\n (result) => result.status === \"rejected\",\n );\n if (failedTools.length > 0) {\n console.error(\n \"Failed to register tools from MCP servers:\",\n failedTools.map((result) => result.reason),\n );\n }\n\n // Register the successful tools\n const allTools = toolResults\n .filter((result) => result.status === \"fulfilled\")\n .map((result) => result.value)\n .flat();\n allTools.forEach((tool) => {\n registerTool({\n description: tool.description ?? \"\",\n name: tool.name,\n tool: async (args: Record<string, unknown>) => {\n const mcpServer = mcpServerMap.get(tool.name);\n if (!mcpServer) {\n // should never happen\n throw new Error(`MCP server for tool ${tool.name} not found`);\n }\n if (!mcpServer.client) {\n // this can't actually happen because the tool can't be registered if the server is not connected\n throw new Error(\n `MCP server for tool ${tool.name} is not connected`,\n );\n }\n const result = await mcpServer.client.callTool(tool.name, args);\n if (result.isError) {\n const errorMessage = extractErrorMessage(result.content);\n throw new Error(errorMessage);\n }\n return result.content;\n },\n toolSchema: tool.inputSchema as TamboTool[\"toolSchema\"],\n transformToContent: (content: unknown) => {\n // MCP tools can return content in various formats; pass through arrays of content parts\n // unchanged, otherwise stringify into a text content part.\n if (isContentPartArray(content)) {\n return content;\n }\n return [{ type: \"text\", text: toText(content) }];\n },\n });\n });\n }\n\n // normalize the server infos\n const mcpServerInfos = mcpServers.map((mcpServer) =>\n typeof mcpServer === \"string\"\n ? { url: mcpServer, transport: MCPTransport.SSE }\n : mcpServer,\n );\n\n registerMcpServers(mcpServerInfos);\n }, [mcpServers, registerTool]);\n\n return (\n <McpProviderContext.Provider value={connectedMcpServers}>\n {children}\n </McpProviderContext.Provider>\n );\n};\n\n/**\n * Hook to access the actual MCP servers, as they are connected (or fail to\n * connect).\n *\n * You can call methods on the MCP client that is included in the MCP server\n * object.\n *\n * If the server fails to connect, the `client` property will be `undefined` and\n * the `connectionError` property will be set.\n *\n * For example, to forcibly disconnect and reconnect all MCP servers:\n *\n * ```tsx\n * const mcpServers = useTamboMcpServers();\n * mcpServers.forEach((mcpServer) => {\n * mcpServer.client?.reconnect();\n * });\n * ```\n *\n * Note that the MCP servers are not guaranteed to be in the same order as the\n * input array, because they are added as they are connected.\n * @returns The MCP servers\n */\nexport const useTamboMcpServers = () => {\n return useContext(McpProviderContext);\n};\nfunction equalsMcpServer(s: McpServer, mcpServerInfo: McpServerInfo): boolean {\n return (\n s.url === mcpServerInfo.url &&\n s.transport === mcpServerInfo.transport &&\n deepEqual(s.customHeaders, mcpServerInfo.customHeaders)\n );\n}\n"]}
1
+ {"version":3,"file":"tambo-mcp-provider.js","sourceRoot":"","sources":["../../src/mcp/tambo-mcp-provider.tsx"],"names":[],"mappings":"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","sourcesContent":["import { deepEqual } from \"fast-equals\";\nimport React, {\n createContext,\n FC,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { TamboTool } from \"../model/component-metadata\";\nimport { useTamboMcpToken } from \"../providers/tambo-mcp-token-provider\";\nimport { useTamboRegistry } from \"../providers/tambo-registry-provider\";\nimport { isContentPartArray, toText } from \"../util/content-parts\";\nimport { MCPClient, MCPHandlers, MCPTransport } from \"./mcp-client\";\n\n/**\n * Extracts error message from MCP tool result content.\n * Handles both array and string content formats.\n * Always returns a string, even for invalid/null inputs.\n * @returns The extracted error message as a string\n */\nexport function extractErrorMessage(content: unknown): string {\n if (content === undefined || content === null) {\n return \"Unknown error occurred\";\n }\n\n if (Array.isArray(content)) {\n const textItems = content\n .filter(\n (item) => item && item.type === \"text\" && typeof item.text === \"string\",\n )\n .map((item) => item.text);\n\n return textItems.length > 0\n ? textItems.join(\" \")\n : \"Error occurred but no details provided\";\n }\n\n if (typeof content === \"object\") {\n return JSON.stringify(content);\n }\n\n return `${content}`;\n}\n\n/**\n * Configuration for connecting to an MCP server.\n */\nexport interface McpServerInfo {\n /** Optional name for the MCP server */\n name?: string;\n /** The URL of the MCP server to connect to */\n url: string;\n /** Optional description of the MCP server */\n description?: string;\n /** The transport type to use (SSE or HTTP). Defaults to SSE for string URLs */\n transport?: MCPTransport;\n /** Optional custom headers to include in requests */\n customHeaders?: Record<string, string>;\n /**\n * Optional handlers for elicitation and sampling requests from the server.\n * Note: These callbacks should be stable (e.g., wrapped in useCallback or defined outside the component)\n * to avoid constant re-registration of the MCP server on every render.\n */\n handlers?: Partial<MCPHandlers>;\n}\n\nexport interface ConnectedMcpServer extends McpServerInfo {\n client: MCPClient;\n}\n\nexport interface FailedMcpServer extends McpServerInfo {\n client?: never;\n connectionError: Error;\n}\n\nexport type McpServer = ConnectedMcpServer | FailedMcpServer;\n\n/**\n * Provider-level MCP handlers that receive the McpServerInfo as context in addition to the request.\n * These handlers are applied to all MCP servers unless overridden by per-server handlers.\n */\nexport interface ProviderMCPHandlers {\n elicitation?: (\n request: Parameters<MCPHandlers[\"elicitation\"]>[0],\n serverInfo: McpServerInfo,\n ) => ReturnType<MCPHandlers[\"elicitation\"]>;\n sampling?: (\n request: Parameters<MCPHandlers[\"sampling\"]>[0],\n serverInfo: McpServerInfo,\n ) => ReturnType<MCPHandlers[\"sampling\"]>;\n}\n\nconst McpProviderContext = createContext<McpServer[]>([]);\n\n// Constant for the internal Tambo MCP server name\nconst TAMBO_INTERNAL_MCP_SERVER_NAME = \"__tambo_internal_mcp_server__\";\n\n/**\n * This provider is used to register tools from MCP servers.\n * It automatically includes an internal Tambo MCP server when an MCP access token is available.\n * @param props - The provider props\n * @param props.mcpServers - Array of MCP server configurations\n * @param props.handlers - Optional handlers applied to all MCP servers unless overridden per-server\n * @param props.children - The children to wrap\n * @returns The TamboMcpProvider component\n */\nexport const TamboMcpProvider: FC<{\n mcpServers: (McpServerInfo | string)[];\n handlers?: ProviderMCPHandlers;\n children: React.ReactNode;\n}> = ({ mcpServers, handlers, children }) => {\n const { registerTool } = useTamboRegistry();\n const { mcpAccessToken, tamboBaseUrl } = useTamboMcpToken();\n const providerElicitationHandler = handlers?.elicitation;\n const providerSamplingHandler = handlers?.sampling;\n const [connectedMcpServers, setConnectedMcpServers] = useState<McpServer[]>(\n [],\n );\n\n // Combine user-provided MCP servers with the internal Tambo MCP server\n const allMcpServers = useMemo(() => {\n const servers = [...mcpServers];\n\n // Add internal Tambo MCP server if we have an access token and a base URL\n if (mcpAccessToken && tamboBaseUrl) {\n // Build the internal MCP URL robustly, preserving any existing base path\n const base = new URL(tamboBaseUrl);\n base.pathname = `${base.pathname.replace(/\\/+$/, \"\")}/mcp`;\n const tamboMcpUrl = base.toString();\n servers.push({\n name: TAMBO_INTERNAL_MCP_SERVER_NAME,\n url: tamboMcpUrl,\n transport: MCPTransport.HTTP,\n customHeaders: {\n Authorization: `Bearer ${mcpAccessToken}`,\n },\n });\n }\n\n return servers;\n }, [mcpServers, mcpAccessToken, tamboBaseUrl]);\n\n useEffect(() => {\n if (!allMcpServers.length) {\n return;\n }\n async function registerMcpServers(mcpServerInfos: McpServerInfo[]) {\n // Maps tool names to the MCP client that registered them\n const mcpServerMap = new Map<string, McpServer>();\n setConnectedMcpServers((prev) =>\n // remove any servers that are not in the new list\n prev.filter((s) =>\n mcpServerInfos.some((mcpServerInfo) =>\n equalsMcpServer(s, mcpServerInfo),\n ),\n ),\n );\n\n // initialize the MCP clients, converting McpServerInfo -> McpServer\n const mcpServers = await Promise.allSettled(\n mcpServerInfos.map(async (mcpServerInfo): Promise<McpServer> => {\n try {\n // Merge provider handlers with per-server handlers (per-server takes precedence)\n const effectiveHandlers: Partial<MCPHandlers> = {};\n\n // Apply provider elicitation handler if present and not overridden\n if (mcpServerInfo.handlers?.elicitation) {\n effectiveHandlers.elicitation =\n mcpServerInfo.handlers.elicitation;\n } else if (providerElicitationHandler) {\n const elicitationHandler = providerElicitationHandler;\n effectiveHandlers.elicitation = async (request) =>\n await elicitationHandler(request, mcpServerInfo);\n }\n\n // Apply provider sampling handler if present and not overridden\n if (mcpServerInfo.handlers?.sampling) {\n effectiveHandlers.sampling = mcpServerInfo.handlers.sampling;\n } else if (providerSamplingHandler) {\n const samplingHandler = providerSamplingHandler;\n effectiveHandlers.sampling = async (request) =>\n await samplingHandler(request, mcpServerInfo);\n }\n\n const client = await MCPClient.create(\n mcpServerInfo.url,\n mcpServerInfo.transport,\n mcpServerInfo.customHeaders,\n undefined, // no oauth support yet\n undefined, // starting with no session id at first.\n effectiveHandlers,\n );\n const connectedMcpServer = {\n ...mcpServerInfo,\n client: client,\n };\n // note because the promises may resolve in any order, the resulting\n // array may not be in the same order as the input array\n setConnectedMcpServers((prev) => {\n const existing = prev.find((s) =>\n equalsMcpServer(s, mcpServerInfo),\n );\n try {\n existing?.client?.close();\n } catch {\n // best-effort cleanup\n }\n return [\n // replace the server if it already exists\n ...prev.filter((s) => !equalsMcpServer(s, mcpServerInfo)),\n connectedMcpServer,\n ];\n });\n return connectedMcpServer;\n } catch (error) {\n const failedMcpServer = {\n ...mcpServerInfo,\n connectionError: error as Error,\n };\n // note because the promises may resolve in any order, the resulting\n // array may not be in the same order as the input array\n setConnectedMcpServers((prev) => {\n const existing = prev.find((s) =>\n equalsMcpServer(s, mcpServerInfo),\n );\n try {\n existing?.client?.close();\n } catch {\n // best-effort cleanup\n }\n return [\n // replace the server if it already exists\n ...prev.filter((s) => !equalsMcpServer(s, mcpServerInfo)),\n failedMcpServer,\n ];\n });\n return failedMcpServer;\n }\n }),\n );\n\n // note do not rely on the state\n const connectedMcpServers = mcpServers\n .filter((result) => result.status === \"fulfilled\")\n .map((result) => result.value);\n\n // Now create a map of tool name to MCP client\n const serverToolLists = connectedMcpServers.map(async (mcpServer) => {\n const tools = (await mcpServer.client?.listTools()) ?? [];\n tools.forEach((tool) => {\n mcpServerMap.set(tool.name, mcpServer);\n });\n return tools;\n });\n const toolResults = await Promise.allSettled(serverToolLists);\n\n // Just log the failed tools, we can't do anything about them\n const failedTools = toolResults.filter(\n (result) => result.status === \"rejected\",\n );\n if (failedTools.length > 0) {\n console.error(\n \"Failed to register tools from MCP servers:\",\n failedTools.map((result) => result.reason),\n );\n }\n\n // Register the successful tools\n const allTools = toolResults\n .filter((result) => result.status === \"fulfilled\")\n .map((result) => result.value)\n .flat();\n allTools.forEach((tool) => {\n registerTool({\n description: tool.description ?? \"\",\n name: tool.name,\n tool: async (args: Record<string, unknown>) => {\n const mcpServer = mcpServerMap.get(tool.name);\n if (!mcpServer) {\n // should never happen\n throw new Error(`MCP server for tool ${tool.name} not found`);\n }\n if (!mcpServer.client) {\n // this can't actually happen because the tool can't be registered if the server is not connected\n throw new Error(\n `MCP server for tool ${tool.name} is not connected`,\n );\n }\n const result = await mcpServer.client.callTool(tool.name, args);\n if (result.isError) {\n const errorMessage = extractErrorMessage(result.content);\n throw new Error(errorMessage);\n }\n return result.content;\n },\n toolSchema: tool.inputSchema as TamboTool[\"toolSchema\"],\n transformToContent: (content: unknown) => {\n // MCP tools can return content in various formats; pass through arrays of content parts\n // unchanged, otherwise stringify into a text content part.\n if (isContentPartArray(content)) {\n return content;\n }\n return [{ type: \"text\", text: toText(content) }];\n },\n });\n });\n }\n\n // normalize the server infos\n const mcpServerInfos = allMcpServers.map((mcpServer) =>\n typeof mcpServer === \"string\"\n ? { url: mcpServer, transport: MCPTransport.SSE }\n : mcpServer,\n );\n\n registerMcpServers(mcpServerInfos);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [allMcpServers, registerTool]);\n\n // Update handlers when they change\n // We depend only on the handler refs and server identities. The linter cannot\n // infer this shape with optional chaining and derived wrapper functions.\n useEffect(() => {\n const mcpServerInfos = allMcpServers.map((mcpServer) =>\n typeof mcpServer === \"string\"\n ? { url: mcpServer, transport: MCPTransport.SSE }\n : mcpServer,\n );\n\n connectedMcpServers.forEach((connectedServer) => {\n if (!connectedServer.client) {\n // Skip failed servers\n return;\n }\n\n // Find the matching server info to get the current handlers\n const serverInfo = mcpServerInfos.find((info) =>\n equalsMcpServer(connectedServer, info),\n );\n\n if (!serverInfo) {\n // Server was removed, will be handled by the main effect\n return;\n }\n\n // Determine effective elicitation handler (per-server overrides provider)\n const defaultElicitationHandler = providerElicitationHandler;\n const effectiveElicitationHandler =\n serverInfo.handlers?.elicitation ??\n (defaultElicitationHandler\n ? async (request) =>\n await defaultElicitationHandler(request, serverInfo)\n : undefined);\n\n // Determine effective sampling handler (per-server overrides provider)\n const defaultSamplingHandler = providerSamplingHandler;\n const effectiveSamplingHandler =\n serverInfo.handlers?.sampling ??\n (defaultSamplingHandler\n ? async (request) => await defaultSamplingHandler(request, serverInfo)\n : undefined);\n\n // Apply handler updates unconditionally so removals propagate\n connectedServer.client.updateElicitationHandler?.(\n effectiveElicitationHandler,\n );\n connectedServer.client.updateSamplingHandler?.(effectiveSamplingHandler);\n });\n }, [\n allMcpServers,\n connectedMcpServers,\n providerElicitationHandler,\n providerSamplingHandler,\n ]);\n\n return (\n <McpProviderContext.Provider value={connectedMcpServers}>\n {children}\n </McpProviderContext.Provider>\n );\n};\n\n/**\n * Hook to access the actual MCP servers, as they are connected (or fail to\n * connect).\n *\n * You can call methods on the MCP client that is included in the MCP server\n * object.\n *\n * If the server fails to connect, the `client` property will be `undefined` and\n * the `connectionError` property will be set.\n *\n * For example, to forcibly disconnect and reconnect all MCP servers:\n *\n * ```tsx\n * const mcpServers = useTamboMcpServers();\n * mcpServers.forEach((mcpServer) => {\n * mcpServer.client?.reconnect();\n * });\n * ```\n *\n * Note that the MCP servers are not guaranteed to be in the same order as the\n * input array, because they are added as they are connected.\n * @returns The MCP servers\n */\nexport const useTamboMcpServers = () => {\n return useContext(McpProviderContext);\n};\nfunction equalsMcpServer(s: McpServer, mcpServerInfo: McpServerInfo): boolean {\n return (\n s.url === mcpServerInfo.url &&\n s.transport === mcpServerInfo.transport &&\n deepEqual(s.customHeaders, mcpServerInfo.customHeaders)\n );\n}\n"]}
@@ -4,6 +4,7 @@ import React from "react";
4
4
  import { GenerationStage, } from "../../model/generate-component-response";
5
5
  import { useTamboClient, useTamboQueryClient } from "../tambo-client-provider";
6
6
  import { TamboContextHelpersProvider } from "../tambo-context-helpers-provider";
7
+ import { TamboMcpTokenProvider } from "../tambo-mcp-token-provider";
7
8
  import { TamboRegistryProvider } from "../tambo-registry-provider";
8
9
  import { TamboThreadProvider, useTamboThread } from "../tambo-thread-provider";
9
10
  // Mock crypto.randomUUID
@@ -34,7 +35,8 @@ const createMockMessage = (overrides = {}) => ({
34
35
  const createWrapper = (initialMessages = []) => {
35
36
  const TestWrapper = ({ children }) => (React.createElement(TamboRegistryProvider, { components: [], tools: [] },
36
37
  React.createElement(TamboContextHelpersProvider, null,
37
- React.createElement(TamboThreadProvider, { initialMessages: initialMessages }, children))));
38
+ React.createElement(TamboMcpTokenProvider, null,
39
+ React.createElement(TamboThreadProvider, { initialMessages: initialMessages }, children)))));
38
40
  TestWrapper.displayName = "TestWrapper";
39
41
  return TestWrapper;
40
42
  };
@@ -1 +1 @@
1
- {"version":3,"file":"tambo-thread-provider-initial-messages.test.js","sourceRoot":"","sources":["../../../src/providers/__tests__/tambo-thread-provider-initial-messages.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import TamboAI, { advanceStream } from \"@tambo-ai/typescript-sdk\";\nimport { act, renderHook } from \"@testing-library/react\";\nimport React from \"react\";\nimport { DeepPartial } from \"ts-essentials\";\nimport {\n GenerationStage,\n TamboThreadMessage,\n} from \"../../model/generate-component-response\";\nimport { useTamboClient, useTamboQueryClient } from \"../tambo-client-provider\";\nimport { TamboContextHelpersProvider } from \"../tambo-context-helpers-provider\";\nimport { TamboRegistryProvider } from \"../tambo-registry-provider\";\nimport { TamboThreadProvider, useTamboThread } from \"../tambo-thread-provider\";\n\ntype PartialTamboAI = DeepPartial<TamboAI>;\n\n// Mock crypto.randomUUID\nObject.defineProperty(global, \"crypto\", {\n value: {\n randomUUID: jest.fn().mockReturnValue(\"test-uuid\"),\n },\n});\n\n// Mock the required providers\njest.mock(\"../tambo-client-provider\", () => ({\n useTamboClient: jest.fn(),\n useTamboQueryClient: jest.fn(),\n}));\njest.mock(\"@tambo-ai/typescript-sdk\", () => ({\n advanceStream: jest.fn(),\n}));\n\n// Test utilities\nconst createMockMessage = (\n overrides: Partial<TamboThreadMessage> = {},\n): TamboThreadMessage => ({\n id: \"test-message-1\",\n content: [{ type: \"text\", text: \"Hello\" }],\n role: \"user\",\n threadId: \"test-thread-1\",\n createdAt: new Date().toISOString(),\n componentState: {},\n ...overrides,\n});\n\n// Test wrapper\nconst createWrapper = (initialMessages: TamboThreadMessage[] = []) => {\n const TestWrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboRegistryProvider components={[]} tools={[]}>\n <TamboContextHelpersProvider>\n <TamboThreadProvider initialMessages={initialMessages}>\n {children}\n </TamboThreadProvider>\n </TamboContextHelpersProvider>\n </TamboRegistryProvider>\n );\n TestWrapper.displayName = \"TestWrapper\";\n return TestWrapper;\n};\n\ndescribe(\"TamboThreadProvider with initial messages\", () => {\n const mockClient: PartialTamboAI = {\n beta: {\n threads: {\n advance: jest.fn(),\n advanceByID: jest.fn(),\n cancel: jest.fn(),\n messages: {\n create: jest.fn(),\n },\n },\n },\n };\n\n beforeEach(() => {\n jest.clearAllMocks();\n (useTamboClient as jest.Mock).mockReturnValue(mockClient);\n // Provide a minimal mock for the query client used by the provider\n const mockQueryClient = {\n setQueryData: jest.fn(),\n invalidateQueries: jest.fn(),\n };\n (useTamboQueryClient as jest.Mock).mockReturnValue(mockQueryClient);\n (advanceStream as jest.Mock).mockImplementation(async function* () {\n yield {\n responseMessageDto: {\n id: \"response-1\",\n role: \"assistant\",\n content: [{ type: \"text\", text: \"Hello back!\" }],\n threadId: \"new-thread-id\",\n componentState: {},\n createdAt: new Date().toISOString(),\n },\n generationStage: GenerationStage.COMPLETE,\n };\n });\n });\n\n it(\"should initialize with empty messages when no initial messages provided\", () => {\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(),\n });\n\n expect(result.current.thread.messages).toEqual([]);\n });\n\n it(\"should initialize with provided initial messages\", () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n createMockMessage({\n id: \"initial-2\",\n role: \"user\",\n content: [{ type: \"text\", text: \"Hello!\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n expect(result.current.thread.messages).toHaveLength(2);\n expect(result.current.thread.messages[0].content[0].text).toBe(\n \"You are a helpful assistant.\",\n );\n expect(result.current.thread.messages[1].content[0].text).toBe(\"Hello!\");\n });\n\n it(\"should include initial messages when sending a message to a new thread\", async () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n await act(async () => {\n await result.current.sendThreadMessage(\"Test message\");\n });\n\n // Check that advanceStream was called with initial messages\n expect(advanceStream).toHaveBeenCalledWith(\n mockClient,\n expect.objectContaining({\n initialMessages: [\n {\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n role: \"system\",\n additionalContext: undefined,\n },\n ],\n }),\n undefined,\n );\n });\n\n it(\"should not include initial messages when sending to an existing thread\", async () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n // Switch to an existing thread first\n await act(async () => {\n result.current.switchCurrentThread(\"existing-thread-id\", false);\n });\n\n await act(async () => {\n await result.current.sendThreadMessage(\"Test message\");\n });\n\n // Check that advanceStream was called without initial messages\n expect(advanceStream).toHaveBeenCalledWith(\n mockClient,\n expect.not.objectContaining({\n initialMessages: expect.anything(),\n }),\n \"existing-thread-id\",\n );\n });\n\n it(\"should reset to initial messages when starting a new thread\", () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n // Switch to an existing thread\n act(() => {\n result.current.switchCurrentThread(\"existing-thread-id\", false);\n });\n\n // Start a new thread\n act(() => {\n result.current.startNewThread();\n });\n\n expect(result.current.thread.messages).toHaveLength(1);\n expect(result.current.thread.messages[0].content[0].text).toBe(\n \"You are a helpful assistant.\",\n );\n });\n});\n"]}
1
+ {"version":3,"file":"tambo-thread-provider-initial-messages.test.js","sourceRoot":"","sources":["../../../src/providers/__tests__/tambo-thread-provider-initial-messages.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import TamboAI, { advanceStream } from \"@tambo-ai/typescript-sdk\";\nimport { act, renderHook } from \"@testing-library/react\";\nimport React from \"react\";\nimport { DeepPartial } from \"ts-essentials\";\nimport {\n GenerationStage,\n TamboThreadMessage,\n} from \"../../model/generate-component-response\";\nimport { useTamboClient, useTamboQueryClient } from \"../tambo-client-provider\";\nimport { TamboContextHelpersProvider } from \"../tambo-context-helpers-provider\";\nimport { TamboMcpTokenProvider } from \"../tambo-mcp-token-provider\";\nimport { TamboRegistryProvider } from \"../tambo-registry-provider\";\nimport { TamboThreadProvider, useTamboThread } from \"../tambo-thread-provider\";\n\ntype PartialTamboAI = DeepPartial<TamboAI>;\n\n// Mock crypto.randomUUID\nObject.defineProperty(global, \"crypto\", {\n value: {\n randomUUID: jest.fn().mockReturnValue(\"test-uuid\"),\n },\n});\n\n// Mock the required providers\njest.mock(\"../tambo-client-provider\", () => ({\n useTamboClient: jest.fn(),\n useTamboQueryClient: jest.fn(),\n}));\njest.mock(\"@tambo-ai/typescript-sdk\", () => ({\n advanceStream: jest.fn(),\n}));\n\n// Test utilities\nconst createMockMessage = (\n overrides: Partial<TamboThreadMessage> = {},\n): TamboThreadMessage => ({\n id: \"test-message-1\",\n content: [{ type: \"text\", text: \"Hello\" }],\n role: \"user\",\n threadId: \"test-thread-1\",\n createdAt: new Date().toISOString(),\n componentState: {},\n ...overrides,\n});\n\n// Test wrapper\nconst createWrapper = (initialMessages: TamboThreadMessage[] = []) => {\n const TestWrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboRegistryProvider components={[]} tools={[]}>\n <TamboContextHelpersProvider>\n <TamboMcpTokenProvider>\n <TamboThreadProvider initialMessages={initialMessages}>\n {children}\n </TamboThreadProvider>\n </TamboMcpTokenProvider>\n </TamboContextHelpersProvider>\n </TamboRegistryProvider>\n );\n TestWrapper.displayName = \"TestWrapper\";\n return TestWrapper;\n};\n\ndescribe(\"TamboThreadProvider with initial messages\", () => {\n const mockClient: PartialTamboAI = {\n beta: {\n threads: {\n advance: jest.fn(),\n advanceByID: jest.fn(),\n cancel: jest.fn(),\n messages: {\n create: jest.fn(),\n },\n },\n },\n };\n\n beforeEach(() => {\n jest.clearAllMocks();\n (useTamboClient as jest.Mock).mockReturnValue(mockClient);\n // Provide a minimal mock for the query client used by the provider\n const mockQueryClient = {\n setQueryData: jest.fn(),\n invalidateQueries: jest.fn(),\n };\n (useTamboQueryClient as jest.Mock).mockReturnValue(mockQueryClient);\n (advanceStream as jest.Mock).mockImplementation(async function* () {\n yield {\n responseMessageDto: {\n id: \"response-1\",\n role: \"assistant\",\n content: [{ type: \"text\", text: \"Hello back!\" }],\n threadId: \"new-thread-id\",\n componentState: {},\n createdAt: new Date().toISOString(),\n },\n generationStage: GenerationStage.COMPLETE,\n };\n });\n });\n\n it(\"should initialize with empty messages when no initial messages provided\", () => {\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(),\n });\n\n expect(result.current.thread.messages).toEqual([]);\n });\n\n it(\"should initialize with provided initial messages\", () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n createMockMessage({\n id: \"initial-2\",\n role: \"user\",\n content: [{ type: \"text\", text: \"Hello!\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n expect(result.current.thread.messages).toHaveLength(2);\n expect(result.current.thread.messages[0].content[0].text).toBe(\n \"You are a helpful assistant.\",\n );\n expect(result.current.thread.messages[1].content[0].text).toBe(\"Hello!\");\n });\n\n it(\"should include initial messages when sending a message to a new thread\", async () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n await act(async () => {\n await result.current.sendThreadMessage(\"Test message\");\n });\n\n // Check that advanceStream was called with initial messages\n expect(advanceStream).toHaveBeenCalledWith(\n mockClient,\n expect.objectContaining({\n initialMessages: [\n {\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n role: \"system\",\n additionalContext: undefined,\n },\n ],\n }),\n undefined,\n );\n });\n\n it(\"should not include initial messages when sending to an existing thread\", async () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n // Switch to an existing thread first\n await act(async () => {\n result.current.switchCurrentThread(\"existing-thread-id\", false);\n });\n\n await act(async () => {\n await result.current.sendThreadMessage(\"Test message\");\n });\n\n // Check that advanceStream was called without initial messages\n expect(advanceStream).toHaveBeenCalledWith(\n mockClient,\n expect.not.objectContaining({\n initialMessages: expect.anything(),\n }),\n \"existing-thread-id\",\n );\n });\n\n it(\"should reset to initial messages when starting a new thread\", () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n // Switch to an existing thread\n act(() => {\n result.current.switchCurrentThread(\"existing-thread-id\", false);\n });\n\n // Start a new thread\n act(() => {\n result.current.startNewThread();\n });\n\n expect(result.current.thread.messages).toHaveLength(1);\n expect(result.current.thread.messages[0].content[0].text).toBe(\n \"You are a helpful assistant.\",\n );\n });\n});\n"]}
@@ -6,6 +6,7 @@ import { GenerationStage, } from "../../model/generate-component-response";
6
6
  import { serializeRegistry } from "../../testing/tools";
7
7
  import { useTamboClient, useTamboQueryClient } from "../tambo-client-provider";
8
8
  import { TamboContextHelpersProvider } from "../tambo-context-helpers-provider";
9
+ import { TamboMcpTokenProvider } from "../tambo-mcp-token-provider";
9
10
  import { TamboRegistryProvider } from "../tambo-registry-provider";
10
11
  import { TamboThreadProvider, useTamboThread } from "../tambo-thread-provider";
11
12
  // Mock crypto.randomUUID
@@ -111,7 +112,8 @@ describe("TamboThreadProvider", () => {
111
112
  currentTimeContextHelper: () => null,
112
113
  currentPageContextHelper: () => null,
113
114
  } },
114
- React.createElement(TamboThreadProvider, { streaming: false }, children))));
115
+ React.createElement(TamboMcpTokenProvider, null,
116
+ React.createElement(TamboThreadProvider, { streaming: false }, children)))));
115
117
  beforeEach(() => {
116
118
  jest.clearAllMocks();
117
119
  // Setup mock query client
@@ -327,7 +329,8 @@ describe("TamboThreadProvider", () => {
327
329
  currentTimeContextHelper: () => null,
328
330
  currentPageContextHelper: () => null,
329
331
  } },
330
- React.createElement(TamboThreadProvider, { streaming: false }, children))));
332
+ React.createElement(TamboMcpTokenProvider, null,
333
+ React.createElement(TamboThreadProvider, { streaming: false }, children)))));
331
334
  const mockUnregisteredToolCallResponse = {
332
335
  responseMessageDto: {
333
336
  id: "unregistered-tool-call-1",
@@ -425,7 +428,8 @@ describe("TamboThreadProvider", () => {
425
428
  currentTimeContextHelper: () => null,
426
429
  currentPageContextHelper: () => null,
427
430
  } },
428
- React.createElement(TamboThreadProvider, { streaming: true }, children))));
431
+ React.createElement(TamboMcpTokenProvider, null,
432
+ React.createElement(TamboThreadProvider, { streaming: true }, children)))));
429
433
  const mockStreamResponse = {
430
434
  responseMessageDto: {
431
435
  id: "stream-response",
@@ -486,7 +490,8 @@ describe("TamboThreadProvider", () => {
486
490
  currentTimeContextHelper: () => null,
487
491
  currentPageContextHelper: () => null,
488
492
  } },
489
- React.createElement(TamboThreadProvider, { streaming: true }, children))));
493
+ React.createElement(TamboMcpTokenProvider, null,
494
+ React.createElement(TamboThreadProvider, { streaming: true }, children)))));
490
495
  const { result } = renderHook(() => useTamboThread(), {
491
496
  wrapper: wrapperWithStreaming,
492
497
  });
@@ -528,7 +533,8 @@ describe("TamboThreadProvider", () => {
528
533
  currentTimeContextHelper: () => null,
529
534
  currentPageContextHelper: () => null,
530
535
  } },
531
- React.createElement(TamboThreadProvider, { streaming: false }, children))));
536
+ React.createElement(TamboMcpTokenProvider, null,
537
+ React.createElement(TamboThreadProvider, { streaming: false }, children)))));
532
538
  const { result } = renderHook(() => useTamboThread(), {
533
539
  wrapper: wrapperWithoutStreaming,
534
540
  });
@@ -570,7 +576,8 @@ describe("TamboThreadProvider", () => {
570
576
  currentTimeContextHelper: () => null,
571
577
  currentPageContextHelper: () => null,
572
578
  } },
573
- React.createElement(TamboThreadProvider, null, children))));
579
+ React.createElement(TamboMcpTokenProvider, null,
580
+ React.createElement(TamboThreadProvider, null, children)))));
574
581
  const mockStreamResponse = {
575
582
  responseMessageDto: {
576
583
  id: "stream-response",
@@ -631,7 +638,8 @@ describe("TamboThreadProvider", () => {
631
638
  currentTimeContextHelper: () => null,
632
639
  currentPageContextHelper: () => null,
633
640
  } },
634
- React.createElement(TamboThreadProvider, { streaming: true }, children))));
641
+ React.createElement(TamboMcpTokenProvider, null,
642
+ React.createElement(TamboThreadProvider, { streaming: true }, children)))));
635
643
  const { result } = renderHook(() => useTamboThread(), {
636
644
  wrapper: wrapperWithStreaming,
637
645
  });
@@ -675,7 +683,8 @@ describe("TamboThreadProvider", () => {
675
683
  currentTimeContextHelper: () => null,
676
684
  currentPageContextHelper: () => null,
677
685
  } },
678
- React.createElement(TamboThreadProvider, { streaming: false }, children))));
686
+ React.createElement(TamboMcpTokenProvider, null,
687
+ React.createElement(TamboThreadProvider, { streaming: false }, children)))));
679
688
  const mockStreamResponse = {
680
689
  responseMessageDto: {
681
690
  id: "stream-response",
@@ -878,7 +887,8 @@ describe("TamboThreadProvider", () => {
878
887
  currentTimeContextHelper: () => null,
879
888
  currentPageContextHelper: () => null,
880
889
  } },
881
- React.createElement(TamboThreadProvider, { streaming: false }, children))));
890
+ React.createElement(TamboMcpTokenProvider, null,
891
+ React.createElement(TamboThreadProvider, { streaming: false }, children)))));
882
892
  const mockToolCallResponse = {
883
893
  responseMessageDto: {
884
894
  id: "tool-call-1",
@@ -971,7 +981,8 @@ describe("TamboThreadProvider", () => {
971
981
  currentTimeContextHelper: () => null,
972
982
  currentPageContextHelper: () => null,
973
983
  } },
974
- React.createElement(TamboThreadProvider, { streaming: true }, children))));
984
+ React.createElement(TamboMcpTokenProvider, null,
985
+ React.createElement(TamboThreadProvider, { streaming: true }, children)))));
975
986
  const mockToolCallChunk = {
976
987
  responseMessageDto: {
977
988
  id: "tool-call-chunk",
@@ -1072,7 +1083,8 @@ describe("TamboThreadProvider", () => {
1072
1083
  currentTimeContextHelper: () => null,
1073
1084
  currentPageContextHelper: () => null,
1074
1085
  } },
1075
- React.createElement(TamboThreadProvider, { streaming: false }, children))));
1086
+ React.createElement(TamboMcpTokenProvider, null,
1087
+ React.createElement(TamboThreadProvider, { streaming: false }, children)))));
1076
1088
  const mockToolCallResponse = {
1077
1089
  responseMessageDto: {
1078
1090
  id: "tool-call-1",
@@ -1159,7 +1171,8 @@ describe("TamboThreadProvider", () => {
1159
1171
  currentTimeContextHelper: () => null,
1160
1172
  currentPageContextHelper: () => null,
1161
1173
  } },
1162
- React.createElement(TamboThreadProvider, { streaming: false }, children))));
1174
+ React.createElement(TamboMcpTokenProvider, null,
1175
+ React.createElement(TamboThreadProvider, { streaming: false }, children)))));
1163
1176
  const mockToolCallResponse = {
1164
1177
  responseMessageDto: {
1165
1178
  id: "tool-call-1",