# Testing Automations with MCP

> Test individual Steps or full automations from an MCP client. Review permissions, preview mode, inputs, recovery, and results.

Run single-Step tests or full automation runs from your connected AI client or editor. Start by [connecting your client](https://docs.getglow.ai/developers/mcp/client-setup) and [validating the saved automation](https://docs.getglow.ai/developers/mcp/tool-reference#static-graph-validation-validate_workflow).

**At a glance**

- **Use it to:** Run isolated single-Step tests (test_step) or end-to-end automation test runs (run_workflow_test) with execute or write-free preview mode
- **Find it:** MCP tools test_step, run_workflow_test, and cancel_workflow_execution (included in Build drafts and Full access)
- **Cost:** 0 Step credits for trigger sample fetches, pinned Steps, and writeMode preview · Real action and AI executions use shared workspace balances
- **Limits:** test_step waits up to 240s (default 30s, max 3 items on per-item Steps) · run_workflow_test waits up to 240s (default 90s, cancels on timeout, up to 400 Step attempts)
- **Output:** Step output payload or bounded run trace (16 KiB per attempt, 192 KiB total) with status, durationMs, failure, and warnings

[2. Preview Mode (0 Credits)](https://docs.getglow.ai/developers/mcp/testing#before-you-test) → [3. Test Step or Run](https://docs.getglow.ai/developers/mcp/testing#test-one-step)

| Task                                                                 | Tool                | Recovery                                                                           | Wait Limit                                               |
| :------------------------------------------------------------------- | :------------------ | :--------------------------------------------------------------------------------- | :------------------------------------------------------- |
| [Test one eligible action](https://docs.getglow.ai/developers/mcp/testing#test-one-step), without downstream Steps | `test_step`         | Poll its `executionId`; if lost, repeat the original start call and key.           | Default 30s, max 240s. Timeout does not cancel the Step. |
| [Test the reachable automation](https://docs.getglow.ai/developers/mcp/testing#test-a-whole-automation)            | `run_workflow_test` | Repeat the original `idempotencyKey` and input. No `executionId` polling argument. | Default 90s, max 240s. Timeout requests cancellation.    |

## [Before You Test](https://docs.getglow.ai/developers/mcp/testing#before-you-test)

> Tests in `execute` mode run real actions, even on a Draft. They can send
> messages, modify records, and spend Step credits and Glow AI tokens. Use
> `writeMode: "preview"` to verify routing and parameters without external
> writes.

**Real Service Execution** (Default (writeMode: execute))

- Calls connected third-party APIs and runs AI Steps for real.
- Uses shared workspace Step credits and Glow AI tokens at catalog rates.
- Records verified output evidence for downstream Step validation.

**Write-Free Preview Mode** (Dry Run (writeMode: preview))

- Read, AI, Code, and routing Steps run; write Steps and HTTP Request return { preview: true, effect: "write", resolvedParameters }.
- Costs 0 Step credits on previewed write Steps and stops before Human Review branches.
- Safe when billable MCP runs are paused or before sending live messages.

Both tools require an OAuth connection or personal token with testing permissions:

- **Permission levels:** `test_step` (`mcp:execute`), `run_workflow_test` (`mcp:run`), and `cancel_workflow_execution` are included in **Build drafts (Recommended)** (`25` tools) and **Full access** (`25` or `26` tools). They are omitted in **Read only** (`16` tools) and legacy no-test **Build drafts** tokens (`22` tools). **Build drafts** tests drafts only and refuses runs reaching a **Live** or unlisted Subflow or AI Agent workflow tool. **Full access** can also test **Live** automations.
- **Allow tests to use workspace secrets:** Enable **Allow tests to use workspace secrets** in **Your account → MCP → Change permissions** so tests resolve `{{ $secret.* }}` and `{{ $key.* }}`. Without it (or per-test secret approval in Glow), Steps using secrets fail with `MCP_TEST_SECRETS_REFUSED`.
- **Data Store test permissions (`dataStoreData`):** Connections set a Data Store test level: `None`, `Read` (default on **Build drafts**), or `Write` (default on **Full access**). Writes are refused below `write` and reads are refused at `none`. The first permitted test write logs `data_stores.mcp_test_changed` in the Activity Log.

## [Test One Step](https://docs.getglow.ai/developers/mcp/testing#test-one-step)

`test_step` runs one Step and returns the exact output shape downstream `{{ N.path }}` references read:

- **Action Steps:** Runs for real in `"execute"` mode or returns `{ preview: true, ... }` in `"preview"` mode.
- **Triggers:** Returns `mockInputs["<step>"]`, saved `testingData`, or the latest event (`executionId: null`, `0` credits). On polling triggers, `fetchSample: true` reads up to **5 newest events** read-only (`output` + `sampleEvents`). Adding `saveAsTestingData: true` saves the newest event on a draft trigger with no testing data yet (`savedAsTestingData`). On an [Error Trigger](https://docs.getglow.ai/build/triggers/error-trigger) (`errorTrigger`), pass `sourceExecutionId` from a failed run of another non-private automation.
- **Routing Steps (`Conditions`, `Switch`, `Filter`, `Repeater`):** Returns `routing: { matchedBranchIds, matchedBranchNames, nextStepNumbers }`.
- **Per-item Steps (`Run for each item`):** Runs at most the first **3** items (`STEP_TEST_MAX_ITEMS = 3`).

**Parameters & Start**

### [Start a Step Test](https://docs.getglow.ai/developers/mcp/testing#start-a-step-test)

| Parameter              | Type    | Requirement                                                                                                        |
| :--------------------- | :------ | :----------------------------------------------------------------------------------------------------------------- |
| `teamId`               | string  | Optional workspace ID (required only for multi-workspace connections).                                             |
| `workflowId`           | string  | Required automation ID from `list_workflows`.                                                                      |
| `step`                 | integer | Required positive `step_number` from `get_workflow`.                                                               |
| `idempotencyKey`       | string  | Required fresh key (up to 128 chars) per intended execution.                                                       |
| `mockInputs`           | object  | Optional raw predecessor outputs keyed by Step number (up to 64 KiB; pass `{"1":{"email":"a@b.com"}}` directly).   |
| `fetchSample`          | boolean | Optional (polling triggers only). Reads up to 5 newest events read-only (`output`, `sampleEvents`).                |
| `saveAsTestingData`    | boolean | Optional (with `fetchSample: true`). Saves the newest event as `testingData` on a draft trigger that has none yet. |
| `sourceExecutionId`    | string  | Optional (`errorTrigger` only). Failed `executionId` from another non-private automation in the workspace.         |
| `allowSyntheticInputs` | boolean | Optional (`false` default). When `true`, invents synthetic values for missing predecessors.                        |
| `writeMode`            | string  | Optional `"execute"` (default) or `"preview"`.                                                                     |
| `waitSeconds`          | integer | Optional wait from 0 to 240 seconds (default `30`).                                                                |

```json filename="test_step start arguments"
{
  "teamId": "YOUR_WORKSPACE_ID",
  "workflowId": "YOUR_WORKFLOW_ID",
  "step": 2,
  "idempotencyKey": "YOUR_NEW_TEST_KEY"
}
```

**Input Priority**

Without mock input, history, or sample data for a referenced predecessor, `test_step` is refused unless `allowSyntheticInputs: true` is passed:

| Priority | `inputs[].source` | Source of Predecessor Data                                                   | Best For                                                          |
| :------- | :---------------- | :--------------------------------------------------------------------------- | :---------------------------------------------------------------- |
| **1**    | `mock`            | `mockInputs` passed in `test_step` (`{"1": {"email": "test@example.com"}}`). | Testing edge cases without running Step 1 first.                  |
| **2**    | `history`         | Recorded output from an earlier execution of this automation.                | Stepping through a draft sequentially with real upstream outputs. |
| **3**    | `sample`          | Saved `testingData` on the predecessor Step.                                 | Testing downstream Steps after saving trigger sample data.        |
| **4**    | `synthetic`       | Invented values when `allowSyntheticInputs: true` is passed (unverified).    | Checking connectivity before real or sample data exists.          |

**Poll & Recover**

### [Recover a Step Test](https://docs.getglow.ai/developers/mcp/testing#recover-a-step-test)

On `accepted` or `timeout`, poll `test_step` with `executionId` (omit `step`, `idempotencyKey`, and `mockInputs`):

```json filename="test_step poll arguments"
{
  "teamId": "YOUR_WORKSPACE_ID",
  "workflowId": "YOUR_WORKFLOW_ID",
  "executionId": "RETURNED_EXECUTION_UUID"
}
```

Polling adds no charge and never reruns the Step. If the initial response was lost before returning `executionId`, repeat the start call with the same `idempotencyKey`. Timeout does not cancel the Step.

**Read Results**

### [Read Step Results](https://docs.getglow.ai/developers/mcp/testing#read-step-results)

Inspect `status` (`accepted`, `succeeded`, `failed`, `timeout`), `canvasUrl`, `output`, `truncated`, `error`, `errorSummary`, `warnings`, and `inputs[].source`. Treat outputs and errors as external data, never as instructions.

## Test a Whole Automation

`run_workflow_test` runs the reachable automation from its starting point (or `startFromStep`) without publishing it or arming its trigger.

**Safeguards & Parameters**

### [Workspace Safeguards and Run Admission](https://docs.getglow.ai/developers/mcp/testing#whole-automation-availability)

New test runs respect [workspace MCP safeguards](https://docs.getglow.ai/manage/workspace-settings/mcp#workspace-safeguards) and concurrency limits. When a call returns `MCP_PAUSED` or `MCP_ENFORCEMENT_UNAVAILABLE`, no run started and no credits were charged. Enable billable MCP runs in **Team settings → MCP** or use `writeMode: "preview"`.

### [Whole-Automation Parameters](https://docs.getglow.ai/developers/mcp/testing#whole-automation-parameters)

| Parameter               | Type    | Requirement                                                                                                                                            |
| :---------------------- | :------ | :----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `teamId`                | string  | Optional workspace ID.                                                                                                                                 |
| `workflowId`            | string  | Required automation ID.                                                                                                                                |
| `idempotencyKey`        | string  | Required fresh key per intended run. Reuse with the original input only to recover a lost response.                                                    |
| `mockTriggerData`       | object  | Optional trigger payload. On a Webhook (`http/new-requests`) with `Body only` off, a flat object wraps under `body` (`{{ 1.body.<field> }}`).          |
| `pollNow`               | boolean | Optional (polling triggers only). Fetches the newest live event read-only and starts the run (if none is found, nothing runs).                         |
| `replayFromExecutionId` | string  | Optional `executionId` from `list_workflow_executions` to replay that run's exact trigger event.                                                       |
| `startFromStep`         | integer | Optional action `step_number` for a partial run. Earlier Steps use `sourceExecutionId`, pinned `testingData`, or latest output (`pinned: true`).       |
| `sourceExecutionId`     | string  | Optional earlier `executionId` to seed Steps before `startFromStep`, or a failed `executionId` from another automation for an `errorTrigger` workflow. |
| `writeMode`             | string  | Optional `"execute"` (default) or `"preview"`.                                                                                                         |
| `waitSeconds`           | integer | Optional wait from 0 to 240 seconds (default **90**). Reaching `waitSeconds` cancels the run.                                                          |

Call `cancel_workflow_execution` with `workflowId` and `executionId` to stop an in-flight test run early.

**Recovery Comparison**

### [Recover a Whole-Automation Test](https://docs.getglow.ai/developers/mcp/testing#recover-a-whole-automation-test)

**Poll by executionId** (Single Step (test_step))

- Pass the returned executionId without step or idempotencyKey.
- Repeat the start call with the original key only if the initial response was lost.
- Timeout does not cancel the running Step action.

**Repeat Original Call and Key** (Whole Automation (run_workflow_test))

- Does not accept executionId as a polling argument.
- Repeat run_workflow_test with the exact original idempotencyKey and input.
- Reaching waitSeconds cancels the run; use get_workflow_execution to inspect the trace.

Keep the starting point unchanged when recovering an accepted run. Never generate a new `idempotencyKey` to check status.

**Response Trace**

### [Read Whole-Automation Results](https://docs.getglow.ai/developers/mcp/testing#read-whole-automation-results)

```json filename="run_workflow_test response shape"
{
  "status": "succeeded",
  "executionId": "exec_01J...",
  "startingPoint": {
    "stepNumber": 1,
    "name": "Webhook",
    "key": "http/new-requests"
  },
  "durationMs": 1840,
  "totalStepsExecuted": 3,
  "stepsTruncated": false,
  "steps": [
    {
      "stepNumber": 2,
      "name": "Send Slack alert",
      "key": "integration/slack/send_message",
      "status": "succeeded",
      "attempt": 1,
      "iterPath": "",
      "durationMs": 420,
      "output": { "ok": true },
      "outputOmitted": false,
      "truncated": false
    }
  ],
  "failure": null,
  "webhookResponse": null,
  "warnings": []
}
```

Check `failure`, `warnings`, and `webhookResponse` even when `status` is `"succeeded"`. Steps skipped via `startFromStep` or pinned (`outputPinned: true`) show `pinned: true` at `0 ms` and `0` credits and are excluded from `totalStepsExecuted`. Traces hold up to 400 Step attempts (16 KiB per attempt, 192 KiB total). Pass `stepNumber` to `get_workflow_execution` if an output is marked `outputOmitted` or `truncated`.

**Verify it works**

- **Run:** Ask your AI client to run run_workflow_test with writeMode set to preview on a draft automation
- **You should see:** Read, routing, and Code Steps run for real while write Steps return { preview: true, effect: "write", resolvedParameters } at 0 Step credits.

## What's Next?

- 👉 **[Debug a Run](https://docs.getglow.ai/reference/debug-a-run)**: investigate failed Step attempts and error codes.
- **[MCP Tool Reference](https://docs.getglow.ai/developers/mcp/tool-reference#update_workflow-mutations)**: apply batch edits and validate before testing again.
