Skip to main content
Glama

validate

Validate workflow structure and check for common issues to ensure proper functionality and reliability.

Instructions

Validate a workflow structure and check for common issues

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
workflowNoThe workflow JSON object to validate
pathNoPath to workflow file to validate
autofixNoAutomatically fix common issues like multiplex mode

Implementation Reference

  • Input schema and definition for the 'validate' MCP tool
      name: 'validate',
      description: 'Validate a workflow structure and check for common issues',
      inputSchema: {
        type: 'object',
        properties: {
          workflow: {
            type: 'object',
            description: 'The workflow JSON object to validate',
          },
          path: {
            type: 'string',
            description: 'Path to workflow file to validate',
          },
          autofix: {
            type: 'boolean',
            description: 'Automatically fix common issues like multiplex mode',
          },
        },
      },
    },
  • MCP server registers all tools (including 'validate') by providing getToolDefinitions() in the list tools handler
    this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: getToolDefinitions(),
    }));
  • ToolHandler switch case for 'validate': handles input args, reads workflow file if path provided, supports autofix, delegates to validateWorkflow
    case 'validate':
      const validatePath = args?.path as string;
      const validateWorkflow = args?.workflow as any;
      const autofix = args?.autofix as boolean;
    
      if (validatePath) {
        const fullPath = path.join(this.workflowsPath, validatePath);
        const content = await fs.readFile(fullPath, 'utf-8');
        const workflow = JSON.parse(content);
    
        if (autofix) {
          const fixed = await autofixWorkflow(workflow);
          if (fixed.changed) {
            await fs.writeFile(fullPath, JSON.stringify(fixed.workflow, null, 2));
            return {
              content: [{
                type: 'text',
                text: `✅ Fixed ${fixed.fixes.length} issues:\n${fixed.fixes.join('\n')}\n\nWorkflow saved!`
              }]
            };
          }
        }
    
        return await validateWorkflow(workflow);
      } else {
        return await validateWorkflow(validateWorkflow);
      }
  • Core validateWorkflow function: performs comprehensive validation of workflow structure, nodes, connections, identifies issues/warnings/recommendations
    export async function validateWorkflow(workflow: any): Promise<any> {
      const issues: string[] = [];
      const warnings: string[] = [];
      const recommendations: string[] = [];
    
      if (!workflow.name) {
        issues.push('Workflow must have a name');
      }
    
      if (!workflow.nodes || !Array.isArray(workflow.nodes)) {
        issues.push('Workflow must have a nodes array');
      } else {
        const nodeIds = new Set();
        let hasTrigger = false;
    
        for (const node of workflow.nodes) {
          if (!node.id) {
            issues.push(`Node missing ID: ${JSON.stringify(node)}`);
          } else if (nodeIds.has(node.id)) {
            issues.push(`Duplicate node ID: ${node.id}`);
          } else {
            nodeIds.add(node.id);
          }
    
          if (!node.type) {
            issues.push(`Node ${node.id} missing type`);
          } else {
            if (node.type.includes('trigger') || node.type.includes('Trigger')) {
              hasTrigger = true;
            }
    
            if (node.type === 'n8n-nodes-base.merge') {
              const mode = node.parameters?.mode;
              const combinationMode = node.parameters?.combinationMode;
    
              if (mode === 'multiplex') {
                issues.push(`⚠️ Node "${node.name}" uses 'multiplex' mode which often outputs empty data.`);
                recommendations.push(`Change "${node.name}" from multiplex to: mode='combine', combinationMode='mergeByPosition'`);
              } else if (mode === 'combine' && !combinationMode) {
                warnings.push(`Node "${node.name}" is missing combinationMode parameter`);
              }
    
              if (workflow.connections) {
                let inputCount = 0;
                for (const [, targets] of Object.entries(workflow.connections)) {
                  const targetList = targets as any;
                  if (targetList.main) {
                    for (const outputs of targetList.main) {
                      if (Array.isArray(outputs)) {
                        for (const connection of outputs) {
                          if (connection.node === node.name || connection.node === node.id) {
                            inputCount++;
                          }
                        }
                      }
                    }
                  }
                }
                if (inputCount < 2) {
                  warnings.push(`Merge node "${node.name}" has only ${inputCount} input(s). Merge nodes need at least 2 inputs.`);
                }
              }
            }
    
            if (node.type === 'n8n-nodes-base.rssFeedRead') {
              if (!node.parameters?.url) {
                issues.push(`RSS node "${node.name}" is missing URL parameter`);
              }
            }
          }
    
          if (!node.position || typeof node.position[0] !== 'number' || typeof node.position[1] !== 'number') {
            warnings.push(`Node ${node.id} has invalid position`);
          }
        }
    
        if (!hasTrigger) {
          warnings.push('Workflow has no trigger node');
        }
      }
    
      if (workflow.connections) {
        for (const [, outputs] of Object.entries(workflow.connections as any)) {
          for (const [, connections] of Object.entries(outputs as any)) {
            for (const connection of connections as any[]) {
              for (const target of connection) {
                if (!workflow.nodes.find((n: any) => n.id === target.node)) {
                  issues.push(`Connection references non-existent node: ${target.node}`);
                }
              }
            }
          }
        }
      }
    
      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify({
              valid: issues.length === 0,
              issues,
              warnings,
              recommendations,
            }, null, 2),
          },
        ],
      };
    }
  • autofixWorkflow helper: automatically fixes common issues like multiplex mode in merge nodes and returns list of fixes applied
    export async function autofixWorkflow(workflow: any): Promise<{changed: boolean, fixes: string[], workflow: any}> {
      const fixes: string[] = [];
      let changed = false;
    
      if (workflow.nodes && Array.isArray(workflow.nodes)) {
        for (const node of workflow.nodes) {
          if (node.type === 'n8n-nodes-base.merge') {
            const mode = node.parameters?.mode;
            const combinationMode = node.parameters?.combinationMode;
    
            if (mode === 'multiplex') {
              node.parameters.mode = 'combine';
              node.parameters.combinationMode = 'mergeByPosition';
              fixes.push(`Fixed "${node.name}": Changed from multiplex to combine mode with mergeByPosition`);
              changed = true;
            }
    
            if (mode === 'combine' && combinationMode === 'multiplex') {
              node.parameters.combinationMode = 'mergeByPosition';
              fixes.push(`Fixed "${node.name}": Changed combinationMode from multiplex to mergeByPosition`);
              changed = true;
            }
    
            if (mode === 'combine' && !combinationMode) {
              node.parameters.combinationMode = 'mergeByPosition';
              fixes.push(`Fixed "${node.name}": Added missing combinationMode: mergeByPosition`);
              changed = true;
            }
          }
        }
      }
    
      return { changed, fixes, workflow };
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden for behavioral disclosure. While 'validate' implies a read-only analysis, the description doesn't clarify whether this tool makes changes (especially with the 'autofix' parameter), what types of issues it checks for, or what happens on failure. For a tool with potential side effects (via autofix) and no annotations, this is insufficient transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that clearly states the tool's purpose. It's appropriately sized for a validation tool and front-loaded with the essential information. There's no wasted verbiage or unnecessary elaboration.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a validation tool with 3 parameters (including a nested object and boolean flag), no annotations, and no output schema, the description is incomplete. It doesn't explain what constitutes valid workflow structure, what common issues are checked, what the output looks like, or how autofix interacts with validation. The description should provide more context about the tool's behavior and results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all parameters are documented in the schema. The description adds no additional parameter information beyond what's in the schema (workflow object, file path, autofix boolean). This meets the baseline of 3 for high schema coverage, but doesn't provide extra context about parameter relationships or usage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose with a specific verb ('validate') and resource ('workflow structure'), and mentions checking for common issues. It distinguishes from siblings like 'analyze' or 'compile' by focusing on validation rather than analysis or transformation. However, it doesn't explicitly differentiate from all possible alternatives, keeping it at a 4 rather than a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. With siblings like 'analyze', 'compile', and 'execute' that might overlap in workflow-related contexts, there's no indication of when validation is appropriate versus other operations. The description only states what the tool does, not when to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

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/mckinleymedia/mcflow-mcp'

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