Skip to main content

Overview

The n8n-MCP validation system provides multi-level configuration validation to catch errors before execution. It supports different validation modes for performance, profiles for strictness levels, and node-specific validators for complex nodes.

Validation Architecture

Two-Tier System

  1. Node Validation - Single node configuration
  2. Workflow Validation - Entire workflow structure
// Node validation
const result = await validate_node({
  nodeType: "nodes-base.slack",
  config: { resource: "message", operation: "send" },
  mode: "full",
  profile: "ai-friendly"
})

// Workflow validation
const workflowResult = await validate_workflow({
  workflow: { nodes: [...], connections: {...} },
  options: {
    validateNodes: true,
    validateConnections: true,
    validateExpressions: true
  }
})

Validation Modes

Minimal Mode

Quick validation checking only required fields. Best for rapid iteration.
{
  "mode": "minimal"
}
What it checks:
  • Missing required properties
  • Null/undefined values for required fields
Response:
{
  "valid": false,
  "missingRequiredFields": ["url", "method"]
}
Use minimal mode when:
  • Building configurations iteratively
  • You want fast feedback
  • Only basic validation is needed
  • Token usage is critical

Full Mode (Default)

Comprehensive validation with errors, warnings, and suggestions.
{
  "mode": "full",
  "profile": "ai-friendly"  // Choose validation strictness
}
What it checks:
  • String properties receive string values
  • Number properties receive numeric values
  • Boolean properties receive true/false
  • Object properties receive valid objects
  • Array properties receive arrays
// Invalid type example
{
  "sendBody": "true"  // ❌ Should be boolean: true
}
  • Options match allowed values
  • Enums contain valid choices
  • Ranges fall within min/max bounds
  • Formats match expected patterns (URLs, emails, etc.)
// Invalid value example
{
  "method": "GETS"  // ❌ Should be "GET", "POST", etc.
}
  • ResourceLocator has mode and value
  • Filter has combinator and conditions
  • FixedCollection uses proper array structure
  • AssignmentCollection has assignments array
// Invalid structure example
{
  "model": "gpt-4"  // ❌ Should be: { mode: "list", value: "gpt-4" }
}
  • Properties match their displayOptions.show conditions
  • Hidden properties aren’t configured unnecessarily
  • Conditional logic evaluates correctly
// Visibility example
{
  "sendBody": false,
  "jsonBody": "{...}"  // ⚠️ Won't be used since sendBody=false
}
  • Hardcoded credentials warnings
  • SQL injection patterns
  • eval/exec usage in code
  • Unsafe URL patterns
// Security warning example
{
  "query": "DELETE FROM users WHERE id = ${userId}"  // ⚠️ SQL injection risk
}

Validation Profiles

Minimal Profile

Only critical errors that would cause immediate failure.
{
  "profile": "minimal"
}
Reports:
  • Missing required fields
  • Critical security issues
  • Deprecated features
Filters out:
  • Warnings
  • Suggestions
  • Best practice advice
  • Property visibility issues
Use minimal profile for:
  • AI agents that need fast responses
  • Iterative development
  • When you’ll validate again later with stricter profile

Runtime Profile

Errors that would cause runtime failures.
{
  "profile": "runtime"
}
Reports:
  • Missing required fields
  • Invalid types that crash at runtime
  • Invalid values that fail validation
  • Critical security issues
Filters out:
  • Property visibility warnings (too noisy)
  • Best practice suggestions
  • Performance tips

AI-Friendly Profile (Default)

Balanced validation optimized for AI agents.
{
  "profile": "ai-friendly"
}
Reports:
  • All errors
  • Security warnings
  • Deprecated features
  • Missing common properties
  • Best practices
Filters out:
  • Internal property warnings
  • Hardcoded credential type warnings (shown only in strict)
Why ai-friendly?
  • Provides helpful context without overwhelming
  • Includes suggestions for fixing issues
  • Balances completeness with readability
  • Optimized for LLM token usage

Strict Profile

Everything including advanced best practices.
{
  "profile": "strict"
}
Reports:
  • Everything from other profiles
  • All best practice violations
  • All security considerations
  • Performance optimization tips
  • Error handling requirements
  • Hardcoded credential warnings
Use strict profile for:
  • Production deployments
  • Security audits
  • Code reviews
  • Comprehensive validation

Validation Response Structure

interface ValidationResult {
  valid: boolean;                    // Overall validity
  
  errors: ValidationError[];         // Must fix
  warnings: ValidationWarning[];     // Should fix
  suggestions: string[];             // Consider
  
  visibleProperties: string[];       // Properties shown with current config
  hiddenProperties: string[];        // Properties hidden
  
  autofix?: Record<string, any>;     // Suggested automatic fixes
  
  summary: {
    hasErrors: boolean;
    errorCount: number;
    warningCount: number;
    suggestionCount: number;
  };
}

Error Types

type ErrorType = 
  | 'missing_required'      // Required property not provided
  | 'invalid_type'          // Wrong type (string vs number)
  | 'invalid_value'         // Value not in allowed options
  | 'invalid_configuration' // Structure doesn't match expected format
  | 'syntax_error'          // Code/expression syntax error
  | 'incompatible';         // Conflicting settings

Warning Types

type WarningType = 
  | 'missing_common'   // Common property not set
  | 'deprecated'       // Using deprecated feature
  | 'inefficient'      // Non-optimal configuration
  | 'security'         // Potential security issue
  | 'best_practice';   // Not following best practices

Node-Specific Validation

Some nodes have custom validation logic for complex configuration patterns.

HTTP Request Validation

private static validateHttpRequest(
  config: Record<string, any>,
  errors: ValidationError[],
  warnings: ValidationWarning[],
  suggestions: string[]
): void {
  // URL validation
  if (config.url && !shouldSkipLiteralValidation(config.url)) {
    if (!config.url.startsWith('http://') && !config.url.startsWith('https://')) {
      errors.push({
        type: 'invalid_value',
        property: 'url',
        message: 'URL must start with http:// or https://',
        fix: 'Add https:// to the beginning of your URL'
      });
    }
  }
  
  // POST without body warning
  if (['POST', 'PUT', 'PATCH'].includes(config.method) && !config.sendBody) {
    warnings.push({
      type: 'missing_common',
      property: 'sendBody',
      message: `${config.method} requests typically send a body`,
      suggestion: 'Set sendBody=true and configure body content'
    });
  }
}

Code Node Validation

private static validateCode(
  config: Record<string, any>,
  errors: ValidationError[],
  warnings: ValidationWarning[]
): void {
  const code = config.jsCode || config.pythonCode;
  
  // Check for return statement
  if (!code.includes('return')) {
    warnings.push({
      type: 'missing_common',
      message: 'No return statement found',
      suggestion: 'Code node must return data: return [{json: {result: "success"}}]'
    });
  }
  
  // Check for proper return format
  if (/return\s+{[^}]+}\s*;/.test(code) && !code.includes('[')) {
    warnings.push({
      type: 'invalid_value',
      message: 'Return value must be an array',
      suggestion: 'Wrap your return object in an array: return [{json: {...}}]'
    });
  }
}

Slack Node Validation

static validateSlack(context: NodeValidationContext): void {
  const { config, errors, warnings } = context;
  
  // Channel validation for message sending
  if (config.resource === 'message' && config.operation === 'send') {
    if (!config.channel && !config.channelId) {
      errors.push({
        type: 'missing_required',
        property: 'channel',
        message: 'Either channel or channelId is required',
        fix: 'Add channel: "#general" or channelId: "C1234567890"'
      });
    }
  }
}

Conditional Validation

The validator supports n8n’s displayOptions including _cnd conditional operators:

Simple Conditions

// Property only visible when operation=send
{
  displayOptions: {
    show: {
      operation: ['send']
    }
  }
}

Advanced Conditions

// Property visible when value >= 10
{
  displayOptions: {
    show: {
      retries: [{ _cnd: { gte: 10 } }]
    }
  }
}
Supported operators:
  • eq - Equals
  • not - Not equals
  • gt - Greater than
  • lt - Less than
  • gte - Greater than or equal
  • lte - Less than or equal
  • between - Between two values
{ _cnd: { gte: 5, lte: 10 } }  // Between 5 and 10
  • startsWith - String starts with
  • endsWith - String ends with
  • includes - String contains
  • regex - Matches regex pattern
{ _cnd: { startsWith: 'https://' } }  // URL check
  • exists - Property has a value
  • notExists - Property is undefined/null
{ _cnd: { exists: true } }  // Must be defined

Complex Type Validation

ResourceLocator

Used by AI model nodes (OpenAI, Anthropic):
// ❌ Invalid - string instead of object
{
  "model": "gpt-4"
}

// ✅ Valid - proper structure
{
  "model": {
    "mode": "list",    // or "id", "url", "name"
    "value": "gpt-4"
  }
}

Filter Type

Used by Filter and If nodes:
// ❌ Invalid - missing combinator
{
  "conditions": [
    { "leftValue": "={{ $json.age }}", "operation": "gt", "rightValue": 18 }
  ]
}

// ✅ Valid - proper structure
{
  "combinator": "and",  // or "or"
  "conditions": [
    {
      "leftValue": "={{ $json.age }}",
      "operation": "largerEqual",
      "rightValue": 18
    }
  ]
}

FixedCollection

Used by nodes with repeating groups (headers, parameters):
// ❌ Invalid - object instead of array
{
  "headers": {
    "parameter": {
      "name": "Authorization",
      "value": "Bearer token"
    }
  }
}

// ✅ Valid - proper array structure
{
  "headers": {
    "parameter": [
      {
        "name": "Authorization",
        "value": "Bearer token"
      },
      {
        "name": "Content-Type",
        "value": "application/json"
      }
    ]
  }
}

Workflow Validation

Validate entire workflows including nodes, connections, and expressions.
const result = await validate_workflow({
  workflow: {
    nodes: [
      {
        id: "webhook",
        type: "n8n-nodes-base.webhook",
        parameters: { path: "test" }
      },
      {
        id: "slack",
        type: "n8n-nodes-base.slack",
        parameters: { resource: "message", operation: "send" }
      }
    ],
    connections: {
      webhook: {
        main: [[{ node: "slack", type: "main", index: 0 }]]
      }
    }
  },
  options: {
    validateNodes: true,
    validateConnections: true,
    validateExpressions: true,
    profile: "runtime"
  }
})
Workflow validation checks:
  • All nodes have valid configurations
  • Required properties are set
  • No type mismatches
  • Proper structure for complex types
  • All connections point to existing nodes
  • Connection types match (main, ai, source)
  • No orphaned nodes (except triggers)
  • No circular dependencies
  • Output indices are valid
  • n8n expression syntax is correct
  • Referenced variables exist
  • No undefined node references
  • Proper use of $json, $node, $workflow

Autofix Suggestions

Some validation errors include automatic fix suggestions:
{
  "valid": false,
  "errors": [
    {
      "type": "invalid_configuration",
      "property": "conditions",
      "message": "Filter must be array with 'values' key"
    }
  ],
  "autofix": {
    "conditions": {
      "values": []  // Corrected structure
    }
  }
}
Apply autofixes carefully: Review suggested fixes before applying them, as they may not match your intended configuration.

Best Practices

Validation Workflow:
  1. Start with mode="minimal" during development
  2. Use profile="ai-friendly" for balanced feedback
  3. Switch to profile="strict" before production
  4. Always validate workflows before deployment
  5. Handle validation errors gracefully in your code

Common Validation Patterns

Iterative Development

// 1. Quick check during building
const quick = await validate_node({
  nodeType: "nodes-base.httpRequest",
  config: { url: "https://api.example.com" },
  mode: "minimal"
})

if (!quick.valid) {
  // Fix required fields
}

// 2. Full validation before saving
const full = await validate_node({
  nodeType: "nodes-base.httpRequest",
  config: completedConfig,
  mode: "full",
  profile: "ai-friendly"
})

Production Deployment

// Strict validation before deploying
const result = await validate_workflow({
  workflow: productionWorkflow,
  options: {
    validateNodes: true,
    validateConnections: true,
    validateExpressions: true,
    profile: "strict"
  }
})

if (!result.valid) {
  console.error('Validation failed:', result.errors)
  throw new Error('Cannot deploy invalid workflow')
}

Next Steps

MCP Tools

Explore all validation tools

Workflows

Learn about workflow validation

Build docs developers (and LLMs) love