Skip to main content
Ask your AI

MCP servers

walkerOS provides Model Context Protocol servers for AI assistant integration.

PackagePurpose
@walkeros/mcpFlow development: tools, reference resources, guided prompts, cloud API
@walkeros/mcp-source-browserHTML 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:

  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_loadflow_validateflow_simulate and shows you the result.

Environment variables

VariableUsed byRequiredDefaultPurpose
WALKEROS_TOKENmcpNononeAn automation token (wos_pat_...) from Account, Automation tokens. An alternative to the auth tool login, for a machine with no browser
WALKEROS_PROJECT_IDmcpNononeActive project ID (proj_...)
WALKEROS_APP_URLmcpNohttps://app.walkeros.ioBase 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/mcp

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

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.

ParameterTypeRequiredDescription
sourcestringNoFlow source: file path, URL, inline JSON, or API flow/config ID (flow_... / cfg_...). Omit to create new.
platform"web" | "server"NoPlatform 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.

ParameterTypeRequiredDescription
type"event" | "flow" | "mapping" | "contract"YesValidation type
inputstringYesJSON string, file path, or URL to validate
flowstringNoFlow name for multi-flow configs
pathstringNoEntry path for package schema validation
flow_bundle

Bundle a walkerOS flow configuration into deployable JavaScript.

ParameterTypeRequiredDescription
configPathstringYesFlow source: file path, or an API flow/config ID (flow_... / cfg_...) resolved like flow_load
flowstringNoFlow name for multi-flow configs
statsbooleanNoReturn bundle statistics (default: true)
outputstringNoOutput 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.

ParameterTypeRequiredDescription
configPathstringYesFlow source: file path, or an API flow/config ID (flow_... / cfg_...) resolved like flow_load
eventstring | objectYesEvent input (see shapes below). JSON string, file path, or URL also accepted.
stepstringYesTarget step as "type.name" (e.g. "source.demo", "collector.default", "destination.gtag", "transformer.router")
flowstringNoFlow name for multi-flow configs
platform"web" | "server"NoOverride platform detection
verbosebooleanNoInclude 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

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.

ParameterTypeRequiredDescription
configPathstringYesPath to flow configuration file
eventstringYesEvent as JSON string, file path, or URL
flowstringNoFlow name for multi-flow configs
platform"web" | "server"NoOverride platform detection
flow_examples

List all step examples in a walkerOS flow configuration.

ParameterTypeRequiredDescription
configPathstringYesFlow source: file path, or an API flow/config ID (flow_... / cfg_...) resolved like flow_load
flowstringNoFlow name for multi-flow configs
stepstringNoFilter to a specific step (e.g., "destination.gtag")
fullbooleanNoReturn 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.

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

ParameterTypeRequiredDescription
packagestringNoExact npm package name for lookup
type"source" | "destination" | "transformer" | "store"NoFilter by type (browse)
platform"web" | "server"NoFilter by platform (browse)
versionstringNoPackage 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.

ParameterTypeRequiredDescription
packagestringYesExact npm package name
versionstringNoPackage version (default: latest)
section"hints" | "examples" | "all"NoSection 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

☁️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 →

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.

ParameterTypeRequiredDescription
action"status" | "login" | "logout"YesAuth action
deviceCodestringNoDevice 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.

ParameterTypeRequiredDescription
action"list" | "get" | "create" | "update" | "delete" | "set_default"YesProject action
projectIdstringNoProject ID (proj_...). Required for: get, update, delete, set_default. Falls back to WALKEROS_PROJECT_ID env.
namestringNoName for create/update operations
flow_manage

Manage walkerOS flow configurations and previews in the cloud.

ParameterTypeRequiredDescription
action"list" | "get" | "create" | "update" | "delete" | "duplicate" | "preview_list" | "preview_get" | "preview_create" | "preview_delete" | "preview_regrant"YesFlow action
projectIdstringNoProject ID (proj_...). Optional filter for list. Required for create if no default project set. Falls back to WALKEROS_PROJECT_ID env.
flowIdstringNoFlow ID (flow_...) or config ID (cfg_...). Required for: get, update, delete, duplicate, preview_list, preview_get, preview_create, preview_delete, preview_regrant.
namestringNoFlow name. Required for create. Optional for update (to rename) and duplicate.
contentobjectNoFlow.Json content. Used for create and update.
patchbooleanNoMerge-patch for update (default: true). When true, only provided fields are updated.
fieldsstring[]NoDot-path selectors for get to return only specific fields.
sort"name" | "updated_at" | "created_at"NoSort field for list.
order"asc" | "desc"NoSort order for list.
includeDeletedbooleanNoInclude soft-deleted flows in list results.
previewIdstringNoPreview ID (prv_...). Required for: preview_get, preview_delete, preview_regrant.
flowNamestringNoFlow settings name. Used by preview_create as an alternative to flowSettingsId.
flowSettingsIdstringNoFlow settings ID. Used by preview_create as an alternative to flowName.
sourceobjectNoWhat preview_create should run: { "kind": "draft" } (default) or { "kind": "deployment-version", "deploymentVersionId": "..." } to preview a deployed version's stored config ("preview what's live").
siteUrlstringNoOptional 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).
originsstring[]NoSite 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.

ParameterTypeRequiredDescription
action"deploy" | "list" | "get" | "delete"YesDeployment action
flowIdstringConditionalFlow ID. Required for: deploy, get, delete. Optional filter for list.
slugstringNoDeployment slug. Optional disambiguator for get/delete when the flow has multiple active deployments.
projectIdstringNoProject ID. Optional; falls back to the default project.
type"web" | "server"NoDeployment type filter for list.
statusstringNoStatus filter for list.
waitbooleanNoWait 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.
flowNamestringNoFlow name for multi-settings flows. Only used with deploy.
cursorstringNoPagination cursor from a previous list response. Only used with list.
limitnumberNoMax 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.

ParameterTypeRequiredDescription
action"list" | "set" | "update" | "delete"YesSecret action
flowIdstringYesFlow ID (flow_...) or config ID (cfg_...). Secrets are flow-scoped, so it is required for every action.
projectIdstringNoProject ID. Optional; falls back to the default project.
namestringConditionalSecret name (UPPER_SNAKE_CASE, referenced as $env.<NAME>). Required for set.
valuestringConditionalSecret value (1-65536 chars). Required for set and update. Write-only: never returned or logged.
secretIdstringConditionalSecret ID (sec_...). Required for update and delete. Use list to find it.

Required fields per action:

ActionRequired fieldsEffect
listflowIdReturn secret metadata for the flow
setflowId, name, valueCreate a new secret
updateflowId, secretId, valueRotate an existing secret's value
deleteflowId, secretIdRemove 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.

ParameterTypeRequiredDescription
action"start" | "status" | "stop"Yesstart opens a session, status reports arm state, stop ends the whole session.
flowIdstringYesFlow the Observe session runs on.
projectIdstringNoProject ID. Optional; falls back to the default project.
sessionIdstringNoSession to act on for status/stop. Optional; the flow has at most one session and it is resolved for you.
armsobjectNoWhich runtimes attach. Omit to attach the default preview arm; a web settings that references a server flow brings its container arm with it.
arms.containertrueNoPass 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.previewstringNoName 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.
originsstring[]NoBare https origins (https://host[:port]) the session may ingest web events from.
level"off" | "standard" | "trace"NoContainer observation verbosity. Defaults to the app's own.
replacebooleanNoReplace 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.

ParameterTypeRequiredDescription
flowIdstringYesFlow to read journeys for (its active Observe session).
projectIdstringNoProject ID. Optional; falls back to the default project.
traceIdstringNoReturn only the journeys of this run, which is every event of one page load or container run.
limitnumberNoMax 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.

ParameterTypeRequiredDescription
action"releases" | "release_get" | "step_history" | "rationale_set" | "threads" | "note_add" | "knowledge"YesWhich part of the release history to read or write
projectIdstringNoProject ID (proj_...). Optional: falls back to the default project when omitted.
flowIdstringNoFlow ID (flow_...). Required for every action except knowledge, which hangs on a page rather than a flow and refuses this field.
versionIdstringNoRelease version ID (ver_...) from action releases. Addresses one release for release_get and rationale_set. Pass this or versionNumber.
versionNumbernumberNoSpine release number for this flow, the versionNumber field of action releases. Alternative to versionId. Not the same as a row's deploymentAttempt.
stepstringNoStep key as type.name, e.g. destination.ga4 or contract.checkout. Required for step_history.
flowstringNoNamed 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.
textstringNoThe 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.
limitnumberNoPage 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.
offsetnumberNoReleases to skip. Action releases only.
anchorType"step" | "entity_action" | "release" | "contract" | "tag"NoWhat 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.
anchorKeystringNoWhat 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.
anchorLabelstringNoHow 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.
threadIdstringNoThread 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"NoRead only threads in this state. Action threads only, omit for both.
pageKeystringNoThe 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.
frameIdstringNoOne frame (frm_...), the named rectangle a note hangs on. Action knowledge only. Narrower than pageKey, since a page holds several frames.
markIdstringNoOne 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.

ParameterTypeRequiredDescription
action"list" | "page" | "get"Yeslist returns every frame of the project without marks, page returns one page's frames with their marks, get returns one frame with its marks.
projectIdstringNoProject ID (proj_...). Optional: falls back to the default project when omitted.
pageKeystringNoThe page as its frames address it (the source.key of a page frame, usually the page URL without query). Required for page.
frameIdstringNoFrame ID (frm_...). Required for get. Use action list or page to find one.

Resources

URIDescription
walkeros://reference/flow-schemaFlow.Json structure and connection rules
walkeros://reference/event-modelEvent naming, properties, auto-populated fields
walkeros://reference/mappingMapping syntax (data/map/loop/set/condition/consent/policy)
walkeros://reference/consentConsent model (destination/rule/field level)
walkeros://reference/variablesVariable patterns ($var/$env/$code/$store)
walkeros://reference/contractEvent schemas, wildcards, inheritance
walkeros://reference/openapiOpenAPI 3.1 specification
walkeros://reference/packagesFull package catalog
walkeros://schema/{packageName}Per-package JSON schemas

Prompts

PromptDescription
add-stepAdd a source, destination, transformer, or store to a flow
setup-mappingConfigure event mapping for a step
manage-contractCreate/update event contracts (bidirectional with mappings)

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.

ToolActions that return a linkScreen
flow_manageget, createthe flow page
deploy_managedeploy, getthe deployment's detail page
hub_managereleases, step_history, threadsthe 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

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

DoorHow it runsAuth
Localnpx @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
HostedPOST 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

  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 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

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.

PermissionWhat it means
Read your projects and flowsList and read projects, flows, deployments, settings and observation data.
Change and deploy flowsCreate, edit, deploy and delete flows, and manage project secrets and previews.
Stay connectedKeep 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

SymptomCauseFix
The client says it cannot authenticateThe URL is wrong, or points at an environment that is downCheck it is exactly https://app.walkeros.io/api/mcp
The browser opens on the login page instead of the consent screenNot signed in to walkerOS in that browserSign in; the consent screen follows on its own
Tools are listed but every call is refusedThe plan does not include the mcp featureUpgrade the project's plan
The app suddenly asks to reconnectIt was disconnected under Account, Connected appsReconnect 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-browser

Tools (3)

generate_tagging

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

ParameterTypeRequiredDescription
entitystringNoEntity name (creates data-elb="entity")
dataobjectNoEntity properties as key:value pairs
actionobjectNoTrigger:action pairs for data-elbaction (nearest entity)
actionsobjectNoTrigger:action pairs for data-elbactions (all entities)
contextobjectNoContext properties for data-elbcontext
globalsobjectNoGlobal properties for data-elbglobals
linkobjectNoLink relationships for data-elblink
prefixstringNoCustom 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.

ParameterTypeRequiredDescription
htmlstringYesHTML snippet with data-elb attributes
prefixstringNoCustom 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.

ParameterTypeRequiredDescription
htmlstringYesHTML snippet to validate
prefixstringNoCustom prefix (default: data-elb)

Resources

URIDescription
walkeros://docs/tagging/html-attributesComplete guide to data-elb HTML attribute tagging
walkeros://docs/tagging/taggercreateTagger() 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

☁️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

☁️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

"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

💡 Need implementation support?
elbwalker offers hands-on support: setup review, measurement planning, destination mapping, and live troubleshooting. Book a 2-hour session (€399)