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

# MCP Server Reference

> Complete reference for WebRun's Model Context Protocol server

## Overview

The WebRun MCP (Model Context Protocol) server gives AI assistants browser automation through their native tool interfaces. It exposes 21 tools covering one-off tasks, persistent sessions, live task control, saved workflows, and scheduled agents, with session lifecycle handling and streaming for long-running tasks.

<Note>
  This is the **full reference** for the MCP server. For a quickstart guide, see [MCP Quickstart](/getting-started/mcp-quickstart).
</Note>

***

## Configuration

Every client uses the same server URL:

```
https://api.webrun.ai/mcp
```

Authentication travels in headers, never in the URL.

| Header | Required | Value |
| - | - | - |
| `API-Key` | Yes, unless connecting by OAuth | Your WebRun API key |
| `Environment-Id` | No | The 24-character hex ID of a persistent environment. Provide it and tasks run on that machine, keeping state between them. Omit it and every task gets its own temporary browser, discarded when the task ends |

<Tip>
  A key in a header stays out of browser history, shell history and proxy logs, and can be rotated without editing a URL that may already have been copied elsewhere.
</Tip>

### Connect with OAuth (Claude and ChatGPT)

No API key needed. In Claude or ChatGPT, open **Settings → Connectors → Add custom connector**, paste `https://api.webrun.ai/mcp`, and authorize from WebRun when prompted.

If you have more than one environment, the one you pick during authorization becomes the connection's default.

***

### Claude Code

```bash theme={null}
claude mcp add --transport http webrun https://api.webrun.ai/mcp --header "API-Key: YOUR_API_KEY" --header "Environment-Id: 65f0a1b2c3d4e5f60718293a"
```

`--header` is repeatable — that is how both values are passed in one command.

Or, to share the connection with a project, add this to `.mcp.json` at the repo root:

```json theme={null}
{
  "mcpServers": {
    "webrun": {
      "type": "http",
      "url": "https://api.webrun.ai/mcp",
      "headers": {
        "API-Key": "${WEBRUN_API_KEY}",
        "Environment-Id": "65f0a1b2c3d4e5f60718293a"
      }
    }
  }
}
```

Delete the `Environment-Id` line to get a fresh disposable machine for every task.

<Warning>
  `"type": "http"` is required. Claude Code reads a `url` entry with no `type` as a local command, and the server will not start.
</Warning>

`${WEBRUN_API_KEY}` is expanded from your environment when the file loads, so the file is safe to commit. The environment ID is not a secret and can stay inline.

***

### Cursor

`~/.cursor/mcp.json`, or `.cursor/mcp.json` inside a project:

```json theme={null}
{
  "mcpServers": {
    "webrun": {
      "url": "https://api.webrun.ai/mcp",
      "headers": {
        "API-Key": "${env:WEBRUN_API_KEY}",
        "Environment-Id": "65f0a1b2c3d4e5f60718293a"
      }
    }
  }
}
```

Delete the `Environment-Id` line to get a fresh disposable machine for every task.

Cursor does not use a `type` field for remote servers, and its variable syntax is `${env:NAME}`.

***

### Claude Desktop

Claude Desktop's configuration file only supports local (stdio) servers, so connect through **Settings → Connectors** using the OAuth flow above — no key, no file editing, and you choose the environment during authorization.

If you must use the config file, bridge it with `mcp-remote`:

```json theme={null}
{
  "mcpServers": {
    "webrun": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote", "https://api.webrun.ai/mcp",
        "--header", "API-Key:${WEBRUN_KEY}",
        "--header", "Environment-Id:65f0a1b2c3d4e5f60718293a"
      ],
      "env": { "WEBRUN_KEY": "YOUR_API_KEY" }
    }
  }
}
```

Delete the second `--header` pair to get a fresh disposable machine for every task.

<Note>
  The headers are written without a space after the colon on purpose — `mcp-remote` splits `--header` arguments on spaces.
</Note>

After editing, quit Claude Desktop completely and reopen it.

***

### VS Code

`.vscode/mcp.json` — note the top-level key is `servers`, not `mcpServers`:

```json theme={null}
{
  "servers": {
    "webrun": {
      "type": "http",
      "url": "https://api.webrun.ai/mcp",
      "headers": {
        "API-Key": "${input:webrun-api-key}",
        "Environment-Id": "65f0a1b2c3d4e5f60718293a"
      }
    }
  },
  "inputs": [
    { "type": "promptString", "id": "webrun-api-key", "description": "WebRun API key", "password": true }
  ]
}
```

Delete the `Environment-Id` line to get a fresh disposable machine for every task.

VS Code prompts for the key on first use and stores it securely rather than in the file.

***

### Cline

Open the Cline panel, use the menu in its top-right corner, choose **MCP Servers**, and edit `cline_mcp_settings.json`:

```json theme={null}
{
  "mcpServers": {
    "webrun": {
      "type": "streamableHttp",
      "url": "https://api.webrun.ai/mcp",
      "headers": {
        "API-Key": "YOUR_API_KEY",
        "Environment-Id": "65f0a1b2c3d4e5f60718293a"
      }
    }
  }
}
```

Delete the `Environment-Id` line to get a fresh disposable machine for every task.

<Warning>
  `"type": "streamableHttp"` is camelCase with no hyphen. Writing `streamable-http`, or leaving `type` out, makes Cline fall back to SSE and the connection fails with a 405.
</Warning>

Cline does not expand environment variables in this file, so the key goes in literally — keep the file out of version control.

***

## Environments

An environment is a complete persistent remote machine. It maintains its own Chrome browser, file manager, and desktop state across sessions, so browser profiles, downloaded files, cookies, and any other local state are preserved between tasks and you can pick up exactly where you left off.

**The `Environment-Id` header is optional.** Both ways of running are fully supported:

| Environment ID | What you get |
| - | - |
| **Provided** | Every task runs on that persistent environment. Logins, cookies, downloaded files and browser profile carry over from one task to the next |
| **Omitted** | Every task gets its own temporary browser, created when the task starts and discarded when it ends. Nothing carries over |

Leaving the header out is a normal configuration, not a broken one. Omit it when every task should start from a clean slate, and add an environment when you need the browser to remember something — a logged-in account, a downloaded file, an installed extension.

**Where to find the ID:** ask the assistant to list your environments, or copy it from the Environment page in the dashboard. It is a 24-character hex string, and it is not a secret — it is safe to commit.

**Three ways to choose one:**

| How | When |
| - | - |
| The `Environment-Id` header | A config file — sets the default for the whole connection |
| Chosen during OAuth authorization | Claude and ChatGPT connectors, which have no config file |
| The `environmentId` argument on any task tool | Per task, overriding whatever the connection uses |

The per-task argument means you can keep one connection and still send one task to your logged-in shopping profile and the next to a clean machine.

***

## Full Tool Reference

### browser\_task

Execute a single browser automation task. Creates a session, runs the task, and auto-terminates.

**When to use:**

* One-off research tasks
* Quick data extraction
* Simple automations that don't require follow-up

<Warning>
  Do not use `browser_task` to run or test a saved workflow — use [`trigger_workflow`](#trigger_workflow). Only a workflow run carries the workflow's own rules, tracking and memory.
</Warning>

**Parameters:**

| Parameter | Type | Required | Default | Description |
| - | - | - | - | - |
| `prompt` | string | Yes | - | Natural language description of the task |
| `startingUrl` | string | No | null | URL to start from (e.g., "[https://google.com](https://google.com)") |
| `environmentId` | string | No | connection default | Environment to run in. Without one, the task gets its own temporary browser, discarded when it ends |
| `maxDuration` | number | No | 20 | Max task duration **in minutes** (max 60) |
| `outputType` | string | No | `"text"` | `"text"`, `"structured_json"`, or `"structured_csv"` |
| `outputSchema` | object | Conditional | - | JSON Schema for the output. Required when `outputType` is `"structured_json"` |
| `files` | string\[] | No | - | File IDs to attach (from `/files/upload`). Max 5 |
| `secrets` | object\[] | No | - | Domain-matched secrets `[{match, fields}]`, passed to the instance and not stored |
| `proxy` | object | No | none | Proxy configuration — see [Proxies](/usage-guides/proxies) |
| `policyId` | string | No | - | Policy to apply automation guardrails (domain restrictions, capability controls) |
| `model` | string | No | account default | Model name or profile key |
| `timezone` | string | No | `"UTC"` | IANA timezone name. Date-sensitive instructions ("tomorrow morning") are interpreted in it |
| `webhook` | object | No | - | Completion notification — see [Webhooks](/usage-guides/webhooks) |
| `reach_out_mode` | string | No | `"off"` | Proactive chat messages. `"off"`, `"guardrail_only"`, or `"full"` |

**Example Usage:**

```
User: "Use WebRun to search Google for 'Anthropic Claude' and summarize the first result."

Claude uses browser_task:
{
  "prompt": "Go to google.com, search for 'Anthropic Claude', and summarize the first result",
  "startingUrl": "https://google.com",
  "maxDuration": 10
}
```

**Response:**

```json theme={null}
{
  "success": true,
  "sessionId": "a1b2c3d4e5f6",
  "taskId": "x9y8z7w6v5u4",
  "result": "Anthropic is an AI safety company that created Claude, a next-generation AI assistant...",
  "usage": {
    "prompt_tokens": 12450,
    "completion_tokens": 3200,
    "total_tokens": 15650,
    "cost": 0.0124
  }
}
```

***

### create\_session

Create a persistent browser session for multi-step workflows. Returns a `sessionId` for subsequent commands.

**When to use:**

* Multi-step automations (search → click → extract)
* Tasks requiring context from previous steps
* When you need to send multiple commands to the same browser

**Parameters:**

| Parameter | Type | Required | Default | Description |
| - | - | - | - | - |
| `task` | object | No | - | Initial task. Omit it to create an idle session |
| `environmentId` | string | No | connection default | Environment to run in. Without one, the task gets its own temporary browser, discarded when it ends |
| `mode` | string | No | `"default"` | Session mode |
| `model` | string | No | account default | Model name or profile key |
| `policyId` | string | No | - | Policy to apply automation guardrails |
| `proxy` | object | No | none | Proxy configuration — see [Proxies](/usage-guides/proxies) |
| `timezone` | string | No | `"UTC"` | IANA timezone name for the session |
| `reach_out_mode` | string | No | `"off"` | `"off"`, `"guardrail_only"`, or `"full"` |

The nested `task` object accepts `prompt`, `startingUrl`, `maxDuration` (minutes), `outputType`, `outputSchema`, `files`, `secrets`, `terminateOnCompletion`, and `webhook`.

**Example Usage:**

```
User: "Create a browser session and go to amazon.com"

Claude uses create_session:
{
  "task": {
    "prompt": "Go to amazon.com",
    "startingUrl": "https://amazon.com",
    "maxDuration": 20
  }
}
```

**Response:**

```json theme={null}
{
  "success": true,
  "sessionId": "a1b2c3d4e5f6",
  "message": "Session created successfully. You can now send tasks to this session.",
  "expiresIn": 300000,
  "streamingUrl": "https://a1b2c3d4e5f6.webrun.ai"
}
```

<Tip>
  Save the `sessionId` to send follow-up tasks with [`send_task`](#send_task).
</Tip>

***

### send\_task

Send a new task to an existing session.

**When to use:**

* Follow-up actions in a multi-step workflow
* Continuing work in an existing browser session
* Chaining related tasks together

**Parameters:**

| Parameter | Type | Required | Default | Description |
| - | - | - | - | - |
| `sessionId` | string | Yes | - | ID from `create_session` |
| `prompt` | string | Yes | - | Task description |
| `startingUrl` | string | No | - | URL to navigate to before starting this task |
| `maxDuration` | number | No | session value | Max duration for this task **in minutes** (3–60) |
| `maxInputTokens` | number | No | session value | Max input tokens (100–3,000,000) |
| `maxOutputTokens` | number | No | session value | Max output tokens (100–1,000,000) |
| `outputType` | string | No | `"text"` | `"text"`, `"structured_json"`, or `"structured_csv"` |
| `outputSchema` | object | Conditional | - | Required when `outputType` is `"structured_json"` |
| `files` | string\[] | No | - | File IDs to attach. Max 5 |
| `secrets` | object\[] | No | - | Domain-matched secrets, not stored |
| `terminateOnCompletion` | boolean | No | false | Auto-close session after this task |
| `webhook` | object | No | - | Completion notification |

**Example Usage:**

```
User: "Now search for wireless keyboards"

Claude uses send_task:
{
  "sessionId": "a1b2c3d4e5f6",
  "prompt": "Search for wireless keyboards and list the top 3 results with prices",
  "terminateOnCompletion": false
}
```

**Response:**

```json theme={null}
{
  "success": true,
  "sessionId": "a1b2c3d4e5f6",
  "taskId": "x9y8z7w6v5u4",
  "result": "Found 3 wireless keyboards:\n1. Logitech K380 - $29.99\n2. Keychron K2 - $79.00\n3. ...",
  "usage": {
    "cost": 0.0089
  }
}
```

<Warning>
  Set `terminateOnCompletion: true` on your final task to avoid idle session charges.
</Warning>

***

### get\_task\_status

Check the status of a running task. Read-only — it reports on the task without affecting it.

**When to use:**

* Monitoring long-running tasks
* Detecting when a guardrail needs an answer
* Checking if a task completed while doing other work

**Parameters:**

| Parameter | Type | Required | Description |
| - | - | - | - |
| `sessionId` | string | Yes | Session ID |
| `taskId` | string | Yes | Task ID from previous task |

**Response (still running):**

```json theme={null}
{
  "success": true,
  "status": "active",
  "pending": true,
  "usage": {
    "inputTokens": 8000,
    "outputTokens": 2100,
    "computeTime": 3,
    "cost": 0.0067
  }
}
```

**Response (completed):**

```json theme={null}
{
  "success": true,
  "status": "completed",
  "type": "task_completed",
  "data": {
    "message": "Task completed successfully",
    "prompt_tokens": 12450,
    "completion_tokens": 3200,
    "total_tokens": 15650,
    "completion_time": 23.5
  },
  "usage": {
    "cost": 0.0124
  }
}
```

<Tip>
  When the status reports that input is awaited, answer with [`guardrail_response`](#guardrail_response).
</Tip>

***

### screenshot

Capture the current browser page of an active session and return it as an inline image. Read-only.

**When to use:**

* Seeing what the agent sees before deciding the next step
* Confirming a page loaded as expected
* Debugging a task that is behaving unexpectedly

**Parameters:**

| Parameter | Type | Required | Description |
| - | - | - | - |
| `sessionId` | string | Yes | Session ID |

***

### list\_sessions

List all active browser sessions for the account. Read-only. Takes no parameters.

***

### terminate\_session

End a session and free its resources.

**Parameters:**

| Parameter | Type | Required | Description |
| - | - | - | - |
| `sessionId` | string | Yes | Session ID |

<Warning>
  The session and any task running in it cannot be resumed afterwards.
</Warning>

***

### pause\_session\_task

Pause the task currently running in a session. Resume it later with `resume_session_task`.

**Parameters:** `sessionId` (string, required).

***

### resume\_session\_task

Resume a previously paused task.

**Parameters:** `sessionId` (string, required).

***

### stop\_session\_task

Cancel the task currently running, keeping the session alive for new tasks.

**Parameters:** `sessionId` (string, required).

***

### guardrail\_response

Respond when the browser agent needs human input — credentials, a CAPTCHA or 2FA prompt, a clarification, or an approval. The response is handed to the live agent, which continues acting on it.

**Parameters:**

| Parameter | Type | Required | Default | Description |
| - | - | - | - | - |
| `sessionId` | string | Yes | - | Session ID |
| `response` | string | Conditional | - | Your response or instructions to the agent. Required when `newState` is `"resume"` |
| `newState` | string | No | `"resume"` | `"resume"` provides the input and continues; `"deny"` declines the request |
| `files` | string\[] | No | - | File IDs to attach. Max 5 |

**Example Usage:**

```
Claude uses get_task_status and sees the agent is waiting on a login code.

Claude uses guardrail_response:
{
  "sessionId": "a1b2c3d4e5f6",
  "response": "The verification code is 481920",
  "newState": "resume"
}
```

<Note>
  MCP has no manual-takeover tool. For hands-on control of the browser — clicking and typing yourself — use the REST or WebSocket [manual interaction](/usage-guides/manual-interaction) actions alongside the [video stream](/usage-guides/video-streaming).
</Note>

See [Handling Guardrails](/usage-guides/handling-guardrails) for the full flow.

***

### list\_environments

List available persistent environments for the account and show which one the connection is using. Read-only. Takes no parameters.

Use it to find the `environmentId` for a persistent session. Workflows and agents use the connection's environment automatically.

***

### list\_workflows

List saved workflows — prompt-templated browser automations — with each one's title, schedule, `{{variables}}`, and run stats. Read-only.

**Parameters:**

| Parameter | Type | Required | Default | Description |
| - | - | - | - | - |
| `scope` | string | No | `"environment"` | `"environment"` lists workflows in the bound environment; `"all"` lists every workflow on the account |

***

### get\_workflow

Full detail of one workflow: prompt template, variables and defaults, trigger and schedule, run settings, memory state, and any pending logins. Read-only; proxy credentials are masked.

**Parameters:** `workflowId` (24-hex ID) or `title` (exact, case-insensitive).

***

### create\_workflow

Create a new saved workflow.

**Parameters:**

| Parameter | Type | Required | Description |
| - | - | - | - |
| `title` | string | Yes | Workflow title shown on the dashboard |
| `promptTemplate` | string | Yes | The task, written as a browsing runbook: `Goal:`, ground rules, one `Stage N` per site, and an `Output —` contract |
| `memoryContract` | object | Conditional | Required whenever the task must handle each item exactly once. Three plain-English fields: `groundRules`, `memoryInstruction`, `itemIdentity` |
| `startingUrl` | string | No | Page Chrome opens at the start of each run |
| `outputType` | string | No | `"text"`, `"structured"`, or `"structured_csv"` |
| `outputSchema` | object \| array | No | JSON Schema, or column names for `structured_csv` |
| `schedule` | object | No | Saved setting only — see the warning below |
| `templateVariables` | array | No | Metadata for `{{variables}}`, only for deliberately reusable templates |
| `environmentId` | string | No | Rarely needed; the connection's environment is applied automatically |

Presentation and run settings — `model`, `proxy`, `timezone`, `policyId`, `requiredFiles`, `shortDescription`, `triggerPhrase` and others — are all optional and default sensibly.

<Warning>
  A `schedule` on a workflow is recorded as a setting only. The workflow does not run on a timer until it is deployed as a scheduled agent with [`create_agent`](#create_agent).
</Warning>

<Tip>
  Write concrete values (group names, URLs, numbers) directly into `promptTemplate`. Use `{{variables}}` only for a reusable template whose inputs genuinely change per run.
</Tip>

***

### update\_workflow

Update an existing workflow. Supply `workflowId` (required) plus only the fields to change. Object and array fields are replaced whole; pass `null` to clear an optional field. Renaming via `title` keeps the slug stable.

`memoryContract` is the exception to whole-replacement: supplying its three fields updates them while platform tracking details are preserved.

***

### trigger\_workflow

Run a workflow now in its deployed environment. Returns a `sessionId` — poll `get_task_status` for the result.

**Parameters:**

| Parameter | Type | Required | Description |
| - | - | - | - |
| `workflowId` | string | Conditional | 24-hex workflow ID — or use `title` |
| `title` | string | Conditional | Exact workflow title, case-insensitive |
| `variables` | object | No | Values for the workflow's `{{variables}}`, merged over stored defaults |
| `force` | boolean | No | Work-list workflows only: re-open a completed list for a fresh full pass |

<Warning>
  This is the only correct way to run or test a saved workflow. A run started with `browser_task` or `create_session` does not carry the workflow's rules, tracking or memory, so it will behave differently.
</Warning>

***

### create\_agent

Create a scheduled agent — a recurring or one-time automation that runs on a timer.

**Two modes:**

| Mode | How | What happens |
| - | - | - |
| Workflow | Pass `workflowId` + `schedule` | Prompt, starting URL, output contract, model, proxy, policy and files are copied from the workflow; results and memory stay centralised on it |
| Standalone | Omit `workflowId`; pass `name`, `prompt`, `schedule` | Runs on its own in the connection's environment |

**Parameters:**

| Parameter | Type | Required | Description |
| - | - | - | - |
| `schedule` | object | Yes | `{ type: "at" \| "every" \| "cron", ... }` — see below |
| `workflowId` | string | Conditional | Workflow mode: the workflow to deploy |
| `name` | string | Conditional | Required standalone; defaults to the workflow title otherwise |
| `prompt` | string | Conditional | Required standalone: the browsing runbook to run |
| `variables` | object | No | Workflow mode: values baked in at deploy time and reused every run |
| `startingUrl` | string | No | Standalone: page Chrome opens each run |
| `outputType` / `outputSchema` | - | No | Standalone: output contract |
| `expiresAt` | string | No | ISO 8601 date-time after which the agent auto-pauses |

**Schedule shapes:**

| `type` | Field | Meaning |
| - | - | - |
| `"at"` | `at` | ISO 8601 date-time — fires once |
| `"every"` | `interval` | Repeat interval in ms (minimum 60000) |
| `"cron"` | `cron` | 5-field cron expression |

All three accept `timezone` (IANA name, default UTC), which drives both the fire times and the browser session.

***

### list\_agents

List the account's scheduled agents: schedule, status, next and last run, and whether each is standalone or deployed from a workflow. Read-only.

**Parameters:** `scope` — `"environment"` (default when bound) or `"all"`.

***

### pause\_agent

Pause an active scheduled agent — it stops firing until resumed.

**Parameters:** `agentId` (24-hex, required).

***

### resume\_agent

Resume a paused agent, recomputing its next run. A completed work-list agent restarts with a fresh full pass.

**Parameters:** `agentId` (24-hex, required).

<Note>
  `resume_agent` refuses if the agent's expiry has already passed. Extend it on the dashboard first.
</Note>

***

## Advanced Patterns

### Pattern 1: Multi-Step Research Workflow

```
User: "Research wireless keyboards on Amazon. First go to Amazon, search for wireless keyboards, then tell me about the top 3 results."

Claude's execution:
1. Uses create_session:
   {
     "task": {
       "prompt": "Go to amazon.com",
       "startingUrl": "https://amazon.com"
     }
   }
   → Gets sessionId: "abc123"

2. Uses send_task:
   {
     "sessionId": "abc123",
     "prompt": "Search for wireless keyboards"
   }
   → Gets search results

3. Uses send_task:
   {
     "sessionId": "abc123",
     "prompt": "Extract the names, prices, and ratings of the top 3 results",
     "terminateOnCompletion": true
   }
   → Gets structured data and auto-terminates
```

***

### Pattern 2: Guardrail Handling

```
User: "Log in to example.com and extract my dashboard data"

Claude's execution:
1. Uses create_session:
   {
     "task": {
       "prompt": "Go to example.com and log in",
       "startingUrl": "https://example.com"
     }
   }
   → Agent reaches the login form and raises a guardrail

2. Uses get_task_status:
   { "sessionId": "abc123", "taskId": "task456" }
   → Reports the agent is awaiting input

3. Claude asks the user for the one-time code

4. Uses guardrail_response:
   {
     "sessionId": "abc123",
     "response": "The verification code is 481920",
     "newState": "resume"
   }
   → Agent continues

5. Uses send_task:
   {
     "sessionId": "abc123",
     "prompt": "Extract all dashboard data",
     "terminateOnCompletion": true
   }
   → Completes task
```

<Tip>
  Use an environment for sites you log into repeatedly. The session stays authenticated, so later tasks skip the login entirely.
</Tip>

***

### Pattern 3: Long Task with Status Monitoring

```
User: "Scrape all product listings from this marketplace (might take a while)"

Claude's execution:
1. Uses create_session, then send_task with maxDuration: 45

2. While the task runs, uses get_task_status every 30 seconds:
   {
     "sessionId": "abc123",
     "taskId": "task456"
   }

3. Reports progress to user:
   "Task is still running. So far used 15,000 tokens, cost: $0.012"

4. When status changes to "completed", retrieves final result
```

***

### Pattern 4: Inspect, Then Correct

```
User: "Go to example.com and extract all links"

Claude's execution:
1. Uses create_session with the task
   → Result looks wrong: far fewer links than expected

2. Uses screenshot:
   { "sessionId": "abc123" }
   → Sees a cookie banner covering the page

3. Uses send_task:
   {
     "sessionId": "abc123",
     "prompt": "Dismiss the cookie banner, then extract all links",
     "terminateOnCompletion": true
   }
   → Succeeds
```

***

### Pattern 5: Run a Saved Workflow on a Schedule

```
User: "Run my 'Daily competitor prices' workflow every weekday at 8am UK time."

Claude's execution:
1. Uses list_workflows to find it
   → workflowId: "65f0a1b2c3d4e5f60718293b"

2. Uses trigger_workflow once to check it works:
   { "workflowId": "65f0a1b2c3d4e5f60718293b" }
   → Polls get_task_status for the result

3. Uses create_agent to put it on a timer:
   {
     "workflowId": "65f0a1b2c3d4e5f60718293b",
     "schedule": { "type": "cron", "cron": "0 8 * * 1-5", "timezone": "Europe/London" }
   }
```

***

## Troubleshooting

### Tools Not Appearing

**Symptoms:** MCP tools don't show up, or no browser automation options are available.

**Solutions:**

1. **Claude Code:** run `claude mcp get webrun`. The most common cause is a missing `"type": "http"` — without it the entry is treated as a local command.

2. **Cursor and VS Code:** confirm the top-level key. Cursor uses `mcpServers`, VS Code uses `servers`.

3. **Cline:** confirm `"type": "streamableHttp"` — camelCase, no hyphen. `streamable-http` or a missing `type` falls back to SSE and fails with a 405.

4. **Claude Desktop:** the config file only accepts local (stdio) servers. Use **Settings → Connectors**, or bridge with `mcp-remote` as shown above.

5. **Check JSON syntax:**
   ```bash theme={null}
   cat .mcp.json | jq .
   # Should output valid JSON without errors
   ```

6. **Claude Desktop logs:**
   * macOS: `~/Library/Logs/Claude/mcp*.log`
   * Windows: `%APPDATA%\Claude\logs\mcp*.log`

<Note>
  Claude Code, Cursor and VS Code pick up config changes without a restart. Only Claude Desktop needs a full quit and reopen.
</Note>

***

### It Connects but Every Task Fails

The server lists its tools without a key, so a connection with a missing or wrong key looks perfectly healthy until the first task runs.

**Solutions:**

1. **Check the header name and value.** It is `API-Key`, and the value is the key on its own — no `Bearer` prefix.

2. **Confirm the key is active:** open the dashboard, check the key exists and has not been revoked, and generate a new one if needed.

3. **Check the account has balance.**

4. **Test the key against the REST API:**
   ```bash theme={null}
   curl -X POST https://api.webrun.ai/start/run-task \
     -H "Authorization: Bearer YOUR_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{"task": {"prompt": "Go to google.com"}}'

   # Should return success, not 401
   ```

***

### Authentication Errors

**Error:** `"Invalid API key"` or `"Unauthorized"`

Keys start with `wr_` or `enig_`. Confirm the key is active in the dashboard and that the account has balance. Check for stray spaces or quotes around the header value.

***

### "Environment not found"

The `Environment-Id` must be a 24-character hex string belonging to your account. Ask the assistant to list your environments, or copy the ID from the Environment page in the dashboard.

If you meant to run on a disposable machine, remove the header entirely rather than leaving it blank.

***

### Session Timeout Errors

**Error:** `"Session not found"` or `"Session expired"`

**Cause:** sessions expire after **5 minutes of inactivity** (fixed, not configurable). Separately, a single task runs for up to **20 minutes** by default.

**Solutions:**

1. **Raise the task cap** — pass `maxDuration` in minutes, up to 60:
   ```json theme={null}
   {
     "sessionId": "abc123",
     "prompt": "Complex task",
     "maxDuration": 45
   }
   ```

2. **Break long work into chunks:**
   ```
   // Bad: One huge task
   "Extract data from all 100 pages"

   // Good: Chunked tasks
   "Extract data from pages 1-10"
   "Extract data from pages 11-20"
   ```

3. **Use `get_task_status`** to check progress and detect stalls early.

***

### Task Failures

**Error:** `"Navigation timeout"`, `"Element not found"`, etc.

**Solutions:**

1. **Make instructions more specific:**
   ```
   // Vague
   "Get the price"

   // Specific
   "Find the product price displayed near the 'Add to Cart' button"
   ```

2. **Use `screenshot`** to see what the agent sees before guessing at a fix.

3. **Use `startingUrl` for known websites:**
   ```json theme={null}
   {
     "prompt": "Search for wireless keyboards",
     "startingUrl": "https://amazon.com"
   }
   ```

4. **Check for CAPTCHAs or login requirements** — answer with `guardrail_response`, or use an environment that is already logged in.

***

## Tool Parameter Reference

### Quick Reference Table

| Tool | Required Parameters | Key Optional Parameters |
| - | - | - |
| `browser_task` | `prompt` | `startingUrl`, `environmentId`, `maxDuration`, `outputType`, `outputSchema`, `files`, `secrets`, `proxy`, `policyId`, `model`, `timezone`, `webhook`, `reach_out_mode` |
| `create_session` | - | `task`, `environmentId`, `mode`, `model`, `policyId`, `proxy`, `timezone`, `reach_out_mode` |
| `send_task` | `sessionId`, `prompt` | `startingUrl`, `maxDuration`, `maxInputTokens`, `maxOutputTokens`, `outputType`, `outputSchema`, `files`, `secrets`, `terminateOnCompletion`, `webhook` |
| `get_task_status` | `sessionId`, `taskId` | - |
| `screenshot` | `sessionId` | - |
| `list_sessions` | - | - |
| `terminate_session` | `sessionId` | - |
| `pause_session_task` | `sessionId` | - |
| `resume_session_task` | `sessionId` | - |
| `stop_session_task` | `sessionId` | - |
| `guardrail_response` | `sessionId` | `response`, `newState`, `files` |
| `list_environments` | - | - |
| `list_workflows` | - | `scope` |
| `get_workflow` | `workflowId` or `title` | - |
| `create_workflow` | `title`, `promptTemplate` | `memoryContract`, `startingUrl`, `outputType`, `outputSchema`, `schedule`, `templateVariables` |
| `update_workflow` | `workflowId` | any field to change |
| `trigger_workflow` | `workflowId` or `title` | `variables`, `force` |
| `create_agent` | `schedule` | `workflowId`, `name`, `prompt`, `variables`, `startingUrl`, `expiresAt` |
| `list_agents` | - | `scope` |
| `pause_agent` | `agentId` | - |
| `resume_agent` | `agentId` | - |

### Parameter Details

**prompt** (string)

* Natural language description of the task
* Be specific for better results
* Good: "Search Google for 'Anthropic' and summarize the first result"
* Good: "Extract all product names and prices from this page"
* Avoid: "Search" (too vague)

**startingUrl** (string)

* Must be a valid HTTP/HTTPS URL
* Optional, but speeds up navigation compared to "go to amazon.com"

**environmentId** (string)

* Optional. 24-character hex ID of a persistent environment
* Overrides the connection's `Environment-Id` header for this one call
* Omit it on a connection with no environment and the task runs on its own temporary browser, discarded when the task ends

**maxDuration** (number)

* Maximum task duration **in minutes**
* Default: 20 · Maximum: 60 · On `send_task`, minimum 3
* Examples: `10` = 10 minutes, `45` = 45 minutes

<Warning>
  The MCP tools take `maxDuration` in **minutes**. The [REST API](/api-reference/parameters#maxduration) takes the same parameter in milliseconds — do not copy a value from one to the other.
</Warning>

**sessionId** (string)

* Returned from `create_session`, `browser_task` and `trigger_workflow`

**taskId** (string)

* Returned from task execution, and required by `get_task_status`

**terminateOnCompletion** (boolean)

* `true`: auto-close the session after the task completes
* `false` (default): keep the session alive for follow-up tasks

**newState** (string, `guardrail_response`)

* `"resume"` (default): provides the requested input and continues the task. `response` is required
* `"deny"`: declines the request. `response` is optional

**outputType** (string) and **outputSchema**

* `"text"` (default), `"structured_json"`, or `"structured_csv"`
* `outputSchema` is required for `"structured_json"` — see [Structured Output](/usage-guides/structured-output)

**reach\_out\_mode** (string)

* Controls proactive chat messages to a user (Telegram, WhatsApp, Slack, Discord, Teams) connected to the same environment when no one is watching the session live
* `"off"` (default): no proactive messages — guardrails and results stay on the MCP channel only. Best for sessions handling private data
* `"guardrail_only"`: pings the chat user on guardrails (CAPTCHA, 2FA, verification, login) when the API caller is offline
* `"full"`: pings on guardrails **and** delivers the task result on completion
* Available on `browser_task` and `create_session`. Each bot user additionally filters by their own preference
* See [Routing Guardrails to a Chat User](/usage-guides/handling-guardrails#routing-guardrails-to-a-chat-user)

***

## Best Practices

### 1. Session Management

**Do:**

* Use `browser_task` for one-off tasks
* Use `create_session` + `send_task` for multi-step workflows
* Use `trigger_workflow` — never `browser_task` — to run or test a saved workflow
* Always set `terminateOnCompletion: true` on your final task
* Terminate sessions explicitly with `terminate_session` when done

**Don't:**

* Create multiple sessions for related tasks
* Leave sessions running after completion
* Use `create_session` for simple one-off tasks

***

### 2. Task Instructions

**Do:**

* Be specific and detailed
* Include the expected output format
* Specify wait conditions if needed
* Provide starting URLs when known

**Don't:**

* Use vague instructions like "get data"
* Assume the agent knows which element to click
* Skip important context

***

### 3. Error Handling

**Do:**

* Monitor long tasks with `get_task_status`
* Use `screenshot` to see the real page state before retrying
* Answer CAPTCHAs and 2FA prompts with `guardrail_response`
* Raise `maxDuration` (in minutes) rather than letting a long task be cut off

**Don't:**

* Ignore timeout warnings
* Retry indefinitely without changes
* Assume tasks will always succeed

***

### 4. Cost Optimization

**Do:**

* Terminate sessions when done
* Use `terminateOnCompletion` on final tasks
* Break very long tasks into chunks
* Reuse sessions for related tasks

**Don't:**

* Leave sessions idle
* Create new sessions for each small task
* Ignore session timeout warnings

***

<Accordion title="Related Guides">
  <CardGroup cols={2}>
    <Card title="MCP Quickstart" icon="rocket" href="/getting-started/mcp-quickstart">
      Connect Claude, ChatGPT, Claude Code, Cursor, VS Code or Cline
    </Card>

    <Card title="Multi-Task Workflows" icon="list-check" href="/usage-guides/multi-task-workflows">
      Build complex automation sequences
    </Card>

    <Card title="Handling Guardrails" icon="shield-halved" href="/usage-guides/handling-guardrails">
      Respond to human-in-the-loop requests
    </Card>

    <Card title="Environments" icon="server" href="/environments/overview">
      Persistent machines that keep logins and files
    </Card>
  </CardGroup>
</Accordion>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.