Skip to main content

Workflow Authoring

Create multi-step workflows to test realistic usage patterns of your MCP servers.

When to Use Workflows

Workflows are useful when:

  • Testing multi-step operations (CRUD, transactions)
  • Verifying data flows between tools
  • Testing authentication flows
  • Validating state changes

Creating a Workflow

Create a file with .workflow.yaml extension:

# create-read-delete.workflow.yaml
id: crud_flow
name: CRUD Operations
description: Test create, read, update, delete cycle
expectedOutcome: Resource lifecycle works correctly
steps:
- tool: create_resource
description: Create new resource
args:
name: "Test Resource"
assertions:
- path: "$.id"
condition: exists

- tool: read_resource
description: Read created resource
argMapping:
id: "$steps[0].result.id"
assertions:
- path: "$.name"
condition: equals
value: "Test Resource"

- tool: delete_resource
description: Clean up
argMapping:
id: "$steps[0].result.id"
optional: true

Step Configuration

Static Arguments

- tool: create_file
args:
path: /tmp/test.txt
content: "Hello, World!"

Dynamic Arguments (Argument Mapping)

Pass data from previous steps:

- tool: get_user
argMapping:
id: "$steps[0].result.user_id"

Combined Arguments

- tool: update_user
args:
status: "active"
argMapping:
id: "$steps[0].result.user_id"

JSONPath Reference

ExpressionDescription
$steps[0].resultFirst step's result
$steps[0].result.idid field from first step
$steps[1].result.items[0]First item from second step's array
$steps[0].result.users[*].idAll user IDs

Assertions

Verify step results:

assertions:
# Check existence
- path: "$.data"
condition: exists
message: Response should include data

# Check value
- path: "$.status"
condition: equals
value: "active"

# Check type
- path: "$.items"
condition: type
value: array

# Check content
- path: "$.message"
condition: contains
value: "success"

# Check truthiness
- path: "$.authenticated"
condition: truthy

Assertion Conditions

ConditionDescription
existsValue is present
truthyValue is truthy
equalsExact match
containsContains substring
typeType check

Workflow Patterns

Authentication Flow

id: auth_flow
name: Authentication Flow
steps:
- tool: login
args:
username: testuser
password: ${TEST_PASSWORD}
assertions:
- path: "$.token"
condition: exists

- tool: get_profile
argMapping:
auth_token: "$steps[0].result.token"
assertions:
- path: "$.email"
condition: exists

- tool: logout
argMapping:
auth_token: "$steps[0].result.token"

Data Pipeline

id: data_pipeline
name: Data Pipeline
steps:
- tool: fetch_data
args:
source: "api"
assertions:
- path: "$.data"
condition: type
value: array

- tool: transform_data
argMapping:
input: "$steps[0].result.data"
args:
format: "csv"

- tool: store_data
argMapping:
data: "$steps[1].result.output"
args:
destination: "processed"

Error Recovery

id: error_recovery
name: Error Recovery Flow
steps:
- tool: risky_operation
assertions:
- path: "$.success"
condition: truthy

- tool: verify_state
optional: true # Continue even if fails

- tool: cleanup
optional: true

Environment Variables

Workflow arguments are treated as literal values. Keep secrets in bellwether.yaml under server.env instead of embedding them in workflow files.

Running Workflows

Workflows are available in both check and explore modes. Configure them in bellwether.yaml and run the command normally.

# bellwether.yaml
workflows:
path: "./bellwether-workflows.yaml"
trackState: true
bellwether check

Best Practices

1. Descriptive Step Names

# Good
- tool: create_user
description: Create test user for order workflow

# Bad
- tool: create_user
description: Step 1

2. Meaningful Assertions

# Good
assertions:
- path: "$.order.status"
condition: equals
value: "confirmed"
message: Order should be confirmed after payment

# Bad
assertions:
- path: "$.status"
condition: exists

3. Clean Up Resources

- tool: delete_test_data
description: Clean up test resources
optional: true

4. Keep Focused

One workflow = one user journey:

  • user_registration.workflow.yaml
  • password_reset.workflow.yaml
  • checkout.workflow.yaml

Troubleshooting

"Tool not found"

  • Verify tool name matches exactly (case-sensitive)
  • Run bellwether discover npx server to see available tools

"argMapping failed"

  • Check JSONPath syntax
  • Ensure referenced step has completed
  • Verify path exists in step result

"Assertion failed"

  • Check JSONPath syntax
  • Enable logging.level: debug in bellwether.yaml to see actual response
  • Verify expected value matches response format

See Also