Skip to content

await_control

kubed-io[bot] edited this page Oct 29, 2026 · 6 revisions

await_control

Wait for the person who took control of this browser to hand it back.

MCP tool await_control
HTTP POST /browser/await-control

A person can take control of your browser from the admin's live view, to sign in, solve a captcha or fix something by hand. While they hold it, every call that would change the browser is refused with a message naming this tool; reads still answer. Call this then, rather than retrying the refused call.

It returns the moment they hand back, saying who had control and for how long, the page the browser is on now, every page they reached (visited, oldest first) and an outline of that page. Read it before carrying on: the page may not be where you left it. With nobody in control it returns at once. ended=true means the browser ended while they had it: call open_session.

On a client without background tasks it returns after about 90 seconds with handed_back=false, saying to call again; do, until it hands back.

Parameters

This action takes no parameters.

Every call names its workspace: an Sf-Workspace header, or ?workspace=<name>. Sending both is refused. See Workspaces.

Returns

Field Type Notes
handed_back boolean True when a person handed the browser back: the rest says what they did. False at the cap (call again) or with nobody in control.
ended boolean True when the browser ended while a person had control: there is no page to read; call open_session.
control object Who had control and for how long; at the cap, who has it and since when. Null with nobody in control.
page object Where the browser is now. Absent when it ended.
visited array Every page the person reached, oldest first: the last with its whole URL, earlier ones origin and path. Absent when the pages could not be followed.
dropped integer Earlier pages left out of visited, past its 100.
outline object The current page's elements, as outline maps them.
page_error string Present instead of page and outline when they could not be read.
site_data object Present only when site data was restored, skipped or forgotten in this call.
message string What happened, in a sentence.

Errors

Status Means
400 The request cannot succeed as sent — a missing field, a value that was rejected, a locator that matched nothing before the wait ran out, or a page whose certificate the browser does not trust. Do not retry it unchanged.
401 Missing or wrong bearer token.
413 The body is over its cap: 1 MiB of JSON, 64 MiB of upload, 1 MiB of flow YAML. Send less; retrying it unchanged will fail again.
500 Something failed that this server did not expect.
503 The Grid could not serve this — unreachable, or no free slot for a new browser. Worth retrying after a wait.

Over MCP the same failures arrive as a tool error.

Example

MCP

await_control()

HTTP

curl -X POST $SELENIUM_FLOW/browser/await-control \
  -H "Authorization: Bearer $TOKEN" \
  -H "Sf-Workspace: $WORKSPACE"

When to call it

When a call is refused because a person holds the browser in the admin's Live tab — a 409 over HTTP, a tool error over MCP, saying who and since when — or when a result's control field says a person asked for it or holds it. Call it instead of retrying: every call that would change the browser is refused the same way until they hand back. Reads of the page as it is still answer.

Tasks, or a blocking call with a cap

Over MCP the tool supports background tasks (optional, polled every second). A client that negotiates them gets a task, which waits as long as the person takes; tasks/cancel stops the wait and changes nothing for the person.

A client that does not gets a blocking call. It sends a progress notification every 15 seconds, and at live.await_cap (default 90 seconds, no lower than 30) answers normally — not as an error — with handed_back: false and still in <who>'s control; call again. Call it again until it hands back. The cap sits under Claude Code's two-minute move of a slow call to the background.

POST /browser/await-control is a long poll with the same cap and the same answer.

Through agentgateway

agentgateway v1.6.0 passes MCP Tasks through: per its source, it routes tasks/get, tasks/update and tasks/cancel. It strips the tasks extension from a client on the older protocol, which therefore gets the blocking call. The blocking answer is streamed, so the gateway's backendRequestTimeout does not cut it off.

A task's worker has no request, so the workspace it waits for is the one named when it was submitted. Behind the gateway that is the Sf-Workspace header.

What the answer means

  • page is the page the browser is on now. It is not the page-error hint other results carry under the same name.
  • visited is in the order they were reached. Titles are read just after each page is reached, so on a single-page app a title may still be the previous route's.
  • Nothing here is written to History; the next call records the page as any call does.
  • With nobody in control it answers at once: a hand-back the agent had not been told of yet, or control: null with the page when a browser is open.
  • If the server stops while a call waits, the call usually just ends with the connection; one still running answers the server is stopping: call await_control again once it is back. Either way, call it again once the server is back. Who held Control is forgotten with the process.

Not a flow step

A flow cannot wait for a person. A step refused for control stops the run, whatever its onError, and whoever started the run calls await_control.


← All actions · Installing · Deployment

Clone this wiki locally