MCP servers
walkerOS provides Model Context Protocol 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
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
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
Everything in this loop runs locally, no account:
- Install the plugin:
/plugin install walkeros@elbwalker - Ask: "Create a web flow with a GA4 destination, validate it, and simulate a page view."
- The assistant runs
flow_load→flow_validate→flow_simulateand shows you the result.
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)
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
npm install @walkeros/mcpProgrammatic 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
Local tools (no account)
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
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
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
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: {...} }. Addconsent(e.g.{ marketing: true }) when the destination requires it. - Collector: the enrichment step. It takes a post-
nextpartial event plus an optional state snapshot{ consent?, user?, globals?, timing? }, applies the collector'screateEvent, and returns the fully enriched event. - Sources:
{ content, trigger? }, wherecontentis the walkerOS event{ name, data }and the optionaltriggeris{ type?, options? }. There is noenvfield 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
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
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
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
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
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
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 →
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
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
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 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
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
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
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
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
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
| 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
| 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
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_URLor your CLI config resolves to. Rundiagnosticsif 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
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
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
- Settings, then Connectors.
- Add custom connector.
- URL:
https://app.walkeros.io/api/mcp. Leave every advanced setting alone. - The consent screen opens. Allow.
- The walkerOS tools appear in the client.
Claude Code
claude mcp add --transport http walkeros https://app.walkeros.io/api/mcpThen 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
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
| 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
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 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
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
| 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)
Generate, parse, and validate walkerOS data-elb HTML attributes using real DOM
parsing (JSDOM). No API token or CLI dependency required.
Installation
npm install @walkeros/mcp-source-browserTools (3)
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 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 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
| 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
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 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
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
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
"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 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
"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
- CLI: Learn about the underlying CLI commands
- Flow configuration: Understand flow structure
- HTML attributes: Learn about
data-elbtagging - MCP specification: Learn about the Model Context Protocol