From bd7eeb7bc89032b9a0db467cb53f37bfef71647e Mon Sep 17 00:00:00 2001 From: Benjamin Schroth <68321970+schrothbn@users.noreply.github.com> Date: Tue, 5 May 2026 17:35:13 +0200 Subject: [PATCH] fix(core): Skip disabled tool nodes when mapping AI Agent tool sources (#29460) --- .../@n8n/nodes-langchain/utils/helpers.ts | 14 +++++--- .../utils/tests/helpers.test.ts | 32 +++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/packages/@n8n/nodes-langchain/utils/helpers.ts b/packages/@n8n/nodes-langchain/utils/helpers.ts index 224e2504ba2..2d37c536ce5 100644 --- a/packages/@n8n/nodes-langchain/utils/helpers.ts +++ b/packages/@n8n/nodes-langchain/utils/helpers.ts @@ -200,13 +200,17 @@ export const getConnectedTools = async ( 0, )) as SupplyDataToolResponse[]; - // Get parent nodes to map toolkits to their source nodes + // Get parent nodes to map toolkits to their source nodes. + // getInputConnectionData filters out disabled nodes, so parents must be filtered + // the same way to keep the index alignment between toolkitConnections and parentNodes. const parentNodes = 'getParentNodes' in ctx - ? ctx.getParentNodes(ctx.getNode().name, { - connectionType: NodeConnectionTypes.AiTool, - depth: 1, - }) + ? ctx + .getParentNodes(ctx.getNode().name, { + connectionType: NodeConnectionTypes.AiTool, + depth: 1, + }) + .filter((node) => !node.disabled) : []; const connectedTools = (toolkitConnections ?? []) diff --git a/packages/@n8n/nodes-langchain/utils/tests/helpers.test.ts b/packages/@n8n/nodes-langchain/utils/tests/helpers.test.ts index 0a039d77815..b73f17439a3 100644 --- a/packages/@n8n/nodes-langchain/utils/tests/helpers.test.ts +++ b/packages/@n8n/nodes-langchain/utils/tests/helpers.test.ts @@ -341,6 +341,38 @@ describe('getConnectedTools', () => { sourceNodeName: 'MCP Client Tool', }); }); + + it('should map source node names correctly when a disabled tool node is still connected', async () => { + // getParentNodes returns ALL parents including disabled ones, + // while getInputConnectionData filters disabled nodes out. + // getConnectedTools must skip disabled parents to keep the index in sync. + const mockParentNodes = [ + { name: 'Tool Alpha', disabled: false }, + { name: 'Tool Bravo', disabled: true }, + { name: 'Tool Charlie', disabled: false }, + ]; + const mockTools = [ + { name: 'alpha', description: 'desc-alpha' }, + { name: 'charlie', description: 'desc-charlie' }, + ]; + + mockExecuteFunctions.getInputConnectionData = jest.fn().mockResolvedValue(mockTools); + mockExecuteFunctions.getParentNodes = jest.fn().mockReturnValue(mockParentNodes); + + const tools = await getConnectedTools(mockExecuteFunctions, false); + + expect(tools).toHaveLength(2); + expect(tools[0].name).toBe('alpha'); + expect(tools[0].metadata).toEqual({ + isFromToolkit: false, + sourceNodeName: 'Tool Alpha', + }); + expect(tools[1].name).toBe('charlie'); + expect(tools[1].metadata).toEqual({ + isFromToolkit: false, + sourceNodeName: 'Tool Charlie', + }); + }); }); describe('unwrapNestedOutput', () => {