n8n-nodes-browser-smart-automation 0.1.11 → 0.1.14
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/McpClientEX/McpClient.node.js +3 -3
- package/dist/McpClientEX/McpClient.node.js.map +1 -1
- package/dist/McpClientToolEX/McpClientTool.node.js +76 -20
- package/dist/McpClientToolEX/McpClientTool.node.js.map +1 -1
- package/dist/McpClientToolEX/loadOptions.js +0 -1
- package/dist/McpClientToolEX/loadOptions.js.map +1 -1
- package/dist/McpTriggerEX/McpTrigger.node.js +2 -2
- package/dist/McpTriggerEX/McpTrigger.node.js.map +1 -1
- package/dist/nodes/assets/mcp.dark.svg +7 -0
- package/dist/nodes/assets/mcp.svg +7 -0
- package/dist/shared/utils.js +20 -5
- package/dist/shared/utils.js.map +1 -1
- package/package.json +1 -1
|
@@ -40,8 +40,8 @@ var import_descriptions = require("../shared/descriptions");
|
|
|
40
40
|
var import_utils = require("../shared/utils");
|
|
41
41
|
class McpClient {
|
|
42
42
|
description = {
|
|
43
|
-
displayName: "
|
|
44
|
-
description: "Standalone
|
|
43
|
+
displayName: "Browser Smart Automation (MCP)",
|
|
44
|
+
description: "Standalone Browser Smart Automation (MCP)",
|
|
45
45
|
name: "mcpClient",
|
|
46
46
|
icon: {
|
|
47
47
|
light: "file:nodes/assets/mcp.svg",
|
|
@@ -50,7 +50,7 @@ class McpClient {
|
|
|
50
50
|
group: ["transform"],
|
|
51
51
|
version: 1,
|
|
52
52
|
defaults: {
|
|
53
|
-
name: "
|
|
53
|
+
name: "Browser Smart Automation (MCP)"
|
|
54
54
|
},
|
|
55
55
|
credentials: import_descriptions.credentials,
|
|
56
56
|
inputs: [import_n8n_workflow.NodeConnectionTypes.Main],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../nodes/McpClientEX/McpClient.node.ts"],"sourcesContent":["import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport type {\n\tIBinaryKeyData,\n\tIDataObject,\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeType,\n\tINodeTypeDescription,\n\tNodeExecutionWithMetadata,\n} from 'n8n-workflow';\nimport { jsonParse, NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';\nimport { ZodError } from 'zod';\nimport { prettifyError } from 'zod/v4/core';\nimport * as listSearch from './listSearch';\nimport * as resourceMapping from './resourceMapping';\nimport { credentials, transportSelect } from '../shared/descriptions';\nimport type { McpAuthenticationOption, McpServerTransport } from '../shared/types';\nimport {\n\tgetAuthHeaders,\n\ttryRefreshOAuth2Token,\n\tconnectMcpClient,\n\tmapToNodeOperationError,\n} from '../shared/utils';\n\nexport class McpClient implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'MCP Browser Client',\n\t\tdescription: 'Standalone MCP Browser Client',\n\t\tname: 'mcpClient',\n\t\ticon: {\n\t\t\tlight: 'file:nodes/assets/mcp.svg',\n\t\t\tdark: 'file:nodes/assets/mcp.dark.svg',\n\t\t},\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tdefaults: {\n\t\t\tname: 'MCP Browser Client',\n\t\t},\n\t\tcredentials,\n\t\tinputs: [NodeConnectionTypes.Main],\n\t\toutputs: [NodeConnectionTypes.Main],\n\t\tproperties: [\n\t\t\ttransportSelect({\n\t\t\t\tdefaultOption: 'httpStreamable',\n\t\t\t}),\n\t\t\t{\n\t\t\t\tdisplayName: 'MCP Endpoint URL',\n\t\t\t\tname: 'endpointUrl',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'e.g. https://my-mcp-server.ai/mcp',\n\t\t\t\trequired: true,\n\t\t\t\tdescription: 'The URL of the MCP server to connect to',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Authentication',\n\t\t\t\tname: 'authentication',\n\t\t\t\ttype: 'options',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Bearer Auth',\n\t\t\t\t\t\tvalue: 'bearerAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Header Auth',\n\t\t\t\t\t\tvalue: 'headerAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'MCP OAuth2',\n\t\t\t\t\t\tvalue: 'mcpOAuth2Api',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Multiple Headers Auth',\n\t\t\t\t\t\tvalue: 'multipleHeadersAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'None',\n\t\t\t\t\t\tvalue: 'none',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdefault: 'none',\n\t\t\t\tdescription: 'The way to authenticate with your endpoint',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Credentials',\n\t\t\t\tname: 'credentials',\n\t\t\t\ttype: 'credentials',\n\t\t\t\tdefault: '',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tauthentication: ['headerAuth', 'bearerAuth', 'mcpOAuth2Api', 'multipleHeadersAuth'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Tool',\n\t\t\t\tname: 'tool',\n\t\t\t\ttype: 'resourceLocator',\n\t\t\t\tdefault: { mode: 'list', value: '' },\n\t\t\t\trequired: true,\n\t\t\t\tdescription: 'The tool to use',\n\t\t\t\tmodes: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'From List',\n\t\t\t\t\t\tname: 'list',\n\t\t\t\t\t\ttype: 'list',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\tsearchListMethod: 'getTools',\n\t\t\t\t\t\t\tsearchable: true,\n\t\t\t\t\t\t\tskipCredentialsCheckInRLC: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'ID',\n\t\t\t\t\t\tname: 'id',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Input Mode',\n\t\t\t\tname: 'inputMode',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'manual',\n\t\t\t\tnoDataExpression: true,\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Manual',\n\t\t\t\t\t\tvalue: 'manual',\n\t\t\t\t\t\tdescription: 'Manually specify the input data for each tool parameter',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'JSON',\n\t\t\t\t\t\tvalue: 'json',\n\t\t\t\t\t\tdescription: 'Specify the input data as a JSON object',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Parameters',\n\t\t\t\tname: 'parameters',\n\t\t\t\ttype: 'resourceMapper',\n\t\t\t\tdefault: {\n\t\t\t\t\tmappingMode: 'defineBelow',\n\t\t\t\t\tvalue: null,\n\t\t\t\t},\n\t\t\t\tnoDataExpression: true,\n\t\t\t\trequired: true,\n\t\t\t\ttypeOptions: {\n\t\t\t\t\tloadOptionsDependsOn: ['tool.value'],\n\t\t\t\t\tresourceMapper: {\n\t\t\t\t\t\tresourceMapperMethod: 'getToolParameters',\n\t\t\t\t\t\thideNoDataError: true,\n\t\t\t\t\t\taddAllFields: false,\n\t\t\t\t\t\tsupportAutoMap: false,\n\t\t\t\t\t\tmode: 'add',\n\t\t\t\t\t\tfieldWords: {\n\t\t\t\t\t\t\tsingular: 'parameter',\n\t\t\t\t\t\t\tplural: 'parameters',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tinputMode: ['manual'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'JSON',\n\t\t\t\tname: 'jsonInput',\n\t\t\t\ttype: 'json',\n\t\t\t\ttypeOptions: {\n\t\t\t\t\trows: 5,\n\t\t\t\t},\n\t\t\t\tdefault: '{\\n \"my_field_1\": \"value\",\\n \"my_field_2\": 1\\n}\\n',\n\t\t\t\tvalidateType: 'object',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tinputMode: ['json'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Options',\n\t\t\t\tname: 'options',\n\t\t\t\tplaceholder: 'Add Option',\n\t\t\t\tdescription: 'Additional options to add',\n\t\t\t\ttype: 'collection',\n\t\t\t\tdefault: {},\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Convert to Binary',\n\t\t\t\t\t\tname: 'convertToBinary',\n\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\tdefault: true,\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t'Whether to convert images and audio to binary data. If false, images and audio will be returned as base64 encoded strings.',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Timeout',\n\t\t\t\t\t\tname: 'timeout',\n\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\tminValue: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdefault: 60000,\n\t\t\t\t\t\tdescription: 'Time in ms to wait for tool calls to finish',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\tmethods = {\n\t\tlistSearch,\n\t\tresourceMapping,\n\t};\n\n\tasync execute(\n\t\tthis: IExecuteFunctions,\n\t): Promise<INodeExecutionData[][] | NodeExecutionWithMetadata[][] | null> {\n\t\tconst authentication = this.getNodeParameter('authentication', 0) as McpAuthenticationOption;\n\t\tconst serverTransport = this.getNodeParameter('serverTransport', 0) as McpServerTransport;\n\t\tconst endpointUrl = this.getNodeParameter('endpointUrl', 0) as string;\n\t\tconst node = this.getNode();\n\t\tconst { headers } = await getAuthHeaders(this, authentication);\n\t\tconst client = await connectMcpClient({\n\t\t\tserverTransport,\n\t\t\tendpointUrl,\n\t\t\theaders,\n\t\t\tname: node.type,\n\t\t\tversion: node.typeVersion,\n\t\t\tonUnauthorized: async (headers) => await tryRefreshOAuth2Token(this, authentication, headers),\n\t\t});\n\t\tif (!client.ok) {\n\t\t\tthrow mapToNodeOperationError(node, client.error);\n\t\t}\n\n\t\tconst inputMode = this.getNodeParameter('inputMode', 0, 'manual') as 'manual' | 'json';\n\t\tconst items = this.getInputData();\n\t\tconst returnData: INodeExecutionData[] = [];\n\t\tfor (let itemIndex = 0; itemIndex < items.length; itemIndex++) {\n\t\t\ttry {\n\t\t\t\tconst tool = this.getNodeParameter('tool.value', itemIndex) as string;\n\t\t\t\tconst options = this.getNodeParameter('options', itemIndex);\n\t\t\t\tlet parameters: IDataObject = {};\n\t\t\t\tif (inputMode === 'manual') {\n\t\t\t\t\tparameters = this.getNodeParameter('parameters.value', itemIndex) as IDataObject;\n\t\t\t\t} else {\n\t\t\t\t\tparameters = this.getNodeParameter('jsonInput', itemIndex) as IDataObject;\n\t\t\t\t}\n\n\t\t\t\tconst result = (await client.result.callTool(\n\t\t\t\t\t{\n\t\t\t\t\t\tname: tool,\n\t\t\t\t\t\targuments: parameters,\n\t\t\t\t\t},\n\t\t\t\t\tundefined,\n\t\t\t\t\t{\n\t\t\t\t\t\ttimeout: options.timeout ? Number(options.timeout) : undefined,\n\t\t\t\t\t},\n\t\t\t\t)) as CallToolResult;\n\n\t\t\t\tlet binaryIndex = 0;\n\t\t\t\tconst binary: IBinaryKeyData = {};\n\t\t\t\tconst content: IDataObject[] = [];\n\t\t\t\tconst convertToBinary = options.convertToBinary ?? true;\n\t\t\t\tfor (const contentItem of result.content) {\n\t\t\t\t\tif (contentItem.type === 'text') {\n\t\t\t\t\t\tcontent.push({\n\t\t\t\t\t\t\t...contentItem,\n\t\t\t\t\t\t\ttext: jsonParse(contentItem.text, { fallbackValue: contentItem.text }),\n\t\t\t\t\t\t});\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (convertToBinary && (contentItem.type === 'image' || contentItem.type === 'audio')) {\n\t\t\t\t\t\tbinary[`data_${binaryIndex}`] = await this.helpers.prepareBinaryData(\n\t\t\t\t\t\t\tBuffer.from(contentItem.data, 'base64'),\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tcontentItem.mimeType,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbinaryIndex++;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tcontent.push(contentItem as IDataObject);\n\t\t\t\t}\n\n\t\t\t\treturnData.push({\n\t\t\t\t\tjson: {\n\t\t\t\t\t\tcontent: content.length > 0 ? content : undefined,\n\t\t\t\t\t},\n\t\t\t\t\tbinary: Object.keys(binary).length > 0 ? binary : undefined,\n\t\t\t\t\tpairedItem: {\n\t\t\t\t\t\titem: itemIndex,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} catch (e) {\n\t\t\t\tconst errorMessage =\n\t\t\t\t\te instanceof ZodError ? prettifyError(e) : e instanceof Error ? e.message : String(e);\n\t\t\t\tif (this.continueOnFail()) {\n\t\t\t\t\treturnData.push({\n\t\t\t\t\t\tjson: {\n\t\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\t\tmessage: errorMessage,\n\t\t\t\t\t\t\t\tissues: e instanceof ZodError ? e.issues : undefined,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tpairedItem: {\n\t\t\t\t\t\t\titem: itemIndex,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tthrow new NodeOperationError(node, errorMessage, {\n\t\t\t\t\titemIndex,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn [returnData];\n\t}\n}\n"],"mappings":"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","names":["headers"]}
|
|
1
|
+
{"version":3,"sources":["../../nodes/McpClientEX/McpClient.node.ts"],"sourcesContent":["import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport type {\n\tIBinaryKeyData,\n\tIDataObject,\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeType,\n\tINodeTypeDescription,\n\tNodeExecutionWithMetadata,\n} from 'n8n-workflow';\nimport { jsonParse, NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';\nimport { ZodError } from 'zod';\nimport { prettifyError } from 'zod/v4/core';\nimport * as listSearch from './listSearch';\nimport * as resourceMapping from './resourceMapping';\nimport { credentials, transportSelect } from '../shared/descriptions';\nimport type { McpAuthenticationOption, McpServerTransport } from '../shared/types';\nimport {\n\tgetAuthHeaders,\n\ttryRefreshOAuth2Token,\n\tconnectMcpClient,\n\tmapToNodeOperationError,\n} from '../shared/utils';\n\nexport class McpClient implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Browser Smart Automation (MCP)',\n\t\tdescription: 'Standalone Browser Smart Automation (MCP)',\n\t\tname: 'mcpClient',\n\t\ticon: {\n\t\t\tlight: 'file:nodes/assets/mcp.svg',\n\t\t\tdark: 'file:nodes/assets/mcp.dark.svg',\n\t\t},\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tdefaults: {\n\t\t\tname: 'Browser Smart Automation (MCP)',\n\t\t},\n\t\tcredentials,\n\t\tinputs: [NodeConnectionTypes.Main],\n\t\toutputs: [NodeConnectionTypes.Main],\n\t\tproperties: [\n\t\t\ttransportSelect({\n\t\t\t\tdefaultOption: 'httpStreamable',\n\t\t\t}),\n\t\t\t{\n\t\t\t\tdisplayName: 'MCP Endpoint URL',\n\t\t\t\tname: 'endpointUrl',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'e.g. https://my-mcp-server.ai/mcp',\n\t\t\t\trequired: true,\n\t\t\t\tdescription: 'The URL of the MCP server to connect to',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Authentication',\n\t\t\t\tname: 'authentication',\n\t\t\t\ttype: 'options',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Bearer Auth',\n\t\t\t\t\t\tvalue: 'bearerAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Header Auth',\n\t\t\t\t\t\tvalue: 'headerAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'MCP OAuth2',\n\t\t\t\t\t\tvalue: 'mcpOAuth2Api',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Multiple Headers Auth',\n\t\t\t\t\t\tvalue: 'multipleHeadersAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'None',\n\t\t\t\t\t\tvalue: 'none',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdefault: 'none',\n\t\t\t\tdescription: 'The way to authenticate with your endpoint',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Credentials',\n\t\t\t\tname: 'credentials',\n\t\t\t\ttype: 'credentials',\n\t\t\t\tdefault: '',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tauthentication: ['headerAuth', 'bearerAuth', 'mcpOAuth2Api', 'multipleHeadersAuth'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Tool',\n\t\t\t\tname: 'tool',\n\t\t\t\ttype: 'resourceLocator',\n\t\t\t\tdefault: { mode: 'list', value: '' },\n\t\t\t\trequired: true,\n\t\t\t\tdescription: 'The tool to use',\n\t\t\t\tmodes: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'From List',\n\t\t\t\t\t\tname: 'list',\n\t\t\t\t\t\ttype: 'list',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\tsearchListMethod: 'getTools',\n\t\t\t\t\t\t\tsearchable: true,\n\t\t\t\t\t\t\tskipCredentialsCheckInRLC: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'ID',\n\t\t\t\t\t\tname: 'id',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Input Mode',\n\t\t\t\tname: 'inputMode',\n\t\t\t\ttype: 'options',\n\t\t\t\tdefault: 'manual',\n\t\t\t\tnoDataExpression: true,\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Manual',\n\t\t\t\t\t\tvalue: 'manual',\n\t\t\t\t\t\tdescription: 'Manually specify the input data for each tool parameter',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'JSON',\n\t\t\t\t\t\tvalue: 'json',\n\t\t\t\t\t\tdescription: 'Specify the input data as a JSON object',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Parameters',\n\t\t\t\tname: 'parameters',\n\t\t\t\ttype: 'resourceMapper',\n\t\t\t\tdefault: {\n\t\t\t\t\tmappingMode: 'defineBelow',\n\t\t\t\t\tvalue: null,\n\t\t\t\t},\n\t\t\t\tnoDataExpression: true,\n\t\t\t\trequired: true,\n\t\t\t\ttypeOptions: {\n\t\t\t\t\tloadOptionsDependsOn: ['tool.value'],\n\t\t\t\t\tresourceMapper: {\n\t\t\t\t\t\tresourceMapperMethod: 'getToolParameters',\n\t\t\t\t\t\thideNoDataError: true,\n\t\t\t\t\t\taddAllFields: false,\n\t\t\t\t\t\tsupportAutoMap: false,\n\t\t\t\t\t\tmode: 'add',\n\t\t\t\t\t\tfieldWords: {\n\t\t\t\t\t\t\tsingular: 'parameter',\n\t\t\t\t\t\t\tplural: 'parameters',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tinputMode: ['manual'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'JSON',\n\t\t\t\tname: 'jsonInput',\n\t\t\t\ttype: 'json',\n\t\t\t\ttypeOptions: {\n\t\t\t\t\trows: 5,\n\t\t\t\t},\n\t\t\t\tdefault: '{\\n \"my_field_1\": \"value\",\\n \"my_field_2\": 1\\n}\\n',\n\t\t\t\tvalidateType: 'object',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tinputMode: ['json'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Options',\n\t\t\t\tname: 'options',\n\t\t\t\tplaceholder: 'Add Option',\n\t\t\t\tdescription: 'Additional options to add',\n\t\t\t\ttype: 'collection',\n\t\t\t\tdefault: {},\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Convert to Binary',\n\t\t\t\t\t\tname: 'convertToBinary',\n\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\tdefault: true,\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t'Whether to convert images and audio to binary data. If false, images and audio will be returned as base64 encoded strings.',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Timeout',\n\t\t\t\t\t\tname: 'timeout',\n\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\tminValue: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdefault: 60000,\n\t\t\t\t\t\tdescription: 'Time in ms to wait for tool calls to finish',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\tmethods = {\n\t\tlistSearch,\n\t\tresourceMapping,\n\t};\n\n\tasync execute(\n\t\tthis: IExecuteFunctions,\n\t): Promise<INodeExecutionData[][] | NodeExecutionWithMetadata[][] | null> {\n\t\tconst authentication = this.getNodeParameter('authentication', 0) as McpAuthenticationOption;\n\t\tconst serverTransport = this.getNodeParameter('serverTransport', 0) as McpServerTransport;\n\t\tconst endpointUrl = this.getNodeParameter('endpointUrl', 0) as string;\n\t\tconst node = this.getNode();\n\t\tconst { headers } = await getAuthHeaders(this, authentication);\n\t\tconst client = await connectMcpClient({\n\t\t\tserverTransport,\n\t\t\tendpointUrl,\n\t\t\theaders,\n\t\t\tname: node.type,\n\t\t\tversion: node.typeVersion,\n\t\t\tonUnauthorized: async (headers) => await tryRefreshOAuth2Token(this, authentication, headers),\n\t\t});\n\t\tif (!client.ok) {\n\t\t\tthrow mapToNodeOperationError(node, client.error);\n\t\t}\n\n\t\tconst inputMode = this.getNodeParameter('inputMode', 0, 'manual') as 'manual' | 'json';\n\t\tconst items = this.getInputData();\n\t\tconst returnData: INodeExecutionData[] = [];\n\t\tfor (let itemIndex = 0; itemIndex < items.length; itemIndex++) {\n\t\t\ttry {\n\t\t\t\tconst tool = this.getNodeParameter('tool.value', itemIndex) as string;\n\t\t\t\tconst options = this.getNodeParameter('options', itemIndex);\n\t\t\t\tlet parameters: IDataObject = {};\n\t\t\t\tif (inputMode === 'manual') {\n\t\t\t\t\tparameters = this.getNodeParameter('parameters.value', itemIndex) as IDataObject;\n\t\t\t\t} else {\n\t\t\t\t\tparameters = this.getNodeParameter('jsonInput', itemIndex) as IDataObject;\n\t\t\t\t}\n\n\t\t\t\tconst result = (await client.result.callTool(\n\t\t\t\t\t{\n\t\t\t\t\t\tname: tool,\n\t\t\t\t\t\targuments: parameters,\n\t\t\t\t\t},\n\t\t\t\t\tundefined,\n\t\t\t\t\t{\n\t\t\t\t\t\ttimeout: options.timeout ? Number(options.timeout) : undefined,\n\t\t\t\t\t},\n\t\t\t\t)) as CallToolResult;\n\n\t\t\t\tlet binaryIndex = 0;\n\t\t\t\tconst binary: IBinaryKeyData = {};\n\t\t\t\tconst content: IDataObject[] = [];\n\t\t\t\tconst convertToBinary = options.convertToBinary ?? true;\n\t\t\t\tfor (const contentItem of result.content) {\n\t\t\t\t\tif (contentItem.type === 'text') {\n\t\t\t\t\t\tcontent.push({\n\t\t\t\t\t\t\t...contentItem,\n\t\t\t\t\t\t\ttext: jsonParse(contentItem.text, { fallbackValue: contentItem.text }),\n\t\t\t\t\t\t});\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (convertToBinary && (contentItem.type === 'image' || contentItem.type === 'audio')) {\n\t\t\t\t\t\tbinary[`data_${binaryIndex}`] = await this.helpers.prepareBinaryData(\n\t\t\t\t\t\t\tBuffer.from(contentItem.data, 'base64'),\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tcontentItem.mimeType,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbinaryIndex++;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tcontent.push(contentItem as IDataObject);\n\t\t\t\t}\n\n\t\t\t\treturnData.push({\n\t\t\t\t\tjson: {\n\t\t\t\t\t\tcontent: content.length > 0 ? content : undefined,\n\t\t\t\t\t},\n\t\t\t\t\tbinary: Object.keys(binary).length > 0 ? binary : undefined,\n\t\t\t\t\tpairedItem: {\n\t\t\t\t\t\titem: itemIndex,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} catch (e) {\n\t\t\t\tconst errorMessage =\n\t\t\t\t\te instanceof ZodError ? prettifyError(e) : e instanceof Error ? e.message : String(e);\n\t\t\t\tif (this.continueOnFail()) {\n\t\t\t\t\treturnData.push({\n\t\t\t\t\t\tjson: {\n\t\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\t\tmessage: errorMessage,\n\t\t\t\t\t\t\t\tissues: e instanceof ZodError ? e.issues : undefined,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tpairedItem: {\n\t\t\t\t\t\t\titem: itemIndex,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tthrow new NodeOperationError(node, errorMessage, {\n\t\t\t\t\titemIndex,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn [returnData];\n\t}\n}\n"],"mappings":"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","names":["headers"]}
|
|
@@ -29,6 +29,15 @@ var import_loadOptions = require("./loadOptions");
|
|
|
29
29
|
var import_utils = require("./utils");
|
|
30
30
|
var import_descriptions = require("../shared/descriptions");
|
|
31
31
|
var import_utils2 = require("../shared/utils");
|
|
32
|
+
const mcpClientCache = /* @__PURE__ */ new Map();
|
|
33
|
+
function getCacheKey(serverTransport, endpointUrl, nodeType) {
|
|
34
|
+
return `${nodeType}|${serverTransport}|${endpointUrl}`;
|
|
35
|
+
}
|
|
36
|
+
const cdpConnectedCache = /* @__PURE__ */ new Set();
|
|
37
|
+
function getCdpKey(cacheKey, cdpEndpointUrl) {
|
|
38
|
+
const ep = typeof cdpEndpointUrl === "string" ? cdpEndpointUrl.trim() : "";
|
|
39
|
+
return ep ? `${cacheKey}|cdp:${ep}` : null;
|
|
40
|
+
}
|
|
32
41
|
function getNodeConfig(ctx, itemIndex) {
|
|
33
42
|
const node = ctx.getNode();
|
|
34
43
|
const authentication = ctx.getNodeParameter(
|
|
@@ -36,6 +45,7 @@ function getNodeConfig(ctx, itemIndex) {
|
|
|
36
45
|
itemIndex
|
|
37
46
|
);
|
|
38
47
|
const timeout = ctx.getNodeParameter("options.timeout", itemIndex, 6e4);
|
|
48
|
+
const connectTimeout = ctx.getNodeParameter("options.connectTimeout", itemIndex, 15e3);
|
|
39
49
|
let serverTransport;
|
|
40
50
|
let endpointUrl;
|
|
41
51
|
if (node.typeVersion === 1) {
|
|
@@ -52,6 +62,7 @@ function getNodeConfig(ctx, itemIndex) {
|
|
|
52
62
|
return {
|
|
53
63
|
authentication,
|
|
54
64
|
timeout,
|
|
65
|
+
connectTimeout,
|
|
55
66
|
serverTransport,
|
|
56
67
|
endpointUrl,
|
|
57
68
|
mode,
|
|
@@ -63,17 +74,55 @@ function getNodeConfig(ctx, itemIndex) {
|
|
|
63
74
|
async function connectAndGetTools(ctx, config) {
|
|
64
75
|
const node = ctx.getNode();
|
|
65
76
|
const { headers } = await (0, import_utils2.getAuthHeaders)(ctx, config.authentication);
|
|
77
|
+
const cacheKey = getCacheKey(config.serverTransport, config.endpointUrl, node.type);
|
|
78
|
+
const cachedClient = mcpClientCache.get(cacheKey);
|
|
79
|
+
if (cachedClient) {
|
|
80
|
+
const cdpKey2 = getCdpKey(cacheKey, config.cdp_endpointurl);
|
|
81
|
+
if (cdpKey2 && !cdpConnectedCache.has(cdpKey2)) {
|
|
82
|
+
await cachedClient.callTool(
|
|
83
|
+
{
|
|
84
|
+
name: "browser_connect_cdp",
|
|
85
|
+
arguments: { endpoint: config.cdp_endpointurl }
|
|
86
|
+
},
|
|
87
|
+
void 0,
|
|
88
|
+
{ timeout: config.timeout ? Number(config.timeout) : void 0 }
|
|
89
|
+
);
|
|
90
|
+
cdpConnectedCache.add(cdpKey2);
|
|
91
|
+
}
|
|
92
|
+
const allTools2 = await (0, import_utils2.getAllTools)(cachedClient);
|
|
93
|
+
const mcpTools2 = (0, import_utils.getSelectedTools)({
|
|
94
|
+
tools: allTools2,
|
|
95
|
+
mode: config.mode,
|
|
96
|
+
includeTools: config.includeTools,
|
|
97
|
+
excludeTools: config.excludeTools
|
|
98
|
+
});
|
|
99
|
+
return { client: cachedClient, mcpTools: mcpTools2, error: null };
|
|
100
|
+
}
|
|
66
101
|
const client = await (0, import_utils2.connectMcpClient)({
|
|
67
102
|
serverTransport: config.serverTransport,
|
|
68
103
|
endpointUrl: config.endpointUrl,
|
|
69
104
|
headers,
|
|
70
105
|
name: node.type,
|
|
71
106
|
version: node.typeVersion,
|
|
72
|
-
onUnauthorized: async (headers2) => await (0, import_utils2.tryRefreshOAuth2Token)(ctx, config.authentication, headers2)
|
|
107
|
+
onUnauthorized: async (headers2) => await (0, import_utils2.tryRefreshOAuth2Token)(ctx, config.authentication, headers2),
|
|
108
|
+
connectTimeoutMs: config.connectTimeout
|
|
73
109
|
});
|
|
74
110
|
if (!client.ok) {
|
|
75
111
|
return { client, mcpTools: null, error: client.error };
|
|
76
112
|
}
|
|
113
|
+
mcpClientCache.set(cacheKey, client.result);
|
|
114
|
+
const cdpKey = getCdpKey(cacheKey, config.cdp_endpointurl);
|
|
115
|
+
if (cdpKey && !cdpConnectedCache.has(cdpKey)) {
|
|
116
|
+
await client.result.callTool(
|
|
117
|
+
{
|
|
118
|
+
name: "browser_connect_cdp",
|
|
119
|
+
arguments: { endpoint: config.cdp_endpointurl }
|
|
120
|
+
},
|
|
121
|
+
void 0,
|
|
122
|
+
{ timeout: config.timeout ? Number(config.timeout) : void 0 }
|
|
123
|
+
);
|
|
124
|
+
cdpConnectedCache.add(cdpKey);
|
|
125
|
+
}
|
|
77
126
|
const allTools = await (0, import_utils2.getAllTools)(client.result);
|
|
78
127
|
const mcpTools = (0, import_utils.getSelectedTools)({
|
|
79
128
|
tools: allTools,
|
|
@@ -85,7 +134,7 @@ async function connectAndGetTools(ctx, config) {
|
|
|
85
134
|
}
|
|
86
135
|
class McpClientTool {
|
|
87
136
|
description = {
|
|
88
|
-
displayName: "
|
|
137
|
+
displayName: "Browser Smart Automation (MCP)",
|
|
89
138
|
name: "mcpClientTool",
|
|
90
139
|
icon: {
|
|
91
140
|
light: "file:nodes/assets/mcp.svg",
|
|
@@ -95,14 +144,14 @@ class McpClientTool {
|
|
|
95
144
|
version: [1, 1.1, 1.2],
|
|
96
145
|
description: "Connect tools from an MCP Server",
|
|
97
146
|
defaults: {
|
|
98
|
-
name: "
|
|
147
|
+
name: "Browser Smart Automation (MCP)"
|
|
99
148
|
},
|
|
100
149
|
codex: {
|
|
101
150
|
categories: ["AI"],
|
|
102
151
|
subcategories: {
|
|
103
152
|
AI: ["Model Context Protocol", "Tools"]
|
|
104
153
|
},
|
|
105
|
-
alias: ["Model Context Protocol", "
|
|
154
|
+
alias: ["Model Context Protocol", "Browser Smart Automation (MCP)"],
|
|
106
155
|
resources: {
|
|
107
156
|
primaryDocumentation: [
|
|
108
157
|
{
|
|
@@ -304,6 +353,16 @@ class McpClientTool {
|
|
|
304
353
|
},
|
|
305
354
|
description: "The WebSocket endpoint URL for CDP connection"
|
|
306
355
|
},
|
|
356
|
+
{
|
|
357
|
+
displayName: "Connect Timeout (ms)",
|
|
358
|
+
name: "connectTimeout",
|
|
359
|
+
type: "number",
|
|
360
|
+
typeOptions: {
|
|
361
|
+
minValue: 1e3
|
|
362
|
+
},
|
|
363
|
+
default: 15e3,
|
|
364
|
+
description: "Max time in ms to wait when connecting to the MCP server before aborting"
|
|
365
|
+
},
|
|
307
366
|
{
|
|
308
367
|
displayName: "Timeout",
|
|
309
368
|
name: "timeout",
|
|
@@ -359,7 +418,19 @@ class McpClientTool {
|
|
|
359
418
|
);
|
|
360
419
|
this.logger.debug(`McpClientTool: Connected to MCP Server with ${tools.length} tools`);
|
|
361
420
|
const toolkit = new import_utils.McpToolkit(tools);
|
|
362
|
-
|
|
421
|
+
const cacheKey = getCacheKey(config.serverTransport, config.endpointUrl, node.type);
|
|
422
|
+
const cdpKey = getCdpKey(cacheKey, config.cdp_endpointurl);
|
|
423
|
+
return {
|
|
424
|
+
response: toolkit,
|
|
425
|
+
closeFunction: async () => {
|
|
426
|
+
try {
|
|
427
|
+
await client.close();
|
|
428
|
+
} finally {
|
|
429
|
+
mcpClientCache.delete(cacheKey);
|
|
430
|
+
if (cdpKey) cdpConnectedCache.delete(cdpKey);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
};
|
|
363
434
|
}
|
|
364
435
|
async execute() {
|
|
365
436
|
const node = this.getNode();
|
|
@@ -375,21 +446,6 @@ class McpClientTool {
|
|
|
375
446
|
if (!mcpTools?.length) {
|
|
376
447
|
throw new import_n8n_workflow.NodeOperationError(node, "MCP Server returned no tools", { itemIndex });
|
|
377
448
|
}
|
|
378
|
-
if (config.cdp_endpointurl && typeof config.cdp_endpointurl === "string" && config.cdp_endpointurl.trim() !== "") {
|
|
379
|
-
await client.callTool(
|
|
380
|
-
{
|
|
381
|
-
name: "browser_connect_cdp",
|
|
382
|
-
arguments: {
|
|
383
|
-
// Pass common keys to maximize compatibility across server implementations
|
|
384
|
-
endpoint: config.cdp_endpointurl
|
|
385
|
-
}
|
|
386
|
-
},
|
|
387
|
-
void 0,
|
|
388
|
-
{
|
|
389
|
-
timeout: config.timeout ? Number(config.timeout) : void 0
|
|
390
|
-
}
|
|
391
|
-
);
|
|
392
|
-
}
|
|
393
449
|
for (const tool of mcpTools) {
|
|
394
450
|
if (!item.json.tool || typeof item.json.tool !== "string") {
|
|
395
451
|
throw new import_n8n_workflow.NodeOperationError(node, "Tool name not found in item.json.tool or item.tool", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../nodes/McpClientToolEX/McpClientTool.node.ts"],"sourcesContent":["import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport {\n\ttype IDataObject,\n\ttype IExecuteFunctions,\n\ttype INodeExecutionData,\n\tNodeConnectionTypes,\n\tNodeOperationError,\n\ttype INodeType,\n\ttype INodeTypeDescription,\n\ttype ISupplyDataFunctions,\n\ttype SupplyData,\n} from 'n8n-workflow';\n\nimport { logWrapper } from '../shared/logWrapper';\nimport { getConnectionHintNoticeField } from '../shared/sharedFields';\n\nimport { getTools } from './loadOptions';\nimport type { McpToolIncludeMode } from './types';\nimport { createCallTool, getSelectedTools, McpToolkit, mcpToolToDynamicTool } from './utils';\nimport { credentials, transportSelect } from '../shared/descriptions';\nimport type { McpAuthenticationOption, McpServerTransport } from '../shared/types';\nimport {\n\tconnectMcpClient,\n\tgetAllTools,\n\tgetAuthHeaders,\n\tmapToNodeOperationError,\n\ttryRefreshOAuth2Token,\n} from '../shared/utils';\n\n/**\n * Get node parameters for MCP client configuration\n */\nfunction getNodeConfig(\n\tctx: ISupplyDataFunctions | IExecuteFunctions,\n\titemIndex: number,\n): {\n\tauthentication: McpAuthenticationOption;\n\ttimeout: number;\n\tserverTransport: McpServerTransport;\n\tendpointUrl: string;\n\tcdp_endpointurl?: string;\n\tmode: McpToolIncludeMode;\n\tincludeTools: string[];\n\texcludeTools: string[];\n} {\n\tconst node = ctx.getNode();\n\tconst authentication = ctx.getNodeParameter(\n\t\t'authentication',\n\t\titemIndex,\n\t) as McpAuthenticationOption;\n\tconst timeout = ctx.getNodeParameter('options.timeout', itemIndex, 60000) as number;\n\tlet serverTransport: McpServerTransport;\n\tlet endpointUrl: string;\n\tif (node.typeVersion === 1) {\n\t\tserverTransport = 'sse';\n\t\tendpointUrl = ctx.getNodeParameter('sseEndpoint', itemIndex) as string;\n\t} else {\n\t\tserverTransport = ctx.getNodeParameter('serverTransport', itemIndex) as McpServerTransport;\n\t\tendpointUrl = ctx.getNodeParameter('endpointUrl', itemIndex) as string;\n\t}\n\tconst cdp_endpointurl = ctx.getNodeParameter('options.cdp_endpointurl', itemIndex,'wss://gridnew.doingerp.com/devtools/02451af47fd279b6a42ff166683ad96f') as string;\n\tconst mode = ctx.getNodeParameter('include', itemIndex) as McpToolIncludeMode;\n\tconst includeTools = ctx.getNodeParameter('includeTools', itemIndex, []) as string[];\n\tconst excludeTools = ctx.getNodeParameter('excludeTools', itemIndex, []) as string[];\n\n\treturn {\n\t\tauthentication,\n\t\ttimeout,\n\t\tserverTransport,\n\t\tendpointUrl,\n\t\tmode,\n\t\tcdp_endpointurl,\n\t\tincludeTools,\n\t\texcludeTools,\n\t};\n}\n\n/**\n * Connect to MCP server and get filtered tools\n */\nasync function connectAndGetTools(\n\tctx: ISupplyDataFunctions | IExecuteFunctions,\n\tconfig: ReturnType<typeof getNodeConfig>,\n) {\n\tconst node = ctx.getNode();\n\tconst { headers } = await getAuthHeaders(ctx, config.authentication);\n\n\tconst client = await connectMcpClient({\n\t\tserverTransport: config.serverTransport,\n\t\tendpointUrl: config.endpointUrl,\n\t\theaders,\n\t\tname: node.type,\n\t\tversion: node.typeVersion,\n\t\tonUnauthorized: async (headers) =>\n\t\t\tawait tryRefreshOAuth2Token(ctx, config.authentication, headers),\n\t});\n\n\tif (!client.ok) {\n\t\treturn { client, mcpTools: null, error: client.error };\n\t}\n\n\tconst allTools = await getAllTools(client.result);\n\tconst mcpTools = getSelectedTools({\n\t\ttools: allTools,\n\t\tmode: config.mode,\n\t\tincludeTools: config.includeTools,\n\t\texcludeTools: config.excludeTools,\n\t});\n\n\treturn { client: client.result, mcpTools, error: null };\n}\n\nexport class McpClientTool implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'MCP Browser Tool',\n\t\tname: 'mcpClientTool',\n\t\ticon: {\n\t\t\tlight: 'file:nodes/assets/mcp.svg',\n\t\t\tdark: 'file:nodes/assets/mcp.dark.svg',\n\t\t},\n\t\tgroup: ['output'],\n\t\tversion: [1, 1.1, 1.2],\n\t\tdescription: 'Connect tools from an MCP Server',\n\t\tdefaults: {\n\t\t\tname: 'MCP Browser Tool',\n\t\t},\n\t\tcodex: {\n\t\t\tcategories: ['AI'],\n\t\t\tsubcategories: {\n\t\t\t\tAI: ['Model Context Protocol', 'Tools'],\n\t\t\t},\n\t\t\talias: ['Model Context Protocol', 'MCP Browser Tool'],\n\t\t\tresources: {\n\t\t\t\tprimaryDocumentation: [\n\t\t\t\t\t{\n\t\t\t\t\t\turl: 'https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.toolmcp/',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t},\n\t\tinputs: [],\n\t\toutputs: [{ type: NodeConnectionTypes.AiTool, displayName: 'Tools' }],\n\t\tcredentials,\n\t\tproperties: [\n\t\t\tgetConnectionHintNoticeField([NodeConnectionTypes.AiAgent]),\n\t\t\t{\n\t\t\t\tdisplayName: 'SSE Endpoint',\n\t\t\t\tname: 'sseEndpoint',\n\t\t\t\ttype: 'string',\n\t\t\t\tdescription: 'SSE Endpoint of your MCP server',\n\t\t\t\tplaceholder: 'e.g. https://my-mcp-server.ai/sse',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'@version': [1],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Endpoint',\n\t\t\t\tname: 'endpointUrl',\n\t\t\t\ttype: 'string',\n\t\t\t\tdescription: 'Endpoint of your MCP server',\n\t\t\t\tplaceholder: 'e.g. https://my-mcp-server.ai/mcp',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'@version': [{ _cnd: { gte: 1.1 } }],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\ttransportSelect({\n\t\t\t\tdefaultOption: 'sse',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'@version': [1.1],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t\ttransportSelect({\n\t\t\t\tdefaultOption: 'httpStreamable',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'@version': [{ _cnd: { gte: 1.2 } }],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t\t{\n\t\t\t\tdisplayName: 'Authentication',\n\t\t\t\tname: 'authentication',\n\t\t\t\ttype: 'options',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Bearer Auth',\n\t\t\t\t\t\tvalue: 'bearerAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Header Auth',\n\t\t\t\t\t\tvalue: 'headerAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'None',\n\t\t\t\t\t\tvalue: 'none',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdefault: 'none',\n\t\t\t\tdescription: 'The way to authenticate with your endpoint',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'@version': [{ _cnd: { lt: 1.2 } }],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Authentication',\n\t\t\t\tname: 'authentication',\n\t\t\t\ttype: 'options',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Bearer Auth',\n\t\t\t\t\t\tvalue: 'bearerAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Header Auth',\n\t\t\t\t\t\tvalue: 'headerAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'MCP OAuth2',\n\t\t\t\t\t\tvalue: 'mcpOAuth2Api',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Multiple Headers Auth',\n\t\t\t\t\t\tvalue: 'multipleHeadersAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'None',\n\t\t\t\t\t\tvalue: 'none',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdefault: 'none',\n\t\t\t\tdescription: 'The way to authenticate with your endpoint',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'@version': [{ _cnd: { gte: 1.2 } }],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Credentials',\n\t\t\t\tname: 'credentials',\n\t\t\t\ttype: 'credentials',\n\t\t\t\tdefault: '',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tauthentication: ['headerAuth', 'bearerAuth', 'mcpOAuth2Api', 'multipleHeadersAuth'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Tools to Include',\n\t\t\t\tname: 'include',\n\t\t\t\ttype: 'options',\n\t\t\t\tdescription: 'How to select the tools you want to be exposed to the AI Agent',\n\t\t\t\tdefault: 'all',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'All',\n\t\t\t\t\t\tvalue: 'all',\n\t\t\t\t\t\tdescription: 'Also include all unchanged fields from the input',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Selected',\n\t\t\t\t\t\tvalue: 'selected',\n\t\t\t\t\t\tdescription: 'Also include the tools listed in the parameter \"Tools to Include\"',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'All Except',\n\t\t\t\t\t\tvalue: 'except',\n\t\t\t\t\t\tdescription: 'Exclude the tools listed in the parameter \"Tools to Exclude\"',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Tools to Include',\n\t\t\t\tname: 'includeTools',\n\t\t\t\ttype: 'multiOptions',\n\t\t\t\tdefault: [],\n\t\t\t\tdescription:\n\t\t\t\t\t'Choose from the list, or specify IDs using an <a href=\"https://docs.n8n.io/code/expressions/\">expression</a>',\n\t\t\t\ttypeOptions: {\n\t\t\t\t\tloadOptionsMethod: 'getTools',\n\t\t\t\t\tloadOptionsDependsOn: ['sseEndpoint'],\n\t\t\t\t},\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tinclude: ['selected'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Tools to Exclude',\n\t\t\t\tname: 'excludeTools',\n\t\t\t\ttype: 'multiOptions',\n\t\t\t\tdefault: [],\n\t\t\t\tdescription:\n\t\t\t\t\t'Choose from the list, or specify IDs using an <a href=\"https://docs.n8n.io/code/expressions/\">expression</a>',\n\t\t\t\ttypeOptions: {\n\t\t\t\t\tloadOptionsMethod: 'getTools',\n\t\t\t\t},\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tinclude: ['except'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Options',\n\t\t\t\tname: 'options',\n\t\t\t\tplaceholder: 'Add Option',\n\t\t\t\tdescription: 'Additional options to add',\n\t\t\t\ttype: 'collection',\n\t\t\t\tdefault: {},\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'cdp Endpoint URL',\n\t\t\t\t\t\tname: 'cdp_endpointurl',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdefault: '',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\tplaceholder: 'wss://gridnew.doingerp.com/devtools/02451af47fd279b6a42ff166683ad96f',\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdescription: 'The WebSocket endpoint URL for CDP connection',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Timeout',\n\t\t\t\t\t\tname: 'timeout',\n\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\tminValue: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdefault: 60000,\n\t\t\t\t\t\tdescription: 'Time in ms to wait for tool calls to finish',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\tmethods = {\n\t\tloadOptions: {\n\t\t\tgetTools,\n\t\t},\n\t};\n\n\tasync supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData> {\n\t\tconst node = this.getNode();\n\t\tconst config = getNodeConfig(this, itemIndex);\n\t\tconst setError = (error: NodeOperationError): SupplyData => {\n\t\t\tthis.addOutputData(NodeConnectionTypes.AiTool, itemIndex, error);\n\t\t\tthrow error;\n\t\t};\n\n\t\tconst { client, mcpTools, error } = await connectAndGetTools(this, config);\n\n\t\tif (error) {\n\t\t\tthis.logger.error('McpClientTool: Failed to connect to MCP Server', { error });\n\t\t\treturn setError(mapToNodeOperationError(node, error));\n\t\t}\n\n\t\tthis.logger.debug('McpClientTool: Successfully connected to MCP Server');\n\n\t\tif (!mcpTools?.length) {\n\t\t\treturn setError(\n\t\t\t\tnew NodeOperationError(node, 'MCP Server returned no tools', {\n\t\t\t\t\titemIndex,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t'Connected successfully to your MCP server but it returned an empty list of tools.',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tconst tools = mcpTools.map((tool) =>\n\t\t\tlogWrapper(\n\t\t\t\tmcpToolToDynamicTool(\n\t\t\t\t\ttool,\n\t\t\t\t\tcreateCallTool(tool.name, client, config.timeout, (errorMessage) => {\n\t\t\t\t\t\tconst error = new NodeOperationError(node, errorMessage, { itemIndex });\n\t\t\t\t\t\tvoid this.addOutputData(NodeConnectionTypes.AiTool, itemIndex, error);\n\t\t\t\t\t\tthis.logger.error(`McpClientTool: Tool \"${tool.name}\" failed to execute`, { error });\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t\tthis,\n\t\t\t),\n\t\t);\n\n\t\tthis.logger.debug(`McpClientTool: Connected to MCP Server with ${tools.length} tools`);\n\n\t\tconst toolkit = new McpToolkit(tools);\n\n\t\treturn { response: toolkit, closeFunction: async () => await client.close() };\n\t}\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst node = this.getNode();\n\t\tconst items = this.getInputData();\n\t\tconst returnData: INodeExecutionData[] = [];\n\n\t\tfor (let itemIndex = 0; itemIndex < items.length; itemIndex++) {\n\t\t\tconst item = items[itemIndex];\n\t\t\tconst config = getNodeConfig(this, itemIndex);\n\n\t\t\tconst { client, mcpTools, error } = await connectAndGetTools(this, config);\n\n\t\t\tif (error) {\n\t\t\t\tthrow new NodeOperationError(node, error.error, { itemIndex });\n\t\t\t}\n\n\t\t\tif (!mcpTools?.length) {\n\t\t\t\tthrow new NodeOperationError(node, 'MCP Server returned no tools', { itemIndex });\n\t\t\t}\n\t\t\t// Attempt to establish CDP connection first if an endpoint is provided\n\t\t\tif (config.cdp_endpointurl && typeof config.cdp_endpointurl === 'string' && config.cdp_endpointurl.trim() !== '') {\n\t\t\t\tawait client.callTool(\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'browser_connect_cdp',\n\t\t\t\t\t\targuments: {\n\t\t\t\t\t\t\t// Pass common keys to maximize compatibility across server implementations\n\t\t\t\t\t\t\tendpoint: config.cdp_endpointurl,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tundefined,\n\t\t\t\t\t{\n\t\t\t\t\t\ttimeout: config.timeout ? Number(config.timeout) : undefined,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\tfor (const tool of mcpTools) {\n\t\t\t\t// Check for tool name in item.json.tool (for toolkit execution from agent)\n\t\t\t\t// or item.tool (for direct execution)\n\t\t\t\tif (!item.json.tool || typeof item.json.tool !== 'string') {\n\t\t\t\t\tthrow new NodeOperationError(node, 'Tool name not found in item.json.tool or item.tool', {\n\t\t\t\t\t\titemIndex,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst toolName = item.json.tool;\n\t\t\t\tif (toolName === tool.name) {\n\t\t\t\t\t// Extract the tool name from arguments before passing to MCP\n\t\t\t\t\tconst { tool: _, ...toolArguments } = item.json;\n\t\t\t\t\tconst params: {\n\t\t\t\t\t\tname: string;\n\t\t\t\t\t\targuments: IDataObject;\n\t\t\t\t\t} = {\n\t\t\t\t\t\tname: tool.name,\n\t\t\t\t\t\targuments: toolArguments,\n\t\t\t\t\t};\n\t\t\t\t\tconst result = await client.callTool(params, CallToolResultSchema, {\n\t\t\t\t\t\ttimeout: config.timeout,\n\t\t\t\t\t});\n\t\t\t\t\treturnData.push({\n\t\t\t\t\t\tjson: {\n\t\t\t\t\t\t\tresponse: (result.content || result) as IDataObject,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tpairedItem: {\n\t\t\t\t\t\t\titem: itemIndex,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn [returnData];\n\t}\n}"],"mappings":"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","names":["import_utils","headers","error"]}
|
|
1
|
+
{"version":3,"sources":["../../nodes/McpClientToolEX/McpClientTool.node.ts"],"sourcesContent":["import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport {\n\ttype IDataObject,\n\ttype IExecuteFunctions,\n\ttype INodeExecutionData,\n\tNodeConnectionTypes,\n\tNodeOperationError,\n\ttype INodeType,\n\ttype INodeTypeDescription,\n\ttype ISupplyDataFunctions,\n\ttype SupplyData,\n} from 'n8n-workflow';\n\nimport { logWrapper } from '../shared/logWrapper';\nimport { getConnectionHintNoticeField } from '../shared/sharedFields';\n\nimport { getTools } from './loadOptions';\nimport type { McpToolIncludeMode } from './types';\nimport { createCallTool, getSelectedTools, McpToolkit, mcpToolToDynamicTool } from './utils';\nimport { credentials, transportSelect } from '../shared/descriptions';\nimport type { McpAuthenticationOption, McpServerTransport } from '../shared/types';\nimport {\n\tconnectMcpClient,\n\tgetAllTools,\n\tgetAuthHeaders,\n\tmapToNodeOperationError,\n\ttryRefreshOAuth2Token,\n} from '../shared/utils';\n\n// Simple in-memory cache to avoid creating a new MCP session per call\nconst mcpClientCache: Map<string, Client> = new Map();\nfunction getCacheKey(serverTransport: McpServerTransport, endpointUrl: string, nodeType: string) {\n return `${nodeType}|${serverTransport}|${endpointUrl}`;\n}\n// Track CDP connections per cached client+cdp endpoint so we call once\nconst cdpConnectedCache: Set<string> = new Set();\nfunction getCdpKey(cacheKey: string, cdpEndpointUrl?: string) {\n\tconst ep = typeof cdpEndpointUrl === 'string' ? cdpEndpointUrl.trim() : '';\n\treturn ep ? `${cacheKey}|cdp:${ep}` : null;\n}\n\n/**\n * Get node parameters for MCP client configuration\n */\nfunction getNodeConfig(\n\tctx: ISupplyDataFunctions | IExecuteFunctions,\n\titemIndex: number,\n): {\n\tauthentication: McpAuthenticationOption;\n\ttimeout: number;\n\t\tconnectTimeout?: number;\n\tserverTransport: McpServerTransport;\n\tendpointUrl: string;\n\tcdp_endpointurl?: string;\n\tmode: McpToolIncludeMode;\n\tincludeTools: string[];\n\texcludeTools: string[];\n} {\n\tconst node = ctx.getNode();\n\tconst authentication = ctx.getNodeParameter(\n\t\t'authentication',\n\t\titemIndex,\n\t) as McpAuthenticationOption;\n\tconst timeout = ctx.getNodeParameter('options.timeout', itemIndex, 60000) as number;\n\tconst connectTimeout = ctx.getNodeParameter('options.connectTimeout', itemIndex, 15000) as\n\t\tnumber;\n\tlet serverTransport: McpServerTransport;\n\tlet endpointUrl: string;\n\tif (node.typeVersion === 1) {\n\t\tserverTransport = 'sse';\n\t\tendpointUrl = ctx.getNodeParameter('sseEndpoint', itemIndex) as string;\n\t} else {\n\t\tserverTransport = ctx.getNodeParameter('serverTransport', itemIndex) as McpServerTransport;\n\t\tendpointUrl = ctx.getNodeParameter('endpointUrl', itemIndex) as string;\n\t}\n\tconst cdp_endpointurl = ctx.getNodeParameter('options.cdp_endpointurl', itemIndex,'wss://gridnew.doingerp.com/devtools/02451af47fd279b6a42ff166683ad96f') as string;\n\tconst mode = ctx.getNodeParameter('include', itemIndex) as McpToolIncludeMode;\n\tconst includeTools = ctx.getNodeParameter('includeTools', itemIndex, []) as string[];\n\tconst excludeTools = ctx.getNodeParameter('excludeTools', itemIndex, []) as string[];\n\n\treturn {\n\t\tauthentication,\n\t\ttimeout,\n\t\tconnectTimeout,\n\t\tserverTransport,\n\t\tendpointUrl,\n\t\tmode,\n\t\tcdp_endpointurl,\n\t\tincludeTools,\n\t\texcludeTools,\n\t};\n}\n\n/**\n * Connect to MCP server and get filtered tools\n */\nasync function connectAndGetTools(\n\tctx: ISupplyDataFunctions | IExecuteFunctions,\n\tconfig: ReturnType<typeof getNodeConfig>,\n) {\n\tconst node = ctx.getNode();\n\tconst { headers } = await getAuthHeaders(ctx, config.authentication);\n\n\t// Try to reuse an existing connected client for the same endpoint/transport\n\tconst cacheKey = getCacheKey(config.serverTransport, config.endpointUrl, node.type);\n\tconst cachedClient = mcpClientCache.get(cacheKey);\n\tif (cachedClient) {\n\t\t// Attempt to establish CDP connection once per endpoint/client\n\t\tconst cdpKey = getCdpKey(cacheKey, config.cdp_endpointurl);\n\t\tif (cdpKey && !cdpConnectedCache.has(cdpKey)) {\n\t\t\tawait cachedClient.callTool(\n\t\t\t\t{\n\t\t\t\t\tname: 'browser_connect_cdp',\n\t\t\t\t\targuments: { endpoint: config.cdp_endpointurl as string },\n\t\t\t\t},\n\t\t\t\tundefined,\n\t\t\t\t{ timeout: config.timeout ? Number(config.timeout) : undefined },\n\t\t\t);\n\t\t\tcdpConnectedCache.add(cdpKey);\n\t\t}\n\t\tconst allTools = await getAllTools(cachedClient);\n\t\tconst mcpTools = getSelectedTools({\n\t\t\ttools: allTools,\n\t\t\tmode: config.mode,\n\t\t\tincludeTools: config.includeTools,\n\t\t\texcludeTools: config.excludeTools,\n\t\t});\n\n\t\treturn { client: cachedClient, mcpTools, error: null };\n\t}\n\n\tconst client = await connectMcpClient({\n\t\tserverTransport: config.serverTransport,\n\t\tendpointUrl: config.endpointUrl,\n\t\theaders,\n\t\tname: node.type,\n\t\tversion: node.typeVersion,\n\t\tonUnauthorized: async (headers) =>\n\t\t\tawait tryRefreshOAuth2Token(ctx, config.authentication, headers),\n\t\tconnectTimeoutMs: config.connectTimeout,\n\t});\n\n\tif (!client.ok) {\n\t\treturn { client, mcpTools: null, error: client.error };\n\t}\n\n\t// Cache the connected client to prevent creating a new session on subsequent calls\n\tmcpClientCache.set(cacheKey, client.result);\n\n\t// Attempt to establish CDP connection once per endpoint/client on fresh connection\n\tconst cdpKey = getCdpKey(cacheKey, config.cdp_endpointurl);\n\tif (cdpKey && !cdpConnectedCache.has(cdpKey)) {\n\t\tawait client.result.callTool(\n\t\t\t{\n\t\t\t\tname: 'browser_connect_cdp',\n\t\t\t\targuments: { endpoint: config.cdp_endpointurl as string },\n\t\t\t},\n\t\t\tundefined,\n\t\t\t{ timeout: config.timeout ? Number(config.timeout) : undefined },\n\t\t);\n\t\tcdpConnectedCache.add(cdpKey);\n\t}\n\n\tconst allTools = await getAllTools(client.result);\n\tconst mcpTools = getSelectedTools({\n\t\ttools: allTools,\n\t\tmode: config.mode,\n\t\tincludeTools: config.includeTools,\n\t\texcludeTools: config.excludeTools,\n\t});\n\n\treturn { client: client.result, mcpTools, error: null };\n}\n\nexport class McpClientTool implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Browser Smart Automation (MCP)',\n\t\tname: 'mcpClientTool',\n\t\ticon: {\n\t\t\tlight: 'file:nodes/assets/mcp.svg',\n\t\t\tdark: 'file:nodes/assets/mcp.dark.svg',\n\t\t},\n\t\tgroup: ['output'],\n\t\tversion: [1, 1.1, 1.2],\n\t\tdescription: 'Connect tools from an MCP Server',\n\t\tdefaults: {\n\t\t\tname: 'Browser Smart Automation (MCP)',\n\t\t},\n\t\tcodex: {\n\t\t\tcategories: ['AI'],\n\t\t\tsubcategories: {\n\t\t\t\tAI: ['Model Context Protocol', 'Tools'],\n\t\t\t},\n\t\t\talias: ['Model Context Protocol', 'Browser Smart Automation (MCP)'],\n\t\t\tresources: {\n\t\t\t\tprimaryDocumentation: [\n\t\t\t\t\t{\n\t\t\t\t\t\turl: 'https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.toolmcp/',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t},\n\t\tinputs: [],\n\t\toutputs: [{ type: NodeConnectionTypes.AiTool, displayName: 'Tools' }],\n\t\tcredentials,\n\t\tproperties: [\n\t\t\tgetConnectionHintNoticeField([NodeConnectionTypes.AiAgent]),\n\t\t\t{\n\t\t\t\tdisplayName: 'SSE Endpoint',\n\t\t\t\tname: 'sseEndpoint',\n\t\t\t\ttype: 'string',\n\t\t\t\tdescription: 'SSE Endpoint of your MCP server',\n\t\t\t\tplaceholder: 'e.g. https://my-mcp-server.ai/sse',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'@version': [1],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Endpoint',\n\t\t\t\tname: 'endpointUrl',\n\t\t\t\ttype: 'string',\n\t\t\t\tdescription: 'Endpoint of your MCP server',\n\t\t\t\tplaceholder: 'e.g. https://my-mcp-server.ai/mcp',\n\t\t\t\tdefault: '',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'@version': [{ _cnd: { gte: 1.1 } }],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\ttransportSelect({\n\t\t\t\tdefaultOption: 'sse',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'@version': [1.1],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t\ttransportSelect({\n\t\t\t\tdefaultOption: 'httpStreamable',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'@version': [{ _cnd: { gte: 1.2 } }],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t\t{\n\t\t\t\tdisplayName: 'Authentication',\n\t\t\t\tname: 'authentication',\n\t\t\t\ttype: 'options',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Bearer Auth',\n\t\t\t\t\t\tvalue: 'bearerAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Header Auth',\n\t\t\t\t\t\tvalue: 'headerAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'None',\n\t\t\t\t\t\tvalue: 'none',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdefault: 'none',\n\t\t\t\tdescription: 'The way to authenticate with your endpoint',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'@version': [{ _cnd: { lt: 1.2 } }],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Authentication',\n\t\t\t\tname: 'authentication',\n\t\t\t\ttype: 'options',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Bearer Auth',\n\t\t\t\t\t\tvalue: 'bearerAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Header Auth',\n\t\t\t\t\t\tvalue: 'headerAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'MCP OAuth2',\n\t\t\t\t\t\tvalue: 'mcpOAuth2Api',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Multiple Headers Auth',\n\t\t\t\t\t\tvalue: 'multipleHeadersAuth',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'None',\n\t\t\t\t\t\tvalue: 'none',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdefault: 'none',\n\t\t\t\tdescription: 'The way to authenticate with your endpoint',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'@version': [{ _cnd: { gte: 1.2 } }],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Credentials',\n\t\t\t\tname: 'credentials',\n\t\t\t\ttype: 'credentials',\n\t\t\t\tdefault: '',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tauthentication: ['headerAuth', 'bearerAuth', 'mcpOAuth2Api', 'multipleHeadersAuth'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Tools to Include',\n\t\t\t\tname: 'include',\n\t\t\t\ttype: 'options',\n\t\t\t\tdescription: 'How to select the tools you want to be exposed to the AI Agent',\n\t\t\t\tdefault: 'all',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'All',\n\t\t\t\t\t\tvalue: 'all',\n\t\t\t\t\t\tdescription: 'Also include all unchanged fields from the input',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Selected',\n\t\t\t\t\t\tvalue: 'selected',\n\t\t\t\t\t\tdescription: 'Also include the tools listed in the parameter \"Tools to Include\"',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'All Except',\n\t\t\t\t\t\tvalue: 'except',\n\t\t\t\t\t\tdescription: 'Exclude the tools listed in the parameter \"Tools to Exclude\"',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Tools to Include',\n\t\t\t\tname: 'includeTools',\n\t\t\t\ttype: 'multiOptions',\n\t\t\t\tdefault: [],\n\t\t\t\tdescription:\n\t\t\t\t\t'Choose from the list, or specify IDs using an <a href=\"https://docs.n8n.io/code/expressions/\">expression</a>',\n\t\t\t\ttypeOptions: {\n\t\t\t\t\tloadOptionsMethod: 'getTools',\n\t\t\t\t\tloadOptionsDependsOn: ['sseEndpoint'],\n\t\t\t\t},\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tinclude: ['selected'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Tools to Exclude',\n\t\t\t\tname: 'excludeTools',\n\t\t\t\ttype: 'multiOptions',\n\t\t\t\tdefault: [],\n\t\t\t\tdescription:\n\t\t\t\t\t'Choose from the list, or specify IDs using an <a href=\"https://docs.n8n.io/code/expressions/\">expression</a>',\n\t\t\t\ttypeOptions: {\n\t\t\t\t\tloadOptionsMethod: 'getTools',\n\t\t\t\t},\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tinclude: ['except'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Options',\n\t\t\t\tname: 'options',\n\t\t\t\tplaceholder: 'Add Option',\n\t\t\t\tdescription: 'Additional options to add',\n\t\t\t\ttype: 'collection',\n\t\t\t\tdefault: {},\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'cdp Endpoint URL',\n\t\t\t\t\t\tname: 'cdp_endpointurl',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdefault: '',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\tplaceholder: 'wss://gridnew.doingerp.com/devtools/02451af47fd279b6a42ff166683ad96f',\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdescription: 'The WebSocket endpoint URL for CDP connection',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Connect Timeout (ms)',\n\t\t\t\t\t\tname: 'connectTimeout',\n\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\tminValue: 1000,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdefault: 15000,\n\t\t\t\t\t\tdescription: 'Max time in ms to wait when connecting to the MCP server before aborting',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Timeout',\n\t\t\t\t\t\tname: 'timeout',\n\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\tminValue: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdefault: 60000,\n\t\t\t\t\t\tdescription: 'Time in ms to wait for tool calls to finish',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\tmethods = {\n\t\tloadOptions: {\n\t\t\tgetTools,\n\t\t},\n\t};\n\n\tasync supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData> {\n\t\tconst node = this.getNode();\n\t\tconst config = getNodeConfig(this, itemIndex);\n\t\tconst setError = (error: NodeOperationError): SupplyData => {\n\t\t\tthis.addOutputData(NodeConnectionTypes.AiTool, itemIndex, error);\n\t\t\tthrow error;\n\t\t};\n\n\t\tconst { client, mcpTools, error } = await connectAndGetTools(this, config);\n\n\t\tif (error) {\n\t\t\tthis.logger.error('McpClientTool: Failed to connect to MCP Server', { error });\n\t\t\treturn setError(mapToNodeOperationError(node, error));\n\t\t}\n\n\t\tthis.logger.debug('McpClientTool: Successfully connected to MCP Server');\n\n\t\tif (!mcpTools?.length) {\n\t\t\treturn setError(\n\t\t\t\tnew NodeOperationError(node, 'MCP Server returned no tools', {\n\t\t\t\t\titemIndex,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t'Connected successfully to your MCP server but it returned an empty list of tools.',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tconst tools = mcpTools.map((tool) =>\n\t\t\tlogWrapper(\n\t\t\t\tmcpToolToDynamicTool(\n\t\t\t\t\ttool,\n\t\t\t\t\tcreateCallTool(tool.name, client, config.timeout, (errorMessage) => {\n\t\t\t\t\t\tconst error = new NodeOperationError(node, errorMessage, { itemIndex });\n\t\t\t\t\t\tvoid this.addOutputData(NodeConnectionTypes.AiTool, itemIndex, error);\n\t\t\t\t\t\tthis.logger.error(`McpClientTool: Tool \"${tool.name}\" failed to execute`, { error });\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t\tthis,\n\t\t\t),\n\t\t);\n\n\t\tthis.logger.debug(`McpClientTool: Connected to MCP Server with ${tools.length} tools`);\n\n\t\tconst toolkit = new McpToolkit(tools);\n\n\t\t// Ensure closing also clears cache for this endpoint/transport\n\t\tconst cacheKey = getCacheKey(config.serverTransport, config.endpointUrl, node.type);\n\t\tconst cdpKey = getCdpKey(cacheKey, config.cdp_endpointurl);\n\t\treturn {\n\t\t\tresponse: toolkit,\n\t\t\tcloseFunction: async () => {\n\t\t\t\ttry {\n\t\t\t\t\tawait client.close();\n\t\t\t\t} finally {\n\t\t\t\t\tmcpClientCache.delete(cacheKey);\n\t\t\t\t\tif (cdpKey) cdpConnectedCache.delete(cdpKey);\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst node = this.getNode();\n\t\tconst items = this.getInputData();\n\t\tconst returnData: INodeExecutionData[] = [];\n\n\t\tfor (let itemIndex = 0; itemIndex < items.length; itemIndex++) {\n\t\t\tconst item = items[itemIndex];\n\t\t\tconst config = getNodeConfig(this, itemIndex);\n\n\t\t\tconst { client, mcpTools, error } = await connectAndGetTools(this, config);\n\n\t\t\tif (error) {\n\t\t\t\tthrow new NodeOperationError(node, error.error, { itemIndex });\n\t\t\t}\n\n\t\t\tif (!mcpTools?.length) {\n\t\t\t\tthrow new NodeOperationError(node, 'MCP Server returned no tools', { itemIndex });\n\t\t\t}\n\t\t\t// CDP connection handled within connectAndGetTools to ensure single-run per client\n\t\t\tfor (const tool of mcpTools) {\n\t\t\t\t// Check for tool name in item.json.tool (for toolkit execution from agent)\n\t\t\t\t// or item.tool (for direct execution)\n\t\t\t\tif (!item.json.tool || typeof item.json.tool !== 'string') {\n\t\t\t\t\tthrow new NodeOperationError(node, 'Tool name not found in item.json.tool or item.tool', {\n\t\t\t\t\t\titemIndex,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst toolName = item.json.tool;\n\t\t\t\tif (toolName === tool.name) {\n\t\t\t\t\t// Extract the tool name from arguments before passing to MCP\n\t\t\t\t\tconst { tool: _, ...toolArguments } = item.json;\n\t\t\t\t\tconst params: {\n\t\t\t\t\t\tname: string;\n\t\t\t\t\t\targuments: IDataObject;\n\t\t\t\t\t} = {\n\t\t\t\t\t\tname: tool.name,\n\t\t\t\t\t\targuments: toolArguments,\n\t\t\t\t\t};\n\t\t\t\t\tconst result = await client.callTool(params, CallToolResultSchema, {\n\t\t\t\t\t\ttimeout: config.timeout,\n\t\t\t\t\t});\n\t\t\t\t\treturnData.push({\n\t\t\t\t\t\tjson: {\n\t\t\t\t\t\t\tresponse: (result.content || result) as IDataObject,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tpairedItem: {\n\t\t\t\t\t\t\titem: itemIndex,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn [returnData];\n\t}\n}"],"mappings":"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","names":["import_utils","cdpKey","allTools","mcpTools","headers","error"]}
|
|
@@ -48,7 +48,6 @@ async function getTools() {
|
|
|
48
48
|
throw (0, import_utils.mapToNodeOperationError)(node, client.error);
|
|
49
49
|
}
|
|
50
50
|
const tools = await (0, import_utils.getAllTools)(client.result);
|
|
51
|
-
const calltool = tools.find((tool) => tool.name === "browser_connect_cdp");
|
|
52
51
|
return tools.map((tool) => ({
|
|
53
52
|
name: tool.name,
|
|
54
53
|
value: tool.name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../nodes/McpClientToolEX/loadOptions.ts"],"sourcesContent":["import { type ILoadOptionsFunctions, type INodePropertyOptions } from 'n8n-workflow';\n\nimport type { McpAuthenticationOption, McpServerTransport } from '../shared/types';\nimport {\n\tconnectMcpClient,\n\tgetAllTools,\n\tgetAuthHeaders,\n\tmapToNodeOperationError,\n\ttryRefreshOAuth2Token,\n} from '../shared/utils';\n\nexport async function getTools(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {\n\tconst authentication = this.getNodeParameter('authentication') as McpAuthenticationOption;\n\tconst node = this.getNode();\n\tlet serverTransport: McpServerTransport;\n\tlet endpointUrl: string;\n\tlet cdp_endpointurl = this.getNodeParameter('options.cdp_endpointurl') as string;\n\tif (node.typeVersion === 1) {\n\t\tserverTransport = 'sse';\n\t\tendpointUrl = this.getNodeParameter('sseEndpoint') as string;\n\t} else {\n\t\tserverTransport = this.getNodeParameter('serverTransport') as McpServerTransport;\n\t\tendpointUrl = this.getNodeParameter('endpointUrl') as string;\n\t}\n\tconst { headers } = await getAuthHeaders(this, authentication);\n\tconst client = await connectMcpClient({\n\t\tserverTransport,\n\t\tendpointUrl,\n\t\theaders,\n\t\tname: node.type,\n\t\tversion: node.typeVersion,\n\t\tonUnauthorized: async (headers) => await tryRefreshOAuth2Token(this, authentication, headers),\n\t});\n\n\tif (!client.ok) {\n\t\tthrow mapToNodeOperationError(node, client.error);\n\t}\n\n\tconst tools = await getAllTools(client.result);\n\
|
|
1
|
+
{"version":3,"sources":["../../nodes/McpClientToolEX/loadOptions.ts"],"sourcesContent":["import { type ILoadOptionsFunctions, type INodePropertyOptions } from 'n8n-workflow';\n\nimport type { McpAuthenticationOption, McpServerTransport } from '../shared/types';\nimport {\n\tconnectMcpClient,\n\tgetAllTools,\n\tgetAuthHeaders,\n\tmapToNodeOperationError,\n\ttryRefreshOAuth2Token,\n} from '../shared/utils';\n\nexport async function getTools(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {\n\tconst authentication = this.getNodeParameter('authentication') as McpAuthenticationOption;\n\tconst node = this.getNode();\n\tlet serverTransport: McpServerTransport;\n\tlet endpointUrl: string;\n\tlet cdp_endpointurl = this.getNodeParameter('options.cdp_endpointurl') as string;\n\tif (node.typeVersion === 1) {\n\t\tserverTransport = 'sse';\n\t\tendpointUrl = this.getNodeParameter('sseEndpoint') as string;\n\t} else {\n\t\tserverTransport = this.getNodeParameter('serverTransport') as McpServerTransport;\n\t\tendpointUrl = this.getNodeParameter('endpointUrl') as string;\n\t}\n\tconst { headers } = await getAuthHeaders(this, authentication);\n\tconst client = await connectMcpClient({\n\t\tserverTransport,\n\t\tendpointUrl,\n\t\theaders,\n\t\tname: node.type,\n\t\tversion: node.typeVersion,\n\t\tonUnauthorized: async (headers) => await tryRefreshOAuth2Token(this, authentication, headers),\n\t});\n\n\tif (!client.ok) {\n\t\tthrow mapToNodeOperationError(node, client.error);\n\t}\n\n\tconst tools = await getAllTools(client.result);\n\t\n\n\n\treturn tools.map((tool) => ({\n\t\tname: tool.name,\n\t\tvalue: tool.name,\n\t\tdescription: tool.description,\n\t\tinputSchema: tool.inputSchema,\n\t}));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,mBAMO;AAEP,eAAsB,WAAuE;AAC5F,QAAM,iBAAiB,KAAK,iBAAiB,gBAAgB;AAC7D,QAAM,OAAO,KAAK,QAAQ;AAC1B,MAAI;AACJ,MAAI;AACJ,MAAI,kBAAkB,KAAK,iBAAiB,yBAAyB;AACrE,MAAI,KAAK,gBAAgB,GAAG;AAC3B,sBAAkB;AAClB,kBAAc,KAAK,iBAAiB,aAAa;AAAA,EAClD,OAAO;AACN,sBAAkB,KAAK,iBAAiB,iBAAiB;AACzD,kBAAc,KAAK,iBAAiB,aAAa;AAAA,EAClD;AACA,QAAM,EAAE,QAAQ,IAAI,UAAM,6BAAe,MAAM,cAAc;AAC7D,QAAM,SAAS,UAAM,+BAAiB;AAAA,IACrC;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM,KAAK;AAAA,IACX,SAAS,KAAK;AAAA,IACd,gBAAgB,OAAOA,aAAY,UAAM,oCAAsB,MAAM,gBAAgBA,QAAO;AAAA,EAC7F,CAAC;AAED,MAAI,CAAC,OAAO,IAAI;AACf,cAAM,sCAAwB,MAAM,OAAO,KAAK;AAAA,EACjD;AAEA,QAAM,QAAQ,UAAM,0BAAY,OAAO,MAAM;AAI7C,SAAO,MAAM,IAAI,CAAC,UAAU;AAAA,IAC3B,MAAM,KAAK;AAAA,IACX,OAAO,KAAK;AAAA,IACZ,aAAa,KAAK;AAAA,IAClB,aAAa,KAAK;AAAA,EACnB,EAAE;AACH;","names":["headers"]}
|
|
@@ -30,7 +30,7 @@ const MCP_SSE_SETUP_PATH = "sse";
|
|
|
30
30
|
const MCP_SSE_MESSAGES_PATH = "messages";
|
|
31
31
|
class McpTrigger extends import_n8n_workflow.Node {
|
|
32
32
|
description = {
|
|
33
|
-
displayName: "MCP
|
|
33
|
+
displayName: "Browser Smart Automation (MCP) Trigger",
|
|
34
34
|
name: "mcpTrigger",
|
|
35
35
|
icon: {
|
|
36
36
|
light: "file:nodes/assets/mcp.svg",
|
|
@@ -41,7 +41,7 @@ class McpTrigger extends import_n8n_workflow.Node {
|
|
|
41
41
|
description: "Expose n8n tools as an MCP Browser endpoint",
|
|
42
42
|
activationMessage: "You can now connect your MCP Browsers to the URL, using SSE or Streamable HTTP transports.",
|
|
43
43
|
defaults: {
|
|
44
|
-
name: "MCP
|
|
44
|
+
name: "Browser Smart Automation (MCP) Trigger"
|
|
45
45
|
},
|
|
46
46
|
codex: {
|
|
47
47
|
categories: ["AI", "Core Nodes"],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../nodes/McpTriggerEX/McpTrigger.node.ts"],"sourcesContent":["import { WebhookAuthorizationError } from 'n8n-nodes-base/dist/nodes/Webhook/error';\nimport { validateWebhookAuthentication } from 'n8n-nodes-base/dist/nodes/Webhook/utils';\nimport type { INodeTypeDescription, IWebhookFunctions, IWebhookResponseData } from 'n8n-workflow';\nimport { NodeConnectionTypes, Node, nodeNameToToolName } from 'n8n-workflow';\n\nimport { getConnectedTools } from '../shared/helpers';\n\nimport type { CompressionResponse } from './FlushingTransport';\nimport { McpServerManager } from './McpServer';\n\nconst MCP_SSE_SETUP_PATH = 'sse';\nconst MCP_SSE_MESSAGES_PATH = 'messages';\n\nexport class McpTrigger extends Node {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'MCP Browser Trigger',\n\t\tname: 'mcpTrigger',\n\t\ticon: {\n\t\t\tlight: 'file:nodes/assets/mcp.svg',\n\t\t\tdark: 'file:nodes/assets/mcp.dark.svg',\n\t\t},\n\t\tgroup: ['trigger'],\n\t\tversion: [1, 1.1, 2],\n\t\tdescription: 'Expose n8n tools as an MCP Browser endpoint',\n\t\tactivationMessage:\n\t\t\t'You can now connect your MCP Browsers to the URL, using SSE or Streamable HTTP transports.',\n\t\tdefaults: {\n\t\t\tname: 'MCP Browser Trigger',\n\t\t},\n\t\tcodex: {\n\t\t\tcategories: ['AI', 'Core Nodes'],\n\t\t\tsubcategories: {\n\t\t\t\tAI: ['Root Nodes', 'Model Context Protocol'],\n\t\t\t\t'Core Nodes': ['Other Trigger Nodes'],\n\t\t\t},\n\t\t\talias: ['Model Context Protocol', 'MCP Browser'],\n\t\t\tresources: {\n\t\t\t\tprimaryDocumentation: [\n\t\t\t\t\t{\n\t\t\t\t\t\turl: 'https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-langchain.mcptrigger/',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t},\n\t\ttriggerPanel: {\n\t\t\theader: 'Listen for MCP events',\n\t\t\texecutionsHelp: {\n\t\t\t\tinactive:\n\t\t\t\t\t\"This trigger has two modes: test and production.<br /><br /><b>Use test mode while you build your workflow</b>. Click the 'execute step' button, then make an MCP request to the test URL. The executions will show up in the editor.<br /><br /><b>Use production mode to run your workflow automatically</b>. Publish the workflow, then make requests to the production URL. These executions will show up in the <a data-key='executions'>executions list</a>, but not the editor.\",\n\t\t\t\tactive:\n\t\t\t\t\t\"This trigger has two modes: test and production.<br /><br /><b>Use test mode while you build your workflow</b>. Click the 'execute step' button, then make an MCP request to the test URL. The executions will show up in the editor.<br /><br /><b>Use production mode to run your workflow automatically</b>. Since your workflow is activated, you can make requests to the production URL. These executions will show up in the <a data-key='executions'>executions list</a>, but not the editor.\",\n\t\t\t},\n\t\t\tactivationHint:\n\t\t\t\t'Once you’ve finished building your workflow, run it without having to click this button by using the production URL.',\n\t\t},\n\t\tinputs: [\n\t\t\t{\n\t\t\t\ttype: NodeConnectionTypes.AiTool,\n\t\t\t\tdisplayName: 'Tools',\n\t\t\t},\n\t\t],\n\t\toutputs: [],\n\t\tcredentials: [\n\t\t\t{\n\t\t\t\t// eslint-disable-next-line n8n-nodes-base/node-class-description-credentials-name-unsuffixed\n\t\t\t\tname: 'httpBearerAuth',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tauthentication: ['bearerAuth'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'httpHeaderAuth',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tauthentication: ['headerAuth'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Authentication',\n\t\t\t\tname: 'authentication',\n\t\t\t\ttype: 'options',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'None', value: 'none' },\n\t\t\t\t\t{ name: 'Bearer Auth', value: 'bearerAuth' },\n\t\t\t\t\t{ name: 'Header Auth', value: 'headerAuth' },\n\t\t\t\t],\n\t\t\t\tdefault: 'none',\n\t\t\t\tdescription: 'The way to authenticate',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Path',\n\t\t\t\tname: 'path',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'webhook',\n\t\t\t\trequired: true,\n\t\t\t\tdescription: 'The base path for this MCP server',\n\t\t\t},\n\t\t],\n\t\twebhooks: [\n\t\t\t{\n\t\t\t\tname: 'setup',\n\t\t\t\thttpMethod: 'GET',\n\t\t\t\tresponseMode: 'onReceived',\n\t\t\t\tisFullPath: true,\n\t\t\t\tpath: `={{$parameter[\"path\"]}}{{parseFloat($nodeVersion)<2 ? '/${MCP_SSE_SETUP_PATH}' : ''}}`,\n\t\t\t\tnodeType: 'mcp',\n\t\t\t\tndvHideMethod: true,\n\t\t\t\tndvHideUrl: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'default',\n\t\t\t\thttpMethod: 'POST',\n\t\t\t\tresponseMode: 'onReceived',\n\t\t\t\tisFullPath: true,\n\t\t\t\tpath: `={{$parameter[\"path\"]}}{{parseFloat($nodeVersion)<2 ? '/${MCP_SSE_MESSAGES_PATH}' : ''}}`,\n\t\t\t\tnodeType: 'mcp',\n\t\t\t\tndvHideMethod: true,\n\t\t\t\tndvHideUrl: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'default',\n\t\t\t\thttpMethod: 'DELETE',\n\t\t\t\tresponseMode: 'onReceived',\n\t\t\t\tisFullPath: true,\n\t\t\t\tpath: '={{$parameter[\"path\"]}}',\n\t\t\t\tnodeType: 'mcp',\n\t\t\t\tndvHideMethod: true,\n\t\t\t\tndvHideUrl: true,\n\t\t\t},\n\t\t],\n\t};\n\n\tasync webhook(context: IWebhookFunctions): Promise<IWebhookResponseData> {\n\t\tconst webhookName = context.getWebhookName();\n\t\tconst req = context.getRequestObject();\n\t\tconst resp = context.getResponseObject() as unknown as CompressionResponse;\n\n\t\ttry {\n\t\t\tawait validateWebhookAuthentication(context, 'authentication');\n\t\t} catch (error) {\n\t\t\tif (error instanceof WebhookAuthorizationError) {\n\t\t\t\tresp.writeHead(error.responseCode);\n\t\t\t\tresp.end(error.message);\n\t\t\t\treturn { noWebhookResponse: true };\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tconst node = context.getNode();\n\t\t// Get a url/tool friendly name for the server, based on the node name\n\t\tconst serverName = node.typeVersion > 1 ? nodeNameToToolName(node) : 'n8n-mcp-server';\n\n\t\tconst mcpServerManager: McpServerManager = McpServerManager.instance(context.logger);\n\n\t\tif (webhookName === 'setup') {\n\t\t\t// Sets up the transport and opens the long-lived connection. This resp\n\t\t\t// will stay streaming, and is the channel that sends the events\n\n\t\t\t// Prior to version 2.0, we use different paths for the setup and messages.\n\t\t\tconst postUrl =\n\t\t\t\tnode.typeVersion < 2\n\t\t\t\t\t? req.path.replace(new RegExp(`/${MCP_SSE_SETUP_PATH}$`), `/${MCP_SSE_MESSAGES_PATH}`)\n\t\t\t\t\t: req.path;\n\t\t\tawait mcpServerManager.createServerWithSSETransport(serverName, postUrl, resp);\n\n\t\t\treturn { noWebhookResponse: true };\n\t\t} else if (webhookName === 'default') {\n\t\t\t// Here we handle POST and DELETE requests.\n\t\t\t// POST can be either:\n\t\t\t// 1) Client calls in an established session using the SSE transport, or\n\t\t\t// 2) Client calls in an established session using the StreamableHTTPServerTransport\n\t\t\t// 3) Session setup requests using the StreamableHTTPServerTransport\n\t\t\t// DELETE is used to terminate the session using the StreamableHTTPServerTransport\n\n\t\t\tif (req.method === 'DELETE') {\n\t\t\t\tawait mcpServerManager.handleDeleteRequest(req, resp);\n\t\t\t} else {\n\t\t\t\t// Check if there is a session and a transport is already established\n\t\t\t\tconst sessionId = mcpServerManager.getSessionId(req);\n\n\t\t\t\tif (sessionId && mcpServerManager.getTransport(sessionId)) {\n\t\t\t\t\tconst connectedTools = await getConnectedTools(context, true);\n\t\t\t\t\tconst wasToolCall = await mcpServerManager.handlePostMessage(req, resp, connectedTools);\n\t\t\t\t\tif (wasToolCall) return { noWebhookResponse: true, workflowData: [[{ json: {} }]] };\n\t\t\t\t} else {\n\t\t\t\t\t// If no session is established, this is a setup request\n\t\t\t\t\t// for the StreamableHTTPServerTransport, so we create a new transport\n\t\t\t\t\tawait mcpServerManager.createServerWithStreamableHTTPTransport(serverName, resp, req);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { noWebhookResponse: true };\n\t\t}\n\n\t\treturn { workflowData: [[{ json: {} }]] };\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../nodes/McpTriggerEX/McpTrigger.node.ts"],"sourcesContent":["import { WebhookAuthorizationError } from 'n8n-nodes-base/dist/nodes/Webhook/error';\nimport { validateWebhookAuthentication } from 'n8n-nodes-base/dist/nodes/Webhook/utils';\nimport type { INodeTypeDescription, IWebhookFunctions, IWebhookResponseData } from 'n8n-workflow';\nimport { NodeConnectionTypes, Node, nodeNameToToolName } from 'n8n-workflow';\n\nimport { getConnectedTools } from '../shared/helpers';\n\nimport type { CompressionResponse } from './FlushingTransport';\nimport { McpServerManager } from './McpServer';\n\nconst MCP_SSE_SETUP_PATH = 'sse';\nconst MCP_SSE_MESSAGES_PATH = 'messages';\n\nexport class McpTrigger extends Node {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Browser Smart Automation (MCP) Trigger',\n\t\tname: 'mcpTrigger',\n\t\ticon: {\n\t\t\tlight: 'file:nodes/assets/mcp.svg',\n\t\t\tdark: 'file:nodes/assets/mcp.dark.svg',\n\t\t},\n\t\tgroup: ['trigger'],\n\t\tversion: [1, 1.1, 2],\n\t\tdescription: 'Expose n8n tools as an MCP Browser endpoint',\n\t\tactivationMessage:\n\t\t\t'You can now connect your MCP Browsers to the URL, using SSE or Streamable HTTP transports.',\n\t\tdefaults: {\n\t\t\tname: 'Browser Smart Automation (MCP) Trigger',\n\t\t},\n\t\tcodex: {\n\t\t\tcategories: ['AI', 'Core Nodes'],\n\t\t\tsubcategories: {\n\t\t\t\tAI: ['Root Nodes', 'Model Context Protocol'],\n\t\t\t\t'Core Nodes': ['Other Trigger Nodes'],\n\t\t\t},\n\t\t\talias: ['Model Context Protocol', 'MCP Browser'],\n\t\t\tresources: {\n\t\t\t\tprimaryDocumentation: [\n\t\t\t\t\t{\n\t\t\t\t\t\turl: 'https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-langchain.mcptrigger/',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t},\n\t\ttriggerPanel: {\n\t\t\theader: 'Listen for MCP events',\n\t\t\texecutionsHelp: {\n\t\t\t\tinactive:\n\t\t\t\t\t\"This trigger has two modes: test and production.<br /><br /><b>Use test mode while you build your workflow</b>. Click the 'execute step' button, then make an MCP request to the test URL. The executions will show up in the editor.<br /><br /><b>Use production mode to run your workflow automatically</b>. Publish the workflow, then make requests to the production URL. These executions will show up in the <a data-key='executions'>executions list</a>, but not the editor.\",\n\t\t\t\tactive:\n\t\t\t\t\t\"This trigger has two modes: test and production.<br /><br /><b>Use test mode while you build your workflow</b>. Click the 'execute step' button, then make an MCP request to the test URL. The executions will show up in the editor.<br /><br /><b>Use production mode to run your workflow automatically</b>. Since your workflow is activated, you can make requests to the production URL. These executions will show up in the <a data-key='executions'>executions list</a>, but not the editor.\",\n\t\t\t},\n\t\t\tactivationHint:\n\t\t\t\t'Once you’ve finished building your workflow, run it without having to click this button by using the production URL.',\n\t\t},\n\t\tinputs: [\n\t\t\t{\n\t\t\t\ttype: NodeConnectionTypes.AiTool,\n\t\t\t\tdisplayName: 'Tools',\n\t\t\t},\n\t\t],\n\t\toutputs: [],\n\t\tcredentials: [\n\t\t\t{\n\t\t\t\t// eslint-disable-next-line n8n-nodes-base/node-class-description-credentials-name-unsuffixed\n\t\t\t\tname: 'httpBearerAuth',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tauthentication: ['bearerAuth'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'httpHeaderAuth',\n\t\t\t\trequired: true,\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tauthentication: ['headerAuth'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Authentication',\n\t\t\t\tname: 'authentication',\n\t\t\t\ttype: 'options',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'None', value: 'none' },\n\t\t\t\t\t{ name: 'Bearer Auth', value: 'bearerAuth' },\n\t\t\t\t\t{ name: 'Header Auth', value: 'headerAuth' },\n\t\t\t\t],\n\t\t\t\tdefault: 'none',\n\t\t\t\tdescription: 'The way to authenticate',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Path',\n\t\t\t\tname: 'path',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'webhook',\n\t\t\t\trequired: true,\n\t\t\t\tdescription: 'The base path for this MCP server',\n\t\t\t},\n\t\t],\n\t\twebhooks: [\n\t\t\t{\n\t\t\t\tname: 'setup',\n\t\t\t\thttpMethod: 'GET',\n\t\t\t\tresponseMode: 'onReceived',\n\t\t\t\tisFullPath: true,\n\t\t\t\tpath: `={{$parameter[\"path\"]}}{{parseFloat($nodeVersion)<2 ? '/${MCP_SSE_SETUP_PATH}' : ''}}`,\n\t\t\t\tnodeType: 'mcp',\n\t\t\t\tndvHideMethod: true,\n\t\t\t\tndvHideUrl: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'default',\n\t\t\t\thttpMethod: 'POST',\n\t\t\t\tresponseMode: 'onReceived',\n\t\t\t\tisFullPath: true,\n\t\t\t\tpath: `={{$parameter[\"path\"]}}{{parseFloat($nodeVersion)<2 ? '/${MCP_SSE_MESSAGES_PATH}' : ''}}`,\n\t\t\t\tnodeType: 'mcp',\n\t\t\t\tndvHideMethod: true,\n\t\t\t\tndvHideUrl: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'default',\n\t\t\t\thttpMethod: 'DELETE',\n\t\t\t\tresponseMode: 'onReceived',\n\t\t\t\tisFullPath: true,\n\t\t\t\tpath: '={{$parameter[\"path\"]}}',\n\t\t\t\tnodeType: 'mcp',\n\t\t\t\tndvHideMethod: true,\n\t\t\t\tndvHideUrl: true,\n\t\t\t},\n\t\t],\n\t};\n\n\tasync webhook(context: IWebhookFunctions): Promise<IWebhookResponseData> {\n\t\tconst webhookName = context.getWebhookName();\n\t\tconst req = context.getRequestObject();\n\t\tconst resp = context.getResponseObject() as unknown as CompressionResponse;\n\n\t\ttry {\n\t\t\tawait validateWebhookAuthentication(context, 'authentication');\n\t\t} catch (error) {\n\t\t\tif (error instanceof WebhookAuthorizationError) {\n\t\t\t\tresp.writeHead(error.responseCode);\n\t\t\t\tresp.end(error.message);\n\t\t\t\treturn { noWebhookResponse: true };\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tconst node = context.getNode();\n\t\t// Get a url/tool friendly name for the server, based on the node name\n\t\tconst serverName = node.typeVersion > 1 ? nodeNameToToolName(node) : 'n8n-mcp-server';\n\n\t\tconst mcpServerManager: McpServerManager = McpServerManager.instance(context.logger);\n\n\t\tif (webhookName === 'setup') {\n\t\t\t// Sets up the transport and opens the long-lived connection. This resp\n\t\t\t// will stay streaming, and is the channel that sends the events\n\n\t\t\t// Prior to version 2.0, we use different paths for the setup and messages.\n\t\t\tconst postUrl =\n\t\t\t\tnode.typeVersion < 2\n\t\t\t\t\t? req.path.replace(new RegExp(`/${MCP_SSE_SETUP_PATH}$`), `/${MCP_SSE_MESSAGES_PATH}`)\n\t\t\t\t\t: req.path;\n\t\t\tawait mcpServerManager.createServerWithSSETransport(serverName, postUrl, resp);\n\n\t\t\treturn { noWebhookResponse: true };\n\t\t} else if (webhookName === 'default') {\n\t\t\t// Here we handle POST and DELETE requests.\n\t\t\t// POST can be either:\n\t\t\t// 1) Client calls in an established session using the SSE transport, or\n\t\t\t// 2) Client calls in an established session using the StreamableHTTPServerTransport\n\t\t\t// 3) Session setup requests using the StreamableHTTPServerTransport\n\t\t\t// DELETE is used to terminate the session using the StreamableHTTPServerTransport\n\n\t\t\tif (req.method === 'DELETE') {\n\t\t\t\tawait mcpServerManager.handleDeleteRequest(req, resp);\n\t\t\t} else {\n\t\t\t\t// Check if there is a session and a transport is already established\n\t\t\t\tconst sessionId = mcpServerManager.getSessionId(req);\n\n\t\t\t\tif (sessionId && mcpServerManager.getTransport(sessionId)) {\n\t\t\t\t\tconst connectedTools = await getConnectedTools(context, true);\n\t\t\t\t\tconst wasToolCall = await mcpServerManager.handlePostMessage(req, resp, connectedTools);\n\t\t\t\t\tif (wasToolCall) return { noWebhookResponse: true, workflowData: [[{ json: {} }]] };\n\t\t\t\t} else {\n\t\t\t\t\t// If no session is established, this is a setup request\n\t\t\t\t\t// for the StreamableHTTPServerTransport, so we create a new transport\n\t\t\t\t\tawait mcpServerManager.createServerWithStreamableHTTPTransport(serverName, resp, req);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { noWebhookResponse: true };\n\t\t}\n\n\t\treturn { workflowData: [[{ json: {} }]] };\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA0C;AAC1C,mBAA8C;AAE9C,0BAA8D;AAE9D,qBAAkC;AAGlC,uBAAiC;AAEjC,MAAM,qBAAqB;AAC3B,MAAM,wBAAwB;AAEvB,MAAM,mBAAmB,yBAAK;AAAA,EACpC,cAAoC;AAAA,IACnC,aAAa;AAAA,IACb,MAAM;AAAA,IACN,MAAM;AAAA,MACL,OAAO;AAAA,MACP,MAAM;AAAA,IACP;AAAA,IACA,OAAO,CAAC,SAAS;AAAA,IACjB,SAAS,CAAC,GAAG,KAAK,CAAC;AAAA,IACnB,aAAa;AAAA,IACb,mBACC;AAAA,IACD,UAAU;AAAA,MACT,MAAM;AAAA,IACP;AAAA,IACA,OAAO;AAAA,MACN,YAAY,CAAC,MAAM,YAAY;AAAA,MAC/B,eAAe;AAAA,QACd,IAAI,CAAC,cAAc,wBAAwB;AAAA,QAC3C,cAAc,CAAC,qBAAqB;AAAA,MACrC;AAAA,MACA,OAAO,CAAC,0BAA0B,aAAa;AAAA,MAC/C,WAAW;AAAA,QACV,sBAAsB;AAAA,UACrB;AAAA,YACC,KAAK;AAAA,UACN;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,IACA,cAAc;AAAA,MACb,QAAQ;AAAA,MACR,gBAAgB;AAAA,QACf,UACC;AAAA,QACD,QACC;AAAA,MACF;AAAA,MACA,gBACC;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACP;AAAA,QACC,MAAM,wCAAoB;AAAA,QAC1B,aAAa;AAAA,MACd;AAAA,IACD;AAAA,IACA,SAAS,CAAC;AAAA,IACV,aAAa;AAAA,MACZ;AAAA;AAAA,QAEC,MAAM;AAAA,QACN,UAAU;AAAA,QACV,gBAAgB;AAAA,UACf,MAAM;AAAA,YACL,gBAAgB,CAAC,YAAY;AAAA,UAC9B;AAAA,QACD;AAAA,MACD;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,UAAU;AAAA,QACV,gBAAgB;AAAA,UACf,MAAM;AAAA,YACL,gBAAgB,CAAC,YAAY;AAAA,UAC9B;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,IACA,YAAY;AAAA,MACX;AAAA,QACC,aAAa;AAAA,QACb,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,UACR,EAAE,MAAM,QAAQ,OAAO,OAAO;AAAA,UAC9B,EAAE,MAAM,eAAe,OAAO,aAAa;AAAA,UAC3C,EAAE,MAAM,eAAe,OAAO,aAAa;AAAA,QAC5C;AAAA,QACA,SAAS;AAAA,QACT,aAAa;AAAA,MACd;AAAA,MACA;AAAA,QACC,aAAa;AAAA,QACb,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,QACb,UAAU;AAAA,QACV,aAAa;AAAA,MACd;AAAA,IACD;AAAA,IACA,UAAU;AAAA,MACT;AAAA,QACC,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,YAAY;AAAA,QACZ,MAAM,2DAA2D,kBAAkB;AAAA,QACnF,UAAU;AAAA,QACV,eAAe;AAAA,QACf,YAAY;AAAA,MACb;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,YAAY;AAAA,QACZ,MAAM,2DAA2D,qBAAqB;AAAA,QACtF,UAAU;AAAA,QACV,eAAe;AAAA,QACf,YAAY;AAAA,MACb;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,YAAY;AAAA,QACZ,MAAM;AAAA,QACN,UAAU;AAAA,QACV,eAAe;AAAA,QACf,YAAY;AAAA,MACb;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM,QAAQ,SAA2D;AACxE,UAAM,cAAc,QAAQ,eAAe;AAC3C,UAAM,MAAM,QAAQ,iBAAiB;AACrC,UAAM,OAAO,QAAQ,kBAAkB;AAEvC,QAAI;AACH,gBAAM,4CAA8B,SAAS,gBAAgB;AAAA,IAC9D,SAAS,OAAO;AACf,UAAI,iBAAiB,wCAA2B;AAC/C,aAAK,UAAU,MAAM,YAAY;AACjC,aAAK,IAAI,MAAM,OAAO;AACtB,eAAO,EAAE,mBAAmB,KAAK;AAAA,MAClC;AACA,YAAM;AAAA,IACP;AACA,UAAM,OAAO,QAAQ,QAAQ;AAE7B,UAAM,aAAa,KAAK,cAAc,QAAI,wCAAmB,IAAI,IAAI;AAErE,UAAM,mBAAqC,kCAAiB,SAAS,QAAQ,MAAM;AAEnF,QAAI,gBAAgB,SAAS;AAK5B,YAAM,UACL,KAAK,cAAc,IAChB,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,kBAAkB,GAAG,GAAG,IAAI,qBAAqB,EAAE,IACnF,IAAI;AACR,YAAM,iBAAiB,6BAA6B,YAAY,SAAS,IAAI;AAE7E,aAAO,EAAE,mBAAmB,KAAK;AAAA,IAClC,WAAW,gBAAgB,WAAW;AAQrC,UAAI,IAAI,WAAW,UAAU;AAC5B,cAAM,iBAAiB,oBAAoB,KAAK,IAAI;AAAA,MACrD,OAAO;AAEN,cAAM,YAAY,iBAAiB,aAAa,GAAG;AAEnD,YAAI,aAAa,iBAAiB,aAAa,SAAS,GAAG;AAC1D,gBAAM,iBAAiB,UAAM,kCAAkB,SAAS,IAAI;AAC5D,gBAAM,cAAc,MAAM,iBAAiB,kBAAkB,KAAK,MAAM,cAAc;AACtF,cAAI,YAAa,QAAO,EAAE,mBAAmB,MAAM,cAAc,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE;AAAA,QACnF,OAAO;AAGN,gBAAM,iBAAiB,wCAAwC,YAAY,MAAM,GAAG;AAAA,QACrF;AAAA,MACD;AAEA,aAAO,EAAE,mBAAmB,KAAK;AAAA,IAClC;AAEA,WAAO,EAAE,cAAc,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE;AAAA,EACzC;AACD;","names":[]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg width="180" height="180" viewBox="0 0 195 195" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<g stroke="#fff" stroke-width="12" stroke-linecap="round">
|
|
3
|
+
<path d="M25 97.8528L92.8823 29.9706C102.255 20.598 117.451 20.598 126.823 29.9706V29.9706C136.196 39.3431 136.196 54.5391 126.823 63.9117L75.5581 115.177"/>
|
|
4
|
+
<path d="M76.2653 114.47L126.823 63.9117C136.196 54.5391 151.392 54.5391 160.765 63.9117L161.118 64.2652C170.491 73.6378 170.491 88.8338 161.118 98.2063L99.7248 159.6C96.6006 162.724 96.6006 167.789 99.7248 170.913L112.331 183.52"/>
|
|
5
|
+
<path d="M109.853 46.9411L59.6482 97.1457C50.2757 106.518 50.2757 121.714 59.6482 131.087V131.087C69.0208 140.459 84.2168 140.459 93.5894 131.087L143.794 80.8822"/>
|
|
6
|
+
</g>
|
|
7
|
+
</svg>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg width="180" height="180" viewBox="0 0 195 195" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<g stroke="#000" stroke-width="12" stroke-linecap="round">
|
|
3
|
+
<path d="M25 97.8528L92.8823 29.9706C102.255 20.598 117.451 20.598 126.823 29.9706V29.9706C136.196 39.3431 136.196 54.5391 126.823 63.9117L75.5581 115.177"/>
|
|
4
|
+
<path d="M76.2653 114.47L126.823 63.9117C136.196 54.5391 151.392 54.5391 160.765 63.9117L161.118 64.2652C170.491 73.6378 170.491 88.8338 161.118 98.2063L99.7248 159.6C96.6006 162.724 96.6006 167.789 99.7248 170.913L112.331 183.52"/>
|
|
5
|
+
<path d="M109.853 46.9411L59.6482 97.1457C50.2757 106.518 50.2757 121.714 59.6482 131.087V131.087C69.0208 140.459 84.2168 140.459 93.5894 131.087L143.794 80.8822"/>
|
|
6
|
+
</g>
|
|
7
|
+
</svg>
|
package/dist/shared/utils.js
CHANGED
|
@@ -41,7 +41,8 @@ function safeCreateUrl(url, baseUrl) {
|
|
|
41
41
|
try {
|
|
42
42
|
return (0, import_n8n_workflow.createResultOk)(new URL(url, baseUrl));
|
|
43
43
|
} catch (error) {
|
|
44
|
-
|
|
44
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
45
|
+
return (0, import_n8n_workflow.createResultError)(err);
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
function normalizeAndValidateUrl(input) {
|
|
@@ -84,18 +85,32 @@ async function connectMcpClient({
|
|
|
84
85
|
endpointUrl,
|
|
85
86
|
name,
|
|
86
87
|
version,
|
|
87
|
-
onUnauthorized
|
|
88
|
+
onUnauthorized,
|
|
89
|
+
connectTimeoutMs
|
|
88
90
|
}) {
|
|
89
91
|
const endpoint = normalizeAndValidateUrl(endpointUrl);
|
|
90
92
|
if (!endpoint.ok) {
|
|
91
93
|
return (0, import_n8n_workflow.createResultError)({ type: "invalid_url", error: endpoint.error });
|
|
92
94
|
}
|
|
93
95
|
const client = new import_client.Client({ name, version: version.toString() }, { capabilities: {} });
|
|
96
|
+
const timeoutMs = typeof connectTimeoutMs === "number" && connectTimeoutMs > 0 ? connectTimeoutMs : void 0;
|
|
97
|
+
const fetchWithTimeout = async (input, init) => {
|
|
98
|
+
if (!timeoutMs) {
|
|
99
|
+
return await (0, import_httpProxyAgent.proxyFetch)(input, init);
|
|
100
|
+
}
|
|
101
|
+
const controller = new AbortController();
|
|
102
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
103
|
+
try {
|
|
104
|
+
return await (0, import_httpProxyAgent.proxyFetch)(input, { ...init, signal: controller.signal });
|
|
105
|
+
} finally {
|
|
106
|
+
clearTimeout(timer);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
94
109
|
if (serverTransport === "httpStreamable") {
|
|
95
110
|
try {
|
|
96
111
|
const transport = new import_streamableHttp.StreamableHTTPClientTransport(endpoint.result, {
|
|
97
112
|
requestInit: { headers },
|
|
98
|
-
fetch:
|
|
113
|
+
fetch: fetchWithTimeout
|
|
99
114
|
});
|
|
100
115
|
await client.connect(transport);
|
|
101
116
|
return (0, import_n8n_workflow.createResultOk)(client);
|
|
@@ -122,7 +137,7 @@ async function connectMcpClient({
|
|
|
122
137
|
try {
|
|
123
138
|
const sseTransport = new import_sse.SSEClientTransport(endpoint.result, {
|
|
124
139
|
eventSourceInit: {
|
|
125
|
-
fetch: async (url, init) => await (
|
|
140
|
+
fetch: async (url, init) => await fetchWithTimeout(url, {
|
|
126
141
|
...init,
|
|
127
142
|
headers: {
|
|
128
143
|
...headers,
|
|
@@ -130,7 +145,7 @@ async function connectMcpClient({
|
|
|
130
145
|
}
|
|
131
146
|
})
|
|
132
147
|
},
|
|
133
|
-
fetch:
|
|
148
|
+
fetch: fetchWithTimeout,
|
|
134
149
|
requestInit: { headers }
|
|
135
150
|
});
|
|
136
151
|
await client.connect(sseTransport);
|
package/dist/shared/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../nodes/shared/utils.ts"],"sourcesContent":["import { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport type { ClientOAuth2TokenData } from '@n8n/client-oauth2';\nimport type {\n\tIExecuteFunctions,\n\tILoadOptionsFunctions,\n\tINode,\n\tISupplyDataFunctions,\n\tResult,\n} from 'n8n-workflow';\nimport { createResultError, createResultOk, NodeOperationError } from 'n8n-workflow';\n\nimport { proxyFetch } from './httpProxyAgent';\n\nimport type { McpAuthenticationOption, McpServerTransport, McpTool } from './types';\n\nexport async function getAllTools(client: Client, cursor?: string): Promise<McpTool[]> {\n\tconst { tools, nextCursor } = await client.listTools({ cursor });\n\n\tif (nextCursor) {\n\t\treturn (tools as McpTool[]).concat(await getAllTools(client, nextCursor));\n\t}\n\n\treturn tools as McpTool[];\n}\n\nfunction safeCreateUrl(url: string, baseUrl?: string | URL): Result<URL, Error> {\n\ttry {\n\t\treturn createResultOk(new URL(url, baseUrl));\n\t} catch (error) {\n\t\treturn createResultError(error);\n\t}\n}\n\nfunction normalizeAndValidateUrl(input: string): Result<URL, Error> {\n\tconst withProtocol = !/^https?:\\/\\//i.test(input) ? `https://${input}` : input;\n\tconst parsedUrl = safeCreateUrl(withProtocol);\n\n\tif (!parsedUrl.ok) {\n\t\treturn createResultError(parsedUrl.error);\n\t}\n\n\treturn parsedUrl;\n}\n\nfunction errorHasCode(error: unknown, code: number): boolean {\n\treturn (\n\t\t!!error &&\n\t\ttypeof error === 'object' &&\n\t\t(('code' in error && Number(error.code) === code) ||\n\t\t\t('message' in error &&\n\t\t\t\ttypeof error.message === 'string' &&\n\t\t\t\terror.message.includes(code.toString())))\n\t);\n}\n\nfunction isUnauthorizedError(error: unknown): boolean {\n\treturn errorHasCode(error, 401);\n}\n\nfunction isForbiddenError(error: unknown): boolean {\n\treturn errorHasCode(error, 403);\n}\n\ntype OnUnauthorizedHandler = (\n\theaders?: Record<string, string>,\n) => Promise<Record<string, string> | null>;\n\ntype ConnectMcpClientError =\n\t| { type: 'invalid_url'; error: Error }\n\t| { type: 'connection'; error: Error }\n\t| { type: 'auth'; error: Error };\n\nexport function mapToNodeOperationError(\n\tnode: INode,\n\terror: ConnectMcpClientError,\n): NodeOperationError {\n\tswitch (error.type) {\n\t\tcase 'invalid_url':\n\t\t\treturn new NodeOperationError(node, error.error, {\n\t\t\t\tmessage: 'Could not connect to your MCP server. The provided URL is invalid.',\n\t\t\t});\n\t\tcase 'auth':\n\t\t\treturn new NodeOperationError(node, error.error, {\n\t\t\t\tmessage: 'Could not connect to your MCP server. Authentication failed.',\n\t\t\t});\n\t\tcase 'connection':\n\t\tdefault:\n\t\t\treturn new NodeOperationError(node, error.error, {\n\t\t\t\tmessage: 'Could not connect to your MCP server',\n\t\t\t});\n\t}\n}\n\nexport async function connectMcpClient({\n\theaders,\n\tserverTransport,\n\tendpointUrl,\n\tname,\n\tversion,\n\tonUnauthorized,\n}: {\n\tserverTransport: McpServerTransport;\n\tendpointUrl: string;\n\theaders?: Record<string, string>;\n\tname: string;\n\tversion: number;\n\tonUnauthorized?: OnUnauthorizedHandler;\n}): Promise<Result<Client, ConnectMcpClientError>> {\n\tconst endpoint = normalizeAndValidateUrl(endpointUrl);\n\n\tif (!endpoint.ok) {\n\t\treturn createResultError({ type: 'invalid_url', error: endpoint.error });\n\t}\n\n\tconst client = new Client({ name, version: version.toString() }, { capabilities: {} });\n\n\tif (serverTransport === 'httpStreamable') {\n\t\ttry {\n\t\t\tconst transport = new StreamableHTTPClientTransport(endpoint.result, {\n\t\t\t\trequestInit: { headers },\n\t\t\t\tfetch: proxyFetch,\n\t\t\t});\n\t\t\tawait client.connect(transport);\n\t\t\treturn createResultOk(client);\n\t\t} catch (error) {\n\t\t\tif (onUnauthorized && isUnauthorizedError(error)) {\n\t\t\t\tconst newHeaders = await onUnauthorized(headers);\n\t\t\t\tif (newHeaders) {\n\t\t\t\t\t// Don't pass `onUnauthorized` to avoid possible infinite recursion\n\t\t\t\t\treturn await connectMcpClient({\n\t\t\t\t\t\theaders: newHeaders,\n\t\t\t\t\t\tserverTransport,\n\t\t\t\t\t\tendpointUrl,\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tversion,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isUnauthorizedError(error) || isForbiddenError(error)) {\n\t\t\t\treturn createResultError({ type: 'auth', error: error as Error });\n\t\t\t} else {\n\t\t\t\treturn createResultError({ type: 'connection', error: error as Error });\n\t\t\t}\n\t\t}\n\t}\n\n\ttry {\n\t\tconst sseTransport = new SSEClientTransport(endpoint.result, {\n\t\t\teventSourceInit: {\n\t\t\t\tfetch: async (url, init) =>\n\t\t\t\t\tawait proxyFetch(url, {\n\t\t\t\t\t\t...init,\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t...headers,\n\t\t\t\t\t\t\tAccept: 'text/event-stream',\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t},\n\t\t\tfetch: proxyFetch,\n\t\t\trequestInit: { headers },\n\t\t});\n\t\tawait client.connect(sseTransport);\n\t\treturn createResultOk(client);\n\t} catch (error) {\n\t\tif (onUnauthorized && isUnauthorizedError(error)) {\n\t\t\tconst newHeaders = await onUnauthorized(headers);\n\t\t\tif (newHeaders) {\n\t\t\t\t// Don't pass `onUnauthorized` to avoid possible infinite recursion\n\t\t\t\treturn await connectMcpClient({\n\t\t\t\t\theaders: newHeaders,\n\t\t\t\t\tserverTransport,\n\t\t\t\t\tendpointUrl,\n\t\t\t\t\tname,\n\t\t\t\t\tversion,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (isUnauthorizedError(error) || isForbiddenError(error)) {\n\t\t\treturn createResultError({ type: 'auth', error: error as Error });\n\t\t} else {\n\t\t\treturn createResultError({ type: 'connection', error: error as Error });\n\t\t}\n\t}\n}\n\nexport async function getAuthHeaders(\n\tctx: Pick<IExecuteFunctions, 'getCredentials'>,\n\tauthentication: McpAuthenticationOption,\n): Promise<{ headers?: Record<string, string> }> {\n\tswitch (authentication) {\n\t\tcase 'headerAuth': {\n\t\t\tconst header = await ctx\n\t\t\t\t.getCredentials<{ name: string; value: string }>('httpHeaderAuth')\n\t\t\t\t.catch(() => null);\n\n\t\t\tif (!header) return {};\n\n\t\t\treturn { headers: { [header.name]: header.value } };\n\t\t}\n\t\tcase 'bearerAuth': {\n\t\t\tconst result = await ctx\n\t\t\t\t.getCredentials<{ token: string }>('httpBearerAuth')\n\t\t\t\t.catch(() => null);\n\n\t\t\tif (!result) return {};\n\n\t\t\treturn { headers: { Authorization: `Bearer ${result.token}` } };\n\t\t}\n\t\tcase 'mcpOAuth2Api': {\n\t\t\tconst result = await ctx\n\t\t\t\t.getCredentials<{ oauthTokenData: { access_token: string } }>('mcpOAuth2Api')\n\t\t\t\t.catch(() => null);\n\n\t\t\tif (!result) return {};\n\n\t\t\treturn { headers: { Authorization: `Bearer ${result.oauthTokenData.access_token}` } };\n\t\t}\n\t\tcase 'multipleHeadersAuth': {\n\t\t\tconst result = await ctx\n\t\t\t\t.getCredentials<{ headers: { values: Array<{ name: string; value: string }> } }>(\n\t\t\t\t\t'httpMultipleHeadersAuth',\n\t\t\t\t)\n\t\t\t\t.catch(() => null);\n\n\t\t\tif (!result) return {};\n\n\t\t\treturn {\n\t\t\t\theaders: result.headers.values.reduce(\n\t\t\t\t\t(acc, cur) => {\n\t\t\t\t\t\tacc[cur.name] = cur.value;\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{} as Record<string, string>,\n\t\t\t\t),\n\t\t\t};\n\t\t}\n\t\tcase 'none':\n\t\tdefault: {\n\t\t\treturn {};\n\t\t}\n\t}\n}\n\n/**\n * Tries to refresh the OAuth2 token, storing them in the database if successful\n * @param ctx - The execution context\n * @param authentication - The authentication method\n * @param headers - The headers to refresh\n * @returns The refreshed headers or null if the authentication method is not oAuth2Api or has failed\n */\nexport async function tryRefreshOAuth2Token(\n\tctx: IExecuteFunctions | ISupplyDataFunctions | ILoadOptionsFunctions,\n\tauthentication: McpAuthenticationOption,\n\theaders?: Record<string, string>,\n) {\n\tif (authentication !== 'mcpOAuth2Api') {\n\t\treturn null;\n\t}\n\n\tlet access_token: string | null = null;\n\ttry {\n\t\tconst result = (await ctx.helpers.refreshOAuth2Token.call(\n\t\t\tctx,\n\t\t\t'mcpOAuth2Api',\n\t\t)) as ClientOAuth2TokenData;\n\t\taccess_token = result?.access_token;\n\t} catch (error) {\n\t\treturn null;\n\t}\n\n\tif (!access_token) {\n\t\treturn null;\n\t}\n\n\tif (!headers) {\n\t\treturn {\n\t\t\tAuthorization: `Bearer ${access_token}`,\n\t\t};\n\t}\n\n\treturn {\n\t\t...headers,\n\t\tAuthorization: `Bearer ${access_token}`,\n\t};\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../nodes/shared/utils.ts"],"sourcesContent":["import { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport type { ClientOAuth2TokenData } from '@n8n/client-oauth2';\nimport type {\n\tIExecuteFunctions,\n\tILoadOptionsFunctions,\n\tINode,\n\tISupplyDataFunctions,\n\tResult,\n} from 'n8n-workflow';\nimport { createResultError, createResultOk, NodeOperationError } from 'n8n-workflow';\n\nimport { proxyFetch } from './httpProxyAgent';\n\nimport type { McpAuthenticationOption, McpServerTransport, McpTool } from './types';\n\nexport async function getAllTools(client: Client, cursor?: string): Promise<McpTool[]> {\n\tconst { tools, nextCursor } = await client.listTools({ cursor });\n\n\tif (nextCursor) {\n\t\treturn (tools as McpTool[]).concat(await getAllTools(client, nextCursor));\n\t}\n\n\treturn tools as McpTool[];\n}\n\nfunction safeCreateUrl(url: string, baseUrl?: string | URL): Result<URL, Error> {\n\ttry {\n\t\treturn createResultOk(new URL(url, baseUrl));\n\t} catch (error) {\n\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\treturn createResultError(err);\n\t}\n}\n\nfunction normalizeAndValidateUrl(input: string): Result<URL, Error> {\n\tconst withProtocol = !/^https?:\\/\\//i.test(input) ? `https://${input}` : input;\n\tconst parsedUrl = safeCreateUrl(withProtocol);\n\n\tif (!parsedUrl.ok) {\n\t\treturn createResultError(parsedUrl.error);\n\t}\n\n\treturn parsedUrl;\n}\n\nfunction errorHasCode(error: unknown, code: number): boolean {\n\treturn (\n\t\t!!error &&\n\t\ttypeof error === 'object' &&\n\t\t(('code' in error && Number(error.code) === code) ||\n\t\t\t('message' in error &&\n\t\t\t\ttypeof error.message === 'string' &&\n\t\t\t\terror.message.includes(code.toString())))\n\t);\n}\n\nfunction isUnauthorizedError(error: unknown): boolean {\n\treturn errorHasCode(error, 401);\n}\n\nfunction isForbiddenError(error: unknown): boolean {\n\treturn errorHasCode(error, 403);\n}\n\ntype OnUnauthorizedHandler = (\n\theaders?: Record<string, string>,\n) => Promise<Record<string, string> | null>;\n\ntype ConnectMcpClientError =\n\t| { type: 'invalid_url'; error: Error }\n\t| { type: 'connection'; error: Error }\n\t| { type: 'auth'; error: Error };\n\nexport function mapToNodeOperationError(\n\tnode: INode,\n\terror: ConnectMcpClientError,\n): NodeOperationError {\n\tswitch (error.type) {\n\t\tcase 'invalid_url':\n\t\t\treturn new NodeOperationError(node, error.error, {\n\t\t\t\tmessage: 'Could not connect to your MCP server. The provided URL is invalid.',\n\t\t\t});\n\t\tcase 'auth':\n\t\t\treturn new NodeOperationError(node, error.error, {\n\t\t\t\tmessage: 'Could not connect to your MCP server. Authentication failed.',\n\t\t\t});\n\t\tcase 'connection':\n\t\tdefault:\n\t\t\treturn new NodeOperationError(node, error.error, {\n\t\t\t\tmessage: 'Could not connect to your MCP server',\n\t\t\t});\n\t}\n}\n\nexport async function connectMcpClient({\n\theaders,\n\tserverTransport,\n\tendpointUrl,\n\tname,\n\tversion,\n\tonUnauthorized,\n connectTimeoutMs,\n}: {\n\tserverTransport: McpServerTransport;\n\tendpointUrl: string;\n\theaders?: Record<string, string>;\n\tname: string;\n\tversion: number;\n\tonUnauthorized?: OnUnauthorizedHandler;\n connectTimeoutMs?: number;\n}): Promise<Result<Client, ConnectMcpClientError>> {\n\tconst endpoint = normalizeAndValidateUrl(endpointUrl);\n\n\tif (!endpoint.ok) {\n\t\treturn createResultError({ type: 'invalid_url', error: endpoint.error });\n\t}\n\n\tconst client = new Client({ name, version: version.toString() }, { capabilities: {} });\n\n\tconst timeoutMs = typeof connectTimeoutMs === 'number' && connectTimeoutMs > 0 ? connectTimeoutMs : undefined;\n\n\t// Wrap proxyFetch with an AbortController-based timeout if specified\n\tconst fetchWithTimeout = async (input: string | URL, init?: RequestInit) => {\n\t\tif (!timeoutMs) {\n\t\t\treturn await proxyFetch(input, init);\n\t\t}\n\t\tconst controller = new AbortController();\n\t\tconst timer = setTimeout(() => controller.abort(), timeoutMs);\n\t\ttry {\n\t\t\treturn await proxyFetch(input, { ...init, signal: controller.signal });\n\t\t} finally {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t};\n\n\tif (serverTransport === 'httpStreamable') {\n\t\ttry {\n\t\t\tconst transport = new StreamableHTTPClientTransport(endpoint.result, {\n\t\t\t\trequestInit: { headers },\n\t\t\t\tfetch: fetchWithTimeout,\n\t\t\t});\n\t\t\tawait client.connect(transport);\n\t\t\treturn createResultOk(client);\n\t\t} catch (error) {\n\t\t\tif (onUnauthorized && isUnauthorizedError(error)) {\n\t\t\t\tconst newHeaders = await onUnauthorized(headers);\n\t\t\t\tif (newHeaders) {\n\t\t\t\t\t// Don't pass `onUnauthorized` to avoid possible infinite recursion\n\t\t\t\t\treturn await connectMcpClient({\n\t\t\t\t\t\theaders: newHeaders,\n\t\t\t\t\t\tserverTransport,\n\t\t\t\t\t\tendpointUrl,\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tversion,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isUnauthorizedError(error) || isForbiddenError(error)) {\n\t\t\t\treturn createResultError({ type: 'auth', error: error as Error });\n\t\t\t} else {\n\t\t\t\treturn createResultError({ type: 'connection', error: error as Error });\n\t\t\t}\n\t\t}\n\t}\n\n\ttry {\n\t\tconst sseTransport = new SSEClientTransport(endpoint.result, {\n\t\t\teventSourceInit: {\n\t\t\t\tfetch: async (url, init) =>\n\t\t\t\t\tawait fetchWithTimeout(url, {\n\t\t\t\t\t\t...init,\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t...headers,\n\t\t\t\t\t\t\tAccept: 'text/event-stream',\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t},\n\t\t\tfetch: fetchWithTimeout,\n\t\t\trequestInit: { headers },\n\t\t});\n\t\tawait client.connect(sseTransport);\n\t\treturn createResultOk(client);\n\t} catch (error) {\n\t\tif (onUnauthorized && isUnauthorizedError(error)) {\n\t\t\tconst newHeaders = await onUnauthorized(headers);\n\t\t\tif (newHeaders) {\n\t\t\t\t// Don't pass `onUnauthorized` to avoid possible infinite recursion\n\t\t\t\treturn await connectMcpClient({\n\t\t\t\t\theaders: newHeaders,\n\t\t\t\t\tserverTransport,\n\t\t\t\t\tendpointUrl,\n\t\t\t\t\tname,\n\t\t\t\t\tversion,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (isUnauthorizedError(error) || isForbiddenError(error)) {\n\t\t\treturn createResultError({ type: 'auth', error: error as Error });\n\t\t} else {\n\t\t\treturn createResultError({ type: 'connection', error: error as Error });\n\t\t}\n\t}\n}\n\nexport async function getAuthHeaders(\n\tctx: Pick<IExecuteFunctions, 'getCredentials'>,\n\tauthentication: McpAuthenticationOption,\n): Promise<{ headers?: Record<string, string> }> {\n\tswitch (authentication) {\n\t\tcase 'headerAuth': {\n\t\t\tconst header = await ctx\n\t\t\t\t.getCredentials<{ name: string; value: string }>('httpHeaderAuth')\n\t\t\t\t.catch(() => null);\n\n\t\t\tif (!header) return {};\n\n\t\t\treturn { headers: { [header.name]: header.value } };\n\t\t}\n\t\tcase 'bearerAuth': {\n\t\t\tconst result = await ctx\n\t\t\t\t.getCredentials<{ token: string }>('httpBearerAuth')\n\t\t\t\t.catch(() => null);\n\n\t\t\tif (!result) return {};\n\n\t\t\treturn { headers: { Authorization: `Bearer ${result.token}` } };\n\t\t}\n\t\tcase 'mcpOAuth2Api': {\n\t\t\tconst result = await ctx\n\t\t\t\t.getCredentials<{ oauthTokenData: { access_token: string } }>('mcpOAuth2Api')\n\t\t\t\t.catch(() => null);\n\n\t\t\tif (!result) return {};\n\n\t\t\treturn { headers: { Authorization: `Bearer ${result.oauthTokenData.access_token}` } };\n\t\t}\n\t\tcase 'multipleHeadersAuth': {\n\t\t\tconst result = await ctx\n\t\t\t\t.getCredentials<{ headers: { values: Array<{ name: string; value: string }> } }>(\n\t\t\t\t\t'httpMultipleHeadersAuth',\n\t\t\t\t)\n\t\t\t\t.catch(() => null);\n\n\t\t\tif (!result) return {};\n\n\t\t\treturn {\n\t\t\t\theaders: result.headers.values.reduce(\n\t\t\t\t\t(acc, cur) => {\n\t\t\t\t\t\tacc[cur.name] = cur.value;\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{} as Record<string, string>,\n\t\t\t\t),\n\t\t\t};\n\t\t}\n\t\tcase 'none':\n\t\tdefault: {\n\t\t\treturn {};\n\t\t}\n\t}\n}\n\n/**\n * Tries to refresh the OAuth2 token, storing them in the database if successful\n * @param ctx - The execution context\n * @param authentication - The authentication method\n * @param headers - The headers to refresh\n * @returns The refreshed headers or null if the authentication method is not oAuth2Api or has failed\n */\nexport async function tryRefreshOAuth2Token(\n\tctx: IExecuteFunctions | ISupplyDataFunctions | ILoadOptionsFunctions,\n\tauthentication: McpAuthenticationOption,\n\theaders?: Record<string, string>,\n) {\n\tif (authentication !== 'mcpOAuth2Api') {\n\t\treturn null;\n\t}\n\n\tlet access_token: string | null = null;\n\ttry {\n\t\tconst result = (await ctx.helpers.refreshOAuth2Token.call(\n\t\t\tctx,\n\t\t\t'mcpOAuth2Api',\n\t\t)) as ClientOAuth2TokenData;\n\t\taccess_token = result?.access_token;\n\t} catch (error) {\n\t\treturn null;\n\t}\n\n\tif (!access_token) {\n\t\treturn null;\n\t}\n\n\tif (!headers) {\n\t\treturn {\n\t\t\tAuthorization: `Bearer ${access_token}`,\n\t\t};\n\t}\n\n\treturn {\n\t\t...headers,\n\t\tAuthorization: `Bearer ${access_token}`,\n\t};\n}\n"],"mappings":"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","names":[]}
|