Overview
A workflow in n8n is a directed graph of nodes connected by edges that define the flow of data. The n8n-MCP server provides comprehensive workflow validation to ensure your automation runs correctly.
Workflow Structure
Basic Components
interface Workflow {
nodes : Node []; // Array of node configurations
connections : Connections ; // Connection graph
settings ?: Settings ; // Workflow-level settings
name ?: string ; // Workflow name
active ?: boolean ; // Whether workflow is active
}
Node Structure
interface Node {
id : string ; // Unique node identifier
name : string ; // Display name
type : string ; // Node type (e.g., "n8n-nodes-base.webhook")
typeVersion : number ; // Node type version
position : [ number , number ]; // [x, y] coordinates
parameters : Record < string , any >; // Node configuration
credentials ?: Record < string , any >; // Credential references
disabled ?: boolean ; // Whether node is disabled
}
Example Node:
{
"id" : "webhook-1" ,
"name" : "Webhook Trigger" ,
"type" : "n8n-nodes-base.webhook" ,
"typeVersion" : 1 ,
"position" : [ 250 , 300 ],
"parameters" : {
"path" : "my-webhook" ,
"httpMethod" : "POST" ,
"responseMode" : "onReceived"
}
}
Connection Structure
interface Connections {
[ sourceNodeName : string ] : {
[ outputType : string ] : Connection [][];
};
}
interface Connection {
node : string ; // Target node name
type : string ; // Connection type: "main", "ai", "source"
index : number ; // Output/input index
}
Example Connections:
{
"Webhook Trigger" : {
"main" : [
[
{
"node" : "HTTP Request" ,
"type" : "main" ,
"index" : 0
}
]
]
},
"HTTP Request" : {
"main" : [
[
{
"node" : "Slack" ,
"type" : "main" ,
"index" : 0
}
]
]
}
}
Connection Types:
main - Standard data flow (most common)
ai - AI agent tool connections (LangChain nodes)
source - Source data for AI operations
Workflow Validation
Validation Scope
The validate_workflow tool checks:
All nodes have valid configurations
Required parameters are set
Types match expected values
Complex structures (filter, resourceLocator) are correct
No syntax errors in code nodes
{
"validateNodes" : true // Enable node validation
}
All connections reference existing nodes
Connection types are valid
Output/input indices are within bounds
No orphaned nodes (except triggers)
No circular dependencies
Connection graph is well-formed
{
"validateConnections" : true // Enable connection validation
}
n8n expression syntax is correct (={{ ... }})
Referenced variables exist:
$json - Current item data
$node - Access other node data
$workflow - Workflow metadata
$execution - Execution info
Node references are valid
No undefined variable access
{
"validateExpressions" : true // Enable expression validation
}
Validation Options
interface ValidationOptions {
validateNodes ?: boolean ; // Default: true
validateConnections ?: boolean ; // Default: true
validateExpressions ?: boolean ; // Default: true
profile ?: ValidationProfile ; // "minimal" | "runtime" | "ai-friendly" | "strict"
}
Validation Response
interface WorkflowValidationResult {
valid : boolean ;
summary : {
totalNodes : number ;
enabledNodes : number ;
triggerNodes : number ;
validConnections : number ;
invalidConnections : number ;
expressionsValidated : number ;
errorCount : number ;
warningCount : number ;
};
errors : WorkflowError [];
warnings : WorkflowWarning [];
suggestions : string [];
}
Error Structure:
interface WorkflowError {
node : string ; // Node name where error occurred
message : string ; // Error description
details : string ; // Additional context
}
Common Workflow Patterns
Webhook to API to Notification
{
"nodes" : [
{
"id" : "webhook" ,
"name" : "Webhook" ,
"type" : "n8n-nodes-base.webhook" ,
"parameters" : {
"path" : "contact-form" ,
"httpMethod" : "POST"
}
},
{
"id" : "http" ,
"name" : "Save to CRM" ,
"type" : "n8n-nodes-base.httpRequest" ,
"parameters" : {
"url" : "https://api.crm.com/contacts" ,
"method" : "POST" ,
"sendBody" : true ,
"bodyParameters" : {
"parameters" : [
{
"name" : "email" ,
"value" : "={{ $json.email }}"
}
]
}
}
},
{
"id" : "slack" ,
"name" : "Notify Team" ,
"type" : "n8n-nodes-base.slack" ,
"parameters" : {
"resource" : "message" ,
"operation" : "send" ,
"channel" : "#sales" ,
"text" : "New contact: {{ $json.email }}"
}
}
],
"connections" : {
"Webhook" : {
"main" : [[{ "node" : "Save to CRM" , "type" : "main" , "index" : 0 }]]
},
"Save to CRM" : {
"main" : [[{ "node" : "Notify Team" , "type" : "main" , "index" : 0 }]]
}
}
}
Conditional Branching
{
"nodes" : [
{
"id" : "trigger" ,
"name" : "Schedule" ,
"type" : "n8n-nodes-base.scheduleTrigger"
},
{
"id" : "if" ,
"name" : "Check Time" ,
"type" : "n8n-nodes-base.if" ,
"parameters" : {
"conditions" : {
"values" : [
{
"conditions" : [
{
"leftValue" : "={{ new Date().getHours() }}" ,
"operation" : "largerEqual" ,
"rightValue" : 9
}
]
}
]
}
}
},
{
"id" : "business-hours" ,
"name" : "Business Hours Action" ,
"type" : "n8n-nodes-base.noOp"
},
{
"id" : "after-hours" ,
"name" : "After Hours Action" ,
"type" : "n8n-nodes-base.noOp"
}
],
"connections" : {
"Schedule" : {
"main" : [[{ "node" : "Check Time" , "type" : "main" , "index" : 0 }]]
},
"Check Time" : {
"main" : [
[{ "node" : "Business Hours Action" , "type" : "main" , "index" : 0 }],
[{ "node" : "After Hours Action" , "type" : "main" , "index" : 0 }]
]
}
}
}
If Node Outputs:
Output 0 (first array): True path
Output 1 (second array): False path
Error Handling
{
"nodes" : [
{
"id" : "http" ,
"name" : "API Call" ,
"type" : "n8n-nodes-base.httpRequest" ,
"parameters" : {
"url" : "https://api.example.com/data"
},
"onError" : "continueErrorOutput" ,
"retryOnFail" : true ,
"maxTries" : 3 ,
"waitBetweenTries" : 1000
},
{
"id" : "success" ,
"name" : "Process Success" ,
"type" : "n8n-nodes-base.set"
},
{
"id" : "error-handler" ,
"name" : "Handle Error" ,
"type" : "n8n-nodes-base.set" ,
"parameters" : {
"assignments" : {
"assignments" : [
{
"name" : "error" ,
"value" : "={{ $json.error.message }}"
}
]
}
}
}
],
"connections" : {
"API Call" : {
"main" : [[{ "node" : "Process Success" , "type" : "main" , "index" : 0 }]],
"error" : [[{ "node" : "Handle Error" , "type" : "main" , "index" : 0 }]]
}
}
}
Error Output Configuration:
onError: "continueErrorOutput" - Route errors to error output
onError: "continueRegularOutput" - Continue with empty data
onError: "stopWorkflow" - Stop workflow execution
Connection Types
Main Connections
Standard data flow between nodes:
{
"Source Node" : {
"main" : [
[
{ "node" : "Target Node" , "type" : "main" , "index" : 0 }
]
]
}
}
Multiple Outputs
Nodes like If, Switch have multiple output paths:
{
"If Node" : {
"main" : [
[{ "node" : "True Path" , "type" : "main" , "index" : 0 }],
[{ "node" : "False Path" , "type" : "main" , "index" : 0 }]
]
}
}
AI Connections
LangChain agent connections:
{
"AI Agent" : {
"ai" : [
[
{ "node" : "Tool Node" , "type" : "ai" , "index" : 0 }
]
]
}
}
Workflow Settings
interface Settings {
executionOrder ?: 'v0' | 'v1' ; // Execution order version
saveDataErrorExecution ?: 'all' | 'none' ; // Save error data
saveDataSuccessExecution ?: 'all' | 'none' ; // Save success data
saveManualExecutions ?: boolean ; // Save manual runs
callerPolicy ?: 'workflowsFromSameOwner' | 'any' ; // Who can call
timezone ?: string ; // Workflow timezone
}
Validation Examples
Basic Validation
const result = await validate_workflow ({
workflow: {
nodes: [ ... ],
connections: { ... }
}
})
if ( ! result . valid ) {
console . error ( 'Validation failed:' )
result . errors . forEach ( error => {
console . error ( ` [ ${ error . node } ] ${ error . message } ` )
})
}
Strict Pre-Deployment Validation
const result = await validate_workflow ({
workflow: productionWorkflow ,
options: {
validateNodes: true ,
validateConnections: true ,
validateExpressions: true ,
profile: "strict" // Most thorough validation
}
})
if ( ! result . valid ) {
throw new Error ( `Cannot deploy: ${ result . errors . length } errors found` )
}
// Check warnings too
if ( result . warnings . length > 0 ) {
console . warn ( 'Warnings:' , result . warnings )
}
Expression Validation
const result = await validate_workflow ({
workflow: {
nodes: [
{
name: "Set Node" ,
type: "n8n-nodes-base.set" ,
parameters: {
values: {
string: [
{
name: "email" ,
value: "={{ $json.user.email }}" // Validate this expression
}
]
}
}
}
]
},
options: {
validateExpressions: true
}
})
Common Validation Errors
Missing Node Connection
{
"node" : "HTTP Request" ,
"message" : "Node has no input connection" ,
"details" : "Non-trigger nodes must have at least one input connection"
}
Fix: Connect a trigger or previous node to this node.
Invalid Connection Target
{
"node" : "Webhook" ,
"message" : "Connection references non-existent node 'Slak'" ,
"details" : "Target node 'Slak' not found in workflow"
}
Fix: Correct the node name typo or remove the invalid connection.
Expression Error
{
"node" : "Set Node" ,
"message" : "Invalid expression syntax in parameter 'value'" ,
"details" : "Unclosed bracket in expression: ={{ $json.name"
}
Fix: Close the expression: ={{ $json.name }}
Type Mismatch
{
"node" : "HTTP Request" ,
"message" : "Parameter 'sendBody' must be boolean, got string" ,
"details" : "Expected: true/false, Received: 'true'"
}
Fix: Use boolean value: "sendBody": true not "sendBody": "true"
Best Practices
Workflow Design Guidelines:
Start with a trigger - Every workflow needs an entry point
Use descriptive node names - “Webhook” → “Customer Form Webhook”
Handle errors - Add error outputs and handlers
Validate before deploy - Use strict profile validation
Test expressions - Validate all ={{ }} expressions
Document complex logic - Use Sticky Note nodes for comments
Keep it simple - Break complex workflows into sub-workflows
Avoid circular dependencies - Check connection graph
Workflow Execution Order
v1 (Recommended)
Nodes execute when all required inputs are ready:
{
"settings" : {
"executionOrder" : "v1"
}
}
Benefits:
More intuitive
Better for parallel processing
Handles multiple inputs correctly
v0 (Legacy)
Nodes execute in linear order:
{
"settings" : {
"executionOrder" : "v0"
}
}
Use v1 execution order for new workflows. It provides better handling of complex flows and parallel operations.
Testing Workflows
// 1. Build workflow
const workflow = {
nodes: [ ... ],
connections: { ... }
}
// 2. Validate structure
const validation = await validate_workflow ({ workflow })
if ( ! validation . valid ) {
throw new Error ( 'Invalid workflow structure' )
}
// 3. Validate each node
for ( const node of workflow . nodes ) {
const nodeValidation = await validate_node ({
nodeType: node . type ,
config: node . parameters ,
profile: "strict"
})
if ( ! nodeValidation . valid ) {
console . error ( `Node ${ node . name } is invalid:` , nodeValidation . errors )
}
}
// 4. Deploy with confidence
Next Steps
MCP Tools Learn about workflow validation tools
Validation Deep dive into validation system
Templates Start with pre-built workflows
Node Search Find nodes for your workflow