Coding agents
MCP tools
Every tool, resource and prompt danwo's MCP server gives a coding agent, and what each is for.
danwo's MCP server is what your agent calls to work with your project. Start it with
npx @danwo/cli mcp; Set up your agent registers it for you. This page lists
everything it offers.
Run and explain tests
The tools an agent uses most. They work on the project's tests as danwo test would:
| Tool | What it does |
|---|---|
list_tests | Lists the tests by file, with skip/only, and whether each has an invariant. |
run_tests | Runs all tests, or some by file, grep or name, and reports each failure's step, error and record. |
run_matrix | Runs the fault matrix on one test: a clean run, then a run per fault, judged. |
show_run | Explains a recorded run: the error, the steps, console errors, provider calls and webhooks. |
read_screenshot | Returns a screenshot from a flight record: the screen at failure, or after a step. |
scaffold_test | Writes a new *.danwo.ts file: the page it opens, its steps, and an invariant stub. |
inspect_page | Opens one page of your app through the project's environment and returns its accessibility tree and its calls. |
Pass format: "md" to show_run to get the same failure page danwo show --format md prints.
Drive the app step by step
A session is your app opened in danwo's browser, with its emulators and proxy, for the agent to explore before it writes a test. Every action answers with the page as it is now:
| Tool | What it does |
|---|---|
open_session, close_session | Starts the app, emulators and browser (or a device), or stops them. |
navigate | Goes to a path or URL, or back, forward, reload. |
click, hover, fill, press, select, check | Acts on an element, by a ref from the last snapshot or by a locator. |
fill_secret | Fills a field with a configured secret by name. The value never appears anywhere. |
upload | Puts files into a file input, or the file picker a button opens. Up to 10 MB a call. |
drag | Drags an element (target) and drops it on another (to), such as a card onto a column. |
tabs, switch_tab, close_tab | Lists the open tabs, moves actions to another, or closes one. |
dialog | Answers the alert, confirm or prompt the page has open: OK or Cancel, with text for a prompt. |
snapshot, screenshot | The page as an accessibility tree with refs, or as an image with secrets masked. |
check_locator | Checks a locator matches exactly one element, and returns the line to paste. |
start_recording, stop_recording | Records the session's screenshots, and video when no secret was filled. |
Find an element inside another
A target is a ref from the last snapshot, or a locator as a test writes it. When one locator matches several elements, chain it inside the part of the page that holds the one you want:
getByRole("region", { name: "Cart" }).getByRole("button", { name: "Remove" })A chain can also narrow what it found:
| Link | What it keeps |
|---|---|
.getBy…(…) | Matches inside each element so far. |
.filter({ hasText: … }) | The elements that contain this text. |
.first(), .last() | The first or last element. |
.nth(n) | The element at index n, from 0. |
check_locator takes chains too. When a chain matches nothing, it names the first link after
which nothing matched, so you know which part to fix.
Click with keys held, twice or with the right button
click takes three options beyond its target:
| Option | What it does | Default |
|---|---|---|
modifiers | Keys held during the click: Shift, Alt, Meta, Control. | none |
button | right opens a context menu; middle is the wheel button. | "left" |
double | true double-clicks, such as to edit a cell or select a word. | false |
ControlOrMeta is Meta on macOS and Control elsewhere. Use it to add an item to a selection or
open a link in a new tab, so the same step works on every machine.
Follow a new tab
When the app opens a tab, such as a popup or a link to a new window, actions go to it straight away. The answer says so:
clicked screen.getByRole("link", { name: "Open receipt" })
tab: 2 of 2 (actions now go to it)
url: http://localhost:3000/receipt/42tabs lists every open tab by number. switch_tab moves back to one, and close_tab closes one,
or the active tab without a number. When the active tab closes, the newest one left takes over.
Answer a dialog
A dialog is the box alert, confirm or prompt opens. It blocks the page until someone answers
it, so danwo holds it open and the answer tells your agent:
a confirm dialog is open: "Empty the basket?"
the page waits for an answer: dialog with accept: true (OK) or false (Cancel)Call dialog with accept: true for OK or false for Cancel.
Add text to type into a prompt; without it, the prompt keeps its default. The click that opened
the dialog then finishes, and the answer shows what changed. Until then, every other page tool
says the dialog is open.
Upload a file
upload takes a list of files. Give each one in whichever form you have it:
| Form | What it is |
|---|---|
{ path } | A file in your project, relative to the project folder. |
{ file } | A file your config offers tests by name, under files. |
{ name, text } | A file the agent writes on the spot, such as a small CSV. |
{ name, base64 } | Any other bytes, such as an image. |
{
"session": "s1",
"target": "getByLabel(\"Receipt\")",
"files": [{ "path": "fixtures/receipt.pdf" }, { "name": "notes.csv", "text": "item,qty\noats,2" }]
}A test uploads by name only, so a recording never holds a path. Add the file under files in
danwo.config.ts, then call setInputFiles("receipt"). An empty list clears the input.
Drive a mobile app
A device session drives your app on the Android emulator or iOS Simulator your config's
environment sets up, in place of a browser. Open one with device: true:
{ "device": true }The app starts afresh, and the answer is its screen. It reads like a page's tree, with a line that says what is in front:
session s1 is open.
device: iOS Simulator
in front: the app com.danwo.shopmobile
- heading "Danwo Shop" [ref=e2]
- text "Credits: 0" [testId=credits] [ref=e3]
- button "Buy 500 credits" [testId=buy] [ref=e4]The same tools work, the way a person uses a phone:
| Tool | On a device |
|---|---|
click | Taps the element. |
fill, fill_secret | Types into a field, replacing what it holds. |
check | Taps a switch or checkbox, unless it already shows that state. |
press | Taps the target, then presses the key. iOS has Enter only. |
navigate | Opens a path by the app's link scheme, a full URL, or goes back. |
back | Goes back: Android's Back button, or the screen's back control. |
scroll | Scrolls the screen, or one list, up, down, left or right. |
swipe | Swipes a finger across the screen or an element, for duration_ms. |
long_press | Presses and holds an element. |
dismiss_keyboard | Puts the on-screen keyboard away. |
tap_at | Taps a point, in screenshot pixels, for what the tree can't show. |
screenshot | The screen, with password and secret fields painted over. |
snapshot, check_locator | The screen's tree, and locators checked against it. |
Locators take the same chains as on a page. Tools only a browser has, such as hover or drag,
answer with an error that says so. When the app opens a browser, such as a checkout page, the
answer's in front line names it and its URL.
Before each action, danwo reads the screen again. If the element a ref names has moved or gone, nothing is tapped: the answer says so and shows the screen as it is now, with fresh refs.
Look behind the app
These show what the app did at its providers during a session. They're how an agent finds the right invariant:
| Tool | What it does |
|---|---|
exchanges | The calls the app and browser made through danwo's proxy since the last look. |
deliver_webhooks | Delivers the webhooks the emulators have queued, then lists the deliveries. |
emulator_state | What each emulated service holds now: Stripe objects, sent mail, Slack messages, S3 objects. |
inject_fault | Arms one fault, named as the matrix names it, to fire on the next matching call or delivery. |
clear_faults | Disarms the faults that haven't fired yet. |
Resources and the prompt
The server also offers resources your agent can read, and one prompt:
| Name | What it is |
|---|---|
danwo://config | Where tests live, how the app runs, the model, and your secrets' names. |
danwo://runs/latest | The newest run, with its failures explained. |
danwo://spec | Every API, option, fault label and error code, generated from danwo's code. |
danwo://guide/<topic> | A task guide, such as first-test, matrix or debugging. |
write-danwo-test | A prompt: inspect the app, scaffold a test, run it and fix it until it passes. |
Secrets stay hidden from the agent everywhere: answers, screenshots, recordings and records are
all redacted. A video can't mask a typed secret, so start_recording refuses video once one is
filled.