Skip to main content
Glama

n8n-MCP

by 88-888
bridge.tsβ€’4.31 kB
import { INodeExecutionData, IDataObject } from 'n8n-workflow'; export class N8NMCPBridge { /** * Convert n8n workflow data to MCP tool arguments */ static n8nToMCPToolArgs(data: IDataObject): any { // Handle different data formats from n8n if (data.json) { return data.json; } // Remove n8n-specific metadata const { pairedItem, ...cleanData } = data; return cleanData; } /** * Convert MCP tool response to n8n execution data */ static mcpToN8NExecutionData(mcpResponse: any, itemIndex: number = 0): INodeExecutionData { // Handle MCP content array format if (mcpResponse.content && Array.isArray(mcpResponse.content)) { const textContent = mcpResponse.content .filter((c: any) => c.type === 'text') .map((c: any) => c.text) .join('\n'); try { // Try to parse as JSON if possible const parsed = JSON.parse(textContent); return { json: parsed, pairedItem: itemIndex, }; } catch { // Return as text if not JSON return { json: { result: textContent }, pairedItem: itemIndex, }; } } // Handle direct object response return { json: mcpResponse, pairedItem: itemIndex, }; } /** * Convert n8n workflow definition to MCP-compatible format */ static n8nWorkflowToMCP(workflow: any): any { return { id: workflow.id, name: workflow.name, description: workflow.description || '', nodes: workflow.nodes?.map((node: any) => ({ id: node.id, type: node.type, name: node.name, parameters: node.parameters, position: node.position, })), connections: workflow.connections, settings: workflow.settings, metadata: { createdAt: workflow.createdAt, updatedAt: workflow.updatedAt, active: workflow.active, }, }; } /** * Convert MCP workflow format to n8n-compatible format */ static mcpToN8NWorkflow(mcpWorkflow: any): any { return { name: mcpWorkflow.name, nodes: mcpWorkflow.nodes || [], connections: mcpWorkflow.connections || {}, settings: mcpWorkflow.settings || { executionOrder: 'v1', }, staticData: null, pinData: {}, }; } /** * Convert n8n execution data to MCP resource format */ static n8nExecutionToMCPResource(execution: any): any { return { uri: `execution://${execution.id}`, name: `Execution ${execution.id}`, description: `Workflow: ${execution.workflowData?.name || 'Unknown'}`, mimeType: 'application/json', data: { id: execution.id, workflowId: execution.workflowId, status: execution.finished ? 'completed' : execution.stoppedAt ? 'stopped' : 'running', mode: execution.mode, startedAt: execution.startedAt, stoppedAt: execution.stoppedAt, error: execution.data?.resultData?.error, executionData: execution.data, }, }; } /** * Convert MCP prompt arguments to n8n-compatible format */ static mcpPromptArgsToN8N(promptArgs: any): IDataObject { return { prompt: promptArgs.name || '', arguments: promptArgs.arguments || {}, messages: promptArgs.messages || [], }; } /** * Validate and sanitize data before conversion */ static sanitizeData(data: any): any { if (data === null || data === undefined) { return {}; } if (typeof data !== 'object') { return { value: data }; } // Remove circular references const seen = new WeakSet(); return JSON.parse(JSON.stringify(data, (_key, value) => { if (typeof value === 'object' && value !== null) { if (seen.has(value)) { return '[Circular]'; } seen.add(value); } return value; })); } /** * Extract error information for both n8n and MCP formats */ static formatError(error: any): any { return { message: error.message || 'Unknown error', type: error.name || 'Error', stack: error.stack, details: { code: error.code, statusCode: error.statusCode, data: error.data, }, }; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/88-888/n8n-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server