@tambo-ai/react 0.58.1 → 0.60.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.
- package/dist/hooks/react-query-hooks.d.ts +14 -1
- package/dist/hooks/react-query-hooks.d.ts.map +1 -1
- package/dist/hooks/react-query-hooks.js +13 -0
- package/dist/hooks/react-query-hooks.js.map +1 -1
- package/dist/hooks/use-tambo-stream-status.js +1 -1
- package/dist/hooks/use-tambo-stream-status.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/__tests__/elicitation.test.d.ts +2 -0
- package/dist/mcp/__tests__/elicitation.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/elicitation.test.js +261 -0
- package/dist/mcp/__tests__/elicitation.test.js.map +1 -0
- package/dist/mcp/__tests__/mcp-client.test.js +0 -266
- package/dist/mcp/__tests__/mcp-client.test.js.map +1 -1
- package/dist/mcp/__tests__/mcp-hooks.test.d.ts +2 -0
- package/dist/mcp/__tests__/mcp-hooks.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/mcp-hooks.test.js +504 -0
- package/dist/mcp/__tests__/mcp-hooks.test.js.map +1 -0
- package/dist/mcp/__tests__/tambo-mcp-provider.test.js +361 -16
- package/dist/mcp/__tests__/tambo-mcp-provider.test.js.map +1 -1
- package/dist/mcp/__tests__/use-mcp-servers.test.js +34 -9
- package/dist/mcp/__tests__/use-mcp-servers.test.js.map +1 -1
- package/dist/mcp/elicitation.d.ts +80 -0
- package/dist/mcp/elicitation.d.ts.map +1 -0
- package/dist/mcp/elicitation.js +55 -0
- package/dist/mcp/elicitation.js.map +1 -0
- package/dist/mcp/index.d.ts +4 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +5 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/mcp-client.d.ts +51 -86
- package/dist/mcp/mcp-client.d.ts.map +1 -1
- package/dist/mcp/mcp-client.js +22 -159
- package/dist/mcp/mcp-client.js.map +1 -1
- package/dist/mcp/mcp-hooks.d.ts +107 -0
- package/dist/mcp/mcp-hooks.d.ts.map +1 -0
- package/dist/mcp/mcp-hooks.js +103 -0
- package/dist/mcp/mcp-hooks.js.map +1 -0
- package/dist/mcp/tambo-mcp-provider.d.ts +86 -4
- package/dist/mcp/tambo-mcp-provider.d.ts.map +1 -1
- package/dist/mcp/tambo-mcp-provider.js +275 -106
- package/dist/mcp/tambo-mcp-provider.js.map +1 -1
- package/dist/providers/__tests__/tambo-thread-provider-initial-messages.test.js +3 -1
- package/dist/providers/__tests__/tambo-thread-provider-initial-messages.test.js.map +1 -1
- package/dist/providers/__tests__/tambo-thread-provider.test.js +25 -12
- package/dist/providers/__tests__/tambo-thread-provider.test.js.map +1 -1
- package/dist/providers/tambo-interactable-provider.d.ts.map +1 -1
- package/dist/providers/tambo-interactable-provider.js +11 -4
- package/dist/providers/tambo-interactable-provider.js.map +1 -1
- package/dist/providers/tambo-mcp-token-provider.d.ts +34 -0
- package/dist/providers/tambo-mcp-token-provider.d.ts.map +1 -0
- package/dist/providers/tambo-mcp-token-provider.js +69 -0
- package/dist/providers/tambo-mcp-token-provider.js.map +1 -0
- package/dist/providers/tambo-provider.d.ts.map +1 -1
- package/dist/providers/tambo-provider.js +7 -9
- package/dist/providers/tambo-provider.js.map +1 -1
- package/dist/providers/tambo-thread-provider.d.ts.map +1 -1
- package/dist/providers/tambo-thread-provider.js +14 -0
- package/dist/providers/tambo-thread-provider.js.map +1 -1
- package/esm/hooks/react-query-hooks.d.ts +14 -1
- package/esm/hooks/react-query-hooks.d.ts.map +1 -1
- package/esm/hooks/react-query-hooks.js +13 -1
- package/esm/hooks/react-query-hooks.js.map +1 -1
- package/esm/hooks/use-tambo-stream-status.js +1 -1
- package/esm/hooks/use-tambo-stream-status.js.map +1 -1
- package/esm/index.js +2 -0
- package/esm/index.js.map +1 -1
- package/esm/mcp/__tests__/elicitation.test.d.ts +2 -0
- package/esm/mcp/__tests__/elicitation.test.d.ts.map +1 -0
- package/esm/mcp/__tests__/elicitation.test.js +259 -0
- package/esm/mcp/__tests__/elicitation.test.js.map +1 -0
- package/esm/mcp/__tests__/mcp-client.test.js +0 -266
- package/esm/mcp/__tests__/mcp-client.test.js.map +1 -1
- package/esm/mcp/__tests__/mcp-hooks.test.d.ts +2 -0
- package/esm/mcp/__tests__/mcp-hooks.test.d.ts.map +1 -0
- package/esm/mcp/__tests__/mcp-hooks.test.js +469 -0
- package/esm/mcp/__tests__/mcp-hooks.test.js.map +1 -0
- package/esm/mcp/__tests__/tambo-mcp-provider.test.js +361 -16
- package/esm/mcp/__tests__/tambo-mcp-provider.test.js.map +1 -1
- package/esm/mcp/__tests__/use-mcp-servers.test.js +34 -9
- package/esm/mcp/__tests__/use-mcp-servers.test.js.map +1 -1
- package/esm/mcp/elicitation.d.ts +80 -0
- package/esm/mcp/elicitation.d.ts.map +1 -0
- package/esm/mcp/elicitation.js +52 -0
- package/esm/mcp/elicitation.js.map +1 -0
- package/esm/mcp/index.d.ts +4 -1
- package/esm/mcp/index.d.ts.map +1 -1
- package/esm/mcp/index.js +2 -1
- package/esm/mcp/index.js.map +1 -1
- package/esm/mcp/mcp-client.d.ts +51 -86
- package/esm/mcp/mcp-client.d.ts.map +1 -1
- package/esm/mcp/mcp-client.js +22 -159
- package/esm/mcp/mcp-client.js.map +1 -1
- package/esm/mcp/mcp-hooks.d.ts +107 -0
- package/esm/mcp/mcp-hooks.d.ts.map +1 -0
- package/esm/mcp/mcp-hooks.js +99 -0
- package/esm/mcp/mcp-hooks.js.map +1 -0
- package/esm/mcp/tambo-mcp-provider.d.ts +86 -4
- package/esm/mcp/tambo-mcp-provider.d.ts.map +1 -1
- package/esm/mcp/tambo-mcp-provider.js +275 -107
- package/esm/mcp/tambo-mcp-provider.js.map +1 -1
- package/esm/providers/__tests__/tambo-thread-provider-initial-messages.test.js +3 -1
- package/esm/providers/__tests__/tambo-thread-provider-initial-messages.test.js.map +1 -1
- package/esm/providers/__tests__/tambo-thread-provider.test.js +25 -12
- package/esm/providers/__tests__/tambo-thread-provider.test.js.map +1 -1
- package/esm/providers/tambo-interactable-provider.d.ts.map +1 -1
- package/esm/providers/tambo-interactable-provider.js +11 -4
- package/esm/providers/tambo-interactable-provider.js.map +1 -1
- package/esm/providers/tambo-mcp-token-provider.d.ts +34 -0
- package/esm/providers/tambo-mcp-token-provider.d.ts.map +1 -0
- package/esm/providers/tambo-mcp-token-provider.js +31 -0
- package/esm/providers/tambo-mcp-token-provider.js.map +1 -0
- package/esm/providers/tambo-provider.d.ts.map +1 -1
- package/esm/providers/tambo-provider.js +7 -9
- package/esm/providers/tambo-provider.js.map +1 -1
- package/esm/providers/tambo-thread-provider.d.ts.map +1 -1
- package/esm/providers/tambo-thread-provider.js +14 -0
- package/esm/providers/tambo-thread-provider.js.map +1 -1
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-client.test.js","sourceRoot":"","sources":["../../../src/mcp/__tests__/mcp-client.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { MCPClient, MCPTransport } from \"../mcp-client\";\n\n// Mock the MCP SDK modules\njest.mock(\"@modelcontextprotocol/sdk/client/index.js\", () => ({\n Client: jest.fn().mockImplementation(() => ({\n connect: jest.fn(),\n close: jest.fn(),\n listTools: jest.fn(),\n callTool: jest.fn(),\n setRequestHandler: jest.fn(),\n removeRequestHandler: jest.fn(),\n onclose: null,\n })),\n}));\n\njest.mock(\"@modelcontextprotocol/sdk/client/sse.js\", () => ({\n SSEClientTransport: jest.fn().mockImplementation(() => ({\n // SSE transport doesn't have sessionId\n })),\n}));\n\njest.mock(\"@modelcontextprotocol/sdk/client/streamableHttp.js\", () => ({\n StreamableHTTPClientTransport: jest\n .fn()\n .mockImplementation((url, options) => ({\n sessionId: options?.sessionId,\n })),\n}));\n\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { SSEClientTransport } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\n\n// Type the mocked modules\nconst MockedClient = Client as jest.MockedClass<typeof Client>;\nconst MockedSSEClientTransport = SSEClientTransport as jest.MockedClass<\n typeof SSEClientTransport\n>;\nconst MockedStreamableHTTPClientTransport =\n StreamableHTTPClientTransport as jest.MockedClass<\n typeof StreamableHTTPClientTransport\n >;\n\ndescribe(\"MCPClient\", () => {\n let mockClientInstance: any;\n let mockTransportInstance: any;\n\n beforeEach(() => {\n jest.clearAllMocks();\n\n // Create mock instances\n mockClientInstance = {\n connect: jest.fn().mockResolvedValue(undefined),\n close: jest.fn().mockResolvedValue(undefined),\n listTools: jest.fn(),\n callTool: jest.fn(),\n setRequestHandler: jest.fn(),\n removeRequestHandler: jest.fn(),\n onclose: null,\n };\n\n mockTransportInstance = {\n sessionId: \"test-session-id\",\n };\n\n // Setup mocks\n MockedClient.mockImplementation(() => mockClientInstance);\n MockedStreamableHTTPClientTransport.mockImplementation(\n () => mockTransportInstance,\n );\n MockedSSEClientTransport.mockImplementation(\n () => ({}) as SSEClientTransport,\n );\n });\n\n describe(\"create\", () => {\n it(\"should create and connect an MCPClient with HTTP transport by default\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const headers = { Authorization: \"Bearer token\" };\n\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n headers,\n undefined,\n undefined,\n );\n\n expect(MockedStreamableHTTPClientTransport).toHaveBeenCalledWith(\n new URL(endpoint),\n { sessionId: undefined, requestInit: { headers } },\n );\n expect(MockedClient).toHaveBeenCalledWith(\n {\n name: \"tambo-mcp-client\",\n version: \"1.0.0\",\n },\n { capabilities: {} },\n );\n expect(mockClientInstance.connect).toHaveBeenCalledWith(\n mockTransportInstance,\n );\n expect(client).toBeInstanceOf(MCPClient);\n });\n\n it(\"should create and connect an MCPClient with SSE transport\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.SSE,\n undefined,\n undefined,\n undefined,\n );\n\n expect(MockedSSEClientTransport).toHaveBeenCalledWith(new URL(endpoint), {\n requestInit: { headers: {} },\n });\n expect(mockClientInstance.connect).toHaveBeenCalledWith({});\n expect(client).toBeInstanceOf(MCPClient);\n });\n\n it(\"should create client with default headers when none provided\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n\n await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n expect(MockedStreamableHTTPClientTransport).toHaveBeenCalledWith(\n new URL(endpoint),\n { sessionId: undefined, requestInit: { headers: {} } },\n );\n });\n });\n\n describe(\"reconnect\", () => {\n it(\"should create new transport and client instances and call connect when reconnect() is called (default behavior)\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n // Clear previous calls to focus on reconnect behavior\n jest.clearAllMocks();\n\n // Create new mock instances to verify new instances are created\n const newMockClientInstance = {\n connect: jest.fn().mockResolvedValue(undefined),\n close: jest.fn().mockResolvedValue(undefined),\n listTools: jest.fn(),\n callTool: jest.fn(),\n onclose: null,\n };\n\n const newMockTransportInstance = {\n sessionId: \"new-session-id\",\n };\n\n // Mock the constructors to return new instances\n MockedClient.mockImplementation(() => newMockClientInstance as any);\n MockedStreamableHTTPClientTransport.mockImplementation(\n () => newMockTransportInstance as any,\n );\n\n await client.reconnect(); // Uses default parameters\n\n // Verify old client was closed\n expect(mockClientInstance.close).toHaveBeenCalled();\n\n // Verify new transport was created with preserved session ID (default behavior)\n expect(MockedStreamableHTTPClientTransport).toHaveBeenCalledWith(\n new URL(endpoint),\n { sessionId: \"test-session-id\", requestInit: { headers: {} } },\n );\n\n // Verify new client was created\n expect(MockedClient).toHaveBeenCalledWith(\n {\n name: \"tambo-mcp-client\",\n version: \"1.0.0\",\n },\n { capabilities: {} },\n );\n\n // Verify new client's connect was called with new transport\n expect(newMockClientInstance.connect).toHaveBeenCalledWith(\n newMockTransportInstance,\n );\n });\n\n it(\"should reconnect without session ID for SSE transport\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.SSE,\n undefined,\n undefined,\n undefined,\n );\n\n // Clear previous calls\n jest.clearAllMocks();\n\n await client.reconnect();\n\n expect(mockClientInstance.close).toHaveBeenCalled();\n expect(MockedSSEClientTransport).toHaveBeenCalledWith(new URL(endpoint), {\n requestInit: { headers: {} },\n });\n expect(mockClientInstance.connect).toHaveBeenCalledWith({});\n });\n\n it(\"should handle close errors when reportErrorOnClose is true\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n const consoleSpy = jest.spyOn(console, \"error\").mockImplementation();\n\n // Make close throw an error\n mockClientInstance.close.mockRejectedValue(new Error(\"Close failed\"));\n\n await client.reconnect(false, true);\n\n expect(consoleSpy).toHaveBeenCalledWith(\n \"Error closing Tambo MCP Client:\",\n expect.any(Error),\n );\n consoleSpy.mockRestore();\n });\n\n it(\"should not log close errors when reportErrorOnClose is false\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n const consoleSpy = jest.spyOn(console, \"error\").mockImplementation();\n\n // Make close throw an error\n mockClientInstance.close.mockRejectedValue(new Error(\"Close failed\"));\n\n await client.reconnect(false, false);\n\n expect(consoleSpy).not.toHaveBeenCalled();\n consoleSpy.mockRestore();\n });\n\n it(\"should create new session when newSession is true\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n // Clear previous calls to focus on reconnect behavior\n jest.clearAllMocks();\n\n // Create new mock instances to verify new instances are created\n const newMockClientInstance = {\n connect: jest.fn().mockResolvedValue(undefined),\n close: jest.fn().mockResolvedValue(undefined),\n listTools: jest.fn(),\n callTool: jest.fn(),\n onclose: null,\n };\n\n const newMockTransportInstance = {\n sessionId: \"new-session-id\",\n };\n\n // Mock the constructors to return new instances\n MockedClient.mockImplementation(() => newMockClientInstance as any);\n MockedStreamableHTTPClientTransport.mockImplementation(\n () => newMockTransportInstance as any,\n );\n\n await client.reconnect(true, true); // newSession = true, reportErrorOnClose = true\n\n // Verify old client was closed\n expect(mockClientInstance.close).toHaveBeenCalled();\n\n // Verify new transport was created with undefined session ID (new session)\n expect(MockedStreamableHTTPClientTransport).toHaveBeenCalledWith(\n new URL(endpoint),\n { sessionId: undefined, requestInit: { headers: {} } },\n );\n\n // Verify new client was created\n expect(MockedClient).toHaveBeenCalledWith(\n {\n name: \"tambo-mcp-client\",\n version: \"1.0.0\",\n },\n { capabilities: {} },\n );\n\n // Verify new client's connect was called with new transport\n expect(newMockClientInstance.connect).toHaveBeenCalledWith(\n newMockTransportInstance,\n );\n });\n\n it(\"should reuse existing session when newSession is false (default)\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n // Clear previous calls to focus on reconnect behavior\n jest.clearAllMocks();\n\n // Create new mock instances to verify new instances are created\n const newMockClientInstance = {\n connect: jest.fn().mockResolvedValue(undefined),\n close: jest.fn().mockResolvedValue(undefined),\n listTools: jest.fn(),\n callTool: jest.fn(),\n onclose: null,\n };\n\n const newMockTransportInstance = {\n sessionId: \"reused-session-id\",\n };\n\n // Mock the constructors to return new instances\n MockedClient.mockImplementation(() => newMockClientInstance as any);\n MockedStreamableHTTPClientTransport.mockImplementation(\n () => newMockTransportInstance as any,\n );\n\n await client.reconnect(false, true); // newSession = false, reportErrorOnClose = true\n\n // Verify old client was closed\n expect(mockClientInstance.close).toHaveBeenCalled();\n\n // Verify new transport was created with preserved session ID\n expect(MockedStreamableHTTPClientTransport).toHaveBeenCalledWith(\n new URL(endpoint),\n { sessionId: \"test-session-id\", requestInit: { headers: {} } },\n );\n\n // Verify new client was created\n expect(MockedClient).toHaveBeenCalledWith(\n {\n name: \"tambo-mcp-client\",\n version: \"1.0.0\",\n },\n { capabilities: {} },\n );\n\n // Verify new client's connect was called with new transport\n expect(newMockClientInstance.connect).toHaveBeenCalledWith(\n newMockTransportInstance,\n );\n });\n });\n\n describe(\"onclose\", () => {\n it(\"should reconnect MCPClient when client is closed by external means (no backoff on manual preemption)\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n jest.useFakeTimers();\n const consoleSpy = jest.spyOn(console, \"warn\").mockImplementation();\n\n // Create new mock instances to verify reconnection creates new instances\n const newMockClientInstance = {\n connect: jest.fn().mockResolvedValue(undefined),\n close: jest.fn().mockResolvedValue(undefined),\n listTools: jest.fn(),\n callTool: jest.fn(),\n onclose: null,\n };\n\n const newMockTransportInstance = {\n sessionId: \"reconnected-session-id\",\n };\n\n // Mock the constructors to return new instances for reconnection\n MockedClient.mockImplementation(() => newMockClientInstance as any);\n MockedStreamableHTTPClientTransport.mockImplementation(\n () => newMockTransportInstance as any,\n );\n\n // Reset counts after initial creation\n jest.clearAllMocks();\n\n // Trigger automatic onclose (schedules a delayed reconnect)\n (client as any).onclose();\n // Manual reconnect should preempt the scheduled automatic attempt\n const reconnectPromise = client.reconnect();\n // No timers should be pending after manual preemption\n await reconnectPromise;\n\n // Verify warning message is logged\n expect(consoleSpy).toHaveBeenCalled();\n\n // Verify old client was closed\n expect(mockClientInstance.close).toHaveBeenCalled();\n\n // Verify new transport was created with preserved session ID\n expect(MockedStreamableHTTPClientTransport).toHaveBeenCalledWith(\n new URL(endpoint),\n { sessionId: \"test-session-id\", requestInit: { headers: {} } },\n );\n\n // Verify new client was created\n expect(MockedClient).toHaveBeenCalledWith(\n {\n name: \"tambo-mcp-client\",\n version: \"1.0.0\",\n },\n { capabilities: {} },\n );\n\n // Verify new client's connect was called with new transport\n expect(newMockClientInstance.connect).toHaveBeenCalledWith(\n newMockTransportInstance,\n );\n\n // Ensure only a single reconnect attempt occurred\n expect(MockedClient).toHaveBeenCalledTimes(1);\n expect(newMockClientInstance.connect).toHaveBeenCalledTimes(1);\n\n consoleSpy.mockRestore();\n jest.useRealTimers();\n });\n });\n\n describe(\"reconnect re-entrancy and single-flight\", () => {\n it(\"prevents re-entrant onclose during deliberate close and coalesces concurrent calls\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n // Simulate an implementation where closing the client would call its own onclose handler\n const closeImpl = jest.fn(async () => {\n if (typeof mockClientInstance.onclose === \"function\") {\n // would cause recursion if not detached\n (mockClientInstance.onclose as unknown as () => void)();\n }\n return;\n });\n mockClientInstance.close = closeImpl;\n\n // Prepare new instances for the reconnect\n const newMockClientInstance = {\n connect: jest.fn().mockResolvedValue(undefined),\n close: jest.fn().mockResolvedValue(undefined),\n listTools: jest.fn(),\n callTool: jest.fn(),\n onclose: null,\n };\n MockedClient.mockImplementation(() => newMockClientInstance as any);\n\n // Reset counts after initial creation\n jest.clearAllMocks();\n\n // Trigger auto onclose and manual reconnect nearly simultaneously\n (client as any).onclose();\n await client.reconnect();\n\n // Should have detached onclose before calling close, avoiding recursion\n expect(closeImpl).toHaveBeenCalledTimes(1);\n expect(mockClientInstance.onclose).toBeUndefined();\n\n // Single-flight: only one new client/connect\n expect(MockedClient).toHaveBeenCalledTimes(1);\n expect(newMockClientInstance.connect).toHaveBeenCalledTimes(1);\n });\n });\n\n describe(\"backoff + jitter (automatic reconnect)\", () => {\n it(\"applies jitter and resets to initial delay after a successful reconnect (manual preempt)\", async () => {\n jest.useFakeTimers();\n const base = MCPClient.BACKOFF_INITIAL_MS;\n const ratio = MCPClient.BACKOFF_JITTER_RATIO;\n const min = Math.round(base * (1 - ratio));\n const max = Math.round(base * (1 + ratio));\n const setTimeoutSpy = jest.spyOn(global, \"setTimeout\");\n const randSpy = jest.spyOn(Math, \"random\").mockReturnValue(0.0); // extreme low jitter\n\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n // Prepare one attempt that will succeed to avoid rescheduling\n MockedClient.mockImplementation(\n () =>\n ({\n connect: jest.fn().mockResolvedValue(undefined),\n close: jest.fn().mockResolvedValue(undefined),\n listTools: jest.fn(),\n callTool: jest.fn(),\n onclose: null,\n }) as any,\n );\n\n // Trigger once to capture the delay\n (client as any).onclose();\n expect(setTimeoutSpy).toHaveBeenCalled();\n const numericDelays = setTimeoutSpy.mock.calls\n .map((c) => c[1])\n .filter((v) => typeof v === \"number\") as number[];\n expect(numericDelays.length).toBeGreaterThan(0);\n const d = numericDelays[0]!;\n expect(d).toBeGreaterThanOrEqual(min);\n expect(d).toBeLessThanOrEqual(max);\n\n // Manual reconnect succeeds and should reset backoff attempts\n await client.reconnect();\n\n // Trigger onclose again and ensure we start from initial range again\n (client as any).onclose();\n const numericDelays2 = setTimeoutSpy.mock.calls\n .map((c) => c[1])\n .filter((v) => typeof v === \"number\") as number[];\n expect(numericDelays2.length).toBeGreaterThanOrEqual(2);\n const dAgain = numericDelays2[1]!;\n expect(dAgain).toBeGreaterThanOrEqual(min);\n expect(dAgain).toBeLessThanOrEqual(max);\n\n jest.useRealTimers();\n setTimeoutSpy.mockRestore();\n randSpy.mockRestore();\n });\n });\n\n describe(\"listTools\", () => {\n it(\"should list all tools with pagination\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n const mockTools = [\n {\n name: \"tool1\",\n description: \"First tool\",\n inputSchema: {\n type: \"object\",\n properties: { arg1: { type: \"string\" } },\n },\n },\n {\n name: \"tool2\",\n description: \"Second tool\",\n inputSchema: {\n type: \"object\",\n properties: { arg2: { type: \"number\" } },\n },\n },\n ];\n\n const mockResponse1 = {\n tools: [mockTools[0]],\n nextCursor: \"cursor1\",\n };\n\n const mockResponse2 = {\n tools: [mockTools[1]],\n nextCursor: undefined,\n };\n\n mockClientInstance.listTools\n .mockResolvedValueOnce(mockResponse1)\n .mockResolvedValueOnce(mockResponse2);\n\n const result = await client.listTools();\n\n expect(mockClientInstance.listTools).toHaveBeenCalledTimes(2);\n expect(mockClientInstance.listTools).toHaveBeenNthCalledWith(\n 1,\n { cursor: undefined },\n {},\n );\n expect(mockClientInstance.listTools).toHaveBeenNthCalledWith(\n 2,\n { cursor: \"cursor1\" },\n {},\n );\n expect(result).toEqual([\n {\n name: \"tool1\",\n description: \"First tool\",\n inputSchema: {\n type: \"object\",\n properties: { arg1: { type: \"string\" } },\n },\n },\n {\n name: \"tool2\",\n description: \"Second tool\",\n inputSchema: {\n type: \"object\",\n properties: { arg2: { type: \"number\" } },\n },\n },\n ]);\n });\n\n it(\"should handle single page of tools\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n const mockTools = [\n {\n name: \"tool1\",\n description: \"Only tool\",\n inputSchema: {\n type: \"object\",\n properties: { arg1: { type: \"string\" } },\n },\n },\n ];\n\n const mockResponse = {\n tools: mockTools,\n nextCursor: undefined,\n };\n\n mockClientInstance.listTools.mockResolvedValue(mockResponse);\n\n const result = await client.listTools();\n\n expect(mockClientInstance.listTools).toHaveBeenCalledTimes(1);\n expect(result).toEqual([\n {\n name: \"tool1\",\n description: \"Only tool\",\n inputSchema: {\n type: \"object\",\n properties: { arg1: { type: \"string\" } },\n },\n },\n ]);\n });\n\n it(\"should throw error for invalid input schema\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n const mockTools = [\n {\n name: \"invalid-tool\",\n description: \"Tool with invalid schema\",\n inputSchema: { type: \"string\" }, // Invalid - should be object\n },\n ];\n\n const mockResponse = {\n tools: mockTools,\n nextCursor: undefined,\n };\n\n mockClientInstance.listTools.mockResolvedValue(mockResponse);\n\n await expect(client.listTools()).rejects.toThrow(\n \"Input schema for tool invalid-tool is not an object\",\n );\n });\n });\n\n describe(\"callTool\", () => {\n it(\"should call a tool with arguments\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n const mockResult = { success: true, data: \"test result\" };\n mockClientInstance.callTool.mockResolvedValue(mockResult);\n\n const result = await client.callTool(\"testTool\", {\n arg1: \"value1\",\n arg2: 42,\n });\n\n expect(mockClientInstance.callTool).toHaveBeenCalledWith({\n name: \"testTool\",\n arguments: { arg1: \"value1\", arg2: 42 },\n });\n expect(result).toBe(mockResult);\n });\n\n it(\"should handle tool call errors\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n const error = new Error(\"Tool call failed\");\n mockClientInstance.callTool.mockRejectedValue(error);\n\n await expect(client.callTool(\"testTool\", {})).rejects.toThrow(\n \"Tool call failed\",\n );\n });\n });\n\n describe(\"transport initialization\", () => {\n it(\"should initialize HTTP transport with session ID\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const headers = { Authorization: \"Bearer token\" };\n\n await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n headers,\n undefined,\n undefined,\n );\n\n expect(MockedStreamableHTTPClientTransport).toHaveBeenCalledWith(\n new URL(endpoint),\n { sessionId: undefined, requestInit: { headers } },\n );\n });\n\n it(\"should initialize SSE transport without session ID\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const headers = { Authorization: \"Bearer token\" };\n\n await MCPClient.create(\n endpoint,\n MCPTransport.SSE,\n headers,\n undefined,\n undefined,\n );\n\n expect(MockedSSEClientTransport).toHaveBeenCalledWith(new URL(endpoint), {\n requestInit: { headers },\n });\n });\n });\n\n describe(\"client initialization\", () => {\n it(\"should initialize client with correct name and version\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n\n await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n expect(MockedClient).toHaveBeenCalledWith(\n {\n name: \"tambo-mcp-client\",\n version: \"1.0.0\",\n },\n { capabilities: {} },\n );\n });\n\n it(\"should set onclose handler\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const _client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n expect(mockClientInstance.onclose).toBeDefined();\n expect(typeof mockClientInstance.onclose).toBe(\"function\");\n });\n });\n\n describe(\"handlers (elicitation/sampling)\", () => {\n it(\"sets handlers on create when provided\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const elicitation = jest.fn(async () => ({}) as any);\n const sampling = jest.fn(async () => ({}) as any);\n\n await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n { elicitation, sampling },\n );\n\n expect(MockedClient).toHaveBeenLastCalledWith(\n {\n name: \"tambo-mcp-client\",\n version: \"1.0.0\",\n },\n {\n capabilities: {\n elicitation: {},\n sampling: {},\n },\n },\n );\n\n // Request handlers should be set for both\n expect(mockClientInstance.setRequestHandler).toHaveBeenCalled();\n expect(\n (mockClientInstance.setRequestHandler as jest.Mock).mock.calls.length,\n ).toBeGreaterThanOrEqual(2);\n });\n\n it(\"removes elicitation handler when set to undefined\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n {\n elicitation: async () => ({}) as any,\n },\n );\n\n const removeSpy = mockClientInstance.removeRequestHandler as jest.Mock;\n\n // then remove\n removeSpy.mockClear();\n await client.updateElicitationHandler(undefined);\n expect(removeSpy).toHaveBeenCalledWith(expect.any(String));\n });\n\n it(\"removes sampling handler when set to undefined\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n {\n sampling: async () => ({}) as any,\n },\n );\n\n const removeSpy = mockClientInstance.removeRequestHandler as jest.Mock;\n\n // then remove\n removeSpy.mockClear();\n await client.updateSamplingHandler(undefined);\n expect(removeSpy).toHaveBeenCalledWith(expect.any(String));\n });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"mcp-client.test.js","sourceRoot":"","sources":["../../../src/mcp/__tests__/mcp-client.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { MCPClient, MCPTransport } from \"../mcp-client\";\n\n// Mock the MCP SDK modules\njest.mock(\"@modelcontextprotocol/sdk/client/index.js\", () => ({\n Client: jest.fn().mockImplementation(() => ({\n connect: jest.fn(),\n close: jest.fn(),\n listTools: jest.fn(),\n callTool: jest.fn(),\n setRequestHandler: jest.fn(),\n removeRequestHandler: jest.fn(),\n })),\n}));\n\njest.mock(\"@modelcontextprotocol/sdk/client/sse.js\", () => ({\n SSEClientTransport: jest.fn().mockImplementation(() => ({\n // SSE transport doesn't have sessionId\n })),\n}));\n\njest.mock(\"@modelcontextprotocol/sdk/client/streamableHttp.js\", () => ({\n StreamableHTTPClientTransport: jest\n .fn()\n .mockImplementation((url, options) => ({\n sessionId: options?.sessionId,\n })),\n}));\n\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { SSEClientTransport } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\n\n// Type the mocked modules\nconst MockedClient = Client as jest.MockedClass<typeof Client>;\nconst MockedSSEClientTransport = SSEClientTransport as jest.MockedClass<\n typeof SSEClientTransport\n>;\nconst MockedStreamableHTTPClientTransport =\n StreamableHTTPClientTransport as jest.MockedClass<\n typeof StreamableHTTPClientTransport\n >;\n\ndescribe(\"MCPClient\", () => {\n let mockClientInstance: any;\n let mockTransportInstance: any;\n\n beforeEach(() => {\n jest.clearAllMocks();\n\n // Create mock instances\n mockClientInstance = {\n connect: jest.fn().mockResolvedValue(undefined),\n close: jest.fn().mockResolvedValue(undefined),\n listTools: jest.fn(),\n callTool: jest.fn(),\n setRequestHandler: jest.fn(),\n removeRequestHandler: jest.fn(),\n };\n\n mockTransportInstance = {\n sessionId: \"test-session-id\",\n };\n\n // Setup mocks\n MockedClient.mockImplementation(() => mockClientInstance);\n MockedStreamableHTTPClientTransport.mockImplementation(\n () => mockTransportInstance,\n );\n MockedSSEClientTransport.mockImplementation(\n () => ({}) as SSEClientTransport,\n );\n });\n\n describe(\"create\", () => {\n it(\"should create and connect an MCPClient with HTTP transport by default\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const headers = { Authorization: \"Bearer token\" };\n\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n headers,\n undefined,\n undefined,\n );\n\n expect(MockedStreamableHTTPClientTransport).toHaveBeenCalledWith(\n new URL(endpoint),\n { sessionId: undefined, requestInit: { headers } },\n );\n expect(MockedClient).toHaveBeenCalledWith(\n {\n name: \"tambo-mcp-client\",\n version: \"1.0.0\",\n },\n { capabilities: {} },\n );\n expect(mockClientInstance.connect).toHaveBeenCalledWith(\n mockTransportInstance,\n );\n expect(client).toBeInstanceOf(MCPClient);\n });\n\n it(\"should create and connect an MCPClient with SSE transport\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.SSE,\n undefined,\n undefined,\n undefined,\n );\n\n expect(MockedSSEClientTransport).toHaveBeenCalledWith(new URL(endpoint), {\n requestInit: { headers: {} },\n });\n expect(mockClientInstance.connect).toHaveBeenCalledWith({});\n expect(client).toBeInstanceOf(MCPClient);\n });\n\n it(\"should create client with default headers when none provided\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n\n await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n expect(MockedStreamableHTTPClientTransport).toHaveBeenCalledWith(\n new URL(endpoint),\n { sessionId: undefined, requestInit: { headers: {} } },\n );\n });\n });\n\n describe(\"listTools\", () => {\n it(\"should list all tools with pagination\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n const mockTools = [\n {\n name: \"tool1\",\n description: \"First tool\",\n inputSchema: {\n type: \"object\",\n properties: { arg1: { type: \"string\" } },\n },\n },\n {\n name: \"tool2\",\n description: \"Second tool\",\n inputSchema: {\n type: \"object\",\n properties: { arg2: { type: \"number\" } },\n },\n },\n ];\n\n const mockResponse1 = {\n tools: [mockTools[0]],\n nextCursor: \"cursor1\",\n };\n\n const mockResponse2 = {\n tools: [mockTools[1]],\n nextCursor: undefined,\n };\n\n mockClientInstance.listTools\n .mockResolvedValueOnce(mockResponse1)\n .mockResolvedValueOnce(mockResponse2);\n\n const result = await client.listTools();\n\n expect(mockClientInstance.listTools).toHaveBeenCalledTimes(2);\n expect(mockClientInstance.listTools).toHaveBeenNthCalledWith(\n 1,\n { cursor: undefined },\n {},\n );\n expect(mockClientInstance.listTools).toHaveBeenNthCalledWith(\n 2,\n { cursor: \"cursor1\" },\n {},\n );\n expect(result).toEqual([\n {\n name: \"tool1\",\n description: \"First tool\",\n inputSchema: {\n type: \"object\",\n properties: { arg1: { type: \"string\" } },\n },\n },\n {\n name: \"tool2\",\n description: \"Second tool\",\n inputSchema: {\n type: \"object\",\n properties: { arg2: { type: \"number\" } },\n },\n },\n ]);\n });\n\n it(\"should handle single page of tools\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n const mockTools = [\n {\n name: \"tool1\",\n description: \"Only tool\",\n inputSchema: {\n type: \"object\",\n properties: { arg1: { type: \"string\" } },\n },\n },\n ];\n\n const mockResponse = {\n tools: mockTools,\n nextCursor: undefined,\n };\n\n mockClientInstance.listTools.mockResolvedValue(mockResponse);\n\n const result = await client.listTools();\n\n expect(mockClientInstance.listTools).toHaveBeenCalledTimes(1);\n expect(result).toEqual([\n {\n name: \"tool1\",\n description: \"Only tool\",\n inputSchema: {\n type: \"object\",\n properties: { arg1: { type: \"string\" } },\n },\n },\n ]);\n });\n\n it(\"should throw error for invalid input schema\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n const mockTools = [\n {\n name: \"invalid-tool\",\n description: \"Tool with invalid schema\",\n inputSchema: { type: \"string\" }, // Invalid - should be object\n },\n ];\n\n const mockResponse = {\n tools: mockTools,\n nextCursor: undefined,\n };\n\n mockClientInstance.listTools.mockResolvedValue(mockResponse);\n\n await expect(client.listTools()).rejects.toThrow(\n \"Input schema for tool invalid-tool is not an object\",\n );\n });\n });\n\n describe(\"callTool\", () => {\n it(\"should call a tool with arguments\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n const mockResult = { success: true, data: \"test result\" };\n mockClientInstance.callTool.mockResolvedValue(mockResult);\n\n const result = await client.callTool(\"testTool\", {\n arg1: \"value1\",\n arg2: 42,\n });\n\n expect(mockClientInstance.callTool).toHaveBeenCalledWith({\n name: \"testTool\",\n arguments: { arg1: \"value1\", arg2: 42 },\n });\n expect(result).toBe(mockResult);\n });\n\n it(\"should handle tool call errors\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n const error = new Error(\"Tool call failed\");\n mockClientInstance.callTool.mockRejectedValue(error);\n\n await expect(client.callTool(\"testTool\", {})).rejects.toThrow(\n \"Tool call failed\",\n );\n });\n });\n\n describe(\"transport initialization\", () => {\n it(\"should initialize HTTP transport with session ID\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const headers = { Authorization: \"Bearer token\" };\n\n await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n headers,\n undefined,\n undefined,\n );\n\n expect(MockedStreamableHTTPClientTransport).toHaveBeenCalledWith(\n new URL(endpoint),\n { sessionId: undefined, requestInit: { headers } },\n );\n });\n\n it(\"should initialize SSE transport without session ID\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const headers = { Authorization: \"Bearer token\" };\n\n await MCPClient.create(\n endpoint,\n MCPTransport.SSE,\n headers,\n undefined,\n undefined,\n );\n\n expect(MockedSSEClientTransport).toHaveBeenCalledWith(new URL(endpoint), {\n requestInit: { headers },\n });\n });\n });\n\n describe(\"client initialization\", () => {\n it(\"should initialize client with correct name and version\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n\n await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n );\n\n expect(MockedClient).toHaveBeenCalledWith(\n {\n name: \"tambo-mcp-client\",\n version: \"1.0.0\",\n },\n { capabilities: {} },\n );\n });\n });\n\n describe(\"handlers (elicitation/sampling)\", () => {\n it(\"sets handlers on create when provided\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const elicitation = jest.fn(async () => ({}) as any);\n const sampling = jest.fn(async () => ({}) as any);\n\n await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n { elicitation, sampling },\n );\n\n expect(MockedClient).toHaveBeenLastCalledWith(\n {\n name: \"tambo-mcp-client\",\n version: \"1.0.0\",\n },\n {\n capabilities: {\n elicitation: {},\n sampling: {},\n },\n },\n );\n\n // Request handlers should be set for both\n expect(mockClientInstance.setRequestHandler).toHaveBeenCalled();\n expect(\n (mockClientInstance.setRequestHandler as jest.Mock).mock.calls.length,\n ).toBeGreaterThanOrEqual(2);\n });\n\n it(\"removes elicitation handler when set to undefined\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n {\n elicitation: async () => ({}) as any,\n },\n );\n\n const removeSpy = mockClientInstance.removeRequestHandler as jest.Mock;\n\n // then remove\n removeSpy.mockClear();\n await client.updateElicitationHandler(undefined);\n expect(removeSpy).toHaveBeenCalledWith(expect.any(String));\n });\n\n it(\"removes sampling handler when set to undefined\", async () => {\n const endpoint = \"https://api.example.com/mcp\";\n const client = await MCPClient.create(\n endpoint,\n MCPTransport.HTTP,\n undefined,\n undefined,\n undefined,\n {\n sampling: async () => ({}) as any,\n },\n );\n\n const removeSpy = mockClientInstance.removeRequestHandler as jest.Mock;\n\n // then remove\n removeSpy.mockClear();\n await client.updateSamplingHandler(undefined);\n expect(removeSpy).toHaveBeenCalledWith(expect.any(String));\n });\n });\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-hooks.test.d.ts","sourceRoot":"","sources":["../../../src/mcp/__tests__/mcp-hooks.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import { render, waitFor } from "@testing-library/react";
|
|
2
|
+
import { QueryClient } from "@tanstack/react-query";
|
|
3
|
+
import React, { useEffect } from "react";
|
|
4
|
+
import { TamboClientContext } from "../../providers/tambo-client-provider";
|
|
5
|
+
import { TamboMcpTokenProvider } from "../../providers/tambo-mcp-token-provider";
|
|
6
|
+
import { TamboRegistryProvider } from "../../providers/tambo-registry-provider";
|
|
7
|
+
import { MCPTransport } from "../mcp-client";
|
|
8
|
+
import { TamboMcpProvider, useTamboMcpServers } from "../tambo-mcp-provider";
|
|
9
|
+
import { useTamboMcpPromptList } from "../mcp-hooks";
|
|
10
|
+
// Mock the MCP client to avoid ES module issues
|
|
11
|
+
let createImpl = jest.fn();
|
|
12
|
+
jest.mock("../mcp-client", () => ({
|
|
13
|
+
MCPClient: { create: (...args) => createImpl(...args) },
|
|
14
|
+
MCPTransport: { SSE: "sse", HTTP: "http" },
|
|
15
|
+
}));
|
|
16
|
+
describe("useTamboMcpPromptList - individual server caching", () => {
|
|
17
|
+
let queryClient;
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
createImpl = jest.fn();
|
|
20
|
+
queryClient = new QueryClient({
|
|
21
|
+
defaultOptions: {
|
|
22
|
+
queries: {
|
|
23
|
+
retry: false, // Disable retries for tests
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
queryClient.clear();
|
|
30
|
+
});
|
|
31
|
+
it("should fetch and combine prompts from multiple servers", async () => {
|
|
32
|
+
// Mock two servers with different prompts
|
|
33
|
+
const serverAPrompts = {
|
|
34
|
+
prompts: [
|
|
35
|
+
{ name: "prompt-a1", description: "Prompt A1" },
|
|
36
|
+
{ name: "prompt-a2", description: "Prompt A2" },
|
|
37
|
+
],
|
|
38
|
+
};
|
|
39
|
+
const serverBPrompts = {
|
|
40
|
+
prompts: [
|
|
41
|
+
{ name: "prompt-b1", description: "Prompt B1" },
|
|
42
|
+
{ name: "prompt-b2", description: "Prompt B2" },
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
const mockClientA = {
|
|
46
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
47
|
+
listPrompts: jest.fn().mockResolvedValue(serverAPrompts),
|
|
48
|
+
close: jest.fn(),
|
|
49
|
+
};
|
|
50
|
+
const mockClientB = {
|
|
51
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
52
|
+
listPrompts: jest.fn().mockResolvedValue(serverBPrompts),
|
|
53
|
+
close: jest.fn(),
|
|
54
|
+
};
|
|
55
|
+
const clientA = {
|
|
56
|
+
client: mockClientA,
|
|
57
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
58
|
+
close: jest.fn(),
|
|
59
|
+
};
|
|
60
|
+
const clientB = {
|
|
61
|
+
client: mockClientB,
|
|
62
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
63
|
+
close: jest.fn(),
|
|
64
|
+
};
|
|
65
|
+
// Mock MCPClient.create to return different clients for different URLs
|
|
66
|
+
createImpl.mockImplementation(async (url) => {
|
|
67
|
+
if (url === "https://server-a.example")
|
|
68
|
+
return clientA;
|
|
69
|
+
if (url === "https://server-b.example")
|
|
70
|
+
return clientB;
|
|
71
|
+
throw new Error(`Unexpected URL: ${url}`);
|
|
72
|
+
});
|
|
73
|
+
let capturedPrompts = [];
|
|
74
|
+
const Capture = () => {
|
|
75
|
+
const { data: prompts } = useTamboMcpPromptList();
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
if (prompts) {
|
|
78
|
+
capturedPrompts = prompts;
|
|
79
|
+
}
|
|
80
|
+
}, [prompts]);
|
|
81
|
+
return null;
|
|
82
|
+
};
|
|
83
|
+
render(React.createElement(TamboClientContext.Provider, { value: {
|
|
84
|
+
client: { baseURL: "https://api.tambo.co" },
|
|
85
|
+
queryClient,
|
|
86
|
+
isUpdatingToken: false,
|
|
87
|
+
} },
|
|
88
|
+
React.createElement(TamboRegistryProvider, null,
|
|
89
|
+
React.createElement(TamboMcpTokenProvider, null,
|
|
90
|
+
React.createElement(TamboMcpProvider, { mcpServers: [
|
|
91
|
+
{
|
|
92
|
+
url: "https://server-a.example",
|
|
93
|
+
transport: MCPTransport.SSE,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
url: "https://server-b.example",
|
|
97
|
+
transport: MCPTransport.SSE,
|
|
98
|
+
},
|
|
99
|
+
] },
|
|
100
|
+
React.createElement(Capture, null))))));
|
|
101
|
+
// Wait for all prompts to be loaded
|
|
102
|
+
await waitFor(() => {
|
|
103
|
+
expect(capturedPrompts.length).toBe(4);
|
|
104
|
+
});
|
|
105
|
+
// Verify all prompts are present
|
|
106
|
+
const promptNames = capturedPrompts.map((p) => p.prompt.name);
|
|
107
|
+
expect(promptNames).toContain("prompt-a1");
|
|
108
|
+
expect(promptNames).toContain("prompt-a2");
|
|
109
|
+
expect(promptNames).toContain("prompt-b1");
|
|
110
|
+
expect(promptNames).toContain("prompt-b2");
|
|
111
|
+
// Verify each prompt has the correct server info
|
|
112
|
+
const promptA1 = capturedPrompts.find((p) => p.prompt.name === "prompt-a1");
|
|
113
|
+
expect(promptA1?.server.url).toBe("https://server-a.example");
|
|
114
|
+
const promptB1 = capturedPrompts.find((p) => p.prompt.name === "prompt-b1");
|
|
115
|
+
expect(promptB1?.server.url).toBe("https://server-b.example");
|
|
116
|
+
});
|
|
117
|
+
it("should remove prompts when a server is removed", async () => {
|
|
118
|
+
// Mock two servers with different prompts
|
|
119
|
+
const serverAPrompts = {
|
|
120
|
+
prompts: [
|
|
121
|
+
{ name: "prompt-a1", description: "Prompt A1" },
|
|
122
|
+
{ name: "prompt-a2", description: "Prompt A2" },
|
|
123
|
+
],
|
|
124
|
+
};
|
|
125
|
+
const serverBPrompts = {
|
|
126
|
+
prompts: [
|
|
127
|
+
{ name: "prompt-b1", description: "Prompt B1" },
|
|
128
|
+
{ name: "prompt-b2", description: "Prompt B2" },
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
const mockClientA = {
|
|
132
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
133
|
+
listPrompts: jest.fn().mockResolvedValue(serverAPrompts),
|
|
134
|
+
close: jest.fn(),
|
|
135
|
+
};
|
|
136
|
+
const mockClientB = {
|
|
137
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
138
|
+
listPrompts: jest.fn().mockResolvedValue(serverBPrompts),
|
|
139
|
+
close: jest.fn(),
|
|
140
|
+
};
|
|
141
|
+
const clientA = {
|
|
142
|
+
client: mockClientA,
|
|
143
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
144
|
+
close: jest.fn(),
|
|
145
|
+
};
|
|
146
|
+
const clientB = {
|
|
147
|
+
client: mockClientB,
|
|
148
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
149
|
+
close: jest.fn(),
|
|
150
|
+
};
|
|
151
|
+
createImpl.mockImplementation(async (url) => {
|
|
152
|
+
if (url === "https://server-a.example")
|
|
153
|
+
return clientA;
|
|
154
|
+
if (url === "https://server-b.example")
|
|
155
|
+
return clientB;
|
|
156
|
+
throw new Error(`Unexpected URL: ${url}`);
|
|
157
|
+
});
|
|
158
|
+
let capturedPrompts = [];
|
|
159
|
+
const Capture = () => {
|
|
160
|
+
const { data: prompts } = useTamboMcpPromptList();
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
if (prompts) {
|
|
163
|
+
capturedPrompts = prompts;
|
|
164
|
+
}
|
|
165
|
+
}, [prompts]);
|
|
166
|
+
return null;
|
|
167
|
+
};
|
|
168
|
+
const { rerender } = render(React.createElement(TamboClientContext.Provider, { value: {
|
|
169
|
+
client: { baseURL: "https://api.tambo.co" },
|
|
170
|
+
queryClient,
|
|
171
|
+
isUpdatingToken: false,
|
|
172
|
+
} },
|
|
173
|
+
React.createElement(TamboRegistryProvider, null,
|
|
174
|
+
React.createElement(TamboMcpTokenProvider, null,
|
|
175
|
+
React.createElement(TamboMcpProvider, { mcpServers: [
|
|
176
|
+
{
|
|
177
|
+
url: "https://server-a.example",
|
|
178
|
+
transport: MCPTransport.SSE,
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
url: "https://server-b.example",
|
|
182
|
+
transport: MCPTransport.SSE,
|
|
183
|
+
},
|
|
184
|
+
] },
|
|
185
|
+
React.createElement(Capture, null))))));
|
|
186
|
+
// Wait for initial prompts to be loaded
|
|
187
|
+
await waitFor(() => {
|
|
188
|
+
expect(capturedPrompts.length).toBe(4);
|
|
189
|
+
});
|
|
190
|
+
const initialPromptNames = capturedPrompts.map((p) => p.prompt.name);
|
|
191
|
+
expect(initialPromptNames).toContain("prompt-a1");
|
|
192
|
+
expect(initialPromptNames).toContain("prompt-a2");
|
|
193
|
+
expect(initialPromptNames).toContain("prompt-b1");
|
|
194
|
+
expect(initialPromptNames).toContain("prompt-b2");
|
|
195
|
+
// Remove server B
|
|
196
|
+
rerender(React.createElement(TamboClientContext.Provider, { value: {
|
|
197
|
+
client: { baseURL: "https://api.tambo.co" },
|
|
198
|
+
queryClient,
|
|
199
|
+
isUpdatingToken: false,
|
|
200
|
+
} },
|
|
201
|
+
React.createElement(TamboRegistryProvider, null,
|
|
202
|
+
React.createElement(TamboMcpTokenProvider, null,
|
|
203
|
+
React.createElement(TamboMcpProvider, { mcpServers: [
|
|
204
|
+
{
|
|
205
|
+
url: "https://server-a.example",
|
|
206
|
+
transport: MCPTransport.SSE,
|
|
207
|
+
},
|
|
208
|
+
] },
|
|
209
|
+
React.createElement(Capture, null))))));
|
|
210
|
+
// Wait for prompts to be updated (server B prompts should disappear)
|
|
211
|
+
await waitFor(() => {
|
|
212
|
+
expect(capturedPrompts.length).toBe(2);
|
|
213
|
+
});
|
|
214
|
+
const updatedPromptNames = capturedPrompts.map((p) => p.prompt.name);
|
|
215
|
+
expect(updatedPromptNames).toContain("prompt-a1");
|
|
216
|
+
expect(updatedPromptNames).toContain("prompt-a2");
|
|
217
|
+
expect(updatedPromptNames).not.toContain("prompt-b1");
|
|
218
|
+
expect(updatedPromptNames).not.toContain("prompt-b2");
|
|
219
|
+
// Verify server B's client was closed
|
|
220
|
+
expect(clientB.close).toHaveBeenCalled();
|
|
221
|
+
});
|
|
222
|
+
it("should cache prompts individually per server using server key", async () => {
|
|
223
|
+
const serverAPrompts = {
|
|
224
|
+
prompts: [{ name: "prompt-a", description: "Prompt A" }],
|
|
225
|
+
};
|
|
226
|
+
const serverBPrompts = {
|
|
227
|
+
prompts: [{ name: "prompt-b", description: "Prompt B" }],
|
|
228
|
+
};
|
|
229
|
+
const mockClientA = {
|
|
230
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
231
|
+
listPrompts: jest.fn().mockResolvedValue(serverAPrompts),
|
|
232
|
+
close: jest.fn(),
|
|
233
|
+
};
|
|
234
|
+
const mockClientB = {
|
|
235
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
236
|
+
listPrompts: jest.fn().mockResolvedValue(serverBPrompts),
|
|
237
|
+
close: jest.fn(),
|
|
238
|
+
};
|
|
239
|
+
const clientA = {
|
|
240
|
+
client: mockClientA,
|
|
241
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
242
|
+
close: jest.fn(),
|
|
243
|
+
};
|
|
244
|
+
const clientB = {
|
|
245
|
+
client: mockClientB,
|
|
246
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
247
|
+
close: jest.fn(),
|
|
248
|
+
};
|
|
249
|
+
createImpl.mockImplementation(async (url) => {
|
|
250
|
+
if (url === "https://server-a.example")
|
|
251
|
+
return clientA;
|
|
252
|
+
if (url === "https://server-b.example")
|
|
253
|
+
return clientB;
|
|
254
|
+
throw new Error(`Unexpected URL: ${url}`);
|
|
255
|
+
});
|
|
256
|
+
let capturedPrompts = [];
|
|
257
|
+
let capturedServerKeys = [];
|
|
258
|
+
const Capture = () => {
|
|
259
|
+
const { data: prompts } = useTamboMcpPromptList();
|
|
260
|
+
const servers = useTamboMcpServers();
|
|
261
|
+
useEffect(() => {
|
|
262
|
+
if (prompts) {
|
|
263
|
+
capturedPrompts = prompts;
|
|
264
|
+
}
|
|
265
|
+
capturedServerKeys = servers.map((s) => s.key);
|
|
266
|
+
}, [prompts, servers]);
|
|
267
|
+
return null;
|
|
268
|
+
};
|
|
269
|
+
render(React.createElement(TamboClientContext.Provider, { value: {
|
|
270
|
+
client: { baseURL: "https://api.tambo.co" },
|
|
271
|
+
queryClient,
|
|
272
|
+
isUpdatingToken: false,
|
|
273
|
+
} },
|
|
274
|
+
React.createElement(TamboRegistryProvider, null,
|
|
275
|
+
React.createElement(TamboMcpTokenProvider, null,
|
|
276
|
+
React.createElement(TamboMcpProvider, { mcpServers: [
|
|
277
|
+
{
|
|
278
|
+
url: "https://server-a.example",
|
|
279
|
+
transport: MCPTransport.SSE,
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
url: "https://server-b.example",
|
|
283
|
+
transport: MCPTransport.SSE,
|
|
284
|
+
},
|
|
285
|
+
] },
|
|
286
|
+
React.createElement(Capture, null))))));
|
|
287
|
+
// Wait for prompts to be loaded
|
|
288
|
+
await waitFor(() => {
|
|
289
|
+
expect(capturedPrompts.length).toBe(2);
|
|
290
|
+
});
|
|
291
|
+
// Verify that listPrompts was called once per server
|
|
292
|
+
expect(mockClientA.listPrompts).toHaveBeenCalledTimes(1);
|
|
293
|
+
expect(mockClientB.listPrompts).toHaveBeenCalledTimes(1);
|
|
294
|
+
// Verify the query cache has separate entries for each server
|
|
295
|
+
const cacheKeys = queryClient
|
|
296
|
+
.getQueryCache()
|
|
297
|
+
.getAll()
|
|
298
|
+
.map((query) => query.queryKey);
|
|
299
|
+
// Should have separate cache entries for each server's prompts
|
|
300
|
+
const promptCacheKeys = cacheKeys.filter((key) => Array.isArray(key) && key[0] === "mcp-prompts");
|
|
301
|
+
expect(promptCacheKeys.length).toBe(2);
|
|
302
|
+
// Ensure provider keys are populated before asserting
|
|
303
|
+
await waitFor(() => expect(capturedServerKeys.length).toBe(2));
|
|
304
|
+
// Verify each connected server key is present exactly once in the cache keys
|
|
305
|
+
const promptKeySet = new Set(promptCacheKeys.map((k) => String(k[1])));
|
|
306
|
+
// The server keys are captured from the provider to avoid relying on string substrings
|
|
307
|
+
capturedServerKeys.forEach((key) => {
|
|
308
|
+
expect(promptKeySet.has(key)).toBe(true);
|
|
309
|
+
});
|
|
310
|
+
// And no duplicates
|
|
311
|
+
expect(promptKeySet.size).toBe(capturedServerKeys.length);
|
|
312
|
+
});
|
|
313
|
+
it("should handle server errors gracefully without affecting other servers", async () => {
|
|
314
|
+
const serverAPrompts = {
|
|
315
|
+
prompts: [{ name: "prompt-a", description: "Prompt A" }],
|
|
316
|
+
};
|
|
317
|
+
const mockClientA = {
|
|
318
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
319
|
+
listPrompts: jest.fn().mockResolvedValue(serverAPrompts),
|
|
320
|
+
close: jest.fn(),
|
|
321
|
+
};
|
|
322
|
+
const clientA = {
|
|
323
|
+
client: mockClientA,
|
|
324
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
325
|
+
close: jest.fn(),
|
|
326
|
+
};
|
|
327
|
+
// Server B will fail to connect
|
|
328
|
+
createImpl.mockImplementation(async (url) => {
|
|
329
|
+
if (url === "https://server-a.example")
|
|
330
|
+
return clientA;
|
|
331
|
+
if (url === "https://server-b.example") {
|
|
332
|
+
throw new Error("Connection failed");
|
|
333
|
+
}
|
|
334
|
+
throw new Error(`Unexpected URL: ${url}`);
|
|
335
|
+
});
|
|
336
|
+
let capturedPrompts = [];
|
|
337
|
+
let mcpServersCount = 0;
|
|
338
|
+
const Capture = () => {
|
|
339
|
+
const { data: prompts } = useTamboMcpPromptList();
|
|
340
|
+
const servers = useTamboMcpServers();
|
|
341
|
+
useEffect(() => {
|
|
342
|
+
if (prompts) {
|
|
343
|
+
capturedPrompts = prompts;
|
|
344
|
+
}
|
|
345
|
+
mcpServersCount = servers.length;
|
|
346
|
+
}, [prompts, servers]);
|
|
347
|
+
return null;
|
|
348
|
+
};
|
|
349
|
+
render(React.createElement(TamboClientContext.Provider, { value: {
|
|
350
|
+
client: { baseURL: "https://api.tambo.co" },
|
|
351
|
+
queryClient,
|
|
352
|
+
isUpdatingToken: false,
|
|
353
|
+
} },
|
|
354
|
+
React.createElement(TamboRegistryProvider, null,
|
|
355
|
+
React.createElement(TamboMcpTokenProvider, null,
|
|
356
|
+
React.createElement(TamboMcpProvider, { mcpServers: [
|
|
357
|
+
{
|
|
358
|
+
url: "https://server-a.example",
|
|
359
|
+
transport: MCPTransport.SSE,
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
url: "https://server-b.example",
|
|
363
|
+
transport: MCPTransport.SSE,
|
|
364
|
+
},
|
|
365
|
+
] },
|
|
366
|
+
React.createElement(Capture, null))))));
|
|
367
|
+
// Wait for server A prompts to be loaded
|
|
368
|
+
// Server B should fail but not block server A
|
|
369
|
+
await waitFor(() => {
|
|
370
|
+
expect(capturedPrompts.length).toBe(1);
|
|
371
|
+
expect(mcpServersCount).toBe(2); // Both servers should be in the list
|
|
372
|
+
});
|
|
373
|
+
// Verify only server A's prompts are present
|
|
374
|
+
const promptNames = capturedPrompts.map((p) => p.prompt.name);
|
|
375
|
+
expect(promptNames).toContain("prompt-a");
|
|
376
|
+
expect(promptNames).not.toContain("prompt-b");
|
|
377
|
+
});
|
|
378
|
+
it("should add prompts when a new server is added", async () => {
|
|
379
|
+
const serverAPrompts = {
|
|
380
|
+
prompts: [{ name: "prompt-a", description: "Prompt A" }],
|
|
381
|
+
};
|
|
382
|
+
const serverBPrompts = {
|
|
383
|
+
prompts: [{ name: "prompt-b", description: "Prompt B" }],
|
|
384
|
+
};
|
|
385
|
+
const mockClientA = {
|
|
386
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
387
|
+
listPrompts: jest.fn().mockResolvedValue(serverAPrompts),
|
|
388
|
+
close: jest.fn(),
|
|
389
|
+
};
|
|
390
|
+
const mockClientB = {
|
|
391
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
392
|
+
listPrompts: jest.fn().mockResolvedValue(serverBPrompts),
|
|
393
|
+
close: jest.fn(),
|
|
394
|
+
};
|
|
395
|
+
const clientA = {
|
|
396
|
+
client: mockClientA,
|
|
397
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
398
|
+
close: jest.fn(),
|
|
399
|
+
};
|
|
400
|
+
const clientB = {
|
|
401
|
+
client: mockClientB,
|
|
402
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
403
|
+
close: jest.fn(),
|
|
404
|
+
};
|
|
405
|
+
createImpl.mockImplementation(async (url) => {
|
|
406
|
+
if (url === "https://server-a.example")
|
|
407
|
+
return clientA;
|
|
408
|
+
if (url === "https://server-b.example")
|
|
409
|
+
return clientB;
|
|
410
|
+
throw new Error(`Unexpected URL: ${url}`);
|
|
411
|
+
});
|
|
412
|
+
let capturedPrompts = [];
|
|
413
|
+
const Capture = () => {
|
|
414
|
+
const { data: prompts } = useTamboMcpPromptList();
|
|
415
|
+
useEffect(() => {
|
|
416
|
+
if (prompts) {
|
|
417
|
+
capturedPrompts = prompts;
|
|
418
|
+
}
|
|
419
|
+
}, [prompts]);
|
|
420
|
+
return null;
|
|
421
|
+
};
|
|
422
|
+
const { rerender } = render(React.createElement(TamboClientContext.Provider, { value: {
|
|
423
|
+
client: { baseURL: "https://api.tambo.co" },
|
|
424
|
+
queryClient,
|
|
425
|
+
isUpdatingToken: false,
|
|
426
|
+
} },
|
|
427
|
+
React.createElement(TamboRegistryProvider, null,
|
|
428
|
+
React.createElement(TamboMcpTokenProvider, null,
|
|
429
|
+
React.createElement(TamboMcpProvider, { mcpServers: [
|
|
430
|
+
{
|
|
431
|
+
url: "https://server-a.example",
|
|
432
|
+
transport: MCPTransport.SSE,
|
|
433
|
+
},
|
|
434
|
+
] },
|
|
435
|
+
React.createElement(Capture, null))))));
|
|
436
|
+
// Wait for initial prompts from server A
|
|
437
|
+
await waitFor(() => {
|
|
438
|
+
expect(capturedPrompts.length).toBe(1);
|
|
439
|
+
});
|
|
440
|
+
expect(capturedPrompts.map((p) => p.prompt.name)).toContain("prompt-a");
|
|
441
|
+
// Add server B
|
|
442
|
+
rerender(React.createElement(TamboClientContext.Provider, { value: {
|
|
443
|
+
client: { baseURL: "https://api.tambo.co" },
|
|
444
|
+
queryClient,
|
|
445
|
+
isUpdatingToken: false,
|
|
446
|
+
} },
|
|
447
|
+
React.createElement(TamboRegistryProvider, null,
|
|
448
|
+
React.createElement(TamboMcpTokenProvider, null,
|
|
449
|
+
React.createElement(TamboMcpProvider, { mcpServers: [
|
|
450
|
+
{
|
|
451
|
+
url: "https://server-a.example",
|
|
452
|
+
transport: MCPTransport.SSE,
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
url: "https://server-b.example",
|
|
456
|
+
transport: MCPTransport.SSE,
|
|
457
|
+
},
|
|
458
|
+
] },
|
|
459
|
+
React.createElement(Capture, null))))));
|
|
460
|
+
// Wait for server B prompts to be added
|
|
461
|
+
await waitFor(() => {
|
|
462
|
+
expect(capturedPrompts.length).toBe(2);
|
|
463
|
+
});
|
|
464
|
+
const promptNames = capturedPrompts.map((p) => p.prompt.name);
|
|
465
|
+
expect(promptNames).toContain("prompt-a");
|
|
466
|
+
expect(promptNames).toContain("prompt-b");
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
//# sourceMappingURL=mcp-hooks.test.js.map
|