CFFBRWCFFBRWDocumentation
⚠Auto-generated documentation — This content was generated with AI assistance and is currently under review. Information may be incomplete or inaccurate. When in doubt, contact our support team.

BYOA Recovery — Bring Your Own Agent

Use your own AI agent as the first responder when a workflow step fails.

Overview

When a step fails, CFFBRW's Tier 2 recovery normally calls a built-in flash-lite model to diagnose the error and suggest a fix. With BYOA Recovery, you can configure your own MCP server to handle this first. Your agent gets full context — the step spec, the error, prior outputs, the actual HTTP request that failed — and can return a recovery action using the same 5-action protocol as the built-in provider.

If your agent responds within the timeout with a valid action, it is used. If it times out, errors, or returns invalid data, the built-in provider takes over silently. You lose nothing; you only gain.

Why this matters: A flash-lite model knows nothing about your APIs, business rules, or data schemas. Your agent does. Recovery decisions your agent makes will be more accurate — fewer needs_human escalations, better retry parameters, domain-aware fixed outputs.

How It Works

Step fails
    │
    ▼
Is recovery.mcp_server_id configured?
    ├── YES → POST diagnose_step_failure to your MCP server
    │         ├── Valid response → execute action (same pipeline as built-in)
    │         └── Timeout / error / invalid → log + fall through
    └── NO → skip
    │
    ▼
Built-in runtime provider (flash-lite, unchanged behavior)

Your agent is called on the first recovery attempt only. If it fails, the built-in provider handles attempts 1+ as normal. This keeps the total recovery time within budget.

Setting Up

1. Build a recovery MCP server

Your MCP server must expose a tool named diagnose_step_failure. You can get the full JSON Schema for input and output from the BYOM MCP resource:

Resource URI: cffbrw://recovery/diagnose-step-failure-schema

Connect your BYOM MCP client and read this resource to get the complete input/output contract.

2. Input your agent receives

{
  "schema_version": 1,
  "step": {
    "type": "http_request",
    "title": "Fetch user profile",
    "intent": "GET user data from /api/users/:id",
    "index": 2,
    "config": { "url": "https://api.example.com/users/42", "method": "GET" }
  },
  "error": "HTTP 429: Too Many Requests",
  "prior_outputs": {
    "0": "{ \"token\": \"abc...\" }",
    "1": "{ \"userId\": 42 }"
  },
  "workflow_input": { "userId": 42 },
  "resolved_request": {
    "url": "https://api.example.com/users/42",
    "body": null
  }
}

Fields your agent receives:

  • step — step type, title, intent, index, and type-specific config
  • error — the exact error string from the failed execution
  • prior_outputs — summarized outputs from previous steps (500 chars each)
  • workflow_input — the workflow's runtime input (OAuth tokens and connector credentials are stripped)
  • catalog_action — for connector steps: the catalog action params, required fields, and param descriptions
  • resolved_request — for HTTP/connector steps: the actual URL and request body that was sent
  • human_hint — set when a human re-triggered recovery with a hint

3. Output your agent must return

Return one of these 5 actions. They are the same 5 actions the built-in provider uses:

fixed_output — Provide the result directly without retrying:

{
  "type": "fixed_output",
  "diagnosis": "Rate limited. Returning cached profile from prior run context.",
  "output": { "id": 42, "name": "Alice" }
}

retry_with_params — Retry the step with modified parameters:

{
  "type": "retry_with_params",
  "diagnosis": "Wrong endpoint version. Correcting to v2.",
  "modifications": {
    "httpRequest": { "url": "https://api.example.com/v2/users/42" }
  }
}

Allowed modifications keys: httpRequest, connectorCall, timeout, headers, body. The same SAFE_FIELDS guard that applies to built-in recovery applies here — your modifications are deep-merged, not replaced wholesale.

code_fix — Provide JavaScript to compute the output:

{
  "type": "code_fix",
  "diagnosis": "Response shape changed. Transforming to expected format.",
  "code": "return { id: input.userId, name: input.fullName };"
}

Note: code_fix still requires human approval if your workspace has that policy enabled.

retry_with_tool — Call a different MCP tool instead:

{
  "type": "retry_with_tool",
  "diagnosis": "Primary tool unavailable. Using fallback.",
  "toolCall": {
    "server": "my-mcp-server-id",
    "tool": "get_user_fallback",
    "params": { "userId": 42 }
  }
}

needs_human — Escalate to human review:

{
  "type": "needs_human",
  "diagnosis": "Authentication expired and cannot be refreshed automatically.",
  "suggestion": "Re-authorize the API connection in Settings → Connectors."
}

4. Register your MCP server

Register your server under Settings → MCP Servers. It must be reachable from the CFFBRW gateway.

5. Configure recovery settings

Go to Settings → Recovery in the dashboard:

  1. Select your MCP server from the dropdown
  2. Set a timeout (default: 15 seconds, range: 1-60 seconds)
  3. Click Save

Or via API:

curl -X PUT https://api.cffbrw.com/v1/settings/recovery.mcp_server_id \
  -H "Authorization: Bearer <token>" \
  -d '{"value": "your-mcp-server-id"}'

curl -X PUT https://api.cffbrw.com/v1/settings/recovery.timeout_ms \
  -H "Authorization: Bearer <token>" \
  -d '{"value": "15000"}'

Debugging

Step logs

Every step log entry has a recovery_source field:

  • "byoa" — your agent's response was used
  • "builtin" — the built-in provider was used (BYOA was not configured, timed out, or returned invalid data)
  • null — the step did not need recovery

Query via GET /v1/runs/:runId/logs.

WebSocket events

The step:adapting event includes BYOA details (truncated to 1KB):

  • byoa_attempted — whether your agent was called
  • byoa_result_summary — the action type and diagnosis (if valid)
  • byoa_timing_ms — how long your agent took
  • byoa_rejection_reason — why the response was rejected (if applicable)

Common issues

Your agent is never called: Check that recovery.mcp_server_id is set and points to a registered server in your workspace. Use the Recovery settings page — the tool detection badge shows whether diagnose_step_failure is detected.

Response rejected as invalid: Your tool must return exactly one of the 5 action types with all required fields. Get the full JSON Schema from the BYOM MCP resource cffbrw://recovery/diagnose-step-failure-schema.

Agent times out: The default timeout is 15 seconds. Increase via recovery.timeout_ms (max 60 seconds). The built-in provider recovers after timeout — the workflow does not fail.

retry_with_tool references unknown tool: The tool call must reference a server and tool that are registered in your workspace. Specific error is logged to the step's message field.

Tips for building a good recovery agent

  • Load your API specs and error codes into context. Your agent should know what a 429 means for your specific API and what the backoff strategy is.
  • Use prior_outputs to infer state. If step 0 fetched an auth token, it's in prior_outputs["0"].
  • Prefer retry_with_params over fixed_output for transient errors. Fixed outputs bypass the actual API call — retry_with_params lets the step run again with corrections.
  • Use needs_human conservatively. Only escalate when you genuinely cannot recover. The built-in provider will also attempt before needs_human — your agent and the built-in together give 2 recovery attempts.
  • Keep your agent fast. 15 seconds is the default budget. Long-running agents eat into step timeout headroom.

A2A (Agent-to-Agent) Recovery

What is A2A?

A2A is Google's Agent-to-Agent protocol (v1.0.0), an open standard for agent interoperability over JSON-RPC 2.0. Instead of building an MCP server with a diagnose_step_failure tool, you can point CFFBRW at any A2A-compatible agent. The agent receives the same failure context and returns the same 5 recovery action types — the only difference is the transport envelope.

How it works

  1. You have an A2A-compatible agent running somewhere (any language, any platform)
  2. Paste its URL in CFFBRW Settings > Recovery > A2A Agent URL
  3. When a step fails, CFFBRW sends a JSON-RPC 2.0 SendMessage request with the failure context as a data part
  4. Your agent responds with a recovery action in a data part
  5. Same 5 action types as MCP recovery: fixed_output, retry_with_params, code_fix, retry_with_tool, needs_human
Step fails
    |
    v
Is recovery.a2a_agent_url configured?
    |-- YES --> POST /message:send to your A2A agent
    |           |-- Valid response --> execute action
    |           +-- Timeout / error / invalid --> log + fall through
    +-- NO --> skip
    |
    v
Is recovery.mcp_server_id configured?
    |-- YES --> POST diagnose_step_failure to your MCP server
    +-- NO --> skip
    |
    v
Built-in runtime provider (flash-lite)

Configuration

Dashboard: Settings > Recovery > paste your A2A Agent URL. Optionally add a Bearer token for authentication.

API:

# Set A2A agent URL
curl -X PUT https://api.cffbrw.com/v1/settings/recovery.a2a_agent_url \
  -H "Authorization: Bearer <token>" \
  -d '{"value": "https://my-agent.example.com"}'

# Set auth token (optional)
curl -X PUT https://api.cffbrw.com/v1/settings/recovery.a2a_auth_token \
  -H "Authorization: Bearer <token>" \
  -d '{"value": "your-bearer-token"}'

The agent card is fetched automatically when you save the URL. CFFBRW reads /.well-known/agent-card.json from your agent and stores the name and description for display in the dashboard.

Input/Output Contract

The payload inside the A2A envelope is identical to MCP recovery. Your agent receives RecoveryToolInput (step spec, error, prior outputs, workflow input, resolved request) and must return a valid RecoveryAction (one of the 5 action types).

The difference is the transport: instead of an MCP tool call, the data is wrapped in a JSON-RPC 2.0 SendMessage envelope:

Request (CFFBRW to your agent):

{
  "jsonrpc": "2.0",
  "id": "recovery-{runId}-{stepIndex}",
  "method": "SendMessage",
  "params": {
    "message": {
      "messageId": "{uuid}",
      "role": "ROLE_USER",
      "parts": [{ "type": "data", "data": { /* RecoveryToolInput */ } }]
    }
  }
}

Response (your agent to CFFBRW):

{
  "jsonrpc": "2.0",
  "id": "recovery-{runId}-{stepIndex}",
  "result": {
    "message": {
      "role": "ROLE_AGENT",
      "parts": [{ "type": "data", "data": { /* RecoveryAction */ } }],
      "messageId": "..."
    }
  }
}

Error response:

{
  "jsonrpc": "2.0",
  "id": "...",
  "error": { "code": -32000, "message": "reason" }
}

See the BYOM MCP resource cffbrw://recovery/diagnose-step-failure-schema for the full JSON Schema of RecoveryToolInput and RecoveryAction.

Building an A2A Recovery Agent

Your agent must:

  1. Expose POST /message:send — This is the A2A spec endpoint for receiving messages.
  2. Publish /.well-known/agent-card.json — CFFBRW fetches this at configuration time to validate your agent and display its name/description. The card should include name, description, and url fields.
  3. Read the data part — The first data part in the message contains the RecoveryToolInput payload (same schema as the MCP diagnose_step_failure tool).
  4. Return a data part — Your response message must include a data part containing a valid RecoveryAction (one of the 5 action types).
  5. Respond within the timeout — Default is 15 seconds, configurable up to 60 seconds via recovery.timeout_ms.

Any language or framework works. If your agent framework supports the A2A spec, you only need to implement the message handler — the framework handles JSON-RPC routing.

Priority

When both A2A and MCP are configured, A2A takes priority. The MCP server is not called. To use MCP recovery instead, remove the A2A Agent URL from settings.

Agent Mode — Async Recovery via Inbox

The MCP and A2A methods above are synchronous — CFFBRW calls your server in real time when a step fails. Agent mode is asynchronous — the workflow pauses, your agent polls an inbox, and submits a fix whenever it's ready.

This is for AI coding agents (Claude Code, Cursor, Copilot) that can't run a server but can poll an API or read MCP resources.

How it works

Step fails
    │
    ▼
recovery.mode = "agent"?
    ├── YES → open needs_agent gate (waitForEvent, zero cost)
    │         ├── Agent polls GET /v1/recovery/pending (or MCP resource)
    │         ├── Agent reads failure context
    │         ├── Agent submits fix via POST /v1/recovery/:runId/:stepIndex/action
    │         │   (or MCP tool: submit_recovery_action)
    │         └── Workflow resumes with fix applied
    │         └── Timeout (default 300s) → fall through to built-in
    └── NO → synchronous recovery (A2A → MCP → built-in)

Configuration

Set recovery.mode to agent:

curl -X PUT https://api.cffbrw.com/v1/settings/recovery.mode \
  -H "Authorization: Bearer <token>" \
  -d '{"value": "agent"}'

Optional: set timeout (default 300 seconds, range 30–3600):

curl -X PUT https://api.cffbrw.com/v1/settings/recovery.agent_timeout \
  -H "Authorization: Bearer <token>" \
  -d '{"value": "600"}'

Agent workflow

  1. Poll for pending gates:

    • API: GET /v1/recovery/pending (returns all needs_agent gates in workspace)
    • MCP resource: cffbrw://recovery/pending
  2. Read failure context:

    • API: GET /v1/recovery/:runId/:stepIndex (full RecoveryToolInput with step spec, error, prior outputs)
  3. Submit a fix:

    • API: POST /v1/recovery/:runId/:stepIndex/action
    • MCP tool: submit_recovery_action
    • Same 5 action types: fixed_output, retry_with_params, code_fix, retry_with_tool, needs_human
  4. Workflow resumes with the submitted action, same as synchronous recovery.

When to use which mode

ModeSet recovery.mode toBest forRequires
Built-in onlyoff (default)No custom recoveryNothing
Agent (async)agentAI coding agents (Claude Code, Cursor) that can poll but can't host a serverAgent with MCP or API access
Server (sync)serverDedicated recovery servers, production automationRunning A2A or MCP server

Security

  • OAuth tokens and connector credentials are stripped from workflow_input before sending to your agent.
  • Your agent cannot access anything outside what is provided in the tool input.
  • code_fix responses go through the same human approval gate as built-in code fixes.
  • retry_with_params modifications are deep-merged through the same SAFE_FIELDS guard — your agent cannot inject arbitrary fields into the step spec.
  • Your agent's MCP server must be registered in your workspace. Cross-workspace agents are not supported.
  • A2A agent URLs must use HTTPS and pass SSRF validation (no localhost, private IPs, metadata endpoints).