Skip to content

Workflow MCP - Intelligent Task Orchestration

Overview

The Workflow MCP uses Claude as an intelligent orchestrator to execute multi-step workflows, make decisions, and coordinate other SimpleMCPs. It's like having an AI assistant that can automate complex tasks by combining multiple tools.

What Makes This Powerful

  1. Claude-Powered Intelligence: Each step can use Claude's reasoning to analyze results and make decisions
  2. Tool Orchestration: Calls other SimpleMCPs as tools (GitHub, Slack, databases, cloud storage, etc.)
  3. Conditional Logic: Steps can execute based on previous results
  4. State Management: Tracks workflow execution and results
  5. Natural Language Workflows: Generate workflows from plain English descriptions

Installation & Configuration

1. Configure Anthropic API Key

json
{
  "mcpServers": {
    "workflow": {
      "type": "internal",
      "env": {
        "ANTHROPIC_API_KEY": "_USE_SECURE_STORAGE_"
      }
    }
  }
}

Get your API key from: https://console.anthropic.com/

2. Verify Installation

bash
ncp find "workflow"

Core Capabilities

1. Execute Predefined Workflows

Run built-in workflows for common tasks:

bash
# Daily standup: GitHub issues → AI summary → Slack
ncp run workflow:execute \
  workflowName="daily-standup" \
  context='{"slackWebhook":"https://hooks.slack.com/...","repo":"owner/repo"}'

# Content pipeline: Scrape → Analyze → Report → Email
ncp run workflow:execute \
  workflowName="content-pipeline" \
  context='{"sourceUrl":"https://...","recipient":"user@example.com"}'

# Data sync: Database backup → S3 upload → Notify
ncp run workflow:execute \
  workflowName="data-sync" \
  context='{"dbPath":"./data.db","s3Bucket":"backups","slackWebhook":"..."}'

2. Execute Custom Workflows

Define and run your own workflows:

bash
ncp run workflow:execute-custom \
  workflow='{
    "name": "content-analyzer",
    "description": "Analyze website content and save insights",
    "steps": [
      {
        "name": "Scrape Website",
        "description": "Extract content from target URL",
        "tool": "scraper:extract",
        "parameters": {"url": "https://example.com"}
      },
      {
        "name": "Analyze with AI",
        "description": "Extract key insights",
        "tool": "ai:complete",
        "parameters": {
          "prompt": "Analyze this content and extract key insights",
          "provider": "anthropic"
        }
      },
      {
        "name": "Save to Database",
        "description": "Store insights in database",
        "tool": "database:insert",
        "parameters": {
          "dbPath": "./insights.db",
          "tableName": "content_insights"
        }
      }
    ]
  }'

3. Execute Intelligent Tasks

Let Claude figure out how to accomplish a task:

bash
# Simple task
ncp run workflow:execute-task \
  task="Summarize the latest trends in AI from Hacker News"

# Task with context
ncp run workflow:execute-task \
  task="Find and summarize GitHub issues about performance" \
  context='{"repo":"facebook/react","daysBack":7}'

# Task with tool restrictions
ncp run workflow:execute-task \
  task="Create a daily report and send it via email" \
  availableTools='["ai:complete","notify:email","database:query"]'

4. Generate Workflows from Natural Language

Describe what you want, get a workflow definition:

bash
ncp run workflow:generate-workflow \
  description="Every morning, check GitHub issues in my repo, summarize them with AI, and post a summary to our team's Slack channel"

# Returns:
{
  "workflow": {
    "name": "morning-github-summary",
    "description": "Daily GitHub issue summary to Slack",
    "steps": [...]
  }
}

# Then execute the generated workflow:
ncp run workflow:execute-custom workflow='<paste-generated-workflow>'

5. Schedule Workflows

Get cron commands for scheduling:

bash
ncp run workflow:schedule \
  workflowName="daily-standup" \
  schedule="0 9 * * 1-5"

# Returns instructions like:
# Add to crontab: 0 9 * * 1-5 ncp run workflow:execute workflowName="daily-standup"

Built-in Workflows

1. Daily Standup (daily-standup)

What it does: Fetches GitHub issues, summarizes with AI, posts to Slack

Required context:

  • slackWebhook - Slack webhook URL
  • repo - GitHub repository (owner/repo)

Example:

bash
ncp run workflow:execute \
  workflowName="daily-standup" \
  context='{
    "slackWebhook": "https://hooks.slack.com/services/...",
    "repo": "anthropics/claude-code"
  }'

Steps:

  1. Fetch open GitHub issues
  2. AI summarizes issues for standup
  3. Post summary to Slack

2. Content Pipeline (content-pipeline)

What it does: Scrapes content, analyzes with AI, generates PDF report, emails results

Required context:

  • sourceUrl - URL to scrape
  • recipient - Email recipient

Example:

bash
ncp run workflow:execute \
  workflowName="content-pipeline" \
  context='{
    "sourceUrl": "https://news.ycombinator.com",
    "recipient": "team@company.com"
  }'

Steps:

  1. Scrape content from URL
  2. AI analyzes content for insights
  3. Generate PDF report
  4. Email report to recipient

3. Data Sync (data-sync)

What it does: Backs up database to S3, notifies on completion

Required context:

  • dbPath - SQLite database path
  • s3Bucket - S3 bucket name
  • slackWebhook - Slack webhook for notifications

Example:

bash
ncp run workflow:execute \
  workflowName="data-sync" \
  context='{
    "dbPath": "./production.db",
    "s3Bucket": "my-backups",
    "slackWebhook": "https://hooks.slack.com/..."
  }'

Steps:

  1. Export database to JSON
  2. Upload to S3
  3. Notify Slack on success

Creating Custom Workflows

Workflow Definition Structure

typescript
{
  "name": "workflow-name",
  "description": "What this workflow does",
  "steps": [
    {
      "name": "Step Name",
      "description": "What this step does",
      "tool": "mcp-name:tool-name",      // Optional: MCP tool to call
      "parameters": {                     // Optional: Tool parameters
        "param1": "value1",
        "param2": "${context.variable}"   // Use context variables
      },
      "condition": "expression"           // Optional: Execute conditionally
    }
  ]
}

Using Context Variables

Access context and previous results in parameters:

json
{
  "parameters": {
    "url": "${context.websiteUrl}",              // From context
    "content": "${previousResults[0].output}",   // From previous step
    "timestamp": "${timestamp}"                   // Built-in variable
  }
}

Conditional Steps

Execute steps based on conditions:

json
{
  "name": "Send Alert",
  "description": "Alert if error count > 10",
  "tool": "notify:slack",
  "parameters": {...},
  "condition": "previousResults[0].output.errorCount > 10"
}

Available SimpleMCP Tools

AI & Analysis

  • ai:complete - Generate text with AI
  • ai:vision - Analyze images
  • ai:similarity - Compare text similarity
  • ai:embed - Generate embeddings

Notifications

  • notify:slack - Send Slack messages
  • notify:discord - Send Discord messages
  • notify:email - Send emails
  • notify:teams - Send Teams messages
  • notify:broadcast - Send to multiple platforms

Data & Storage

  • database:query - Execute SQL queries
  • database:insert - Insert data
  • database:find - Query with filters
  • database:backup - Backup database
  • cloud:s3-upload - Upload to S3
  • cloud:s3-download - Download from S3
  • cloud:gcs-upload - Upload to Google Cloud
  • cloud:azure-upload - Upload to Azure

Web & Scraping

  • scraper:extract - Extract content from URLs
  • scraper:screenshot - Capture screenshots
  • scraper:fill-form - Automate forms
  • scraper:extract-links - Get all links

Documents

  • document:create-pdf - Generate PDFs
  • document:create-excel - Generate spreadsheets
  • document:create-word - Generate Word docs
  • document:parse-csv - Parse CSV files
  • document:create-invoice - Generate invoices

Version Control

  • github:create-issue - Create GitHub issues
  • github:list-issues - List repository issues

Real-World Examples

Example 1: Automated Content Monitoring

Monitor a website and get notified of changes:

json
{
  "name": "content-monitor",
  "description": "Monitor website, detect changes, notify",
  "steps": [
    {
      "name": "Scrape Current Content",
      "tool": "scraper:extract",
      "parameters": {"url": "https://example.com/news"}
    },
    {
      "name": "Compare with Previous",
      "tool": "ai:similarity",
      "parameters": {
        "text1": "${context.previousContent}",
        "text2": "${previousResults[0].output}"
      }
    },
    {
      "name": "Alert on Changes",
      "tool": "notify:slack",
      "parameters": {
        "webhookUrl": "${context.slackWebhook}",
        "text": "Content changed! Similarity: ${previousResults[1].similarity}"
      },
      "condition": "previousResults[1].similarity < 0.9"
    }
  ]
}

Example 2: Data Pipeline

ETL pipeline with AI enrichment:

json
{
  "name": "data-pipeline",
  "description": "Extract, enrich with AI, load to database",
  "steps": [
    {
      "name": "Extract from API",
      "tool": "scraper:extract",
      "parameters": {"url": "https://api.example.com/data"}
    },
    {
      "name": "Enrich with AI",
      "tool": "ai:complete",
      "parameters": {
        "prompt": "Categorize and tag this data: ${previousResults[0].output}",
        "provider": "anthropic"
      }
    },
    {
      "name": "Load to Database",
      "tool": "database:insert",
      "parameters": {
        "dbPath": "./analytics.db",
        "tableName": "enriched_data",
        "data": "${previousResults[1].output}"
      }
    },
    {
      "name": "Generate Report",
      "tool": "document:create-pdf",
      "parameters": {
        "title": "Daily Analytics Report",
        "content": "${previousResults[1].output}"
      }
    }
  ]
}

Example 3: Weekly Team Report

Aggregate data from multiple sources:

json
{
  "name": "weekly-report",
  "description": "Compile weekly team report from GitHub, database, and analytics",
  "steps": [
    {
      "name": "Get GitHub Activity",
      "tool": "github:list-issues",
      "parameters": {"repo": "team/project", "state": "closed"}
    },
    {
      "name": "Query Database Metrics",
      "tool": "database:query",
      "parameters": {
        "dbPath": "./metrics.db",
        "query": "SELECT * FROM weekly_stats WHERE week = '${context.week}'"
      }
    },
    {
      "name": "Synthesize with AI",
      "tool": "ai:complete",
      "parameters": {
        "prompt": "Create executive summary from: GitHub: ${previousResults[0]}, Metrics: ${previousResults[1]}",
        "provider": "anthropic"
      }
    },
    {
      "name": "Create PDF Report",
      "tool": "document:create-report",
      "parameters": {
        "title": "Weekly Team Report",
        "summary": "${previousResults[2].output}",
        "data": "${previousResults[1].output}"
      }
    },
    {
      "name": "Email to Team",
      "tool": "notify:email",
      "parameters": {
        "to": "${context.teamEmail}",
        "subject": "Weekly Report - Week ${context.week}",
        "text": "${previousResults[2].output}"
      }
    }
  ]
}

Scheduling Workflows with NCP Schedule MCP

The Workflow MCP is designed to be invoked by the Schedule MCP for automated execution.

Setup: Schedule MCP + Workflow MCP

Architecture:

  • Schedule MCP - Handles WHEN to run (timing, cron)
  • Workflow MCP - Handles WHAT to run (intelligent task execution)

Step 1: List Available Workflows

bash
ncp run workflow:list-workflows

Returns:

json
{
  "workflows": [
    {
      "name": "daily-standup",
      "description": "Daily standup: Check issues, summarize, post to Slack",
      "requiredContext": ["slackWebhook", "repo"],
      "recommendedSchedule": "0 9 * * 1-5"
    }
  ]
}

Step 2: Add to Schedule MCP

bash
# Schedule daily standup for weekdays at 9am
ncp run schedule:create \
  name="daily-standup" \
  tool="workflow:execute" \
  parameters='{"workflowName":"daily-standup", "context": {"slackWebhook":"https://hooks.slack.com/...", "repo":"owner/repo"}}' \
  schedule="0 9 * * 1-5"

# Schedule content pipeline daily at midnight
ncp run schedule:create \
  name="content-pipeline" \
  tool="workflow:execute" \
  parameters='{"workflowName":"content-pipeline", "context": {"sourceUrl":"https://...", "recipient":"user@example.com"}}' \
  schedule="0 0 * * *"

# Schedule data sync daily at 2am
ncp run schedule:create \
  name="data-sync" \
  tool="workflow:execute" \
  parameters='{"workflowName":"data-sync", "context": {"dbPath":"./data.db", "s3Bucket":"backups", "slackWebhook":"..."}}' \
  schedule="0 2 * * *"

Step 3: Verify Schedule

bash
# List all scheduled tasks
ncp run schedule:list

# Check specific schedule
ncp run schedule:get name="daily-standup"

Step 4: Run Manually (Test Before Scheduling)

Always test your workflow manually first:

bash
# Test the workflow command
ncp run workflow:execute \
  workflowName="daily-standup" \
  context='{"slackWebhook":"https://...","repo":"owner/repo"}'

# If it works, add to schedule

Example: Complete Setup Flow

bash
# 1. Test workflow manually
ncp run workflow:execute \
  workflowName="daily-standup" \
  context='{"slackWebhook":"https://hooks.slack.com/services/T00/B00/XXX","repo":"anthropics/claude-code"}'

# 2. If successful, schedule it
ncp run schedule:create \
  name="team-standup" \
  tool="workflow:execute" \
  parameters='{"workflowName":"daily-standup", "context": {"slackWebhook":"https://hooks.slack.com/services/T00/B00/XXX", "repo":"anthropics/claude-code"}}' \
  schedule="0 9 * * 1-5" \
  description="Daily standup summary posted to Slack"

# 3. Verify it's scheduled
ncp run schedule:list

# 4. Remove if needed
ncp run schedule:delete job_id="team-standup"

Advanced: Multiple Workflows on Different Schedules

bash
# Morning standup
ncp run schedule:create \
  name="morning-standup" \
  tool="workflow:execute" \
  parameters='{"workflowName":"daily-standup", "context": "..."}' \
  schedule="0 9 * * 1-5"

# Hourly content check
ncp run schedule:create \
  name="hourly-content-monitor" \
  tool="workflow:execute-task" \
  parameters='{"task": "Check website for changes and alert if needed", "context": "..."}' \
  schedule="0 * * * *"

# Nightly backup
ncp run schedule:create \
  name="nightly-backup" \
  tool="workflow:execute" \
  parameters='{"workflowName":"data-sync", "context": "..."}' \
  schedule="0 2 * * *"

# Weekly report
ncp run schedule:create \
  name="weekly-report" \
  tool="workflow:execute-custom" \
  parameters='{"workflow": "..."}' \
  schedule="0 9 * * 1"

Advanced Features

Error Handling

Workflows automatically stop on errors and report:

json
{
  "workflowName": "daily-standup",
  "status": "failed",
  "results": [
    {"step": "Fetch Issues", "success": true, "output": {...}},
    {"step": "Summarize", "success": false, "error": "API key invalid"}
  ]
}

Workflow State

Every execution returns complete state:

json
{
  "workflowName": "content-pipeline",
  "currentStep": 3,
  "status": "completed",
  "startTime": "2024-01-15T09:00:00Z",
  "endTime": "2024-01-15T09:02:30Z",
  "results": [
    {
      "step": "Scrape Content",
      "success": true,
      "output": {...},
      "timestamp": "2024-01-15T09:00:15Z"
    },
    // ... more results
  ]
}

Conditional Execution

Steps execute only when conditions are met:

json
{
  "name": "Alert on High Error Rate",
  "tool": "notify:slack",
  "parameters": {...},
  "condition": "previousResults[0].output.errorRate > 0.05"
}

Best Practices

1. Start Simple

Begin with 2-3 steps, add complexity gradually:

json
{
  "steps": [
    {"name": "Fetch data", "tool": "..."},
    {"name": "Process", "tool": "ai:complete"},
    {"name": "Notify", "tool": "notify:slack"}
  ]
}

2. Use Context for Configuration

Pass environment-specific values via context:

bash
# Development
ncp run workflow:execute workflowName="..." context='{"env":"dev","dbPath":"./dev.db"}'

# Production
ncp run workflow:execute workflowName="..." context='{"env":"prod","dbPath":"./prod.db"}'

3. Test Steps Individually

Before creating a workflow, test each tool separately:

bash
# Test scraping
ncp run scraper:extract url="https://example.com"

# Test AI
ncp run ai:complete prompt="Summarize this..." provider="anthropic"

# Then combine in workflow

4. Use Descriptive Names

Make workflows self-documenting:

json
{
  "name": "github-issues-to-slack-summary",
  "description": "Fetch GitHub issues, generate AI summary, post to Slack",
  "steps": [
    {"name": "Fetch Open Issues from Repository", ...},
    {"name": "Generate Natural Language Summary", ...},
    {"name": "Post Summary to Team Channel", ...}
  ]
}

5. Handle Failures Gracefully

Add notification steps with conditions:

json
{
  "name": "Notify on Failure",
  "tool": "notify:slack",
  "parameters": {
    "text": "Workflow failed at step: ${context.failedStep}"
  },
  "condition": "status === 'failed'"
}

Troubleshooting

Workflow Not Executing

  1. Check API key is configured:

    bash
    # Should show ANTHROPIC_API_KEY
    cat ~/.ncp/all.json | grep ANTHROPIC
  2. Verify workflow exists:

    bash
    ncp run workflow:execute workflowName="invalid-name"
    # Shows available workflows

Tool Calls Failing

  1. Ensure tool MCPs are loaded:

    bash
    ncp list  # Should show github, notify, etc.
  2. Check tool parameters match schema:

    bash
    ncp find "github:list-issues"  # Shows required parameters

Context Variables Not Working

Use correct syntax:

  • ${context.variableName} - From context parameter
  • ${previousResults[0].output} - From previous step
  • ${timestamp} - Built-in variables

Summary

The Workflow MCP turns Claude into an intelligent task orchestrator that can:

✅ Execute multi-step workflows with intelligent decision-making ✅ Coordinate multiple SimpleMCPs as tools ✅ Handle conditional logic and error cases ✅ Generate workflows from natural language ✅ Be scheduled for automated recurring tasks

Key Innovation: Claude isn't just executing steps—it's reasoning about the results and making intelligent decisions at each stage.

Start with built-in workflows, then create your own custom automations!

Released under the Elastic License 2.0.