diff --git a/src/client/index.ts b/src/client/index.ts index 03a6b40b5..f3c6bf97d 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -757,7 +757,7 @@ export class Client< } // Only validate structured content if present (not when there's an error) - if (result.structuredContent) { + if (result.structuredContent && !result.isError) { try { // Validate the structured content against the schema const validationResult = validator(result.structuredContent); diff --git a/src/experimental/tasks/client.ts b/src/experimental/tasks/client.ts index f62941dc8..5c70b3b51 100644 --- a/src/experimental/tasks/client.ts +++ b/src/experimental/tasks/client.ts @@ -122,7 +122,7 @@ export class ExperimentalClientTasks< } // Only validate structured content if present (not when there's an error) - if (result.structuredContent) { + if (result.structuredContent && !result.isError) { try { // Validate the structured content against the schema const validationResult = validator(result.structuredContent); diff --git a/test/client/index.test.ts b/test/client/index.test.ts index f5c6a348d..31e5d2f41 100644 --- a/test/client/index.test.ts +++ b/test/client/index.test.ts @@ -1871,6 +1871,102 @@ describe('outputSchema validation', () => { expect(result.structuredContent).toEqual({ result: 'success', count: 42 }); }); + /*** + * Test: Do Not Validate structuredContent when isError is true + */ + test('should not validate structuredContent when tool returns isError', async () => { + const server = new Server( + { + name: 'test-server', + version: '1.0.0' + }, + { + capabilities: { + tools: {} + } + } + ); + + // Set up server handlers + server.setRequestHandler(InitializeRequestSchema, async request => ({ + protocolVersion: request.params.protocolVersion, + capabilities: { tools: {} }, + serverInfo: { + name: 'test-server', + version: '1.0.0' + } + })); + + server.setRequestHandler(ListToolsRequestSchema, async () => ({ + tools: [ + { + name: 'test-tool', + description: 'A test tool', + inputSchema: { + type: 'object', + properties: {} + }, + outputSchema: { + type: 'object', + properties: { + result: { type: 'string' } + }, + required: ['result'] + } + } + ] + })); + + server.setRequestHandler(CallToolRequestSchema, async request => { + if (request.params.name === 'test-tool') { + return { + content: [{ type: 'text', text: 'Tool failed' }], + structuredContent: {}, + isError: true + }; + } + throw new Error('Unknown tool'); + }); + + const client = new Client( + { + name: 'test-client', + version: '1.0.0' + }, + { + capabilities: { + tasks: { + requests: { + tools: { + call: {} + }, + tasks: { + get: true, + list: {}, + result: true + } + } + } + } + } + ); + + const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); + + await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]); + + // List tools to cache the schemas + await client.listTools(); + + const result = await client.callTool({ name: 'test-tool' }); + expect(result.isError).toBe(true); + expect(result.structuredContent).toEqual({}); + expect(result.content).toEqual([{ type: 'text', text: 'Tool failed' }]); + + await client.close(); + await server.close(); + }); + /*** * Test: Throw Error when structuredContent Does Not Match Schema */