From 6a72cd064bccb5fda4618671c2da63c4e22c1ef9 Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Tue, 5 Aug 2025 15:50:30 -0700 Subject: [PATCH] check for the prompt capability before listing prompts from MCP servers (#5616) Co-authored-by: Jacob Richman Co-authored-by: Sandy Tao --- packages/core/src/tools/mcp-client.test.ts | 51 ++++++++++++++++++---- packages/core/src/tools/mcp-client.ts | 3 ++ 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/packages/core/src/tools/mcp-client.test.ts b/packages/core/src/tools/mcp-client.test.ts index a8289d3b..9997d60e 100644 --- a/packages/core/src/tools/mcp-client.test.ts +++ b/packages/core/src/tools/mcp-client.test.ts @@ -58,9 +58,7 @@ describe('mcp-client', () => { const mockedClient = {} as unknown as ClientLib.Client; const consoleErrorSpy = vi .spyOn(console, 'error') - .mockImplementation(() => { - // no-op - }); + .mockImplementation(() => {}); const testError = new Error('Invalid tool name'); vi.mocked(DiscoveredMCPTool).mockImplementation( @@ -113,12 +111,17 @@ describe('mcp-client', () => { { name: 'prompt2' }, ], }); + const mockGetServerCapabilities = vi.fn().mockReturnValue({ + prompts: {}, + }); const mockedClient = { + getServerCapabilities: mockGetServerCapabilities, request: mockRequest, } as unknown as ClientLib.Client; await discoverPrompts('test-server', mockedClient, mockedPromptRegistry); + expect(mockGetServerCapabilities).toHaveBeenCalledOnce(); expect(mockRequest).toHaveBeenCalledWith( { method: 'prompts/list', params: {} }, expect.anything(), @@ -129,37 +132,67 @@ describe('mcp-client', () => { const mockRequest = vi.fn().mockResolvedValue({ prompts: [], }); + const mockGetServerCapabilities = vi.fn().mockReturnValue({ + prompts: {}, + }); + const mockedClient = { + getServerCapabilities: mockGetServerCapabilities, request: mockRequest, } as unknown as ClientLib.Client; const consoleLogSpy = vi .spyOn(console, 'debug') - .mockImplementation(() => { - // no-op - }); + .mockImplementation(() => {}); await discoverPrompts('test-server', mockedClient, mockedPromptRegistry); + expect(mockGetServerCapabilities).toHaveBeenCalledOnce(); expect(mockRequest).toHaveBeenCalledOnce(); expect(consoleLogSpy).not.toHaveBeenCalled(); consoleLogSpy.mockRestore(); }); + it('should do nothing if the server has no prompt support', async () => { + const mockRequest = vi.fn().mockResolvedValue({ + prompts: [], + }); + const mockGetServerCapabilities = vi.fn().mockReturnValue({}); + + const mockedClient = { + getServerCapabilities: mockGetServerCapabilities, + request: mockRequest, + } as unknown as ClientLib.Client; + + const consoleLogSpy = vi + .spyOn(console, 'debug') + .mockImplementation(() => {}); + + await discoverPrompts('test-server', mockedClient, mockedPromptRegistry); + + expect(mockGetServerCapabilities).toHaveBeenCalledOnce(); + expect(mockRequest).not.toHaveBeenCalled(); + expect(consoleLogSpy).not.toHaveBeenCalled(); + + consoleLogSpy.mockRestore(); + }); + it('should log an error if discovery fails', async () => { const testError = new Error('test error'); testError.message = 'test error'; const mockRequest = vi.fn().mockRejectedValue(testError); + const mockGetServerCapabilities = vi.fn().mockReturnValue({ + prompts: {}, + }); const mockedClient = { + getServerCapabilities: mockGetServerCapabilities, request: mockRequest, } as unknown as ClientLib.Client; const consoleErrorSpy = vi .spyOn(console, 'error') - .mockImplementation(() => { - // no-op - }); + .mockImplementation(() => {}); await discoverPrompts('test-server', mockedClient, mockedPromptRegistry); diff --git a/packages/core/src/tools/mcp-client.ts b/packages/core/src/tools/mcp-client.ts index 00f2197a..26244d9e 100644 --- a/packages/core/src/tools/mcp-client.ts +++ b/packages/core/src/tools/mcp-client.ts @@ -496,6 +496,9 @@ export async function discoverPrompts( promptRegistry: PromptRegistry, ): Promise { try { + // Only request prompts if the server supports them. + if (mcpClient.getServerCapabilities()?.prompts == null) return []; + const response = await mcpClient.request( { method: 'prompts/list', params: {} }, ListPromptsResultSchema,