compose — many commands, one call
Multi-step browser actions usually mean a round-trip per command. compose runs a whole sequence against one tab in a single call: one command per line, executed in order, stopping at the first failure.
The format
Each line is <tool>?<query-string> — a URL query string whose keys are exactly that tool's parameters. No new syntax to learn: serialize it with URLSearchParams (JS), urlencode (Python), or anything that speaks query strings.
fill?selector=%23email&value=me%40example.com
fill?selector=%23password&value=hunter2
click?selector=%23login
wait?t=500
Encoding: only &, %, and newlines (%0A) must be encoded in a value; spaces can be + or %20. An XPath's internal = is fine unencoded, since each pair only splits on its first =.
Eligible commands
The action commands, plus the compose-only wait:
navigatebackforwardreload
clickhoverfocusblur
filltypeinsertTextclearselectkeypressscroll
wait?t=<ms>
Data-returning commands (screenshot, dom, elements, console_logs…), lifecycle commands (new_tab, close, show), and evaluate are not eligible — they're meant to read a result or change the tab set, not advance a sequence.
How it runs
- Validated up front. The whole script is checked first (known command, parseable query, valid args). If anything is wrong, nothing runs and you get the offending line.
- Stops at the first failure. If a command errors or can't find its element, the run halts there — later lines don't execute.
- Returns an array of the per-command responses, in order. On a failure, the last entry holds the error, and the array length tells you how far it got.
- Long batches stay alive. compose emits progress as it goes, so a script with
waits won't trip your client's request timeout.
Examples
Search a site and submit:
fill?selector=.search-box&value=browser+automation
click?selector=button%5Btype%3D%22submit%22%5D
Open a page, let it settle, scroll down, and type into a rich editor:
navigate?url=https%3A%2F%2Fexample.com%2Fdoc
wait?t=800
scroll?y=600
type?selector=.editor&text=Drafting+from+an+AI+agent.
Replace a field's contents (clear, then type) and move focus on:
clear?selector=%23title
type?selector=%23title&text=Q3+roadmap
keypress?key=Tab
Calling it
Over MCP, call the compose tool with tabId and script. Over HTTP, POST the same script:
curl -X POST http://localhost:61822/tab/{tabId}/compose \
-H 'Content-Type: application/json' \
-d '{"script":"fill?selector=%23q&value=hi\nclick?selector=%23go"}'