Skip to content

Navigation

Navigation is intentionally gated. Before an agent can move a tab to a URL, the user has to approve the domain for that session. This is the D1 constraint: allowed domains are session-scoped, wildcard-capable, and always require an explicit call to set them.

Set the session-scoped allowlist. This does not persist across browser restarts and does not survive session close. It is not a permanent grant.

| Name | Type | Required | Description | |------|------|----------|-------------| | domains | array of string | yes | Domain patterns. Wildcards allowed: *.example.com matches any subdomain. Bare hosts like example.com match only that exact host. |

{
"jsonrpc": "2.0",
"id": 5,
"method": "tools/call",
"params": {
"name": "browser_set_allowed_domains",
"arguments": {
"domains": ["example.com", "*.news.example.com"]
}
}
}
{
"allowed_domains": ["example.com", "*.news.example.com"],
"prompted": true
}

prompted: true means the user was shown a confirmation prompt at the moment this call fired. If the exact same allowlist is set twice in the same session, the second call is a no-op and prompted is false.

| Code | When | |------|------| | -32602 | domains missing, empty, or contains an invalid pattern (e.g. *.*.example.com). | | -32603 | User declined the prompt. The session’s allowlist is unchanged. |

  • *.example.com matches a.example.com and a.b.example.com, but not example.com itself. Add both if you need the bare domain too.
  • example.com is treated as an exact match. www.example.com is a different domain.
  • IP literals (192.0.2.1) are matched exactly, no wildcards.
  • Scheme is not part of the pattern. HTTPS is required in practice because HTTP navigations to public origins are already refused by the browser.

Move a tab to a URL. Requires the target’s registrable domain to be in the current session’s allowlist.

| Name | Type | Required | Description | |------|------|----------|-------------| | tab_id | string | yes | Tab to navigate. Get one from browser_tab_list. | | url | string | yes | Fully qualified URL including scheme. | | wait_for_load | boolean | no | Block the response until the navigation has committed and DOMContentLoaded has fired. Default: true. Setting false returns immediately after the load starts. |

{
"jsonrpc": "2.0",
"id": 6,
"method": "tools/call",
"params": {
"name": "browser_navigate",
"arguments": {
"tab_id": "tab_1a2b",
"url": "https://example.com/pricing"
}
}
}
{
"navigated": true,
"final_url": "https://example.com/pricing",
"http_status": 200,
"committed_at_ms": 1719791234123
}

If wait_for_load is false, the response fires as soon as the navigation is committed and http_status may be null when a redirect chain is still in flight.

| Code | When | |------|------| | -32010 | domain_approval_required. The URL’s registrable domain is not covered by the current allowlist. Call browser_set_allowed_domains and retry. | | -32011 | Another session holds the tab lease. | | -32602 | url is malformed or tab_id is missing. | | -32603 | Network-layer failure. The data field carries an error string from net::ERR_*. |

Example domain_approval_required error:

{
"jsonrpc": "2.0",
"id": 6,
"error": {
"code": -32010,
"message": "domain_approval_required",
"data": {
"requested_url": "https://example.com/pricing",
"registrable_domain": "example.com",
"hint": "Call browser_set_allowed_domains with the domain, then retry."
}
}
}
  1. Call browser_set_allowed_domains early, with the smallest allowlist your task needs.
  2. Wait for the user to approve. prompted: true and no error means the allowlist is now active.
  3. Call browser_navigate for each target URL.
  4. If a task needs to visit a new domain later, call browser_set_allowed_domains again with the expanded list. The user is prompted for the delta.
  • The allowlist is per-session, not per-tab. All tabs opened by this MCP session share it.
  • Closing the MCP session clears the allowlist. Reconnecting requires calling browser_set_allowed_domains again.
  • User-initiated navigations (typing in the URL bar, clicking a link) are never blocked by the allowlist. The allowlist only constrains agent-initiated navigation.
  • The lease system runs orthogonally: an agent with a valid lease still needs the domain approval. Domain approval alone does not grant lease access.