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.
browser_set_allowed_domains
Section titled “browser_set_allowed_domains”Set the session-scoped allowlist. This does not persist across browser restarts and does not survive session close. It is not a permanent grant.
Parameters
Section titled “Parameters”| 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. |
Request
Section titled “Request”{ "jsonrpc": "2.0", "id": 5, "method": "tools/call", "params": { "name": "browser_set_allowed_domains", "arguments": { "domains": ["example.com", "*.news.example.com"] } }}Response
Section titled “Response”{ "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.
Errors
Section titled “Errors”| 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. |
Wildcard rules
Section titled “Wildcard rules”*.example.commatchesa.example.comanda.b.example.com, but notexample.comitself. Add both if you need the bare domain too.example.comis treated as an exact match.www.example.comis 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.
browser_navigate
Section titled “browser_navigate”Move a tab to a URL. Requires the target’s registrable domain to be in the current session’s allowlist.
Parameters
Section titled “Parameters”| 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. |
Request
Section titled “Request”{ "jsonrpc": "2.0", "id": 6, "method": "tools/call", "params": { "name": "browser_navigate", "arguments": { "tab_id": "tab_1a2b", "url": "https://example.com/pricing" } }}Response
Section titled “Response”{ "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.
Errors
Section titled “Errors”| 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." } }}Recommended flow
Section titled “Recommended flow”- Call
browser_set_allowed_domainsearly, with the smallest allowlist your task needs. - Wait for the user to approve.
prompted: trueand no error means the allowlist is now active. - Call
browser_navigatefor each target URL. - If a task needs to visit a new domain later, call
browser_set_allowed_domainsagain 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_domainsagain. - 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.