Skip to Content

MCP server

@klera/mcp ships a stdio MCP server (klera-mcp) that exposes the engine plus the bridge as tool calls. The server embeds its own BridgeServer, the Expo app connects to that bridge just like it would for the CLI, and your editor agent drives flows by calling tools — tap, type_text, assert_visible, run_flow, plan_flow.

The MCP path is the right pick when your editor of choice already has LLM credits — Claude Desktop, Claude Code, Cursor. The server defers planning to whichever LLM the host already has wired up.

Tool surface

The server advertises ten tools:

ToolPurpose
tapPress an element matching a target spec
type_textType a value into the matched input
scrollScroll the first visible scrollable container
assert_visible{ visible, elementId? } — does the matcher resolve the target?
query_uiResolve a target and return its key attributes without acting on it
snapshotReturn a small summary of the current element graph
run_flowRun a parsed Flow IR against the connected runtime
plan_and_run_prosePlan a .flow.md body against the live snapshot and execute
plan_flowCompile prose to a SemanticPlan without executing
apply_plan_responseValidate a host-LLM JSON response and return the cached SemanticPlan

Each takes a TargetSpec (an object with at least one of testID, text, or accessibilityLabel) and returns plain JSON. The server resolves targets through the engine’s matcher with self-healing on by default — drift is tolerated and reported as drift: true on the response.

Configure your editor

Edit ~/Library/Application Support/Claude/claude_desktop_config.json:

{ "mcpServers": { "klera": { "command": "node", "args": ["<REPO>/packages/mcp/dist/stdio.js"], "cwd": "<REPO>", "env": { "KLERA_HOST": "127.0.0.1", "KLERA_PORT": "7345" } } } }

Restart Claude Desktop. The tools appear under a klera server in the tool panel.

Environment

  • KLERA_HOST — bind address for the embedded bridge. Default 127.0.0.1.
  • KLERA_PORT — bridge port. Default 7345. Must match the port the app dials (EXPO_PUBLIC_E2E_PORT).
  • KLERA_WAIT_MS — how long each tool call waits for the runtime to attach before failing. Default 30000.
  • KLERA_SELF_HEALING — set to "0" or "false" to disable fuzzy matching; any drift becomes a hard failure.
  • ANTHROPIC_API_KEY — optional. When set, plan_and_run_prose and plan_flow use the Anthropic API directly. Without it, plan_flow returns the prompt body for the host’s LLM to handle (see below).

Launch the app

The MCP setup reuses the standard app launch — only the bridge moves inside the MCP process instead of a CLI pane.

cd my-expo-app pnpm ios # or pnpm android

The first tool call from the agent triggers the bridge to wait for the runtime handshake. Metro’s console prints [e2e-runtime] bridge bound on ws://127.0.0.1:7345 once the app connects.

Smoke test

Prompt your editor agent with:

Call the snapshot tool and tell me what elements are visible.

Expected: the agent invokes snapshot, the MCP process asks the bridge for a live snapshot, the runtime responds with the current element graph, and the agent summarises it.

If the call times out, the app is not connected — reopen the simulator or check the port settings.

Driving flows from prose

plan_and_run_prose is the one-shot tool: prose in, FlowResult out.

Use plan_and_run_prose to: “Sign in with the seeded test user, dismiss the onboarding modal, and assert the welcome greeting is visible.”

The server parses the prose, takes a snapshot, calls the planner, and runs the resulting SemanticPlan. The response carries the same status / driftCount / per-step result shape as the CLI.

Plan without ANTHROPIC_API_KEY

plan_flow is the BYO-LLM split. When ANTHROPIC_API_KEY is set on the server, plan_flow returns the compiled SemanticPlan directly. Without it, the tool returns the prompt body — the same Markdown blob klera plan --manual writes to disk:

{ "kind": "prompt", "prompt": "# klera planner — manual mode\n\n…", "reason": "no_llm_configured", "hint": "Route the prompt through the host's LLM, then call apply_plan_response with the JSON." }

The agent runs the prompt through its host LLM, then calls apply_plan_response with the JSON response, the same prose, and the same snapshot. The server validates against the SemanticPlan Zod schema and returns the cached plan. ANTHROPIC_API_KEY is not required for any of this.

This is why MCP is a good fit for editor agents that already have LLM credits: planning runs on whatever model your editor talks to. The klera server only validates and routes.

apply_plan_response strips a leading ```json fence automatically if the host LLM includes one, so prompt drift between host LLMs is forgiving. Pasted responses are validated against the same Zod schema the API mode uses.

Troubleshooting

  • klera server missing from the tool panel. The stdio process crashed on startup. Check the editor’s MCP log (Claude Desktop: ~/Library/Logs/Claude/mcp-server-klera.log). Common cause: the dist/stdio.js path in args does not exist — rebuild or fix the path.
  • Every tool call times out after 30s. The app is not connected to the bridge. Verify Metro printed bridge bound … and that EXPO_PUBLIC_E2E_PORT matches KLERA_PORT.
  • “target not matched” from tap / type_text. Ask the agent to call snapshot first and check the element graph for the right testID / text. The matcher’s triedStrategies list comes back in the error to narrow the diagnosis.
  • Stale tool surface after rebuilding the MCP package. The editor caches tool descriptions. Restart the editor after a fresh build.

See also

Last updated on