UNPKG

n8n-nodes-mcp-flex

Version:

Enhanced MCP nodes for n8n with flexible parameter handling and improved AI Agent integration

264 lines (263 loc) 9.68 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.McpClient = void 0; const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js"); const n8n_workflow_1 = require("n8n-workflow"); class McpClient { constructor() { this.description = { displayName: 'MCP Client Flex', name: 'mcpClient', icon: 'fa:exchange-alt', group: ['input'], version: 1, subtitle: '={{$parameter["operation"]}}', description: 'Interact with Model Context Protocol (MCP) servers with flexible parameter handling', defaults: { name: 'MCP Client', }, inputs: ["main" /* NodeConnectionType.Main */], outputs: ["main" /* NodeConnectionType.Main */], credentials: [ { name: 'mcpClientApi', required: true, }, ], properties: [ { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, options: [ { name: 'Call Tool', value: 'callTool', action: 'Call a tool', }, ], default: 'callTool', }, { displayName: 'Tool Name', name: 'toolName', type: 'string', required: true, default: '', description: 'Name of the tool to call', }, { displayName: 'Parameter Mode', name: 'parameterMode', type: 'options', options: [ { name: 'JSON String (Original)', value: 'json', }, { name: 'Individual Fields', value: 'fields', }, { name: 'Auto (Try Fields First)', value: 'auto', }, ], default: 'auto', description: 'How to provide parameters to the tool', }, { displayName: 'Parameters (JSON)', name: 'parameters', type: 'json', default: '{}', displayOptions: { show: { parameterMode: ['json', 'auto'], }, }, description: 'Parameters to pass to the tool as JSON object', }, { displayName: 'Calendar Href', name: 'calendarHref', type: 'string', default: '', displayOptions: { show: { parameterMode: ['fields', 'auto'], }, }, description: 'Calendar href parameter', }, { displayName: 'Summary/Title', name: 'summary', type: 'string', default: '', displayOptions: { show: { parameterMode: ['fields', 'auto'], }, }, description: 'Event summary or title', }, { displayName: 'Start DateTime', name: 'startDateTime', type: 'string', default: '', displayOptions: { show: { parameterMode: ['fields', 'auto'], }, }, description: 'Start date and time (ISO format)', }, { displayName: 'End DateTime', name: 'endDateTime', type: 'string', default: '', displayOptions: { show: { parameterMode: ['fields', 'auto'], }, }, description: 'End date and time (ISO format)', }, { displayName: 'Description', name: 'description', type: 'string', default: '', displayOptions: { show: { parameterMode: ['fields', 'auto'], }, }, description: 'Event description', }, { displayName: 'Location', name: 'location', type: 'string', default: '', displayOptions: { show: { parameterMode: ['fields', 'auto'], }, }, description: 'Event location', }, ], }; } buildToolParameters(context, itemIndex) { const mode = context.getNodeParameter('parameterMode', itemIndex, 'auto'); // Individual Fields Mode if (mode === 'fields') { const result = {}; const fieldMapping = { 'calendarHref': 'calendar_href', 'summary': 'summary', 'startDateTime': 'start', 'endDateTime': 'end', 'description': 'description', 'location': 'location' }; Object.keys(fieldMapping).forEach(key => { const value = context.getNodeParameter(key, itemIndex, ''); if (value && value.trim() !== '') { result[fieldMapping[key]] = value; } }); return result; } // JSON Mode if (mode === 'json') { return context.getNodeParameter('parameters', itemIndex, {}); } // Auto Mode - Try individual fields first, fallback to JSON const individualParams = this.buildToolParameters(context, itemIndex); if (Object.keys(individualParams).length > 0) { return individualParams; } return context.getNodeParameter('parameters', itemIndex, {}); } async createMcpClient(credentials) { const client = new index_js_1.Client({ name: 'n8n-mcp-client-flex', version: '0.1.0' }, { capabilities: {} }); let transport; if (credentials.serverUrl) { // HTTP Transport transport = { start: async () => { }, close: async () => { }, send: async (request) => { const response = await fetch(credentials.serverUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', ...(credentials.apiKey && { 'Authorization': `Bearer ${credentials.apiKey}` }) }, body: JSON.stringify(request) }); return response.json(); } }; } else { throw new n8n_workflow_1.NodeOperationError({}, 'No valid transport configuration found'); } await client.connect(transport); return client; } async execute() { const context = this; const items = context.getInputData(); const returnData = []; const credentials = await context.getCredentials('mcpClientApi'); for (let itemIndex = 0; itemIndex < items.length; itemIndex++) { try { const toolName = context.getNodeParameter('toolName', itemIndex); const toolParameters = this.buildToolParameters(context, itemIndex); const client = await this.createMcpClient(credentials); const result = await client.callTool({ name: toolName, arguments: toolParameters }); await client.close(); returnData.push({ json: { toolName, parameters: toolParameters, result: result.content || {} } }); } catch (error) { if (context.continueOnFail()) { returnData.push({ json: { error: error.message }, pairedItem: { item: itemIndex } }); continue; } throw error; } } return [returnData]; } } exports.McpClient = McpClient;