diff --git a/images/workflows/webhook-trigger-rows.png b/images/workflows/webhook-trigger-rows.png
index 03b6323..e9cc6d4 100644
Binary files a/images/workflows/webhook-trigger-rows.png and b/images/workflows/webhook-trigger-rows.png differ
diff --git a/product/embed/mcp-server.mdx b/product/embed/mcp-server.mdx
index aaff870..d3d977b 100644
--- a/product/embed/mcp-server.mdx
+++ b/product/embed/mcp-server.mdx
@@ -14,6 +14,7 @@ The Forest MCP server lets AI tools like Claude, Dust, and others to:
- Access collection schemas
- Securely query and browse your data
- Execute actions on records
+- Start [Workflows](/product/process/workflows/overview) on a record and follow their progress
All of this while respecting the Roles & Permissions of your Forest project, and logging every activity, just like if they were performed through the UI.
@@ -145,6 +146,18 @@ The Forest MCP server exposes the following capabilities:
| `getActionForm` | Get form fields for a smart action |
| `executeAction` | Execute a smart action |
+### Workflows
+
+| Tool | Description |
+| ----------------- | ------------------------------------------------------------ |
+| `listWorkflows` | Discover the workflows enabled for MCP triggering |
+| `triggerWorkflow` | Start a workflow run on a record |
+| `getWorkflowRun` | Poll the status of a run started through MCP |
+
+
+ Workflows are **opt-in per workflow**: only those whose **MCP** trigger is enabled are visible to these tools. See [Triggering workflows from an AI assistant](#triggering-workflows-from-an-ai-assistant).
+
+
## Restrict tools
You can restrict which tools the MCP server exposes using `enabledTools`. Only the tools you list will be available, and **new tools added in future releases will NOT be automatically enabled**, so your configuration stays safe over time.
@@ -267,6 +280,135 @@ url = ""
Use the MCP transport type `"http"` (not `"sse"` or `"url"`): the Forest MCP server uses Streamable HTTP. Your URL should still use `https://`. Clients that rely on `mcp-remote` (Claude Desktop, Windsurf, JetBrains) require Node.js 18\+ (some versions need 20\+).
+## Triggering workflows from an AI assistant
+
+Three tools let an assistant drive a [Workflow](/product/process/workflows/overview) end-to-end from its own context: pick a workflow that fits the record at hand, start it, then watch the run.
+
+
+ A workflow is only reachable through MCP once an editor enables its **MCP** trigger in the workflow's [trigger settings](/product/process/workflows/triggers#the-mcp-trigger). Nothing is exposed by default.
+
+
+### Discover → trigger → poll
+
+The three tools are meant to be chained, and the split is deliberate: MCP has no push channel, and a run is asynchronous — it can be long, or parked waiting for a person. So `triggerWorkflow` returns immediately with a `runId`, and the assistant polls `getWorkflowRun` for as long as it cares about the outcome.
+
+```mermaid
+flowchart LR
+ L["listWorkflows
(pick a workflow)"] --> T["triggerWorkflow
(→ runId)"] --> G["getWorkflowRun
(poll runState)"]
+ G -. "not finished yet" .-> G
+```
+
+1. **Discover** — `listWorkflows` returns the MCP-enabled workflows the connected user can reach, with the collection each one operates on. Pass `collectionName` to narrow it to the collection of the record in context.
+2. **Trigger** — `triggerWorkflow` starts a run on one record and returns its `runId`. The run continues server-side; nothing blocks.
+3. **Poll** — `getWorkflowRun` reports the run's state, the step it is on, whether it is waiting for a human, and, once terminal, its result or error.
+
+### `listWorkflows`
+
+Lists workflows with the MCP trigger enabled, scoped to the connected user's rendering and permissions.
+
+| Argument | Description |
+|---|---|
+| `collectionName` | Optional. Narrows the results to workflows operating on that collection — typically the collection of the record in context. |
+
+```json Returns
+[
+ {
+ "workflowId": "9f1b0c4e-2f7a-4d5b-9e31-6c0a8b7d1234",
+ "name": "KYC review",
+ "collectionName": "customers"
+ }
+]
+```
+
+An empty array means no workflow is MCP-enabled for that user — most often because nobody has turned the toggle on yet.
+
+### `triggerWorkflow`
+
+Starts a run of an MCP-enabled workflow on a specific record.
+
+| Argument | Description |
+|---|---|
+| `workflowId` | As returned by `listWorkflows`. Its MCP trigger must be enabled. |
+| `recordId` | The record to run on. Composite primary keys use the packed form, values joined by `\|` (e.g. `"123\|456"`). |
+
+```json Returns
+{ "runId": 1234, "runState": "loading" }
+```
+
+`runId` is what every subsequent `getWorkflowRun` call needs. `runState` is only the state at that instant — it depends on the workflow's first step, and it moves on without further calls, so treat it as a starting point, not an outcome.
+
+
+ The record is **not** checked when the run is created — the orchestrator has no data access at that point. An id that does not exist, or that the user cannot read, produces a run that fails at its first data step; the assistant sees it through `getWorkflowRun`'s `error`, not as a trigger-time failure.
+
+
+Only **one run per record** can be active at a time. Triggering a record that already has an ongoing run fails and does **not** resume it — the run in flight is left untouched.
+
+### `getWorkflowRun`
+
+Reads the normalized status of a run, given the `runId` returned by `triggerWorkflow`.
+
+| Field | Description |
+|---|---|
+| `runState` | `pending` or `loading` while a step is queued or executing, `started` when the run is parked, `finished` on completion, `aborted` when stopped. |
+| `currentStep` | The step the run sits on — its `name` and `type` (plus a `taskType` on task steps). `null` once the run is finished. |
+| `waitingForHumanInput` | `true` when the run is parked on a step a person must handle. |
+| `result` | The step the run ended on, populated only once `runState` is `finished`. |
+| `error` | The failure recorded on the current step, including a first-data-step failure on an unreachable record. `null` otherwise. |
+
+
+
+```json Parked on a human step
+{
+ "runState": "started",
+ "currentStep": {
+ "name": "Review the KYB documents",
+ "type": "task",
+ "taskType": "guideline"
+ },
+ "waitingForHumanInput": true,
+ "result": null,
+ "error": null
+}
+```
+
+```json Finished
+{
+ "runState": "finished",
+ "currentStep": null,
+ "waitingForHumanInput": false,
+ "result": { "name": "Customer approved", "type": "end", "context": {} },
+ "error": null
+}
+```
+
+
+
+
+ `getWorkflowRun` only exposes runs that were **started through MCP**. A run triggered manually or by webhook is not observable here, even by the same user — asking for its id returns a not-found error.
+
+
+### Runs that need a human
+
+In this first version the assistant can *observe* a parked run but not answer it. When `waitingForHumanInput` is `true`, the run is waiting in the workflow's **fallback inbox**, and someone finishes it from the Forest UI. Relaying the step's question into the chat and submitting the answer through MCP is planned, not available yet.
+
+### Errors
+
+Tool failures come back as tool errors with an explanatory message, so the assistant can react rather than crash:
+
+| Situation | What the assistant gets |
+|---|---|
+| The workflow's MCP trigger is off, is unknown, or the user cannot reach it | Not found — with a hint to call `listWorkflows` |
+| A run is already ongoing on that record | Conflict; no run is started and none is resumed |
+| The `runId` is unknown, belongs to another user's rendering, or was not started through MCP | Not found |
+| The project has no [Forest Runtime](/product/process/workflows/forest-runtime) installed | Conflict — automated triggering needs server-side execution |
+
+### Identity, auditing, and limits
+
+- **Identity** — the run executes as the Forest user of the MCP session, established by the OAuth login. Its permissions bound everything the run can read, write, or trigger.
+- **Auditing** — each trigger is recorded in the run history and in your **Activity Logs**, attributed to that user and labelled *via MCP*, so MCP-started runs are distinguishable from manual and webhook ones.
+- **Rate limiting** — the workflow tools have no dedicated limiter. They inherit the MCP server's authentication and limits; unlike the [webhook trigger](/reference/api/endpoints/trigger-workflow-webhook#rate-limiting), there is no anonymous surface to protect. The single-run-per-record rule also absorbs repeated triggers on the same record.
+- **Turning it off** — drop `triggerWorkflow` from [`enabledTools`](#restrict-tools) to remove MCP triggering across all workflows, or disable a single workflow's MCP toggle. Either way, manual and webhook starts of that workflow keep working.
+
## Use cases
### AI-assisted operations
@@ -286,6 +428,8 @@ Use Claude or other AI assistants to:
> "Execute the 'Send Invoice' action on order #12345"
+> "Start the KYC review workflow on customer #482 and tell me where it gets to"
+
## Security
The Forest MCP server:
@@ -295,6 +439,7 @@ The Forest MCP server:
- Logs all operations for audit purposes
- Never exposes sensitive data without proper access
- Lets you shorten the OAuth token lifetimes (see [Token lifetimes](#token-lifetimes))
+- Exposes no workflow until an editor opts that workflow in (see [Triggering workflows](#triggering-workflows-from-an-ai-assistant))
Only provide MCP server access to trusted AI tools and users. The server can perform any operation that the authenticated user can perform.
diff --git a/product/execute/workflows.mdx b/product/execute/workflows.mdx
index 692487f..81c9e3a 100644
--- a/product/execute/workflows.mdx
+++ b/product/execute/workflows.mdx
@@ -31,7 +31,7 @@ Workflows can be executed from:
The workflow opens in a guided panel. The user works through each step; the workflow context accumulates as they go.
-Workflows can also be started automatically by an external system through a [webhook trigger](/product/process/workflows/triggers), without a user in the interface.
+Workflows can also start without a user in the interface — from an external system through a [webhook](/product/process/workflows/triggers), or from an AI assistant through the [Forest MCP server](/product/embed/mcp-server). When such a run reaches a step that needs a human, it is routed to the workflow's **fallback inbox**, where an operator picks it up and finishes it as usual.
## AI-powered steps
diff --git a/product/process/workflows/forest-runtime.mdx b/product/process/workflows/forest-runtime.mdx
index c13a69b..e6895d1 100644
--- a/product/process/workflows/forest-runtime.mdx
+++ b/product/process/workflows/forest-runtime.mdx
@@ -15,13 +15,13 @@ Because it talks to your data through your own Forest agent, **the Forest orches
## Do I need Forest Runtime?
-Yes — Forest Runtime is what executes your workflow steps. **[Webhook-triggered workflows](/product/process/workflows/triggers) especially**: a webhook can fire at any time, with no guarantee anyone has Forest open in a browser, so they can only run server-side.
+Yes — Forest Runtime is what executes your workflow steps. **[Automatically-triggered workflows](/product/process/workflows/triggers) especially**: a webhook call or an AI assistant can fire at any time, with no guarantee anyone has Forest open in a browser, so those runs can only execute server-side. Until Forest Runtime is installed, both automated triggers stay locked in the workflow's settings.
Running on infrastructure you control also keeps the records handled by data steps out of Forest's infrastructure — decisive for compliance or data-residency requirements, or when a step needs access to systems reachable only from within your network.
## How it works
-1. A workflow is triggered — by a user or a [webhook](/product/process/workflows/triggers). The Forest orchestrator queues the pending steps.
+1. A workflow is [triggered](/product/process/workflows/triggers) — by a user, a webhook, or an AI assistant. The Forest orchestrator queues the pending steps.
2. Forest Runtime polls the orchestrator and pulls the steps assigned to it.
3. Each step runs locally, reaching your data and actions through your Forest agent.
4. It reports the step outcome back to the orchestrator, which advances the workflow.
diff --git a/product/process/workflows/overview.mdx b/product/process/workflows/overview.mdx
index 6049e0f..3583a63 100644
--- a/product/process/workflows/overview.mdx
+++ b/product/process/workflows/overview.mdx
@@ -88,10 +88,10 @@ Workflows can also be made available in Summary Views and Workspaces.
### Triggering workflows
-By default, workflows are started manually by users from the interface. A workflow can also be triggered automatically by an external system through a **webhook**, configured in the **Process** section of the workflow settings.
+By default, workflows are started manually by users from the interface. A workflow can also be started without anyone in the interface: by an external system through a **webhook**, or by an AI assistant through the **[Forest MCP server](/product/embed/mcp-server)**. Both are opt-in per workflow, from the **Triggers** section of the workflow settings.
- Enable manual and webhook triggers, and manage the webhook URL and token
+ Enable the manual, webhook, and MCP triggers, and manage access to each
---
diff --git a/product/process/workflows/triggers.mdx b/product/process/workflows/triggers.mdx
index 0adf761..2815c1f 100644
--- a/product/process/workflows/triggers.mdx
+++ b/product/process/workflows/triggers.mdx
@@ -1,14 +1,38 @@
---
title: "Workflow triggers"
-description: "Choose how a workflow starts, manually from the interface, or automatically from an external system via a webhook."
+description: "Choose how a workflow starts — manually from the interface, from an external system via a webhook, or from an AI assistant through the Forest MCP server."
---
-A workflow can be started in two independent ways. Both are configured in the **Process** section of the workflow settings page, beneath the version card. Each trigger type has its own row with an on/off toggle, and the two can be enabled independently.
+A workflow can be started in three independent ways:
-- **Manual** — users start the workflow from a matching record in the interface (List View, Summary/Details, or a Workspace). This is the default. See [Executing workflows](/product/execute/workflows).
-- **Webhook** — external systems start the workflow via an authenticated HTTP POST. **Disabled by default.**
+| Trigger | Who starts the run | Default |
+|---|---|---|
+| **Manual** | Users, from a matching record in the interface (List View, Summary/Details, or a Workspace). See [Executing workflows](/product/execute/workflows). | Enabled |
+| **Webhook** | Any external system, via an authenticated HTTP POST to a stable URL. | Disabled |
+| **MCP** | An AI assistant (Claude, Cursor, …) connected to the [Forest MCP server](/product/embed/mcp-server). | Disabled |
+
+Each has its own on/off toggle and they can be enabled in any combination. Toggling one **never** affects the others: turning MCP off blocks MCP triggering only, and the same workflow keeps starting from the interface and from its webhook.
+
+All three are available on **all environments**, with no production-only restriction.
+
+## Where triggers are configured
+
+Open the workflow settings page and go to the **Triggers** section. **Manual** sits at the top with its own toggle, followed by an **Automated** group holding the **Fallback Inbox** selector and the **Webhook** and **MCP** rows.
+
+
+
+
-Webhook triggers are available on **all environments**, with no production-only restriction.
+### Before you can enable an automated trigger
+
+Both automated triggers (Webhook and MCP) share two prerequisites. Until both are met, their toggles stay locked, with a tooltip explaining which one is missing.
+
+- **[Forest Runtime](/product/process/workflows/forest-runtime) must be installed.** An automated run can fire at any time, with nobody holding Forest open in a browser, so its steps can only run server-side. The tooltip reads *"Ask your tech team to install the Workflow Executor."*
+- **A fallback inbox must be selected.** When an automated run reaches a step that needs a human, there is no operator on the other end to hand it to — so the run is routed to that inbox for someone to pick up. See [Inboxes & escalations](/product/manage/inbox).
+
+
+ A trigger that is already enabled stays actionable even if its fallback inbox is later cleared, so you can always turn it **off**. It re-locks once disabled.
+
## The webhook trigger
@@ -21,9 +45,9 @@ Two things are separated by design:
For the full HTTP contract, request body, response codes, idempotency, and rate limits, see the [Trigger a workflow via webhook](/reference/api/endpoints/trigger-workflow-webhook) API reference.
-## Enabling the webhook
+### Enabling the webhook
-1. Open the workflow settings page and go to the **Process** section.
+1. Open the workflow settings page and go to the **Triggers** section.
2. Toggle **Webhook** on.
Once enabled:
@@ -32,13 +56,9 @@ Once enabled:
- a hint shows the JSON body to send, with the target record's `record_id`;
- a **Generate new URL** button lets you rotate the URL (see [Regenerating the URL](#regenerating-the-url)).
-
-
-
-
Copy the URL and use it from your external system with a valid application token. The workflow starts on the record you pass in the request body.
-## Regenerating the URL
+### Regenerating the URL
If a URL may have leaked, or you simply want to rotate it, generate a new one from the **Generate new URL** button below the current URL.
@@ -55,7 +75,7 @@ When you confirm:
-## Revoking access
+### Revoking webhook access
You have three independent levers to stop a webhook, without necessarily touching the others:
@@ -67,9 +87,43 @@ You have three independent levers to stop a webhook, without necessarily touchin
Turning the toggle back on re-enables the *same* URL and token — it is a pause, not a reset.
+## The MCP trigger
+
+When enabled, an AI assistant connected to the [Forest MCP server](/product/embed/mcp-server) can discover this workflow, start it on a record, and follow the run's progress — using three tools: `listWorkflows`, `triggerWorkflow`, and `getWorkflowRun`.
+
+There is nothing to copy or rotate here: **the toggle is the whole configuration**. The assistant is already authenticated against the MCP server through OAuth, and that session's Forest user is the identity the run executes under — the same model as a manual start, not the webhook's separately-provisioned URL and token.
+
+Enabling MCP triggering is what makes the workflow visible to assistants at all:
+
+- `listWorkflows` returns only MCP-enabled workflows, and only those the connected user can reach in the rendering;
+- `triggerWorkflow` on a workflow whose MCP toggle is off fails — even if the assistant already knows its id.
+
+### Enabling MCP triggering
+
+1. Open the workflow settings page and go to the **Triggers** section.
+2. Toggle **MCP** on.
+
+That's it. Assistants connected to your Forest MCP server pick the workflow up on their next `listWorkflows` call.
+
+### What an assistant can and cannot do
+
+- It **can** start the workflow on a record and poll the run's state, current step, and outcome.
+- It **cannot** exceed the connected user's permissions — data and actions are gated by [Roles & permissions](/get-started/control/roles-permissions) exactly as in the interface.
+- It **cannot** answer a step that needs a human. A run parked on such a step is *reported* to the assistant, but finishing it happens in the Forest UI, from the fallback inbox.
+
+For the tool contracts and the discover → trigger → poll flow, see [Triggering workflows from an AI assistant](/product/embed/mcp-server#triggering-workflows-from-an-ai-assistant).
+
+### Revoking MCP access
+
+| Lever | Effect |
+|---|---|
+| **Disable the MCP toggle** | The workflow disappears from `listWorkflows` and can no longer be triggered through MCP. Manual and webhook starts are unaffected. |
+| **Restrict the MCP server's tools** | Drop `triggerWorkflow` from `enabledTools` to remove MCP triggering across *all* workflows at once. See [Restrict tools](/product/embed/mcp-server#restrict-tools). |
+| **Revoke the user's access** | The assistant acts as its connected Forest user; removing that user's access to the rendering or the workflow stops its runs. |
+
## Auditing
-Every webhook-triggered run is recorded in the workflow run history and in your **Activity Logs**, attributed to the token's user and marked as **webhook-triggered** so you can distinguish automated runs from manual ones.
+Every automated run is recorded in the workflow run history and in your **Activity Logs**, attributed to the user the run acted as, and labelled by channel — *via webhook* or *via MCP* — so you can tell automated runs from manual ones, and from each other.
## Learn more
@@ -77,6 +131,12 @@ Every webhook-triggered run is recorded in the workflow run history and in your
The HTTP contract: body, response codes, idempotency, rate limits.
+
+ The workflow tools, and the discover → trigger → poll flow.
+
+
+ Required for automated triggers: run your workflow steps server-side.
+
Build and manage workflows in the no-code editor.
diff --git a/reference/api/endpoints/trigger-workflow-webhook.mdx b/reference/api/endpoints/trigger-workflow-webhook.mdx
index 6675eb6..6e312f3 100644
--- a/reference/api/endpoints/trigger-workflow-webhook.mdx
+++ b/reference/api/endpoints/trigger-workflow-webhook.mdx
@@ -58,7 +58,7 @@ The body is JSON and is validated. Only known fields are extracted; unknown fiel
| Field | Type | Description |
|---|---|---|
-| `record_id` | string | The record the workflow runs on. Composite primary keys are supported in their packed form (e.g. `"123|456"`). |
+| `record_id` | string | The record the workflow runs on. Composite primary keys are supported in their packed form (e.g. `"123\|456"`). |
The `record_id` is **not** verified when the run is created. If the record does not exist or is inaccessible to the token's user, the run is still created and fails at its first data step during execution — observable via the run state.