Inspection¶
Inspection tools let you observe the current state of a browser instance — its accessibility tree, visual appearance, console output, and network activity. browser_snapshot is the primary tool: it returns an LLM-friendly YAML accessibility tree where every interactive element carries a [ref=eN] tag that other tools consume to click, type, or drag without pixel coordinates. These refs are session-scoped and invalidated by navigation; see Refs & snapshots for a full explanation of the ref lifecycle. Use browser_screenshot when visual fidelity matters, and browser_console_messages / browser_network_requests for debugging JavaScript errors and API calls.
Optional page_id selects a live page without changing the selected tab; an invalid
explicit target returns page_not_found. Frame-capable calls also accept frame_id
and return frame_not_found for a detached or foreign frame. Omitted targets retain
existing behavior. See explicit targeting.
browser_snapshot¶
Capture an accessibility snapshot of the active page in LLM-friendly YAML.
Signature
async def browser_snapshot(
instance: str, selector: str | None = None, *, page_id: str | None = None, frame_id: str | None = None
) -> dict[str, Any]
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
instance |
str |
— | Instance name. |
selector |
str \| None |
None |
Optional CSS or aria selector to scope the snapshot to a subtree. When provided, refs are not included in the output. |
page_id |
str \| None |
None |
Stable page ID; omitted uses the selected page. Explicit targeting preserves selection and rejects unavailable IDs. |
frame_id |
str \| None |
None |
Attached frame ID from browser_frames; explicit scope never falls back to another frame. |
Returns — see response envelope. data shape:
{ "snapshot": "<yaml string>", "url": "https://example.com/page" }
Errors — emits error_type codes (see envelope error codes):
instance_not_foundmodal_state_blockedinternal_error
Example
Request:
{ "name": "browser_snapshot", "arguments": { "instance": "main" } }
Response:
{
"status": "success",
"instance": "main",
"data": {
"snapshot": "- button \"Submit\" [ref=e12]\n- textbox \"Email\" [ref=e7]",
"url": "https://example.com/login"
}
}
Snapshot output also includes the resolved page_id and frame_id.
Notes — Default mode (selector=None) uses the internal Frame.ariaSnapshot channel with mode="ai" and annotates every interactive element with [ref=eN]. Pass a ref value to browser_click, browser_type, or other interaction tools to act on that element. Refs are session-scoped and invalidated by navigation or page reload — call browser_snapshot again after any navigation to obtain fresh refs. Selector mode calls Locator.aria_snapshot on the matching element and returns plain aria YAML without refs; use it for scoped inspection of a known subtree when you do not need to interact with the results.
browser_screenshot¶
Take a visual screenshot as base64, or save it to an explicit server-side path.
Signature
async def browser_screenshot(
instance: str,
image_format: str = "png",
*,
full_page: bool = False,
path: str | None = None,
page_id: str | None = None,
original: bool = False,
) -> dict[str, Any]
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
instance |
str |
— | Instance name. |
image_format |
str |
"png" |
"png" (lossless) or "jpeg" (lossy, smaller). |
full_page |
bool |
False |
Capture the entire scrollable page instead of just the current viewport. |
page_id |
str \| None |
None |
Stable page ID; omitted uses the selected page. Explicit targeting preserves selection and rejects unavailable IDs. |
original |
bool |
False |
Save original screenshot bytes; requires an explicit path. |
path is an optional string, default None; when supplied it replaces the inline
image with a file artifact reference.
Returns — see response envelope. data shape:
{
"image_base64": "<base64 string>",
"image_format": "png",
"width": 1280,
"height": 720
}
width and height are null when image processing is unavailable. With
path, the data contains that path instead of image_base64; parent directories
must already exist. The image is still resized before saving.
Errors — emits error_type codes (see envelope error codes):
instance_not_foundinvalid_params—image_formatis not"png"or"jpeg"modal_state_blockedinternal_error
Example
Request:
{ "name": "browser_screenshot", "arguments": { "instance": "main", "image_format": "jpeg" } }
Response:
{
"status": "success",
"instance": "main",
"data": {
"image_base64": "/9j/4AAQ...",
"image_format": "jpeg",
"width": 1280,
"height": 720
}
}
Notes — With original=False, oversized images are automatically downscaled so the longest side is at most 1568 px (the server's image-size convention). The width and height fields reflect delivered dimensions; source_width and source_height retain the original pixel dimensions. Set original=True with an explicit path to save exact Playwright bytes without resizing or inline base64. original=True without a path is invalid_params. All outputs include original; image bytes are still allocated in memory before saving. Prefer browser_snapshot for most inspection tasks; screenshots are most useful for visual debugging or when the accessibility tree does not carry enough detail.
browser_console_messages¶
Read a bounded page of recent console messages retained for the instance.
Signature
async def browser_console_messages(
instance: str,
level: str | None = None,
*,
after: str | None = None,
limit: int = 100,
path: str | None = None,
) -> dict[str, Any]
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
instance |
str |
— | Instance name. |
level |
str \| None |
None |
Filter by message type. Valid values: "log", "info", "warning", "error", "debug". None returns all messages. |
Returns — see response envelope. data shape:
{
"messages": [
{
"type": "error",
"text": "Uncaught ReferenceError: foo is not defined",
"location": "https://example.com/app.js:42:8"
},
{ "type": "log", "text": "page ready", "location": null }
]
}
Errors — emits error_type codes (see envelope error codes):
instance_not_foundinvalid_params—levelis not one of the recognised values
Example
Request:
{ "name": "browser_console_messages", "arguments": { "instance": "main", "level": "error" } }
Response:
{
"status": "success",
"instance": "main",
"data": {
"messages": [
{
"type": "error",
"text": "Uncaught ReferenceError: foo is not defined",
"location": "https://example.com/app.js:42:8"
}
]
}
}
Notes — The buffer retains recent messages across pages and navigations,
evicting the oldest at its configured capacity. See pagination and export. Uncaught page errors are captured as type="error" entries with location=null. Useful for diagnosing JavaScript errors or confirming page-side logging without opening DevTools.
browser_network_requests¶
Read a bounded page of recent network request states retained for the instance.
Signature
async def browser_network_requests(
instance: str,
url_filter: str | None = None,
*,
static: bool = False,
after: str | None = None,
limit: int = 100,
path: str | None = None,
) -> dict[str, Any]
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
instance |
str |
— | Instance name. |
url_filter |
str \| None |
None |
Python regular expression. Only requests whose URL matches are returned. Applied after the static filter. An invalid regex returns invalid_params. |
static |
bool |
False |
When False (default), static asset requests (image, font, stylesheet, media, manifest) are filtered out. Pass True to include them. |
Returns — see response envelope. data shape:
{
"requests": [
{
"url": "https://api.example.com/data",
"method": "GET",
"status": 200,
"resource_type": "fetch",
"failure": null
},
{
"url": "https://api.example.com/submit",
"method": "POST",
"status": null,
"resource_type": "fetch",
"failure": "net::ERR_CONNECTION_REFUSED"
}
]
}
status is null until the response arrives or if it never does. failure is null on success or while a request is still pending.
Errors — emits error_type codes (see envelope error codes):
instance_not_foundinvalid_params—url_filteris not a valid regular expression
Example
Request:
{ "name": "browser_network_requests", "arguments": { "instance": "main", "url_filter": "/api/" } }
Response:
{
"status": "success",
"instance": "main",
"data": {
"requests": [
{
"url": "https://example.com/api/users",
"method": "GET",
"status": 200,
"resource_type": "fetch",
"failure": null
}
]
}
}
Notes — The buffer retains recent requests across pages and navigations;
old records are evicted. See pagination and export. By default, static resource types (image, font, stylesheet, media, manifest) are filtered out to reduce noise; pass static=True to include everything. Useful for verifying API calls were made, checking redirect chains, or diagnosing network errors during page load.
Event pagination and export¶
Console and network queries accept these optional arguments:
| Parameter | Default | Meaning |
|---|---|---|
after |
None |
A cursor from this same instance and event stream. Omit it to start at the oldest retained entry. |
limit |
100 |
Maximum matching entries to return, from 1 to 500. |
path |
None |
Save this JSON page to a server-side file instead of returning inline entries. Parent directories must exist. |
Each entry adds a monotonic sequence, UTC timestamp, and page_id identifying
its source tab. Network entries also have a stable request_id. A response or
failure updates that request with a new sequence and timestamp; consumers should
upsert by request_id. A pending request evicted before its response arrives is
not brought back into the retained buffer.
Each result includes next_cursor, has_more, retained_count, dropped_count,
and retention_lost. Reuse next_cursor as after with the same filters. Cursors
are specific to an instance lifetime and event stream; invalid or foreign cursors
return invalid_params. retention_lost means records after the requested cursor
have already been evicted. Filtered-out records are not counted as dropped.
The buffer holds at most BROWSER_MCP_EVENT_BUFFER_SIZE entries per stream
(default 1000). Individual string fields are capped at 4096 characters; shortened
fields are listed in truncated_fields. This is recent diagnostic evidence, not
a complete network archive or response-body capture. Exporting does not restore
evicted records or shortened fields.
When path is provided, the file contains the selected messages or requests
plus pagination metadata. The returned data contains path, count, and the
same pagination metadata, without inline entries. Artifacts refer to files on
the server. Collect those files separately if the MCP client runs elsewhere;
the server does not upload them or manage their long-term retention.
{
"name": "browser_network_requests",
"arguments": {
"instance": "main",
"limit": 50,
"path": "/workspace/evidence/network-page.json"
}
}
browser_downloads¶
List retained download evidence for an instance, optionally filtered by its originating page. This filter can refer to a closed page and does not select or create a page.
async def browser_downloads(
instance: str, *, page_id: str | None = None,
after: str | None = None, limit: int = 100,
) -> dict[str, Any]
The data.downloads array contains download_id, page_id, url,
suggested_filename, status, created_at, and available, plus event sequence,
timestamp, and truncation fields. Save updates can add path or failure.
Statuses are detected, saving, saved, and failed; detected means the
browser emitted a download event, not that its bytes finished downloading.
The result includes next_cursor, retention_lost, and dropped_count, using the
same pagination conventions as console/network evidence. Invalid cursors or limits
return invalid_params; a missing instance returns instance_not_found.
Handles and evidence have bounded retention using BROWSER_MCP_EVENT_BUFFER_SIZE.
Persist metadata externally if needed, and save a download while available is
true. Saving pins its handle against eviction. Closing its page does not itself
remove the retained handle; destroying the instance ends access.
browser_download_save¶
Copy a retained browser download to an explicit server file path.
async def browser_download_save(instance: str, download_id: str, path: str) -> dict[str, Any]
Waits for Playwright's download save to finish within the instance operation
deadline. Returns data: {"download_id": "...", "path": "..."} and records the
path in operation artifacts. It uses the download's recorded page owner, even if
that page has closed, and never substitutes the selected page.
Repeated saves to explicit paths are allowed while the handle remains available;
existing files can be overwritten. The tool never chooses a destination from
suggested_filename, and it does not upload the file to the MCP client.
Errors include instance_not_found, download_not_found for a foreign or evicted
ID, download_failed for saving failures, and operation_timeout. A failed or
cancelled save may leave a partial file; inspect it before retrying. Browser
teardown removes browser-managed temporary downloads, while explicitly saved
files remain on disk for you to collect or delete.