Skip to Content
webagent docs
MCP

Tools

Reference for every webagent MCP tool, its arguments, what it returns and when it reports an error.

Open as .md

The MCP server offers 15 fixed tools and one skill_<name> tool per skill. This page lists each one. Your client also shows the exact JSON Schema of every tool in tools/list, which is the final word on argument names.

Every tool call runs with your API key, so the same limits, plans and quotas apply as on the REST API. The tools call the same services as the REST routes.

ToolWhat it doesWaits?
create_sessionOpen a cloud browser sessionNo
run_taskGive the browser agent a goal and wait for the answerUp to 90 s
get_taskRead a task, or wait for a running oneUp to 90 s
smoke_testTest a page or flow and return a pass/fail reportUp to 90 s (60 s by default)
get_reportRead the test report of a run or task, or wait for itUp to 90 s (30 s by default)
list_sessionsList the project's sessionsNo
get_sessionRead one sessionNo
stop_sessionEnd a sessionNo
scrapeLoad a URL and return its contentUntil done
screenshotLoad a URL and return an imageUntil done
pdfLoad a URL and return a PDFUntil done
crawlCrawl from a URL and return the pagesUntil done
list_skillsList the skills you can runNo
run_skillStart a skill run, without waitingNo
get_skill_runRead a skill run, or wait for its verdictUp to 120 s
skill_<name>Run one skill and wait for its verdict30 s by default, up to 120 s

Ids look like sess_us_… for sessions, tsk_… for tasks and run_… for skill runs.

Results and errors

Most tools return two things: content (text for the model) and structuredContent (the same data as JSON). A few return an image or a PDF instead.

A call that fails returns normally with isError: true. The text is [code] message. structuredContent.error holds { code, message, details? }. The codes are the API error codes. Argument problems come back as invalid_input, with the validation issues in details.issues. An unknown tool name is not_found.

A failed test is a result, not an error

isError means "the test could not run", not "the app has a problem". A test that ran and found a problem is a normal result. Read the verdict, not isError. See Reading results.

How each tool sets isError:

ToolisError: true when
smoke_test, get_reportThe report verdict is error: the test could not run to a result. Verdict fail is a normal result
run_task, get_taskThe call failed, or the task ended in a way that means the agent could not test: stoppedBy is captcha, blocked, error, aborted, paused, navigation_blocked, capacity_exceeded, capacity_timeout or timeout. A task that ended stuck, budget or unanswered, or finished with ok: false, is a normal result
skill_<name>, get_skill_runThe call failed, or the run status is error, denied or cancelled. A run that is failed is a normal result. A run still running is not an error
every other toolThe call failed

create_session

Opens a cloud browser session, like POST /v1/sessions. Use it when several tasks must share one browser, or when you want to keep the session open and watch it. Then pass the returned id as sessionId to run_task. For a single task, run_task takes the common options itself (recording, headers, proxy, vault login).

ArgumentTypeRequiredNotes
startUrlstringnohttp or https, at most 2048 characters. The browser opens it before the session is live. A blocked address fails with navigation_blocked
devicestringnodesktop, mobile or a device id from the device list
viewportobjectnowidth and height in pixels (200 to 7680 wide, 200 to 4320 high), optional deviceScaleFactor and mobile
recordbooleannoRecord the session as video. Kept after the session closes. See Evidence
headersarraynoExtra request headers sent only to the hosts you name. Up to 20 entries
credentialsboolean or objectnoFill login forms from the credential vault
proxyUrl, allowHostsstring, string arraynoReach a private host through your own proxy. allowHosts needs proxyUrl
idleTimeoutMsintegernoClose after this long with no actions. 10 000 ms to 24 h. Default 5 minutes
maxDurationMsintegernoHard cap on the session's lifetime. 10 000 ms to 24 h. Default 1 hour
engineId, engineVersionstring, integernoRun on a saved engine. engineVersion needs engineId
waitForCapacityMsintegernoWhen every browser is busy, wait up to this long (0 to 30 000 ms) for a free one before failing with capacity_exceeded. Default 0
queueForCapacityobjectno{ "maxWaitSeconds": 1 to 900 }. When every browser is busy, keep the session queued instead of failing. See Sessions. Not together with waitForCapacityMs above 0

The tool takes every field of the POST /v1/sessions body. The table lists the common ones. Do not send url: it is refused with a hint to use startUrl.

Returns: the session record as JSON, with its id, status, endpoints and a short-lived session token.

Arguments
{ "startUrl": "https://staging.example.com", "record": true }
structuredContent (trimmed)
{
  "id": "sess_us_xxxxxxxxxxxxxxxxxxxxxxxx",
  "status": "live",
  "engine": "chromium",
  "createdAt": "2026-01-01T10:00:00.000Z",
  "token": "...",
  "tokenExpiresAt": "2026-01-01T10:15:00.000Z",
  "endpoints": { "http": "https://...", "cdp": "wss://...", "live": "wss://..." }
}

run_task

Gives the browser agent a goal in plain language. The agent looks at the page, decides, acts, and repeats until it is done or stops. The tool returns the answer, why it stopped, the steps and the cost.

Without sessionId, the tool opens a session itself and closes it when the task ends, unless keepOpen is true. With sessionId, the task runs on that open session, and the session stays open.

ArgumentTypeRequiredNotes
goalstringyesWhat to do, 1 to 2000 characters
maxStepsintegerno1 to 50. The agent's default is 25
sessionIdstringnoAn open session of your project. Leave it out to let the tool open one
startUrlstringnoPage to open first. Only when the tool opens the session
engineId, engineVersionstring, integernoEngine for the new session. Only when the tool opens the session
recordbooleannoRecord the session as video. Only when the tool opens the session. The report then links the recording
headersarraynoExtra request headers for the hosts you name, for a staging site behind a gate. Same rules as in create_session. Only when the tool opens the session. See Protected sites
proxyUrl, allowHostsstring, string arraynoReach a private host through your own proxy. allowHosts needs proxyUrl. Only when the tool opens the session. See Test a local app
credentialsboolean or objectnoFill login forms from the credential vault: true, or { namespace, autoSubmit }. Only when the tool opens the session. There is no field for a plain password. See Signed-in sites
modeauto or full_autonoDefault auto. See Tasks
keepOpenbooleannoKeep the session open after the task, when the tool opened it
waitSecondsintegerno1 to 90. How long to wait. Default 90. A value above 90 is refused with invalid_input

Giving startUrl, engineId, engineVersion, record, headers, proxyUrl, allowHosts or credentials together with sessionId is an invalid_input error. These options only apply when run_task opens the session.

Returns, when the task ends within the wait:

  • Text: Task finished|stopped (<stoppedBy>) in N steps, $x, S s. then Answer:, Reason:, a line that says whether the session was closed, and a line that names get_report with the task id.
  • structuredContent: { sessionId, sessionClosed, task }. task has taskId, ok, answer, stoppedBy, reason, limit, steps, costMicros, ms and text. Each step has op, ref, provider, ok, ms, costMicros and error. Costs are in millionths of a US dollar. Long strings are cut at 2000 characters.

Returns, when the wait ends first: the task keeps running and its session stays open. The result is { sessionId, taskId, status: "running", sessionClosed: false, note }. Call get_report with the taskId (or get_task), then stop_session when you are done. A task that runs longer than the wait is normal.

If the call fails before a result exists (for example session_paused), a session the tool opened is closed and the call returns isError. A task that ended because the agent could not test (a CAPTCHA, a blocked address and so on) also returns isError. See Results and errors.

run_task is for an open-ended goal. It checks no assertions: ok: true means the agent says it is done. For a repeatable pass/fail check of a page or flow, use smoke_test.

Arguments
{
  "goal": "Open the first product, add it to the cart and report the cart total",
  "startUrl": "https://staging.example.com",
  "maxSteps": 20,
  "keepOpen": true
}
structuredContent (trimmed)
{
  "sessionId": "sess_us_xxxxxxxxxxxxxxxxxxxxxxxx",
  "sessionClosed": false,
  "task": {
    "taskId": "tsk_xxxxxxxxxxxxxxxxxxxxxxxx",
    "ok": true,
    "answer": "The cart total is 24.00.",
    "stoppedBy": "done",
    "steps": [{ "op": "click", "ok": true, "ms": 410 }],
    "costMicros": 8200,
    "ms": 24000
  }
}

The text for the same call reads Task finished (done) in 2 steps, $0.0006, 5 s., then Answer: ..., then Session sess_us_... is still open: run another task with sessionId, or stop_session when done.

Do not put real passwords in a goal

The goal text goes to the model and into the task record. Use the credential vault for logins. See Signed-in sites.


get_task

Reads a task started by run_task. It waits for a running task, then returns the result. It never closes the session.

ArgumentTypeRequiredNotes
sessionIdstringyesThe session the task ran on
taskIdstringnoDefault: the session's latest task
waitSecondsintegernoAt least 0. Default 30, maximum 90. A larger value is lowered to 90

Returns, when the task is finished: text with the same summary as run_task, and structuredContent { sessionId, taskId, status: "finished", task }. Here task is the stored task record: id, goal, status, ok, stoppedBy, limit, reason, answer, steps, costMicros, ms, startedAt, finishedAt.

Returns, when it still runs: { sessionId, taskId, status: "running", note }. Call again, or use get_report with the taskId.

get_task returns the raw task record. For a verdict with console errors and failed network calls, use get_report.

A session that has no task yet, or a taskId that is not on the session, is not_found.

Arguments
{ "sessionId": "sess_us_xxxxxxxxxxxxxxxxxxxxxxxx", "waitSeconds": 60 }
structuredContent, finished (trimmed)
{
  "sessionId": "sess_us_xxxxxxxxxxxxxxxxxxxxxxxx",
  "taskId": "tsk_us_xxxxxxxxxxxxxxxxxxxxxxxx",
  "status": "finished",
  "task": {
    "id": "tsk_us_xxxxxxxxxxxxxxxxxxxxxxxx",
    "goal": "Open the Pricing page and tell me the page heading",
    "status": "finished",
    "ok": true,
    "stoppedBy": "done",
    "answer": "The Pricing page is open. Its page heading is \"Pricing\".",
    "steps": [{ "op": "click", "ref": "e2", "ok": true, "ms": 3458, "costMicros": 472 }],
    "costMicros": 617,
    "ms": 4753,
    "startedAt": "2026-01-01T10:00:06.000Z",
    "finishedAt": "2026-01-01T10:00:11.000Z"
  }
}

smoke_test

Tests a page or a short user flow and returns a report. This is the tool for "smoke test my app". One call opens a recorded cloud browser, loads the page, runs your plain-language steps, checks what you expect, and returns a verdict. It runs the smoke-uat skill and always records the session.

ArgumentTypeRequiredNotes
urlstringyesThe page to test. http or https, at most 2048 characters
stepsstring arraynoPlain-language steps run in order after the page loads, for example ["click Sign in", "type the username demo into the email field"]. Up to 30 steps of up to 500 characters. The first step that fails stops the flow. Plain steps need the browser agent to read the page. The step text is stored with the run: use a throwaway test account
expectTextstringnoText that must be on the page when the steps are done. Up to 500 characters. Case-sensitive
expectUrlstringnoText the page address must contain when the steps are done, for example /dashboard. Up to 500 characters
expectNoTextstringnoText that must not be on the page when the steps are done, for example Invalid password. Up to 500 characters
maxLinksintegernoHow many same-origin links of the start page to check. 0 to 200. Default 50
strictLinksbooleannoA broken link fails the test. Default true. With false it is a finding only
waitSecondsintegernoHow long to wait for the result. 1 to 90. Default 60
sessionobjectnoSession options for this test, for example proxyUrl and allowHosts to reach a private staging site, or headers for a gate. Recording is always on. Sign-in options (credentials, profileId, persistProfile, profileName, extensionIds) are refused with invalid_input: skill runs cannot sign in yet

The test checks, in this order: the start page loads, basic accessibility, the links of the start page, your steps, the console, then expectText, expectUrl and expectNoText, and last whether every link worked (strictLinks). Links and accessibility are checked on the start page only, not on pages your steps reach. The console check covers the whole run. A failed step does not skip the later checks, so you see a broken link and a failed flow in one report. See Skills.

Returns: the report of the run. The text has the summary, up to five failed steps (with a screenshot link when there is one) and a short-lived link to the full HTML report. structuredContent is the whole report. It has a verdict: pass, fail, error or running.

  • isError is true only for verdict error: the test could not run to a result, for example the run was cancelled, was denied a permission, or the browser failed. A test that ran and failed is a normal result with verdict fail.
  • If the test is still going when the wait ends, the verdict is running and the summary says to call get_report with the id.
Arguments
{
  "url": "https://staging.example.com/login",
  "steps": ["type the username [email protected] into the email field", "type the test password into the password field", "click Sign in"],
  "expectText": "Welcome",
  "expectNoText": "Invalid password",
  "expectUrl": "/dashboard"
}

The text for a failed test reads like this. It is from a run on the Test Arena sign-in page where expectText named a text that is not there (links shortened):

Smoke test of https://webagent-test-web.pages.dev/app/login FAILED in 7 s: 15 of 16 steps passed. Step 13 (assert 1 condition) failed: Expected text "Dashboard overview" is not on the page. No console errors or failed network calls.
Failed steps:
- Step 13 (assert 1 condition): Expected text "Dashboard overview" is not on the page (screenshot: https://...)
Full HTML report (short-lived link): https://...
The whole report is in structuredContent.

A test that passes has a shorter text: Smoke test of https://webagent-test-web.pages.dev/app/login PASSED in 5 s: 17 of 19 steps passed. No console errors or failed network calls., then the report link line and the last line. Steps for checks you did not ask for (here expectUrl and expectNoText) are skipped: they are not counted in the first number, so it can be lower than the second. Step numbers in the text start at 1, the same as in the HTML report; a step inside a loop reads like Step 3.2. In structuredContent the index of a step starts at 0.


get_report

Reads the test report of a smoke test, a skill run or a task. It waits while the test is still running, so call it again with the same id until the verdict is not running.

ArgumentTypeRequiredNotes
idstringyesA run id (run_…) from smoke_test or run_skill, or a task id (tsk_…) from run_task
waitSecondsintegernoHow long to wait while it is still running. 0 to 90. Default 30

Returns: the same as smoke_test: text with the summary and failed steps, and the whole report in structuredContent. isError is true only for verdict error. An id that does not exist in your project is not_found.

A task report says in its notes that a task has no assertions: verdict pass means the agent says it is done. A report of a running test has few details: steps and findings appear when it ends.

The text of a task report reads like this:

Task "Open the Pricing page and tell me the page heading" finished in 3 s: the agent says it is done. 2 agent steps, all ok. Answer: The Pricing page is open at https://webagent-test-web.pages.dev/pricing/. The page heading is "Pricing". No console errors or failed network calls. Note: no assertions were checked, so `ok` only means the agent says it is done.
The whole report is in structuredContent.

Console errors and failed network calls come from the session log. The log is saved when the session ends. A report read while the session is still open has empty lists and no finalUrl, and says in notes that the log is not available: "The session log is not available (it is stored when the session ends), so console errors, failed network calls and URLs are missing." Call stop_session, then read the report again: the same report then has the log data. A task that left its session open (keepOpen, or still running) has no log until you do. smoke_test and a run_task that closes its own session return after the log is saved, so their report is complete at once.

Arguments
{ "id": "run_us_xxxxxxxxxxxxxxxxxxxxxxxx", "waitSeconds": 60 }

For the raw record of a run or task, use get_skill_run or get_task. The report fields are in Reading results. REST: GET /v1/skill-runs/:id/report.json and GET /v1/tasks/:id/report.json return the same report.


list_sessions

Lists the project's sessions, newest first (at most 200). No arguments.

Returns: { "sessions": [ … ] }. Each entry is a session record: id, status, engine, createdAt, endedAt, endReason, title.

Arguments
{}

get_session

Reads one session: status, regions and pool. While the session is open, the record also has its endpoints.

ArgumentTypeRequiredNotes
sessionIdstringyesThe session id
idstringnoDeprecated alias of sessionId. Send one of them, or both with the same value

Returns: the session record as JSON. An unknown id, or one from another project, is not_found.

Arguments
{ "sessionId": "sess_us_xxxxxxxxxxxxxxxxxxxxxxxx" }

stop_session

Stops a session and ends its record. Safe to repeat.

ArgumentTypeRequiredNotes
sessionIdstringyesThe session id
idstringnoDeprecated alias of sessionId

Returns: { "deleted": true, "closed": true }. closed is true when this call stopped a running browser. Repeating the call on a session that already ended returns { "deleted": true, "closed": false }. deleted is false when the id is unknown or not yours.

Arguments
{ "sessionId": "sess_us_xxxxxxxxxxxxxxxxxxxxxxxx" }

scrape

Loads a URL in a cloud browser and returns the page content. Each call opens its own fresh session, so it never sees a page you are signed in to. See Sessions.

ArgumentTypeRequiredNotes
urlstringyesThe page
formatarraynoAny of html, cleaned_html, markdown, readability. Default ["markdown"]
waitUntilstringnodomcontentloaded, load or networkidle. Default load
waitForTextstringnoWait until this text is on the page. At most 500 characters
timeoutMsintegerno1000 to 120 000. Default 30 000
screenshot, pdf, mhtmlbooleannoAlso return the page as base64 inside the JSON
inventorybooleannoAlso list embedded media and third-party hosts
engine, device, viewport, block, allowHosts, proxyUrlnoSame meaning as in create_session

Returns: JSON as text and structuredContent: url, content (one key per requested format), metadata (title, status code, description, word count), links.

Arguments
{ "url": "https://webagent-test-web.pages.dev", "format": ["markdown"] }
structuredContent (trimmed)
{
  "url": "https://webagent-test-web.pages.dev/",
  "content": { "markdown": "[Test Arena](/)\n...\n# A practice site for browser agents\n..." },
  "metadata": {
    "title": "Test Arena · a practice site for browser agents",
    "statusCode": 200,
    "language": "en",
    "wordCount": 190
  },
  "links": [{ "url": "https://webagent-test-web.pages.dev/pricing/", "text": "Pricing", "internal": true }]
}

screenshot

Loads a URL and returns an image. The result is an MCP image content item, with no structuredContent.

ArgumentTypeRequiredNotes
urlstringyesThe page
fullPagebooleannoDefault true
formatstringnopng, jpeg or webp. Default png
qualityintegerno0 to 100
waitUntil, waitForText, timeoutMsnoAs in scrape
engine, device, viewport, block, allowHosts, proxyUrlnoAs in create_session
Arguments
{ "url": "https://example.com", "fullPage": false, "format": "jpeg", "quality": 80 }

This tool takes a screenshot of a fresh page. It cannot show the state a run_task left behind.


pdf

Loads a URL and returns it as a PDF. The result is an MCP resource with uri webagent://quick/pdf, the MIME type application/pdf and the file as a base64 blob.

ArgumentTypeRequiredNotes
urlstringyesThe page
paperstringnoA4, Letter or Legal. Default A4
landscapebooleannoDefault false
printBackgroundbooleannoDefault true
waitUntil, waitForText, timeoutMsnoAs in scrape
engine, device, viewport, block, allowHosts, proxyUrlnoAs in create_session
Arguments
{ "url": "https://example.com", "paper": "Letter" }

crawl

Crawls from a URL and returns the pages it visited.

ArgumentTypeRequiredNotes
urlstringyesWhere to start
scopestring or arraynohost (default), subdomains, or a list of up to 20 hosts
include, excludestring arraynoURL patterns. Up to 50 each
maxPagesintegerno1 to 100. Default 25
maxDepthintegerno0 to 5. Default 2
delayMsintegerno0 to 10 000. Default 500
respectRobotsbooleannoDefault true
sitemapbooleannoDefault false
contentarraynoAlso return page content, in these formats
maxMsintegernoLimit for the whole crawl. 1000 to 600 000. Default 300 000
cursorstringnoContinue a crawl that stopped. Use the cursor from the last result

Returns: JSON with start, pages (each with url, depth, status, title, linksFound, ms), skipped, skippedTotal, stoppedBy (complete, maxPages or timeout), pending and, when the crawl stopped early, a cursor.

The crawl obeys the site's robots.txt unless you set respectRobots to false. A site that disallows everything returns no pages. Only crawl sites you own or may test.

Arguments
{ "url": "https://staging.example.com", "maxPages": 10, "maxDepth": 1 }

list_skills

Lists the skills your project can run, with their inputs and permissions. No arguments. Each skill also has its own skill_<name> tool.

Returns: { "skills": [ … ] }. See Skills.

Arguments
{}

run_skill

Starts a skill run by name and returns at once. It does not wait. Call get_report with the runId for the pass/fail report, or get_skill_run for the raw record. To test a page or flow, smoke_test is easier, because it waits and returns the report. The typed skill_<name> tool also waits.

ArgumentTypeRequiredNotes
namestringyesThe skill name, for example smoke-uat
inputsobjectnoThe skill's inputs. Default {}
versionstringnoA skill version. Default: the newest
grantarraynoPermissions to grant, from network_capture, active_scan, file_access. A skill that does active security probes needs ["active_scan"]. Ask the user first
sessionobjectnoSession options for the run, for example proxyUrl and allowHosts

engineId picks the engine for the run's session, as on the REST route.

Returns: { "runId": "run_…", "sessionId": "sess_us_…", "status": "running", "placement": "queued" }.

Arguments
{ "name": "smoke-uat", "inputs": { "url": "https://staging.example.com" } }

get_skill_run

Reads a skill run. While it runs, the tool waits up to waitSeconds for the verdict.

ArgumentTypeRequiredNotes
runIdstringyesThe run id
waitSecondsintegerno0 to 120. Default 0, which does not wait

Returns: a short text summary and the run in structuredContent. See the skill result below. It sets isError only for status error, denied or cancelled. A failed run is a normal result: read status. For a verdict with failed steps, console errors and failed network calls, call get_report with the runId.

Arguments
{ "runId": "run_xxxxxxxxxxxxxxxxxxxxxxxx", "waitSeconds": 60 }

skill_<name>

One tool exists for each skill your project can see. A skill named smoke-uat becomes skill_smoke_uat: dashes turn into underscores. The tool starts the run, waits for the verdict and returns it with a report link.

The tool's description comes from the skill. Its arguments are the skill's own inputs, flat, plus two more:

ArgumentTypeRequiredNotes
each skill inputthe input's typeas the skill saysA url input is a string. A string[] input is an array of strings. A secret input takes a vault reference such as https://host#password, never the secret itself
options.waitSecondsintegerno0 to 120. Default 30. A run still going when the wait ends comes back with status: "running" and a runId for get_skill_run
options.sessionobjectnoSession options for this run, for example proxyUrl and allowHosts to reach a private staging site
confirmbooleanyes, for active scans onlyMust be true. The tool has this argument only when the skill sends active security probes. Set it only after the user confirms they may test the target

Skill runs cannot sign in yet. If options.session has credentials, profileId, persistProfile, profileName or extensionIds, the tool returns isError with invalid_input ("Signed-in skill runs are not available yet: remove session.credentials") and starts nothing. See Skills.

Returns: the same as get_skill_run: the raw run and a report link. The call sets isError: true only when the run could not run to a result: status error, denied or cancelled. A run that failed is a normal result, and so is one still running. To get a verdict with console errors and failed network calls, use smoke_test or get_report with the runId.

Arguments for skill_smoke_uat
{
  "url": "https://staging.example.com",
  "steps": ["click Sign in", "type \"[email protected]\" into Email"],
  "expectText": "Welcome",
  "options": { "waitSeconds": 60 }
}

The skill result

The text of the result lists, in this order: the skill name, version, run id and status; the skill's summary; the reason for a stop, if there is one; the counts; up to five failed steps; and the report link.

structuredContent is the run: runId, skill, sessionId, status, startedAt, ms, summary, counts, result, hasReport, and reportUrl once a report exists. The statuses are running, passed, failed, error, cancelled and denied.

  • Screenshots and video clips are left out of structuredContent. They are in the report.
  • Strings longer than 2000 characters are cut, and only the last 50 log lines are kept.
  • If the result is larger than 100 000 bytes, each step is reduced to one line: index, path, kind, label, ok, ms and error.
  • reportUrl is a signed link that works without an API key. It stops working after a few minutes. See Evidence.

Limits that apply to tools

Waits are capped so that a single reply never stays silent for too long: 90 seconds for run_task, get_task, smoke_test and get_report, 120 seconds for the skill tools. A longer job keeps running, and you read it with get_report, get_task or get_skill_run. See Limits.

On this page