> ## Documentation Index
> Fetch the complete documentation index at: https://docs.enginy.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Building Workflows with an Agent

> The recommended MCP tool flow for creating, publishing, and running Advanced Workflows.

Every Workflows API endpoint is also an MCP tool, so an AI assistant can build a graph workflow, publish it, and run it end to end. This page is the playbook: the tools, the order to call them in, and how to resolve the values a block needs.

<Info>
  Tool names are derived from each endpoint's summary. If a tool below is missing from your session, your
  workspace may not have the **Advanced Workflows** feature enabled, or your token may lack the
  `WORKFLOWS_READ` / `WORKFLOWS_WRITE` scopes — see [Flag gating](#flag-gating-and-scopes). Read the
  [Workflows API guide](/api-reference/workflows-guide) for the graph model these tools operate on.
</Info>

## The tools

| Endpoint summary              | MCP tool                        | Scope             |
| ----------------------------- | ------------------------------- | ----------------- |
| Get workflow blocks           | `get_workflow_blocks`           | `WORKFLOWS_READ`  |
| Get workflow block inputs     | `get_workflow_block_inputs`     | `WORKFLOWS_READ`  |
| Get workflow condition fields | `get_workflow_condition_fields` | `WORKFLOWS_READ`  |
| Get workflows                 | `get_workflows`                 | `WORKFLOWS_READ`  |
| Create workflow               | `create_workflow`               | `WORKFLOWS_WRITE` |
| Validate workflow             | `validate_workflow`             | `WORKFLOWS_WRITE` |
| Get a single workflow         | `get_a_single_workflow`         | `WORKFLOWS_READ`  |
| Update workflow draft         | `update_workflow_draft`         | `WORKFLOWS_WRITE` |
| Validate workflow draft       | `validate_workflow_draft`       | `WORKFLOWS_READ`  |
| Publish workflow              | `publish_workflow`              | `WORKFLOWS_WRITE` |
| Delete workflow               | `delete_workflow`               | `WORKFLOWS_WRITE` |
| Run workflow                  | `run_workflow`                  | `WORKFLOWS_WRITE` |
| Get workflow runs             | `get_workflow_runs`             | `WORKFLOWS_READ`  |
| Get workflow run status       | `get_workflow_run_status`       | `WORKFLOWS_READ`  |
| Cancel workflow run           | `cancel_workflow_run`           | `WORKFLOWS_WRITE` |
| List workflow folders         | `list_workflow_folders`         | `WORKFLOWS_READ`  |
| Create workflow folder        | `create_workflow_folder`        | `WORKFLOWS_WRITE` |
| Update workflow folder        | `update_workflow_folder`        | `WORKFLOWS_WRITE` |
| Delete workflow folder        | `delete_workflow_folder`        | `WORKFLOWS_WRITE` |

<Info>
  Folders organize workflows only. To move a workflow into a folder, call `update_workflow_draft` with
  `folderId` (or `null` to remove it) — the folder tools manage the folders themselves. A `folderId`-only
  update does not change the plan or advance the workflow `revision`.
</Info>

## Recommended flow

<Steps>
  <Step title="Discover blocks">
    Call `get_workflow_blocks` (optionally filtered by `category` or `search`) to find the step ids for the
    import, enrich, and action steps the goal needs. Never invent a `blockId`.
  </Step>

  <Step title="Learn each block's inputs">
    For every block you'll use, call `get_workflow_block_inputs`. It returns each input's `required` flag,
    `valueShape`, and a `resolution` object telling you exactly how to source the value — including which
    public tools can resolve it (see [Resolving inputs](#resolving-block-inputs)).
  </Step>

  <Step title="Learn condition fields (only if branching)">
    If the plan has a `CONDITIONAL` node, call `get_workflow_condition_fields` for the valid `field` ids and
    `operator` ids. Fields can also be AI-variable or custom names; prefixes `company.`, `anyLead.`,
    `webhookInput.` reach related entities. For a random A/B split, use
    `{ "type": "RANDOM_SPLIT", "percentage": <1-100> }` as the condition instead of a field predicate —
    sibling percentages must sum to ≤ 100 and the remainder falls through to the fallback branch.
  </Step>

  <Step title="Create the draft">
    Assemble the plan and call `create_workflow`. Keep it a draft (omit `publish`) so you can validate before
    going live. Optionally call `validate_workflow` first to check a plan without persisting it.
  </Step>

  <Step title="Validate the stored draft">
    Call `validate_workflow_draft` — publish-grade checks against the saved draft. Fix any `errors` before
    publishing; surface `warnings` to the user.
  </Step>

  <Step title="Publish">
    Call `publish_workflow`. Pass the `revision` from the latest `get_a_single_workflow` to avoid clobbering a
    concurrent edit (a `409` means re-read and retry).
  </Step>

  <Step title="Run and poll">
    Read `get_a_single_workflow` for `runtimeInputContract`. If `EMPTY`, call `run_workflow` with no input; if
    `SUPPORTED`, pass one key from `acceptedKeys`. Then poll `get_workflow_run_status` with the returned
    `runId` until the status is terminal.
  </Step>
</Steps>

```mermaid theme={null}
flowchart TD
    A[get_workflow_blocks] --> B[get_workflow_block_inputs]
    B --> C{branching?}
    C -->|yes| D[get_workflow_condition_fields]
    C -->|no| E[create_workflow]
    D --> E
    E --> F[validate_workflow_draft]
    F --> G[publish_workflow]
    G --> H[run_workflow]
    H --> I[get_workflow_run_status]
```

## Resolving block inputs

`get_workflow_block_inputs` returns, per input, a `resolution.tools` array. Each entry is flagged with
`publicEquivalent`: when `true`, call that public tool to resolve the value; when `false`, the input is editor-only
and can't be fully set over the API yet.

| To resolve…                                                                     | Call this public tool                                                                                              |
| ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| A destination campaign id (`campaignId`)                                        | `get_campaigns`, `get_a_single_campaign`                                                                           |
| A contact or company list id (`leadsGroupId`, `companyGroupId`)                 | `get_lists`                                                                                                        |
| An AI-variable id (`selectedAiFields`)                                          | `list_ai_variables`, `get_an_ai_variable`                                                                          |
| A LinkedIn identity id (`identityId`)                                           | `get_identities`                                                                                                   |
| Exact record ids for a selector step                                            | `search_contacts_with_advanced_filters`, `search_companies_with_advanced_filters`, `get_contacts`, `get_companies` |
| CRM / provider search filters (`source`, `*CRMFilters`, `storeLeadsFilters`, …) | `preview_an_ai_finder_search`                                                                                      |

<Warning>
  **Editor-only inputs.** A handful of inputs resolve through internal editor tools with **no public
  equivalent** — `workflow_get_input_options` (e.g. the `sortedApis` provider order, approver user ids,
  custom-field ids), `workflow_generate_search_filters`, and the Slack helpers (`workflow_get_slack_channels`,
  `workflow_get_slack_teammates`, `workflow_get_slack_message_fields`). When `get_workflow_block_inputs` flags
  an input `publicEquivalent: false`, prefer a block whose inputs are all publicly resolvable, or leave that
  step for a teammate to finish in the app. Remember that entity ids on **downstream** steps should be omitted
  entirely — they flow from the previous step.
</Warning>

## Flag gating and scopes

* The workflow tools are only present when the workspace has the **Advanced Workflows** feature enabled. Without it,
  the tools are hidden and direct calls return **403**.
* A token needs `WORKFLOWS_READ` for the read tools and `WORKFLOWS_WRITE` for the write tools; granting
  `WORKFLOWS_WRITE` implies `WORKFLOWS_READ`. See [Scopes](/mcp/scopes).
* If a tool is present but a call is rejected for permissions after the user authorized, run `mcp_whoami` to confirm
  the session and scopes rather than re-running OAuth.

<CardGroup cols={2}>
  <Card title="Cookbook" icon="book-open" href="/api-reference/workflows-cookbook">
    The same builds as concrete plans and calls.
  </Card>

  <Card title="Endpoints" icon="code" href="/api-reference/workflows/get-workflows">
    The request/response contract each tool wraps.
  </Card>
</CardGroup>
