@n8n/n8n-nodes-langchain
Version:

415 lines • 14.2 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var McpClientTool_node_exports = {};
__export(McpClientTool_node_exports, {
McpClientTool: () => McpClientTool
});
module.exports = __toCommonJS(McpClientTool_node_exports);
var import_types = require("@modelcontextprotocol/sdk/types.js");
var import_n8n_workflow = require("n8n-workflow");
var import_logWrapper = require("../../../utils/logWrapper");
var import_sharedFields = require("../../../utils/sharedFields");
var import_loadOptions = require("./loadOptions");
var import_utils = require("./utils");
var import_descriptions = require("../shared/descriptions");
var import_utils2 = require("../shared/utils");
var import_pick = __toESM(require("lodash/pick"));
function getNodeConfig(ctx, itemIndex) {
const node = ctx.getNode();
const authentication = ctx.getNodeParameter(
"authentication",
itemIndex
);
const timeout = ctx.getNodeParameter("options.timeout", itemIndex, 6e4);
let serverTransport;
let endpointUrl;
if (node.typeVersion === 1) {
serverTransport = "sse";
endpointUrl = ctx.getNodeParameter("sseEndpoint", itemIndex);
} else {
serverTransport = ctx.getNodeParameter("serverTransport", itemIndex);
endpointUrl = ctx.getNodeParameter("endpointUrl", itemIndex);
}
const mode = ctx.getNodeParameter("include", itemIndex);
const includeTools = ctx.getNodeParameter("includeTools", itemIndex, []);
const excludeTools = ctx.getNodeParameter("excludeTools", itemIndex, []);
return {
authentication,
timeout,
serverTransport,
endpointUrl,
mode,
includeTools,
excludeTools
};
}
async function connectAndGetTools(ctx, config) {
const node = ctx.getNode();
const { headers } = await (0, import_utils2.getAuthHeaders)(ctx, config.authentication);
const client = await (0, import_utils2.connectMcpClient)({
serverTransport: config.serverTransport,
endpointUrl: config.endpointUrl,
headers,
name: node.type,
version: node.typeVersion,
onUnauthorized: async (headers2) => await (0, import_utils2.tryRefreshOAuth2Token)(ctx, config.authentication, headers2)
});
if (!client.ok) {
return { client, mcpTools: null, error: client.error };
}
const allTools = await (0, import_utils2.getAllTools)(client.result);
const mcpTools = (0, import_utils.getSelectedTools)({
tools: allTools,
mode: config.mode,
includeTools: config.includeTools,
excludeTools: config.excludeTools
});
return { client: client.result, mcpTools, error: null };
}
class McpClientTool {
constructor() {
this.description = {
displayName: "MCP Client Tool",
name: "mcpClientTool",
icon: {
light: "file:../mcp.svg",
dark: "file:../mcp.dark.svg"
},
group: ["output"],
version: [1, 1.1, 1.2],
description: "Connect tools from an MCP Server",
defaults: {
name: "MCP Client"
},
codex: {
categories: ["AI"],
subcategories: {
AI: ["Model Context Protocol", "Tools"]
},
alias: ["Model Context Protocol", "MCP Client"],
resources: {
primaryDocumentation: [
{
url: "https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.toolmcp/"
}
]
}
},
inputs: [],
outputs: [{ type: import_n8n_workflow.NodeConnectionTypes.AiTool, displayName: "Tools" }],
credentials: import_descriptions.credentials,
properties: [
(0, import_sharedFields.getConnectionHintNoticeField)([import_n8n_workflow.NodeConnectionTypes.AiAgent]),
{
displayName: "SSE Endpoint",
name: "sseEndpoint",
type: "string",
description: "SSE Endpoint of your MCP server",
placeholder: "e.g. https://my-mcp-server.ai/sse",
default: "",
required: true,
displayOptions: {
show: {
"@version": [1]
}
}
},
{
displayName: "Endpoint",
name: "endpointUrl",
type: "string",
description: "Endpoint of your MCP server",
placeholder: "e.g. https://my-mcp-server.ai/mcp",
default: "",
required: true,
displayOptions: {
show: {
"@version": [{ _cnd: { gte: 1.1 } }]
}
}
},
(0, import_descriptions.transportSelect)({
defaultOption: "sse",
displayOptions: {
show: {
"@version": [1.1]
}
}
}),
(0, import_descriptions.transportSelect)({
defaultOption: "httpStreamable",
displayOptions: {
show: {
"@version": [{ _cnd: { gte: 1.2 } }]
}
}
}),
{
displayName: "Authentication",
name: "authentication",
type: "options",
options: [
{
name: "Bearer Auth",
value: "bearerAuth"
},
{
name: "Header Auth",
value: "headerAuth"
},
{
name: "None",
value: "none"
}
],
default: "none",
description: "The way to authenticate with your endpoint",
displayOptions: {
show: {
"@version": [{ _cnd: { lt: 1.2 } }]
}
}
},
{
displayName: "Authentication",
name: "authentication",
type: "options",
options: [
{
name: "Bearer Auth",
value: "bearerAuth"
},
{
name: "Header Auth",
value: "headerAuth"
},
{
name: "MCP OAuth2",
value: "mcpOAuth2Api"
},
{
name: "Multiple Headers Auth",
value: "multipleHeadersAuth"
},
{
name: "None",
value: "none"
}
],
default: "none",
description: "The way to authenticate with your endpoint",
displayOptions: {
show: {
"@version": [{ _cnd: { gte: 1.2 } }]
}
}
},
{
displayName: "Credentials",
name: "credentials",
type: "credentials",
default: "",
displayOptions: {
show: {
authentication: ["headerAuth", "bearerAuth", "mcpOAuth2Api", "multipleHeadersAuth"]
}
}
},
{
displayName: "Tools to Include",
name: "include",
type: "options",
description: "How to select the tools you want to be exposed to the AI Agent",
default: "all",
options: [
{
name: "All",
value: "all",
description: "Also include all unchanged fields from the input"
},
{
name: "Selected",
value: "selected",
description: 'Also include the tools listed in the parameter "Tools to Include"'
},
{
name: "All Except",
value: "except",
description: 'Exclude the tools listed in the parameter "Tools to Exclude"'
}
]
},
{
displayName: "Tools to Include",
name: "includeTools",
type: "multiOptions",
default: [],
description: 'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: "getTools",
loadOptionsDependsOn: ["sseEndpoint"]
},
displayOptions: {
show: {
include: ["selected"]
}
}
},
{
displayName: "Tools to Exclude",
name: "excludeTools",
type: "multiOptions",
default: [],
description: 'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: "getTools"
},
displayOptions: {
show: {
include: ["except"]
}
}
},
{
displayName: "Options",
name: "options",
placeholder: "Add Option",
description: "Additional options to add",
type: "collection",
default: {},
options: [
{
displayName: "Timeout",
name: "timeout",
type: "number",
typeOptions: {
minValue: 1
},
default: 6e4,
description: "Time in ms to wait for tool calls to finish"
}
]
}
]
};
this.methods = {
loadOptions: {
getTools: import_loadOptions.getTools
}
};
}
async supplyData(itemIndex) {
const node = this.getNode();
const config = getNodeConfig(this, itemIndex);
const setError = (error2) => {
this.addOutputData(import_n8n_workflow.NodeConnectionTypes.AiTool, itemIndex, error2);
throw error2;
};
const { client, mcpTools, error } = await connectAndGetTools(this, config);
if (error) {
this.logger.error("McpClientTool: Failed to connect to MCP Server", { error });
return setError((0, import_utils2.mapToNodeOperationError)(node, error));
}
this.logger.debug("McpClientTool: Successfully connected to MCP Server");
if (!mcpTools?.length) {
return setError(
new import_n8n_workflow.NodeOperationError(node, "MCP Server returned no tools", {
itemIndex,
description: "Connected successfully to your MCP server but it returned an empty list of tools."
})
);
}
const tools = mcpTools.map(
(tool) => (0, import_logWrapper.logWrapper)(
(0, import_utils.mcpToolToDynamicTool)(
tool,
(0, import_utils.createCallTool)(tool.name, client, config.timeout, (errorMessage) => {
const error2 = new import_n8n_workflow.NodeOperationError(node, errorMessage, { itemIndex });
void this.addOutputData(import_n8n_workflow.NodeConnectionTypes.AiTool, itemIndex, error2);
this.logger.error(`McpClientTool: Tool "${tool.name}" failed to execute`, { error: error2 });
})
),
this
)
);
this.logger.debug(`McpClientTool: Connected to MCP Server with ${tools.length} tools`);
const toolkit = new import_utils.McpToolkit(tools);
return { response: toolkit, closeFunction: async () => await client.close() };
}
async execute() {
const node = this.getNode();
const items = this.getInputData();
const returnData = [];
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
const item = items[itemIndex];
const config = getNodeConfig(this, itemIndex);
const { client, mcpTools, error } = await connectAndGetTools(this, config);
if (error) {
throw new import_n8n_workflow.NodeOperationError(node, error.error, { itemIndex });
}
if (!mcpTools?.length) {
throw new import_n8n_workflow.NodeOperationError(node, "MCP Server returned no tools", { itemIndex });
}
for (const tool of mcpTools) {
if (!item.json.tool || typeof item.json.tool !== "string") {
throw new import_n8n_workflow.NodeOperationError(node, "Tool name not found in item.json.tool or item.tool", {
itemIndex
});
}
const toolName = item.json.tool;
if (toolName === tool.name) {
const { tool: _, ...toolArguments } = item.json;
const schema = tool.inputSchema;
const sanitizedToolArguments = schema.additionalProperties !== true ? (0, import_pick.default)(toolArguments, Object.keys(schema.properties ?? {})) : toolArguments;
const params = {
name: tool.name,
arguments: sanitizedToolArguments
};
const result = await client.callTool(params, import_types.CallToolResultSchema, {
timeout: config.timeout
});
returnData.push({
json: {
response: result.content
},
pairedItem: {
item: itemIndex
}
});
}
}
}
return [returnData];
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
McpClientTool
});
//# sourceMappingURL=McpClientTool.node.js.map