TestMesh
Features

MCP Integration

Use the Model Context Protocol to embed AI reasoning directly in test flows — for intelligent assertions, dynamic test data, error analysis, and natural language validation.

Model Context Protocol (MCP) is an open protocol by Anthropic that enables AI assistants to securely connect to external tools and data sources. TestMesh supports two directions of MCP integration:

  1. mcp_call action — Call an MCP server from within a flow step (AI as a test step)
  2. testmesh mcp command — Expose TestMesh itself as an MCP server for use with Claude Code, Cursor, and other MCP clients

The mcp Action

Use AI reasoning inline within your test flows for intelligent validation, data extraction, and dynamic decision making.

Basic Usage

- id: ai_analysis
  action: mcp
  config:
    server: "claude"
    prompt: |
      Analyze this API response and determine if it's valid:
      ${api_response.body}

      Check for:
      1. Required fields are present
      2. Data types are correct
      3. Values are reasonable

      Return JSON with: {valid: boolean, issues: string[]}

    response_format: "json"
    model: "claude-sonnet-4-5"
    temperature: 0

  output:
    is_valid: "response.valid"
    issues: "response.issues"

  assert:
    - response.valid == true

MCP Action Configuration

- id: mcp_step
  action: mcp
  config:
    server: string           # Required: "claude" or custom server name
    prompt: string           # Required: instruction for the AI
    context:                 # Optional data/files for the AI to access
      - type: "text"
        content: string
      - type: "file"
        path: string
      - type: "data"
        data: object
    tools: array             # Optional tools the AI can call
    response_format: "json"  # "json", "text", or "structured"
    model: string
    max_tokens: number       # Default: 4000
    temperature: number      # 0 = deterministic, 0.7 = creative
    conversation_id: string  # Continue a multi-turn conversation
    cache_prompt: boolean    # Cache large context (cheaper + faster)
    cache_ttl: duration
    timeout: duration

Server Configuration

Configure MCP servers in .testmesh.yaml:

.testmesh.yaml
mcp:
  servers:
    - name: "claude"
      type: "anthropic"
      config:
        api_key: "${ANTHROPIC_API_KEY}"
        model: "claude-sonnet-4-5"
        max_tokens: 4000
        temperature: 0

    - name: "claude-opus"
      type: "anthropic"
      config:
        api_key: "${ANTHROPIC_API_KEY}"
        model: "claude-opus-4-6"
        max_tokens: 8000

    - name: "custom-analyzer"
      type: "custom"
      config:
        url: "http://localhost:5016/mcp"
        auth:
          type: "bearer"
          token: "${CUSTOM_MCP_TOKEN}"

  settings:
    timeout: "30s"
    cache_enabled: true
    retry_attempts: 3
    log_prompts: true

Use Cases

Natural Language Assertions

Write validation rules in plain English instead of complex JSONPath:

- id: verify_response
  action: mcp
  config:
    server: "claude"
    prompt: |
      Check if this API response is valid:
      ${api_response.body}

      Requirements:
      - User must have an email address
      - User must be over 18 years old
      - Account must be verified
      - No error fields should be present

      Return JSON: {valid: boolean, reason: string}

    response_format: "json"

  assert:
    - response.valid == true

Intelligent Data Extraction

Extract structured data from unstructured or complex responses:

- id: extract_data
  action: mcp
  config:
    server: "claude"
    prompt: |
      Extract user information from this API response:
      ${scrape_api.response.body}

      Return JSON with:
      {
        "full_name": "first and last name combined",
        "email": "email address",
        "phone": "phone number in E.164 format",
        "age": "calculated from birthday",
        "is_active": "true if status is 'active' or 'verified'"
      }

      If any field is missing, return null for that field.

    response_format: "json"

  output:
    user_name: "response.full_name"
    user_email: "response.email"

Complex Business Logic Validation

Validate invoice calculations with business rules that would be tedious to express in assertions:

- id: validate_invoice
  action: mcp
  config:
    server: "claude"
    prompt: |
      Validate this invoice for correctness:
      ${get_invoice.response.body}

      Business rules:
      1. Subtotal must equal sum of line items
      2. Tax must be 8.5% of subtotal (rounded to 2 decimals)
      3. Total must equal subtotal + tax - discount
      4. Discount cannot exceed 20% of subtotal
      5. All line items must have positive quantities

      Return JSON:
      {
        "valid": boolean,
        "issues": [{"field": string, "issue": string, "expected": string, "actual": string}],
        "calculations": {"subtotal": number, "tax": number, "total": number}
      }

    context:
      - type: "data"
        data: "${product_catalog}"

    response_format: "json"

  assert:
    - response.valid == true
    - response.issues.length == 0

AI-Powered Error Analysis

When a step fails, use AI to diagnose the cause:

- id: failing_checkout
  action: http_request
  config:
    method: POST
    url: "${API_URL}/checkout"
    body: { cart_id: "${cart_id}" }
  on_error: "continue"

- id: analyze_failure
  when: "${failing_checkout.status} >= 400"
  action: mcp
  config:
    server: "claude"
    prompt: |
      This API call failed. Analyze the error and suggest fixes:

      Request: POST ${failing_checkout.config.url}
      Body: ${failing_checkout.config.body}
      Response Status: ${failing_checkout.status}
      Response Body: ${failing_checkout.response.body}

      Previous steps succeeded:
      - Cart creation: ${create_cart.status}
      - Cart ID: ${cart_id}

      Return JSON: {
        "root_cause": string,
        "suggested_fix": string,
        "additional_tests": string[]
      }

    response_format: "json"

  output:
    analysis: "response"

Dynamic Decision Making

Let AI decide which code path to follow based on a complex status response:

- id: decide_action
  action: mcp
  config:
    server: "claude"
    prompt: |
      Based on this job status, what should we do next?
      ${check_status.response.body}

      Options:
      1. "continue" - Job is still processing, check again
      2. "success" - Job completed successfully
      3. "retry" - Job failed but should retry
      4. "fail" - Job failed permanently

      Return JSON: {action: string, reason: string}

    response_format: "json"

  output:
    next_action: "response.action"

- id: handle_retry
  when: "${decide_action.next_action} == 'retry'"
  action: http_request
  config:
    method: POST
    url: "${API_URL}/job/${job_id}/retry"

Multi-Turn Conversations

Maintain context across multiple AI steps:

- id: start_analysis
  action: mcp
  config:
    server: "claude"
    prompt: "Analyze this API documentation and tell me what test cases I need. ${api_docs}"
    context:
      - type: "file"
        path: "./api-docs.yaml"
  output:
    conversation_id: "conversation_id"

- id: generate_test_data
  action: mcp
  config:
    server: "claude"
    conversation_id: "${start_analysis.conversation_id}"
    prompt: "Based on the test cases you identified, generate test data for each case. Return as JSON array."
    response_format: "json"
  output:
    test_data: "response"

- id: refine_tests
  action: mcp
  config:
    server: "claude"
    conversation_id: "${start_analysis.conversation_id}"
    prompt: "Are we missing any edge cases? Add 3 more edge case tests."
    response_format: "json"

Built-in Tools for AI

Give the AI access to TestMesh actions so it can perform tasks autonomously:

HTTP Request Tool

- id: ai_with_api_access
  action: mcp
  config:
    server: "claude"
    prompt: |
      Check if user with email "test@example.com" exists.
      If not, create one. Return the user ID.

    tools:
      - name: "http_request"
        config:
          base_url: "${API_URL}"
          auth:
            type: "bearer"
            token: "${API_TOKEN}"

    response_format: "json"

  output:
    user_id: "response.user_id"

Database Query Tool

- id: ai_database_check
  action: mcp
  config:
    server: "claude"
    prompt: |
      Check if we have any users with duplicate emails.
      If found, return their IDs and emails.

    tools:
      - name: "database_query"
        config:
          connection: "${DATABASE_URL}"

    response_format: "json"

Tool Permissions

Restrict what actions the AI is allowed to take:

tools:
  - name: "http_request"
    permissions:
      methods: ["GET"]                     # Read-only
      allowed_hosts: ["api.example.com"]   # Specific host only
      forbidden_paths: ["/admin/*"]

  - name: "database_query"
    permissions:
      read_only: true                      # No INSERT/UPDATE/DELETE
      allowed_tables: ["users", "orders"]

Model Selection

Choose the right model for each task:

# Fast validation tasks → Haiku
- action: mcp
  config:
    model: "claude-haiku-4-5"
    prompt: "Is this JSON valid?"

# General tasks → Sonnet
- action: mcp
  config:
    model: "claude-sonnet-4-5"
    prompt: "Extract data from response"

# Complex reasoning → Opus
- action: mcp
  config:
    model: "claude-opus-4-6"
    prompt: "Analyze this complex business logic and identify all edge cases..."

TestMesh as an MCP Server

Run TestMesh as an MCP server so AI tools like Claude Code can directly analyze workspaces, generate flows, and execute tests.

This requires the TestMesh CLI. Install it first: brew install test-mesh/brew/testmesh or curl -fsSL https://testmesh.io/install.sh | sh. See Installation for all options.

testmesh mcp

This exposes the following tools to MCP clients:

Discovery & Schema

ToolDescription
list_workspacesList all workspaces — always call first to get a workspace ID
list_flowsList flow YAML files on disk recursively under a directory
list_flows_apiList flows stored in the API (returns flow IDs for trigger_execution)
get_action_typesAll supported action types with required/optional config fields
get_yaml_schemaComplete YAML schema with examples for every action type
get_testing_guideBest-practices guide: layers, assertions, async, setup/teardown

Analysis

ToolDescription
analyze_workspaceMulti-service analysis: endpoints, schemas, Kafka topics, DB tables, call graph
analyze_serviceSingle-service analysis: endpoints, DB tables, Kafka topics, Redis keys
get_coverage_gapsShow uncovered endpoints/operations and coverage percentage
generate_test_planStructured context for planning a full test suite across a workspace

Authoring

ToolDescription
generate_flowFocused context for writing one flow (endpoints, schemas, examples, guidance)
write_flowWrite + validate a flow YAML to disk
read_flowRead an existing flow from disk
write_env_fileWrite a shared .env.test file for infrastructure connection strings
validate_flowValidate flow structure, action types, and variable dependencies without executing

Execution

ToolDescription
run_stepRun a single action step in isolation — debug a query, probe an endpoint
run_flowExecute a flow (inline YAML or file path) and return per-step results
run_suiteExecute a directory or test plan with tiered validation (tiers 1–4)
upload_flowUpload a flow to the API — makes it visible in the dashboard
trigger_executionTrigger an API-stored flow by ID; returns execution_id
get_executionPoll an execution_id for full per-step results

Using with Claude Code

Option A — Claude Code plugin (recommended)

The TestMesh plugin is hosted on GitHub. Add the marketplace first, then install:

/plugin marketplace add test-mesh/testmesh
/plugin install testmesh@testmesh

This installs the MCP server and 10 skills (generate-flow, run-flow, validate-flow, action-patterns, debugging-flows, flow-layers, mcp-tools, yaml-schema, setup, coverage) that guide you through common workflows.

If you see Permission denied (publickey) during install, your git is using SSH instead of HTTPS. Fix it with:

git config --global url."https://github.com/".insteadOf "git@github.com:"

Then retry the install.

After install you may see a Failed to download/cache error alongside a successful install. This is a known Claude Code issue when the marketplace and plugin share the same repository — the plugin is fully functional despite the message. It will be resolved once the plugin is available in the official Claude Code marketplace.

Option B — Manual configuration

Add a .mcp.json file at the root of your project:

.mcp.json
{
  "mcpServers": {
    "testmesh": {
      "command": "testmesh",
      "args": ["mcp"],
      "description": "TestMesh MCP server — analyze services, generate, run, and validate E2E flows"
    }
  }
}

Once configured, you can ask Claude Code to analyze your services, generate test flows, and run tests directly from your IDE.


Performance and Cost

Caching Large Context

When your prompt includes a large, static document (like an OpenAPI spec), enable caching to reduce cost and latency:

- action: mcp
  config:
    server: "claude"
    prompt: |
      Using this API specification:
      ${large_api_spec}

      Generate test cases for the /users endpoint.

    cache_prompt: true
    cache_ttl: "24h"   # Cached tokens cost ~90% less

Parallel AI Calls

Run independent AI analysis steps concurrently:

- action: parallel
  config:
    steps:
      - id: analyze_response
        action: mcp
        config:
          prompt: "Analyze response..."

      - id: analyze_logs
        action: mcp
        config:
          prompt: "Analyze logs..."

Best Practices

Use temperature: 0 for validation and data extraction tasks where you need consistent, deterministic results. Use higher temperatures (0.5–0.7) only for creative tasks like generating diverse test data.

  • Be specific in prompts. Tell the AI exactly what fields to return and what rules to check.
  • Always request structured output. Set response_format: "json" and describe the exact JSON structure in the prompt.
  • Handle AI failures gracefully. Set on_error: "continue" and use error_steps for fallback logic.
  • Never hardcode API keys. Always use ${ANTHROPIC_API_KEY} or equivalent environment variables.
  • Use response_schema to enforce JSON structure when the AI must return exact field types.

On this page