add_connection
Create a connection between nodes in an n8n workflow by specifying source and target node IDs, their respective handles, and the workflow name.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| source_node_id | Yes | The ID of the source node for the connection | |
| source_node_output_name | Yes | The name of the output handle on the source node (e.g., 'main') | |
| target_node_id | Yes | The ID of the target node for the connection | |
| target_node_input_index | No | The index for the target node's input handle (default: 0) | |
| target_node_input_name | Yes | The name of the input handle on the target node (e.g., 'main') | |
| workflow_name | Yes | The Name of the workflow to add the connection to |
Implementation Reference
- src/tools/connectionManagement.js:79-185 (handler)Main handler function that adds a connection between two nodes in an n8n workflow. Validates compatibility, checks for duplicates, updates the workflow.connections object, and persists changes.const createConnection = async (params) => { try { const { workflowId, sourceNodeId, targetNodeId, sourceOutput = 'main', targetInput = 'main' } = params; logger.info('Creating connection in workflow', { workflowId, sourceNodeId, targetNodeId, sourceOutput, targetInput }); // Load workflow const workflow = await workflowStorage.loadWorkflow(workflowId); if (!workflow) { throw new Error(`Workflow with ID ${workflowId} not found`); } // Verify nodes exist const sourceNode = workflow.nodes.find(node => node.id === sourceNodeId); const targetNode = workflow.nodes.find(node => node.id === targetNodeId); if (!sourceNode) { throw new Error(`Source node with ID ${sourceNodeId} not found`); } if (!targetNode) { throw new Error(`Target node with ID ${targetNodeId} not found`); } // Check for self-connections if (sourceNodeId === targetNodeId) { throw new Error('Cannot create a connection from a node to itself'); } // Verify connection compatibility const isCompatible = await checkConnectionCompatibility(sourceNode, targetNode, sourceOutput, targetInput); if (!isCompatible) { throw new Error(`Connection between ${sourceNode.type} and ${targetNode.type} is not compatible`); } // Initialize connections object if needed if (!workflow.connections) { workflow.connections = {}; } if (!workflow.connections[sourceNodeId]) { workflow.connections[sourceNodeId] = {}; } if (!workflow.connections[sourceNodeId][sourceOutput]) { workflow.connections[sourceNodeId][sourceOutput] = []; } // Check if connection already exists const existingConnection = workflow.connections[sourceNodeId][sourceOutput].find( conn => conn.node === targetNodeId && conn.type === targetInput ); if (existingConnection) { logger.info('Connection already exists, skipping creation', { sourceNodeId, targetNodeId, sourceOutput, targetInput }); return { success: true, workflow, message: 'Connection already exists', alreadyExists: true }; } // Add connection with proper index const connectionsCount = workflow.connections[sourceNodeId][sourceOutput].length; workflow.connections[sourceNodeId][sourceOutput].push({ node: targetNodeId, type: targetInput, index: connectionsCount }); // Update workflow timestamp workflow.updatedAt = new Date().toISOString(); // Save updated workflow to the same file const filePath = workflowId.includes('/') || workflowId.includes('\\') ? workflowId : `${workflowId}.json`; await workflowStorage.saveWorkflow(workflow.id || 'workflow', workflow, filePath); return { success: true, workflow, message: `Connection created from ${sourceNodeId}:${sourceOutput} to ${targetNodeId}:${targetInput}` }; } catch (error) { logger.error('Error creating connection', { error: error.message }); throw new Error(`Failed to create connection: ${error.message}`); } };
- src/tools/connectionManagement.js:412-439 (registration)Registers the MCP tool using createTool, providing description, input schema, and linking to the createConnection handler.const createConnectionTool = createTool( 'Create a connection between two nodes in a workflow', { workflowId: { type: 'string', description: 'ID or path of the workflow to modify' }, sourceNodeId: { type: 'string', description: 'ID of the source node' }, targetNodeId: { type: 'string', description: 'ID of the target node' }, sourceOutput: { type: 'string', description: 'Output name on source node (default: "main")', optional: true }, targetInput: { type: 'string', description: 'Input name on target node (default: "main")', optional: true } }, createConnection );
- Input schema definition for the add_connection tool parameters.workflowId: { type: 'string', description: 'ID or path of the workflow to modify' }, sourceNodeId: { type: 'string', description: 'ID of the source node' }, targetNodeId: { type: 'string', description: 'ID of the target node' }, sourceOutput: { type: 'string', description: 'Output name on source node (default: "main")', optional: true }, targetInput: { type: 'string', description: 'Input name on target node (default: "main")', optional: true } },
- Helper function to validate if a connection between two nodes is compatible before adding it.const checkConnectionCompatibility = async (sourceNode, targetNode, sourceOutput = 'main', targetInput = 'main') => { try { // Get node type definitions const sourceNodeDef = await getNodeTypeDefinition(sourceNode.type); const targetNodeDef = await getNodeTypeDefinition(targetNode.type); if (!sourceNodeDef || !targetNodeDef) { logger.warn('Unable to validate connection compatibility due to missing node definitions', { sourceType: sourceNode.type, targetType: targetNode.type }); // Default to allowing connection if we can't validate return true; } // Check for trigger nodes - triggers can only be source nodes, not target nodes const sourceCategories = new Set(sourceNodeDef.categories || []); const targetCategories = new Set(targetNodeDef.categories || []); if (targetCategories.has('Trigger')) { logger.warn('Invalid connection: Target node is a Trigger node', { targetType: targetNode.type }); return false; } // Additional compatibility checks could be added here based on node definitions // For now, we'll return true for most connections as n8n is quite flexible return true; } catch (error) { logger.error('Error checking connection compatibility', { error: error.message, sourceNode: sourceNode.id, targetNode: targetNode.id }); // Default to allowing connection if we encounter an error during validation return true; } };
- src/tools/__index.js:61-66 (registration)Central registration where connection tools, including createConnectionTool (add_connection), are grouped and exported for MCP use.// Connection management tools const connectionTools = { create: createConnectionTool, remove: removeConnectionTool, removeAll: removeNodeConnectionsTool };