unotest is an MCP server. Your editor’s agent calls these tools to explore your app, run scenarios, debug failures and write tests. You never wire them by hand.
Core lifecycle & snapshots
Open/close the browser and read what the agent “sees” — a semantic outline, not pixels.
new_context—— Open a fresh, isolated browser context.close_context—— Tear down the active context.get_url—— URL of the active page.get_title—— Document title of the active page.get_page_snapshot—— Compact, region-grouped semantic outline of the page (with[ref=eN]handles).get_aria_snapshot—— YAML ARIA tree; same-origin iframes stitched in.get_frame_snapshot{ locator }— Outline scoped to one iframe.find_element{ role, name?, near?, nth? }— Targeted role+name search (≤20 hits + total count). Pierces open shadow roots.check_locator{ locator, limit? }— Evaluate a locator written exactly as it appears in a scenario against the live page and report what it really matches — verify a selector without re-running the test.
Exploration & recording
The agent drives the live app and records a scenario.
explore_start{ scenario_name, title?, description?, env? }— Begin a recording session; returns available variables, flows, the active environment andgrounder: {available, reason?, hint?}— whether intent locators work for this session.envrecords this session against the.env.<env>/.secrets.<env>overlays.explore_stop{ explorationId }— End recording.explore_state{ explorationId }— Inspect the session and recorded entries.explore_step{ action, locator?, value?, ... }— Execute one action — record it (with a session) or run ad-hoc.explore_steps{ explorationId, steps[], autoRun? }— Run a whole sequence in one call — same per-step shape asexplore_step. Use it when the block is already known (a login: goto + fill + fill + click).explore_record{ action, section, description, ... }— Record an action with mandatory section + intent.explore_remove_step{ explorationId, entryId }— Delete a recorded entry.generate_dsl_from_exploration{ explorationId }— Emit DSL (+ warnings) from the session.save_exploration_as_test{ explorationId, scenarioName? }— Write the scenario to disk; extractflow:steps into helpers.explore_run_flow{ explorationId, name, ... }— Replay a saved flow to seed state, recorded as one step.
Debugger & runtime
Run a scenario through the sandboxed engine and step through it.
run_test{ name, breakpoints?, wait?, waitMs?, env? }— Run a scenario and block until it settles; returns the outcome, runId, effective baseUrl and the active environment. The session auto-attaches to the run’s browser, applying the run’sdialogPolicy.envruns this one scenario against a different environment — the spawned runner child gets that name asUNOTEST_ENV.step{ runtimeId }— Execute one step of a paused runtime.resume{ runtimeId }— Resume to completion or the next breakpoint.inspect_runtime{ runtimeId }— Variables, call stack and last event at the pause point.abort_runtime{ runtimeId }— Abort with clean teardown.list_runtimes—— All active runtimes + status.
Collaborative debugging
You debug in the viewer, the agent joins the SAME browser. It never opens its own copy and never closes yours — control passes back and forth through an explicit token.
attach_debug_session{ runtimeId? }— Join the live browser of your debug run: snapshots and actions now target the page you are looking at, and the run’sdialogPolicyapplies to the attached client too.detach_debug_session—— Drop the connection and go back to its own browser. Your session stays open.take_wheel{ runtimeId? }— Take the control token so the agent may record actions. You see an “Agent driving” badge and can take it back at any time.release_wheel{ runtimeId? }— Hand control back to you; recording is blocked until the agent takes the wheel again.record_action{ ref, action, value?, ... }— Append a DSL line to the live draft: the agent picks an element byref, the runner resolves it to a stable locator and the line appears in your editor.
Multi-context
Tabs and frames.
list_pages—— All open tabs (index + URL).list_frames—— The frame stack.get_active_context—— Which tab is active.switch_page{ index }— Switch the active tab.
Failure artifacts
Read the evidence bundled when a run fails.
list_failures—— All failure bundles with timestamps.get_failure_trace{ runId }— DSL execution trace.get_failure_console{ runId }— Browser console logs.get_failure_a11y{ runId }— ARIA tree at the failure (YAML).get_failure_screenshot{ runId }— Screenshot at the failure.get_failure_network{ runId }— HAR (only if tier3.network is enabled).
Reading a box
The other half of bundle push --run: it hands work to a box and returns a run id, and these read the answer back — no browser, no shell on the box. Authenticated with your PERSONAL read token (UNOTEST_BOX_READ_TOKEN), which is read-only whatever your role there and is not the project token that pushes bundles.
box_envs—— Environments this read token may look at, as<project>/<environment>— the names every otherbox_*tool wants.box_runs{ environment, latest?, running?, scenario?, limit? }— Run history in one environment.latestcollapses it to the last run per scenario with its failing streak;runningshows only what is in flight.box_run{ environment, runId }— What happened in one run: status, the failure, soft-step results, judge verdicts, notes and logs. The tool to call right afterbundle push --run.box_run_download{ environment, runId, screenshots?, dir? }— Fetch the run and unpack its failure bundle into.unotest/failures/, whereget_failure_*andagent_fixalready read — a box failure debugged like a local one.screenshots: falseleaves the step frames on the box.box_queue{ environment }— Who is running, who is waiting, how many slots are in use — why an ordered run has not started.box_screenshot{ environment, runId, step? }— One frame the run captured, returned as an image. Withoutstepyou get the last, which on a failed run is usually the state that failed.
Agent self-service & viewer
Diagnostics, the human-in-the-loop fix flow, and the viewer.
agent_fix{ location, fix }— Composes failure context for a fix. No LLM call, no auto-apply — you review the diff.get_last_mcp_log—— JSONL debug log of the last run (under UNOTEST_DEBUG).audit_last_run—— Deterministic rubric audit of the run against the rules (no LLM).open_viewer—— Launch (or reuse) the local viewer; returns its URL.