Skip to main content
Glama

relay_workflow_validate

Validate workflow structure by checking DAG cycles, dependency references, and model ID format without LLM calls to ensure proper configuration before execution.

Instructions

Validate workflow structure without making any LLM calls (free). Checks DAG structure (no cycles), dependency references, and model ID format. Does NOT validate schema compatibility between steps or prompt effectiveness - use relay_workflow_run for full validation.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
stepsYesSteps to validate (same format as relay_workflow_run)

Implementation Reference

  • The core handler function implementing the relay_workflow_validate tool. Validates workflow steps for duplicates, model/prompt consistency, dependency existence and cycles, MCP format, and computes execution order and parallel groups.
    export async function relayWorkflowValidate(
      input: RelayWorkflowValidateInput
    ): Promise<RelayWorkflowValidateResponse> {
      const errors: ValidationError[] = [];
      const warnings: ValidationWarning[] = [];
      const stepNames = new Set(input.steps.map(s => s.name));
    
      // Check for duplicate step names
      const nameCount = new Map<string, number>();
      for (const step of input.steps) {
        nameCount.set(step.name, (nameCount.get(step.name) || 0) + 1);
      }
      for (const [name, count] of nameCount) {
        if (count > 1) {
          errors.push({
            step: name,
            field: 'name',
            message: `Duplicate step name: "${name}" appears ${count} times`,
          });
        }
      }
    
      // Validate each step
      for (const step of input.steps) {
        // Check step name
        if (!step.name || step.name.trim() === '') {
          errors.push({
            step: '(unnamed)',
            field: 'name',
            message: 'Step name is required',
          });
          continue;
        }
    
        // Check for valid step configuration
        const hasModel = !!step.model;
        const hasPrompt = !!step.prompt;
        const hasMcp = !!step.mcp;
    
        if (hasModel && !hasPrompt) {
          errors.push({
            step: step.name,
            field: 'prompt',
            message: 'Steps with a model must have a prompt',
          });
        }
    
        if (hasPrompt && !hasModel) {
          errors.push({
            step: step.name,
            field: 'model',
            message: 'Steps with a prompt must have a model',
          });
        }
    
        if (!hasModel && !hasMcp) {
          warnings.push({
            step: step.name,
            message: 'Step has no model or MCP tool - it will be a pass-through step',
          });
        }
    
        // Validate model format
        if (hasModel) {
          if (!isValidModelFormat(step.model!)) {
            errors.push({
              step: step.name,
              field: 'model',
              message: `Invalid model format: "${step.model}". Expected "provider:model-id" (e.g., "openai:gpt-4o")`,
            });
          } else if (!isKnownModel(step.model!)) {
            warnings.push({
              step: step.name,
              message: `Unknown model "${step.model}" - using default pricing estimate`,
            });
          }
        }
    
        // Validate MCP format
        if (hasMcp) {
          const parts = step.mcp!.split(':');
          if (parts.length !== 2) {
            errors.push({
              step: step.name,
              field: 'mcp',
              message: `Invalid MCP tool format: "${step.mcp}". Expected "server:tool" (e.g., "crm:search")`,
            });
          }
        }
    
        // Validate dependencies exist
        if (step.depends) {
          for (const dep of step.depends) {
            if (!stepNames.has(dep)) {
              errors.push({
                step: step.name,
                field: 'depends',
                message: `Dependency "${dep}" not found in workflow steps`,
              });
            }
            if (dep === step.name) {
              errors.push({
                step: step.name,
                field: 'depends',
                message: 'Step cannot depend on itself',
              });
            }
          }
        }
      }
    
      // Check for cycles
      const { order, hasCycle, cycleStep } = topologicalSort(input.steps);
    
      if (hasCycle) {
        errors.push({
          step: cycleStep || '(unknown)',
          field: 'depends',
          message: `Circular dependency detected involving step: ${cycleStep}`,
        });
      }
    
      // Calculate parallel groups
      const parallelGroups = hasCycle ? [] : calculateParallelGroups(input.steps);
    
      return {
        valid: errors.length === 0,
        errors,
        warnings,
        structure: {
          totalSteps: input.steps.length,
          executionOrder: hasCycle ? [] : order,
          parallelGroups,
        },
      };
    }
  • Zod schema for input validation of the tool, defining structure for workflow steps.
    const workflowStepSchema = z.object({
      name: z.string(),
      model: z.string().optional(),
      prompt: z.string().optional(),
      systemPrompt: z.string().optional(),
      depends: z.array(z.string()).optional(),
      mcp: z.string().optional(),
      params: z.object({}).passthrough().optional(),
      schema: z.object({}).passthrough().optional(),
    });
    
    export const relayWorkflowValidateSchema = z.object({
      steps: z.array(workflowStepSchema).describe('Steps to validate (same format as relay_workflow_run)'),
    });
  • MCP tool definition including name, description, and input schema for registration.
    export const relayWorkflowValidateDefinition = {
      name: 'relay_workflow_validate',
      description:
        'Validate workflow structure without making any LLM calls (free). Checks DAG structure (no cycles), dependency references, and model ID format. Does NOT validate schema compatibility between steps or prompt effectiveness - use relay_workflow_run for full validation.',
      inputSchema: {
        type: 'object' as const,
        properties: {
          steps: {
            type: 'array',
            description: 'Steps to validate (same format as relay_workflow_run)',
            items: {
              type: 'object',
              properties: {
                name: { type: 'string' },
                model: { type: 'string' },
                prompt: { type: 'string' },
                systemPrompt: { type: 'string' },
                depends: { type: 'array', items: { type: 'string' } },
                mcp: { type: 'string' },
                params: { type: 'object' },
                schema: { type: 'object' },
              },
              required: ['name'],
            },
          },
        },
        required: ['steps'],
      },
    };
  • src/server.ts:59-67 (registration)
    Registration of all tool definitions, including relayWorkflowValidateDefinition, used in listTools response.
    const TOOLS = [
      relayModelsListDefinition,
      relayRunDefinition,
      relayWorkflowRunDefinition,
      relayWorkflowValidateDefinition,
      relaySkillsListDefinition,
      relayRunsListDefinition,
      relayRunGetDefinition,
    ];
  • src/server.ts:124-127 (registration)
    Dispatch handler in callToolRequest that parses input with schema and invokes the relayWorkflowValidate function.
    case 'relay_workflow_validate': {
      const parsed = relayWorkflowValidateSchema.parse(args);
      result = await relayWorkflowValidate(parsed);
      break;
Behavior4/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It effectively describes key traits: it's a validation-only operation ('validate workflow structure'), has no cost ('free'), avoids LLM calls, and specifies what checks are performed and omitted. However, it doesn't mention error handling, response format, or performance characteristics, leaving some gaps.

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 front-loaded with the core purpose, followed by specific checks and exclusions, all in two efficient sentences with zero wasted words. Each sentence earns its place by clarifying scope and usage.

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

Completeness4/5

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

Given the tool's complexity (validation with specific checks), no annotations, and no output schema, the description is largely complete for guiding usage. It covers purpose, limitations, and alternatives well. However, it lacks details on output format or error responses, which could be useful for a validation tool.

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%, with the single parameter 'steps' well-documented in the schema. The description adds minimal value beyond the schema by referencing 'same format as relay_workflow_run', which provides context but no additional semantic details. This meets the baseline of 3 for high schema coverage.

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

Purpose5/5

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

The description clearly states the specific action ('validate workflow structure') and resource ('workflow'), distinguishing it from siblings by explicitly contrasting with 'relay_workflow_run' for full validation. It specifies what is checked (DAG structure, dependency references, model ID format) and what is not (schema compatibility, prompt effectiveness), providing precise scope.

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

Usage Guidelines5/5

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

The description explicitly states when to use this tool ('validate workflow structure without making any LLM calls (free)') and when not to ('Does NOT validate schema compatibility between steps or prompt effectiveness'), with a clear alternative named ('use relay_workflow_run for full validation'). This provides complete guidance on tool selection.

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/RelayPlane/mcp-server'

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