> Part of the walkerOS documentation. Project overview and full index: <https://www.walkeros.io/llms.txt>

# MCP servers

walkerOS provides [Model Context Protocol](https://modelcontextprotocol.io/) servers for AI assistant integration.

| Package                        | Purpose                                                                 |
| ------------------------------ | ----------------------------------------------------------------------- |
| `@walkeros/mcp`                | Flow development: tools, reference resources, guided prompts, cloud API |
| `@walkeros/mcp-source-browser` | HTML tagging: generate, parse, and validate `data-elb` attributes       |

## Claude Code plugin[​](#claude-code-plugin "Direct link to Claude Code plugin")

The recommended way to get started in Claude Code. One plugin installs both MCP servers **and** 22 skills that teach Claude how to build sources, destinations, transformers, and flows.

**Step 1: add the marketplace:**

```
/plugin marketplace add elbwalker/walkerOS
```

**Step 2: install the plugin:**

```
/plugin install walkeros@elbwalker
```

That's it. Claude Code will reload with the MCP tools and skills active.

## Quick start[​](#quick-start "Direct link to Quick start")

For Claude Desktop or other MCP clients, add servers to your configuration manually:

```
{
  "mcpServers": {
    "walkeros-flow": {
      "command": "npx",
      "args": ["@walkeros/mcp"]
    },
    "walkeros-source-browser": {
      "command": "npx",
      "args": ["@walkeros/mcp-source-browser"]
    }
  }
}
```

Each server starts on STDIO and registers its tools automatically.

### Your first flow via AI[​](#your-first-flow-via-ai "Direct link to Your first flow via AI")

Everything in this loop runs locally, no account:

1. Install the plugin: `/plugin install walkeros@elbwalker`
2. Ask: "Create a web flow with a GA4 destination, validate it, and simulate a page view."
3. The assistant runs `flow_load` → `flow_validate` → `flow_simulate` and shows you the result.

## Environment variables[​](#environment-variables "Direct link to Environment variables")

| Variable              | Used by | Required | Default                   | Purpose                                                                                                                                     |
| --------------------- | ------- | -------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `WALKEROS_TOKEN`      | mcp     | No       | none                      | An automation token (`wos_pat_...`) from Account, Automation tokens. An alternative to the `auth` tool login, for a machine with no browser |
| `WALKEROS_PROJECT_ID` | mcp     | No       | none                      | Active project ID (`proj_...`)                                                                                                              |
| `WALKEROS_APP_URL`    | mcp     | No       | `https://app.walkeros.io` | Base URL override                                                                                                                           |

`@walkeros/mcp-source-browser` works without any environment variables. All tools are always registered. To authenticate with the walkerOS cloud, use the `auth` tool, which runs the device authorization grant and holds a session that refreshes itself, or set `WALKEROS_TOKEN` to an automation token when nobody is there to approve anything.

***

## @walkeros/mcp (flow development)[​](#walkerosmcp-flow-development "Direct link to @walkeros/mcp (flow development)")

Unified server for flow development, package discovery, reference resources, guided prompts, and cloud API. Replaces the previous separate `@walkeros/mcp-cli` and `@walkeros/mcp-api` packages.

### Installation[​](#installation "Direct link to Installation")

```
npm install @walkeros/mcp
```

### Programmatic usage[​](#programmatic-usage "Direct link to Programmatic usage")

`@walkeros/mcp` exports a transport-agnostic server factory so host applications can mount the MCP protocol over HTTP (e.g., from a Next.js Route Handler) instead of running the stdio binary:

```
import {
  createWalkerOSMcpServer,
  HttpToolClient,
  createStreamableHttpHandler,
} from '@walkeros/mcp';

const server = createWalkerOSMcpServer({
  client: new HttpToolClient(),
  version: '1.0.0',
});

const handler = createStreamableHttpHandler(server, {
  sessionIdGenerator: () => crypto.randomUUID(),
});

// In a Next.js Route Handler:
export const POST = handler;
```

To use the raw tool registry without the MCP protocol (e.g., with the Vercel AI SDK), import `TOOL_DEFINITIONS` and provide your own `ToolClient` implementation. The stdio binary stays available via `@walkeros/mcp/stdio` and the `walkeros-mcp` bin entry.

### Tools[​](#tools "Direct link to Tools")

#### Local tools (no account)[​](#local-tools-no-account "Direct link to Local tools (no account)")

##### `flow_load`[​](#flow_load "Direct link to flow_load")

Load an existing flow configuration from a local file path, URL, inline JSON, or the walkerOS API, or create a new empty flow by specifying a platform.

| Parameter  | Type                  | Required | Description                                                                                                   |
| ---------- | --------------------- | -------- | ------------------------------------------------------------------------------------------------------------- |
| `source`   | string                | No       | Flow source: file path, URL, inline JSON, or API flow/config ID (`flow_...` / `cfg_...`). Omit to create new. |
| `platform` | `"web"` \| `"server"` | No       | Platform for new flows. Required when source is omitted.                                                      |

Passing a `flow_...` or `cfg_...` ID loads that flow from the API (the same source `flow_manage` reads from). Returned configs are round-trip safe: structural values such as package names, platform, and IDs come back literally, so a loaded config can be edited and sent straight back to `flow_manage({ action: "update" })` without altering anything you did not change.

##### `flow_validate`[​](#flow_validate "Direct link to flow_validate")

Validate walkerOS events, flow configurations, mapping rules, or data contracts.

| Parameter | Type                                                 | Required | Description                                |
| --------- | ---------------------------------------------------- | -------- | ------------------------------------------ |
| `type`    | `"event"` \| `"flow"` \| `"mapping"` \| `"contract"` | Yes      | Validation type                            |
| `input`   | string                                               | Yes      | JSON string, file path, or URL to validate |
| `flow`    | string                                               | No       | Flow name for multi-flow configs           |
| `path`    | string                                               | No       | Entry path for package schema validation   |

##### `flow_bundle`[​](#flow_bundle "Direct link to flow_bundle")

Bundle a walkerOS flow configuration into deployable JavaScript.

| Parameter    | Type    | Required | Description                                                                                         |
| ------------ | ------- | -------- | --------------------------------------------------------------------------------------------------- |
| `configPath` | string  | Yes      | Flow source: file path, or an API flow/config ID (`flow_...` / `cfg_...`) resolved like `flow_load` |
| `flow`       | string  | No       | Flow name for multi-flow configs                                                                    |
| `stats`      | boolean | No       | Return bundle statistics (default: `true`)                                                          |
| `output`     | string  | No       | Output file path                                                                                    |

`configPath` accepts a cloud flow id, so you can bundle a saved flow directly without loading it to a file first. Bundle stats report the real total bundle size and the included package names (no per-package size estimate).

##### `flow_simulate`[​](#flow_simulate "Direct link to flow_simulate")

Simulate events through a walkerOS flow without making real API calls. Returns summarized per-destination results.

| Parameter    | Type                  | Required | Description                                                                                                              |
| ------------ | --------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `configPath` | string                | Yes      | Flow source: file path, or an API flow/config ID (`flow_...` / `cfg_...`) resolved like `flow_load`                      |
| `event`      | string \| object      | Yes      | Event input (see shapes below). JSON string, file path, or URL also accepted.                                            |
| `step`       | string                | Yes      | Target step as `"type.name"` (e.g. `"source.demo"`, `"collector.default"`, `"destination.gtag"`, `"transformer.router"`) |
| `flow`       | string                | No       | Flow name for multi-flow configs                                                                                         |
| `platform`   | `"web"` \| `"server"` | No       | Override platform detection                                                                                              |
| `verbose`    | boolean               | No       | Include full payload per destination (default: `false`)                                                                  |

There are four step types: `source`, `collector`, `transformer`, and `destination`. The `event` shape depends on the step type:

* **Destinations / transformers:** a walkerOS event, `{ name: "entity action", data: {...} }`. Add `consent` (e.g. `{ marketing: true }`) when the destination requires it.
* **Collector:** the enrichment step. It takes a post-`next` partial event plus an optional state snapshot `{ consent?, user?, globals?, timing? }`, applies the collector's `createEvent`, and returns the fully enriched event.
* **Sources:** `{ content, trigger? }`, where `content` is the walkerOS event `{ name, data }` and the optional `trigger` is `{ type?, options? }`. There is no `env` field in the source-step event.

Sources can be simulated as a step, including the `@walkeros/source-demo` demo source.

When `configPath` is a cloud flow id, you can simulate a saved flow without a manual file round-trip. Repeated simulations of the same configuration reuse a prebuilt bundle, so successive calls run faster (local file paths always rebuild).

A `transformer` step also accepts an optional `ingest` field, a raw ingest without `_meta`. Supply it to test a request decoder standalone, for example a GA4 decoder that reads `ctx.ingest.url`: pass `ingest: { url: "..." }` alongside the event.

##### `flow_push`[​](#flow_push "Direct link to flow_push")

Push a real event through a walkerOS flow to actual destinations. **This makes real API calls.** Best for server-side flows. Web destinations require browser globals not available in Node.js.

| Parameter    | Type                  | Required | Description                             |
| ------------ | --------------------- | -------- | --------------------------------------- |
| `configPath` | string                | Yes      | Path to flow configuration file         |
| `event`      | string                | Yes      | Event as JSON string, file path, or URL |
| `flow`       | string                | No       | Flow name for multi-flow configs        |
| `platform`   | `"web"` \| `"server"` | No       | Override platform detection             |

##### `flow_examples`[​](#flow_examples "Direct link to flow_examples")

List all step examples in a walkerOS flow configuration.

| Parameter    | Type    | Required | Description                                                                                         |
| ------------ | ------- | -------- | --------------------------------------------------------------------------------------------------- |
| `configPath` | string  | Yes      | Flow source: file path, or an API flow/config ID (`flow_...` / `cfg_...`) resolved like `flow_load` |
| `flow`       | string  | No       | Flow name for multi-flow configs                                                                    |
| `step`       | string  | No       | Filter to a specific step (e.g., `"destination.gtag"`)                                              |
| `full`       | boolean | No       | Return full in/out/mapping data (default: `false`, metadata only)                                   |

When a step has no inline examples, `flow_examples` falls back to the examples shipped with that step's package, tagged by source so you can tell inline examples from package-provided ones.

##### `package_search`[​](#package_search "Direct link to package_search")

Browse walkerOS packages or look up a specific one. Without package name: returns catalog filtered by type/platform. With package name: returns metadata.

| Parameter  | Type                                                          | Required | Description                       |
| ---------- | ------------------------------------------------------------- | -------- | --------------------------------- |
| `package`  | string                                                        | No       | Exact npm package name for lookup |
| `type`     | `"source"` \| `"destination"` \| `"transformer"` \| `"store"` | No       | Filter by type (browse)           |
| `platform` | `"web"` \| `"server"`                                         | No       | Filter by platform (browse)       |
| `version`  | string                                                        | No       | Package version (default: latest) |

In browse mode the tool returns the complete catalog. If it has to fall back to a partial source or omit packages, the response includes a `warnings` array explaining what is incomplete rather than silently returning a partial list.

##### `package_get`[​](#package_get "Direct link to package_get")

Fetch walkerOS package details from npm. By default returns schemas + hint texts + example summaries. Use `section` parameter for full content.

| Parameter | Type                                 | Required | Description                         |
| --------- | ------------------------------------ | -------- | ----------------------------------- |
| `package` | string                               | Yes      | Exact npm package name              |
| `version` | string                               | No       | Package version (default: latest)   |
| `section` | `"hints"` \| `"examples"` \| `"all"` | No       | Section to expand with full content |

##### `diagnostics`[​](#diagnostics "Direct link to diagnostics")

Report the MCP runtime surface. Read-only, takes no parameters, and works even when logged out. Reach for it when a request fails, to see which versions and backend you are on. The response includes the MCP version, the CLI version, the app URL the client resolved and whether `WALKEROS_APP_URL` is what set it, app `/api/health` reachability, the bundled OpenAPI contract version, and which source served the last package catalog lookup.

This tool has no parameters.

#### Cloud tools[​](#cloud-tools "Direct link to Cloud tools")

☁️walkerOS Cloud

These tools manage flows in the hosted app: shared projects, deploys, secrets, and live-site previews. Self-hosting? Local `flow.json` files and the CLI cover the same flow-development loop. [What Cloud adds →](https://app.walkeros.io)

##### `auth`[​](#auth "Direct link to auth")

Authenticate with the walkerOS cloud through the RFC 8628 device authorization grant. No terminal and no callback server: the tool answers with a URL, the person approves it in a browser they are already signed in to, and a second call with the same `deviceCode` resumes polling until the approval lands. The session that results refreshes itself, and it shows up under Account, Connected apps, where disconnecting it takes effect on the next call.

On the hosted door there is nothing to log in to, because every request carries its own bearer: `auth` reports `authenticated: false` there and `action: "login"` fails.

| Parameter    | Type                                  | Required | Description                                                                                                                |
| ------------ | ------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------- |
| `action`     | `"status"` \| `"login"` \| `"logout"` | Yes      | Auth action                                                                                                                |
| `deviceCode` | string                                | No       | Device code from a previous pending login. Provide with `action: "login"` to resume polling without requesting a new code. |

##### `project_manage`[​](#project_manage "Direct link to project_manage")

Manage walkerOS projects in the cloud.

| Parameter   | Type                                                                             | Required | Description                                                                                                        |
| ----------- | -------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------ |
| `action`    | `"list"` \| `"get"` \| `"create"` \| `"update"` \| `"delete"` \| `"set_default"` | Yes      | Project action                                                                                                     |
| `projectId` | string                                                                           | No       | Project ID (`proj_...`). Required for: get, update, delete, set\_default. Falls back to `WALKEROS_PROJECT_ID` env. |
| `name`      | string                                                                           | No       | Name for create/update operations                                                                                  |

##### `flow_manage`[​](#flow_manage "Direct link to flow_manage")

Manage walkerOS flow configurations and previews in the cloud.

| Parameter        | Type                                                                                                                                                                                     | Required | Description                                                                                                                                                                                                                                        |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `action`         | `"list"` \| `"get"` \| `"create"` \| `"update"` \| `"delete"` \| `"duplicate"` \| `"preview_list"` \| `"preview_get"` \| `"preview_create"` \| `"preview_delete"` \| `"preview_regrant"` | Yes      | Flow action                                                                                                                                                                                                                                        |
| `projectId`      | string                                                                                                                                                                                   | No       | Project ID (`proj_...`). Optional filter for list. Required for create if no default project set. Falls back to `WALKEROS_PROJECT_ID` env.                                                                                                         |
| `flowId`         | string                                                                                                                                                                                   | No       | Flow ID (`flow_...`) or config ID (`cfg_...`). Required for: get, update, delete, duplicate, preview\_list, preview\_get, preview\_create, preview\_delete, preview\_regrant.                                                                      |
| `name`           | string                                                                                                                                                                                   | No       | Flow name. Required for create. Optional for update (to rename) and duplicate.                                                                                                                                                                     |
| `content`        | object                                                                                                                                                                                   | No       | Flow\.Json content. Used for create and update.                                                                                                                                                                                                    |
| `patch`          | boolean                                                                                                                                                                                  | No       | Merge-patch for update (default: `true`). When true, only provided fields are updated.                                                                                                                                                             |
| `fields`         | string\[]                                                                                                                                                                                | No       | Dot-path selectors for get to return only specific fields.                                                                                                                                                                                         |
| `sort`           | `"name"` \| `"updated_at"` \| `"created_at"`                                                                                                                                             | No       | Sort field for list.                                                                                                                                                                                                                               |
| `order`          | `"asc"` \| `"desc"`                                                                                                                                                                      | No       | Sort order for list.                                                                                                                                                                                                                               |
| `includeDeleted` | boolean                                                                                                                                                                                  | No       | Include soft-deleted flows in list results.                                                                                                                                                                                                        |
| `previewId`      | string                                                                                                                                                                                   | No       | Preview ID (`prv_...`). Required for: preview\_get, preview\_delete, preview\_regrant.                                                                                                                                                             |
| `flowName`       | string                                                                                                                                                                                   | No       | Flow settings name. Used by preview\_create as an alternative to `flowSettingsId`.                                                                                                                                                                 |
| `flowSettingsId` | string                                                                                                                                                                                   | No       | Flow settings ID. Used by preview\_create as an alternative to `flowName`.                                                                                                                                                                         |
| `source`         | object                                                                                                                                                                                   | No       | What preview\_create should run: `{ "kind": "draft" }` (default) or `{ "kind": "deployment-version", "deploymentVersionId": "..." }` to preview a deployed version's stored config ("preview what's live").                                        |
| `siteUrl`        | string                                                                                                                                                                                   | No       | Optional site URL for preview\_create. When provided, an app-signed activation grant is minted for that origin and the response's `activationUrl` works there; otherwise `activationUrl` is `null` until a grant is minted (see preview\_regrant). |
| `origins`        | string\[]                                                                                                                                                                                | No       | Site origins (bare `https://host[:port]`) to mint a preview activation grant for. Used by preview\_regrant; the returned `activationUrl` targets the first origin.                                                                                 |

Configs returned by `get` are round-trip safe: structural values (package names, platform, IDs) are returned literally, so a returned config can be edited and sent back to `update` unchanged.

##### `deploy_manage`[​](#deploy_manage "Direct link to deploy_manage")

Deploy walkerOS flows and manage deployments.

| Parameter   | Type                                            | Required    | Description                                                                                                                                                                   |
| ----------- | ----------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `action`    | `"deploy"` \| `"list"` \| `"get"` \| `"delete"` | Yes         | Deployment action                                                                                                                                                             |
| `flowId`    | string                                          | Conditional | Flow ID. Required for: `deploy`, `get`, `delete`. Optional filter for `list`.                                                                                                 |
| `slug`      | string                                          | No          | Deployment slug. Optional disambiguator for `get`/`delete` when the flow has multiple active deployments.                                                                     |
| `projectId` | string                                          | No          | Project ID. Optional; falls back to the default project.                                                                                                                      |
| `type`      | `"web"` \| `"server"`                           | No          | Deployment type filter for `list`.                                                                                                                                            |
| `status`    | string                                          | No          | Status filter for `list`.                                                                                                                                                     |
| `wait`      | boolean                                         | No          | Wait for the deployment to reach a terminal status (default: `true`), with a 120-second budget. Set `false` to return the deployment id immediately. Only used with `deploy`. |
| `flowName`  | string                                          | No          | Flow name for multi-settings flows. Only used with `deploy`.                                                                                                                  |
| `cursor`    | string                                          | No          | Pagination cursor from a previous `list` response. Only used with `list`.                                                                                                     |
| `limit`     | number                                          | No          | Max items per page (1-100). Only used with `list`.                                                                                                                            |

A finished `deploy` carries its status and, on failure, an `errorMessage` with the user-facing reason; use the `get` action to re-read it.

When a flow has more than one active deployment and no `slug` is supplied, `get` and `delete` return a `MULTIPLE_DEPLOYMENTS` error with a `details[]` list so the caller can pick a specific deployment. Soft-deleted deployments are always excluded.

```
{

  "error": "Flow flow_abc has 2 active deployments; pass slug to disambiguate",

  "code": "MULTIPLE_DEPLOYMENTS",

  "details": [

    { "slug": "abc123456789", "type": "web", "status": "active", "updatedAt": "2026-04-20T00:00:00.000Z" },

    { "slug": "def987654321", "type": "web", "status": "active", "updatedAt": "2026-04-21T00:00:00.000Z" }

  ]

}
```

##### `secret_manage`[​](#secret_manage "Direct link to secret_manage")

Manage a flow's secrets, the `$env.<NAME>` values its steps reference at deploy and run time.

| Parameter   | Type                                            | Required    | Description                                                                                                 |
| ----------- | ----------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------- |
| `action`    | `"list"` \| `"set"` \| `"update"` \| `"delete"` | Yes         | Secret action                                                                                               |
| `flowId`    | string                                          | Yes         | Flow ID (`flow_...`) or config ID (`cfg_...`). Secrets are flow-scoped, so it is required for every action. |
| `projectId` | string                                          | No          | Project ID. Optional; falls back to the default project.                                                    |
| `name`      | string                                          | Conditional | Secret name (UPPER\_SNAKE\_CASE, referenced as `$env.<NAME>`). Required for `set`.                          |
| `value`     | string                                          | Conditional | Secret value (1-65536 chars). Required for `set` and `update`. Write-only: never returned or logged.        |
| `secretId`  | string                                          | Conditional | Secret ID (`sec_...`). Required for `update` and `delete`. Use `list` to find it.                           |

Required fields per action:

| Action   | Required fields               | Effect                              |
| -------- | ----------------------------- | ----------------------------------- |
| `list`   | `flowId`                      | Return secret metadata for the flow |
| `set`    | `flowId`, `name`, `value`     | Create a new secret                 |
| `update` | `flowId`, `secretId`, `value` | Rotate an existing secret's value   |
| `delete` | `flowId`, `secretId`          | Remove a secret                     |

Secrets are write-mostly. Values are encrypted at rest and are NEVER returned, listed, or echoed back: `set` and `update` respond with metadata only, and `list` returns names, ids, and timestamps but no values. The only way to learn a secret's value is to rotate it with a new one.

Reference a secret from any flow step as `$env.<NAME>`, for example `$env.API_TOKEN`.

```
{

  "action": "set",

  "flowId": "flow_abc",

  "name": "API_TOKEN",

  "value": "the-secret-value"

}
```

##### `observe_session`[​](#observe_session "Direct link to observe_session")

Open, inspect, or end an Observe session: a time-boxed window on one flow that runtimes attach to as arms. A preview arm streams from a browser, a container arm runs server-side, and both feed one shared journeys feed.

| Parameter        | Type                                 | Required | Description                                                                                                                                                                                                                                                                   |
| ---------------- | ------------------------------------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `action`         | `"start"` \| `"status"` \| `"stop"`  | Yes      | `start` opens a session, `status` reports arm state, `stop` ends the whole session.                                                                                                                                                                                           |
| `flowId`         | string                               | Yes      | Flow the Observe session runs on.                                                                                                                                                                                                                                             |
| `projectId`      | string                               | No       | Project ID. Optional; falls back to the default project.                                                                                                                                                                                                                      |
| `sessionId`      | string                               | No       | Session to act on for `status`/`stop`. Optional; the flow has at most one session and it is resolved for you.                                                                                                                                                                 |
| `arms`           | object                               | No       | Which runtimes attach. Omit to attach the default preview arm; a web settings that references a server flow brings its container arm with it.                                                                                                                                 |
| `arms.container` | `true`                               | No       | Pass `true` to attach the server container arm, which selects the flow's server settings when no preview arm is named. Only `true` is accepted: a web settings that references a server flow always brings its container arm along, so a container cannot be suppressed here. |
| `arms.preview`   | string                               | No       | Name the flow settings this session observes. A web settings attaches the browser preview arm (plus the container arm of any server flow it references); a server settings attaches the container arm alone. Omit to use the flow's single web settings.                      |
| `origins`        | string\[]                            | No       | Bare https origins (`https://host[:port]`) the session may ingest web events from.                                                                                                                                                                                            |
| `level`          | `"off"` \| `"standard"` \| `"trace"` | No       | Container observation verbosity. Defaults to the app's own.                                                                                                                                                                                                                   |
| `replace`        | boolean                              | No       | Replace the flow's existing window instead of attaching to it. Re-provisions from the new config.                                                                                                                                                                             |

A flow has at most one session, so `status` and `stop` resolve it from `flowId` when `sessionId` is omitted. `status` reports per-arm state plus `recordsReceived` and `expiresAt`; `stop` ends the whole session including every arm.

This tool never returns event data and never judges whether events are correct. Read the events with `observe_journeys`.

##### `observe_journeys`[​](#observe_journeys "Direct link to observe_journeys")

Read the assembled, cross-runtime journeys for a flow that is currently being observed (an active Observe session). Read-only.

| Parameter   | Type   | Required | Description                                                                                   |
| ----------- | ------ | -------- | --------------------------------------------------------------------------------------------- |
| `flowId`    | string | Yes      | Flow to read journeys for (its active Observe session).                                       |
| `projectId` | string | No       | Project ID. Optional; falls back to the default project.                                      |
| `traceId`   | string | No       | Return only the journeys of this run, which is every event of one page load or container run. |
| `limit`     | number | No       | Max journeys to return (1-100, most recent kept). Defaults to 50.                             |

Each journey is one event reconstructed end to end across web and server: its ordered hops (source, transformer, collector, destination), each hop status (pending/done/skipped/error), captured in/out payloads, consent, and vendor calls. Use it to see which destinations fired, what mapping ran, where an event was skipped or errored, and whether records were lost (`gaps` plus a journey `lossy` flag).

The result also carries an optional `unattributed` summary: records that belonged to a run but could not be attributed to any event. It is absent when there are none, and it counts the whole session rather than the returned page, so `limit` never hides loss.

When the flow has no active Observe session the result is `{ "sessionId": null, "journeys": [], "gaps": [] }`. Start an Observe session and drive traffic first, then read again.

##### `hub_manage`[​](#hub_manage "Direct link to hub_manage")

Read a flow's release history and the reasoning behind it: what each release changed, and why. `release_get` returns a diff the server computes against the release before it, and a diff is never accepted from a caller. Writes are additive: `rationale_set` records why a release happened, `note_add` appends to a discussion, and there is no delete. Threads are resolved by a person in the app, never here. Steps are addressed as `type.name`, the same form `flow_simulate` takes. Needs the `hub` feature.

| Parameter       | Type                                                                                                                     | Required | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| --------------- | ------------------------------------------------------------------------------------------------------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `action`        | `"releases"` \| `"release_get"` \| `"step_history"` \| `"rationale_set"` \| `"threads"` \| `"note_add"` \| `"knowledge"` | Yes      | Which part of the release history to read or write                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `projectId`     | string                                                                                                                   | No       | Project ID (`proj_...`). Optional: falls back to the default project when omitted.                                                                                                                                                                                                                                                                                                                                                                                                     |
| `flowId`        | string                                                                                                                   | No       | Flow ID (`flow_...`). Required for every action except `knowledge`, which hangs on a page rather than a flow and refuses this field.                                                                                                                                                                                                                                                                                                                                                   |
| `versionId`     | string                                                                                                                   | No       | Release version ID (`ver_...`) from action `releases`. Addresses one release for `release_get` and `rationale_set`. Pass this or `versionNumber`.                                                                                                                                                                                                                                                                                                                                      |
| `versionNumber` | number                                                                                                                   | No       | Spine release number for this flow, the `versionNumber` field of action `releases`. Alternative to `versionId`. Not the same as a row's `deploymentAttempt`.                                                                                                                                                                                                                                                                                                                           |
| `step`          | string                                                                                                                   | No       | Step key as `type.name`, e.g. `destination.ga4` or `contract.checkout`. Required for `step_history`.                                                                                                                                                                                                                                                                                                                                                                                   |
| `flow`          | string                                                                                                                   | No       | Named flow inside the config, e.g. `web` or `server`. Optional for `step_history`: omit to scan every named flow. Ignored for contract steps, which are top-level.                                                                                                                                                                                                                                                                                                                     |
| `text`          | string                                                                                                                   | No       | The text to write (1-4000 chars). Required for `rationale_set` and `note_add`. As rationale it replaces the note already on the release and never touches the machine summary. As a note it is appended to a thread and nothing is ever replaced.                                                                                                                                                                                                                                      |
| `limit`         | number                                                                                                                   | No       | Page size. Releases to list for action `releases` (max 100), or releases to scan for `step_history` (max 50). For `step_history` this bounds releases, not entries: a step present in several named flows yields one entry per flow per release, and the scan stops at 200 entries with `entriesTruncated` set. Narrow with `flow` to avoid that. For `threads` it bounds threads, and a read that carries messages is held to 20 of them. Knowledge entries are bounded the same way. |
| `offset`        | number                                                                                                                   | No       | Releases to skip. Action `releases` only.                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `anchorType`    | `"step"` \| `"entity_action"` \| `"release"` \| `"contract"` \| `"tag"`                                                  | No       | What a thread hangs on. Defaults to `release`, the only anchor the app writes today. Pair it with `anchorKey`, since a key means a different thing under each type.                                                                                                                                                                                                                                                                                                                    |
| `anchorKey`     | string                                                                                                                   | No       | What the anchor addresses within its type: a release version ID (`ver_...`) for `release`, a `type.name` step key for `step`. For a release you can pass `versionId` or `versionNumber` instead. Omit entirely on action `threads` to read every thread on the flow.                                                                                                                                                                                                                   |
| `anchorLabel`   | string                                                                                                                   | No       | How the anchor reads on screen, stored once when a thread is opened so a later rename leaves it readable. Derived for a release (`v14`). Pass it only when opening a thread on another anchor type.                                                                                                                                                                                                                                                                                    |
| `threadId`      | string                                                                                                                   | No       | Thread ID (`thr_...`) from action `threads`. Pass it to `note_add` to reply in that thread, omit it to open a new thread on the anchor.                                                                                                                                                                                                                                                                                                                                                |
| `status`        | `"open"` \| `"resolved"`                                                                                                 | No       | Read only threads in this state. Action `threads` only, omit for both.                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `pageKey`       | string                                                                                                                   | No       | The page a note was left on, as Tag Mode addressed it, usually the page URL. Narrows action `knowledge` to every frame that page holds, at any depth. Omit it to read the whole project.                                                                                                                                                                                                                                                                                               |
| `frameId`       | string                                                                                                                   | No       | One frame (`frm_...`), the named rectangle a note hangs on. Action `knowledge` only. Narrower than `pageKey`, since a page holds several frames.                                                                                                                                                                                                                                                                                                                                       |
| `markId`        | string                                                                                                                   | No       | One mark within `frameId`. Action `knowledge` only, and refused without `frameId`, since a mark id alone addresses nothing. Naming a mark is also what attaches the message bodies.                                                                                                                                                                                                                                                                                                    |

##### `frame_manage`[​](#frame_manage "Direct link to frame_manage")

Read the frames of a measurement plan: named rectangles with marks inside them, drawn in Tag Mode or in the app. A frame name is documentation, the marks inside it carry the meaning. Read-only, because a frame's geometry only means something next to the pixels it was drawn on, so frames are edited where the page is. Use `hub_manage` with action `knowledge` to read what people wrote on a frame. Needs the `frames` feature.

| Parameter   | Type                            | Required | Description                                                                                                                                         |
| ----------- | ------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `action`    | `"list"` \| `"page"` \| `"get"` | Yes      | `list` returns every frame of the project without marks, `page` returns one page's frames with their marks, `get` returns one frame with its marks. |
| `projectId` | string                          | No       | Project ID (`proj_...`). Optional: falls back to the default project when omitted.                                                                  |
| `pageKey`   | string                          | No       | The page as its frames address it (the `source.key` of a page frame, usually the page URL without query). Required for `page`.                      |
| `frameId`   | string                          | No       | Frame ID (`frm_...`). Required for `get`. Use action `list` or `page` to find one.                                                                  |

### Resources[​](#resources "Direct link to Resources")

| URI                                | Description                                                 |
| ---------------------------------- | ----------------------------------------------------------- |
| `walkeros://reference/flow-schema` | Flow\.Json structure and connection rules                   |
| `walkeros://reference/event-model` | Event naming, properties, auto-populated fields             |
| `walkeros://reference/mapping`     | Mapping syntax (data/map/loop/set/condition/consent/policy) |
| `walkeros://reference/consent`     | Consent model (destination/rule/field level)                |
| `walkeros://reference/variables`   | Variable patterns ($var/$env/$code/$store)                  |
| `walkeros://reference/contract`    | Event schemas, wildcards, inheritance                       |
| `walkeros://reference/openapi`     | OpenAPI 3.1 specification                                   |
| `walkeros://reference/packages`    | Full package catalog                                        |
| `walkeros://schema/{packageName}`  | Per-package JSON schemas                                    |

### Prompts[​](#prompts "Direct link to Prompts")

| Prompt            | Description                                                 |
| ----------------- | ----------------------------------------------------------- |
| `add-step`        | Add a source, destination, transformer, or store to a flow  |
| `setup-mapping`   | Configure event mapping for a step                          |
| `manage-contract` | Create/update event contracts (bidirectional with mappings) |

### Links back into the app[​](#links-back-into-the-app "Direct link to Links back into the app")

Cloud tools that answer about something you can look at return a link to that screen, so the answer and the screen arrive together instead of leaving you to go find it.

| Tool            | Actions that return a link            | Screen                                  |
| --------------- | ------------------------------------- | --------------------------------------- |
| `flow_manage`   | `get`, `create`                       | the flow page                           |
| `deploy_manage` | `deploy`, `get`                       | the deployment's detail page            |
| `hub_manage`    | `releases`, `step_history`, `threads` | the flow's release history, or the step |

The link is a full URL in the response field **`appUrl`**. It is `appUrl` and never `url`, because a deployment response already carries `url` and that means where the deployment is serving.

```
{

  "releases": [{ "versionId": "ver_...", "versionNumber": 7, "status": "active" }],

  "total": 12,

  "appUrl": "https://app.walkeros.io/projects/proj_x/flows/flow_y?view=releases"

}
```

The address is the app's own: `/projects/{projectId}/flows/{flowId}` for a flow, `/projects/{projectId}/deployments/{deploymentId}` for a deployment, and a `view` query param for a screen on the flow page (`releases`, `contract`, `step`, and the rest). A step is `?view=step&flow=<named flow>&step=<type.name>`, the same `flow` and `step` vocabulary `hub_manage` takes as parameters.

Two things worth knowing:

* **The link points at the app the door is connected to.** The hosted door answers with its own origin; the local door answers with whatever `WALKEROS_APP_URL` or your CLI config resolves to. Run `diagnostics` if you are unsure which backend you are on.
* **No link is better than a wrong one.** When a tool cannot name a screen that exists, the response simply carries no `appUrl`. A step scan that named no flow, a step whose last change was its removal, and a thread anchored to anything but a release all fall in that bucket.

## Two doors, one tool set[​](#two-doors-one-tool-set "Direct link to Two doors, one tool set")

Every `@walkeros/mcp` tool is registered on both doors, and both doors run the same code against the same app.

| Door   | How it runs                                                                                                                                  | Auth                                       |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| Local  | `npx @walkeros/mcp` over stdio, or the Claude Code plugin. The local tools run on your own machine, the cloud tools call the app over HTTPS. | `auth` tool login, or `WALKEROS_TOKEN`     |
| Hosted | `POST https://app.walkeros.io/api/mcp` over Streamable HTTP. Tools run inside the app.                                                       | OAuth, discovered from the endpoint itself |

Three things behave differently.

**File paths.** `flow_load`, `flow_validate`, `flow_bundle`, `flow_simulate`, `flow_push`, and `flow_examples` accept a file path, and a path names the filesystem of the machine running the door. On the local door that is your machine. On the hosted door it is the app server, which cannot read your files. Give the hosted door inline JSON or a flow ID instead of a path.

**Login.** `auth` runs the device authorization grant on the local door. The hosted door authenticates every request with its own bearer instead, so there is nothing to log in to: `auth` reports `authenticated: false` there and `action: "login"` fails. Skip the tool on that door.

**The selected project.** `project_manage` action `set_default` is remembered differently by each door. The local door writes it to your CLI config file, so it survives restarts. The hosted door holds it only for as long as the connection lasts, and a reconnect starts with no project selected. Passing `projectId` on the call always works and is the form to prefer on the hosted door. A call with no project names both remedies in its error, so an assistant can recover without guessing.

## Connect Claude Desktop, claude.ai or Cursor[​](#connect-claude-desktop-claudeai-or-cursor "Direct link to Connect Claude Desktop, claude.ai or Cursor")

The hosted door is one HTTPS endpoint: `https://app.walkeros.io/api/mcp`. It is the only value a client needs. No token, no header, no advanced field.

The endpoint runs an OAuth 2.1 authorization server, and a standard MCP client finds it on its own. You paste the URL, the client discovers who authorizes it and registers itself, a browser opens on a consent screen, you press Allow, and the client holds a token it refreshes without ever asking again.

### Claude Desktop and claude.ai[​](#claude-desktop-and-claudeai "Direct link to Claude Desktop and claude.ai")

1. Settings, then Connectors.
2. Add custom connector.
3. URL: `https://app.walkeros.io/api/mcp`. Leave every advanced setting alone.
4. The consent screen opens. Allow.
5. The walkerOS tools appear in the client.

### Claude Code[​](#claude-code "Direct link to Claude Code")

```
claude mcp add --transport http walkeros https://app.walkeros.io/api/mcp
```

Then run `/mcp` inside Claude Code and choose to sign in. A browser opens on the consent screen, Allow, and the browser hands back to Claude Code on a local port. `/mcp` then lists the walkerOS tools.

### Cursor and other MCP clients[​](#cursor-and-other-mcp-clients "Direct link to Cursor and other MCP clients")

Any client that speaks Streamable HTTP MCP takes the same URL, `https://app.walkeros.io/api/mcp`, in its MCP server settings. Everything else is discovered.

### What the consent screen asks for[​](#what-the-consent-screen-asks-for "Direct link to What the consent screen asks for")

| Permission                   | What it means                                                                   |
| ---------------------------- | ------------------------------------------------------------------------------- |
| Read your projects and flows | List and read projects, flows, deployments, settings and observation data.      |
| Change and deploy flows      | Create, edit, deploy and delete flows, and manage project secrets and previews. |
| Stay connected               | Keep working without signing in again, until you disconnect it.                 |

Consent is per person, once, and it applies to every project that person belongs to. Which project a given action touches stays a choice made in the conversation, not at connect time.

If you are not signed in to walkerOS in that browser, the magic-link login runs first and hands back to the consent screen afterwards.

### Disconnecting[​](#disconnecting "Direct link to Disconnecting")

Account, then Connected apps, lists every connected client with the permissions it was given and when it last called. Disconnect takes effect on that app's very next request, and it can be connected again at any time.

### A credential for a machine[​](#a-credential-for-a-machine "Direct link to A credential for a machine")

A script, a CI job or a self-hosted MCP server has nobody to press Allow. Mint an automation token instead, under Account, then Automation tokens: pick read or read and write, pick a lifetime, and copy the `wos_pat_...` value once. Pass it as `WALKEROS_TOKEN`, or as `Authorization: Bearer` against either door.

### What your plan has to include[​](#what-your-plan-has-to-include "Direct link to What your plan has to include")

A connected client acts as you: it reads and changes every project you are a member of, within what your plan enables. The endpoint needs the `mcp` feature, `hub_manage` needs `hub`, and `frame_manage` needs `frames`. A call to a feature your plan does not include answers `FEATURE_NOT_AVAILABLE` and names the feature. Connecting before the plan includes MCP is fine; the consent screen says so, and no reconnect is needed after an upgrade.

### If something goes wrong[​](#if-something-goes-wrong "Direct link to If something goes wrong")

| Symptom                                                           | Cause                                                      | Fix                                                   |
| ----------------------------------------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------- |
| The client says it cannot authenticate                            | The URL is wrong, or points at an environment that is down | Check it is exactly `https://app.walkeros.io/api/mcp` |
| The browser opens on the login page instead of the consent screen | Not signed in to walkerOS in that browser                  | Sign in; the consent screen follows on its own        |
| Tools are listed but every call is refused                        | The plan does not include the `mcp` feature                | Upgrade the project's plan                            |
| The app suddenly asks to reconnect                                | It was disconnected under Account, Connected apps          | Reconnect it, or leave it disconnected                |

Against stage, substitute `https://stage.app.walkeros.io/api/mcp`; against a local app, `http://localhost:3000/api/mcp`.

***

## @walkeros/mcp-source-browser (HTML tagging tools)[​](#walkerosmcp-source-browser-html-tagging-tools "Direct link to @walkeros/mcp-source-browser (HTML tagging tools)")

Generate, parse, and validate walkerOS `data-elb` HTML attributes using real DOM parsing (JSDOM). No API token or CLI dependency required.

### Installation[​](#installation-1 "Direct link to Installation")

```
npm install @walkeros/mcp-source-browser
```

### Tools (3)[​](#tools-3 "Direct link to Tools (3)")

#### `generate_tagging`[​](#generate_tagging "Direct link to generate_tagging")

Generate walkerOS `data-elb` HTML attributes from structured input. Returns attribute key-value pairs and an example HTML snippet.

| Parameter | Type   | Required | Description                                                                |
| --------- | ------ | -------- | -------------------------------------------------------------------------- |
| `entity`  | string | No       | Entity name (creates `data-elb="entity"`)                                  |
| `data`    | object | No       | Entity properties as key<!-- -->:value<!-- --> pairs                       |
| `action`  | object | No       | Trigger<!-- -->:action<!-- --> pairs for `data-elbaction` (nearest entity) |
| `actions` | object | No       | Trigger<!-- -->:action<!-- --> pairs for `data-elbactions` (all entities)  |
| `context` | object | No       | Context properties for `data-elbcontext`                                   |
| `globals` | object | No       | Global properties for `data-elbglobals`                                    |
| `link`    | object | No       | Link relationships for `data-elblink`                                      |
| `prefix`  | string | No       | Custom prefix (default: `data-elb`)                                        |

At least one parameter must be provided.

#### `parse_tagging`[​](#parse_tagging "Direct link to parse_tagging")

Parse HTML with `data-elb` attributes using real DOM parsing (JSDOM). Extracts all walkerOS events and globals.

| Parameter | Type   | Required | Description                             |
| --------- | ------ | -------- | --------------------------------------- |
| `html`    | string | Yes      | HTML snippet with `data-elb` attributes |
| `prefix`  | string | No       | Custom prefix (default: `data-elb`)     |

#### `validate_tagging`[​](#validate_tagging "Direct link to validate_tagging")

Validate HTML `data-elb` tagging for common mistakes. Checks for orphan actions, missing entities, unknown triggers, orphan properties, and entities without actions.

| Parameter | Type   | Required | Description                         |
| --------- | ------ | -------- | ----------------------------------- |
| `html`    | string | Yes      | HTML snippet to validate            |
| `prefix`  | string | No       | Custom prefix (default: `data-elb`) |

### Resources[​](#resources-1 "Direct link to Resources")

| URI                                       | Description                                         |
| ----------------------------------------- | --------------------------------------------------- |
| `walkeros://docs/tagging/html-attributes` | Complete guide to `data-elb` HTML attribute tagging |
| `walkeros://docs/tagging/tagger`          | `createTagger()` fluent API reference               |

***

## Example workflows[​](#example-workflows "Direct link to Example workflows")

### Create and validate a flow[​](#create-and-validate-a-flow "Direct link to Create and validate a flow")

Ask your AI assistant:

> "Create a new web flow, add a GA4 destination, then validate it."

The assistant uses `flow_load` to create a skeleton, the `add-step` prompt to add GA4, and `flow_validate` to check the result.

### Simulate events[​](#simulate-events "Direct link to Simulate events")

> "Simulate a page view event through my flow at ./flow\.json."

The assistant calls `flow_simulate` and returns per-destination results showing which destinations received the event.

### Deploy a flow[​](#deploy-a-flow "Direct link to Deploy a flow")

☁️walkerOS Cloud

Requires a walkerOS account. The local loop (create, validate, simulate) needs none.

> "Deploy flow cfg\_abc123 and wait for it to finish."

The assistant calls `deploy_manage({ action: "deploy", flowId: "cfg_abc123" })` and streams progress updates through bundling, publishing, and activation.

### Preview a flow on a live site[​](#preview-a-flow-on-a-live-site "Direct link to Preview a flow on a live site")

☁️walkerOS Cloud

Requires a walkerOS account. The local loop (create, validate, simulate) needs none.

> "Create a preview of my demo settings on flow\_abc123 and give me the link to open on <https://example.com>."

The assistant calls `flow_manage({ action: "preview_create", flowId: "flow_abc123", flowName: "demo", siteUrl: "https://example.com" })` and returns the grant-based `activationUrl` the user clicks to activate preview mode on their site. To activate on additional origins later, the assistant calls `flow_manage({ action: "preview_regrant", flowId: "flow_abc123", previewId: "prv_...", origins: [...] })` to mint a fresh grant. Running `flow_manage({ action: "preview_delete", … })` later removes the bundle; the production walker self-heals on visitors' next page load.

### Set up event mapping[​](#set-up-event-mapping "Direct link to Set up event mapping")

> "Help me set up mapping for the gtag destination in my flow."

The assistant uses the `setup-mapping` prompt, reads the mapping reference resource, fetches package examples, and generates mapping rules.

### Generate HTML tagging[​](#generate-html-tagging "Direct link to Generate HTML tagging")

> "Generate data-elb attributes for a promotion entity with name 'Summer Sale' and a click action."

The assistant calls `generate_tagging` with `entity: "promotion"`, `data: { name: "Summer Sale" }`, and `action: { click: "click" }`, returning ready-to-use HTML attributes.

### Discover a package[​](#discover-a-package "Direct link to Discover a package")

> "What configuration does the Snowplow destination need?"

The assistant calls `package_search` for `@walkeros/web-destination-snowplow`, then `package_get` to fetch schemas, hints, and examples.

## Next steps[​](#next-steps "Direct link to Next steps")

* **[CLI](https://www.walkeros.io/docs/apps/cli.md)**: Learn about the underlying CLI commands
* **[Flow configuration](https://www.walkeros.io/docs/getting-started/modes/bundled.md)**: Understand flow structure
* **[HTML attributes](https://www.walkeros.io/docs/sources/web/browser/tagging/html-attributes.md)**: Learn about `data-elb` tagging
* **[MCP specification](https://modelcontextprotocol.io/)**: Learn about the Model Context Protocol
