mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 10:31:15 +00:00
fix: Do not throw on tool errors, instead return error message (#17558)
This commit is contained in:
@@ -2,6 +2,7 @@ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
||||
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import {
|
||||
NodeConnectionTypes,
|
||||
NodeOperationError,
|
||||
type ILoadOptionsFunctions,
|
||||
type INode,
|
||||
@@ -284,5 +285,78 @@ describe('McpClientTool', () => {
|
||||
headers: { Accept: 'text/event-stream', Authorization: 'Bearer my-token' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should successfully execute a tool', async () => {
|
||||
jest.spyOn(Client.prototype, 'connect').mockResolvedValue();
|
||||
jest.spyOn(Client.prototype, 'callTool').mockResolvedValue({ content: 'Sunny' });
|
||||
jest.spyOn(Client.prototype, 'listTools').mockResolvedValue({
|
||||
tools: [
|
||||
{
|
||||
name: 'Weather Tool',
|
||||
description: 'Gets the current weather',
|
||||
inputSchema: { type: 'object', properties: { location: { type: 'string' } } },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const supplyDataResult = await new McpClientTool().supplyData.call(
|
||||
mock<ISupplyDataFunctions>({
|
||||
getNode: jest.fn(() =>
|
||||
mock<INode>({
|
||||
typeVersion: 1,
|
||||
}),
|
||||
),
|
||||
logger: { debug: jest.fn(), error: jest.fn() },
|
||||
addInputData: jest.fn(() => ({ index: 0 })),
|
||||
}),
|
||||
0,
|
||||
);
|
||||
|
||||
expect(supplyDataResult.closeFunction).toBeInstanceOf(Function);
|
||||
expect(supplyDataResult.response).toBeInstanceOf(McpToolkit);
|
||||
|
||||
const tools = (supplyDataResult.response as McpToolkit).getTools();
|
||||
const toolResult = await tools[0].invoke({ location: 'Berlin' });
|
||||
expect(toolResult).toEqual('Sunny');
|
||||
});
|
||||
|
||||
it('should handle tool errors', async () => {
|
||||
jest.spyOn(Client.prototype, 'connect').mockResolvedValue();
|
||||
jest
|
||||
.spyOn(Client.prototype, 'callTool')
|
||||
.mockResolvedValue({ isError: true, content: [{ text: 'Weather unknown at location' }] });
|
||||
jest.spyOn(Client.prototype, 'listTools').mockResolvedValue({
|
||||
tools: [
|
||||
{
|
||||
name: 'Weather Tool',
|
||||
description: 'Gets the current weather',
|
||||
inputSchema: { type: 'object', properties: { location: { type: 'string' } } },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const supplyDataFunctions = mock<ISupplyDataFunctions>({
|
||||
getNode: jest.fn(() =>
|
||||
mock<INode>({
|
||||
typeVersion: 1,
|
||||
}),
|
||||
),
|
||||
logger: { debug: jest.fn(), error: jest.fn() },
|
||||
addInputData: jest.fn(() => ({ index: 0 })),
|
||||
});
|
||||
const supplyDataResult = await new McpClientTool().supplyData.call(supplyDataFunctions, 0);
|
||||
|
||||
expect(supplyDataResult.closeFunction).toBeInstanceOf(Function);
|
||||
expect(supplyDataResult.response).toBeInstanceOf(McpToolkit);
|
||||
|
||||
const tools = (supplyDataResult.response as McpToolkit).getTools();
|
||||
const toolResult = await tools[0].invoke({ location: 'Berlin' });
|
||||
expect(toolResult).toEqual('Weather unknown at location');
|
||||
expect(supplyDataFunctions.addOutputData).toHaveBeenCalledWith(
|
||||
NodeConnectionTypes.AiTool,
|
||||
0,
|
||||
new NodeOperationError(supplyDataFunctions.getNode(), 'Weather unknown at location'),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user