extension_open
Open an extension surface, or replay an event, in a running session.
Quick start
Open the side panel, then trigger the action button
Asked to open a surface, the agent runs the extension and opens the page in a tab.
How the agent uses it
Pass surface:'popup', 'options' or 'sidebar' to open a UI surface, or 'newtab', 'history' or 'bookmarks' to open the matching chrome_url_overrides page in a tab (always a tab, resolved by the server, never sent to the engine). On Chromium, when Chrome refuses the sidebar for lack of a user gesture, the server opens the real panel through a synthetic click on the extension's own page and says so in warnings; if that fails too it renders the sidebar document as a tab. Pass surface:'devtools' to open the browser's DevTools on a tab (the one url matches, else the first web page) and show the extension's panel there, picked by panel title when there are several: Chromium only, over CDP Target.openDevTools, headed or headless; the result names the panel document's url, which extension_eval reads with context 'page' and that url (the panel is no tab, so the tab-based readers do not reach it). Pass surface:'action' to trigger the toolbar action, which opens its popup or replays chrome.action.onClicked when there is none. Pass surface:'command' with name to replay a chrome.commands.onCommand shortcut. Note that action and command replay invoke your listener without a user gesture, so the gesture-derived activeTab grant does not apply; the engine's own frame is returned as is. Rides the dev session's control channel, on unless extension_dev was called with allowControl:false.
Page text in the answer
Part of this tool's answer is text a web page or the extension wrote. The server fences it between <untrusted-data-ID> and </untrusted-data-ID> with a fresh random ID per call, named in untrusted.boundary. A fence is a signal to the model, not a gate: pair it with --no-ship when the agent reads pages you do not trust. See Server flags and telemetry.
Reference
| Group | local, on by default |
| Tier | Act |
| Needs | a dev session, which carries control unless started with allowControl: false |
| Read only | no |
| Destructive | no |
| Idempotent | no |
| Reaches the open web | yes |
Inputs
| Input | Type | Required | Default | What it does |
|---|---|---|---|---|
projectPath | string | yes | Extension project root (needs a live dev session) | |
surface | "popup" | "options" | "sidebar" | "devtools" | "newtab" | "history" | "bookmarks" | "action" | "command" | no | Which surface to open or event to replay. | |
name | string | no | For surface 'command': the chrome.commands name to trigger. | |
panel | string | no | For surface 'devtools': the title the extension gave chrome.devtools.panels.create, when it registers more than one panel. Omitted, the extension's first panel is shown. | |
waitMs | number | no | For surface 'devtools': how long to wait for the panel to register after DevTools opens (default 15000, up to 120000). Extensions that create their panel on a page event need longer, or reload. | |
reload | boolean | no | false | For surface 'devtools': reload the inspected tab once DevTools is open, for extensions that create their panel only when the page reports to them on a load that starts with DevTools open (Preact Devtools). Discards the page state under test. |
url | string | no | Navigate a real tab here instead of opening a surface, in a NEW tab unless tab names one (a blank or new-tab page is reused). An absolute url opens as given; a path with no scheme, such as pages/options.html, is resolved against the extension's own origin. Use for content-script test pages, or a surface as a page. | |
tab | number | no | With url: navigate this chrome.tabs id in place instead of opening a new tab (rides the engine's navigate verb over the control channel, which a dev session carries unless started with allowControl: false). Without it an existing page is never taken over. | |
asTab | boolean | no | false | popup/options/sidebar: render the surface's document in a real tab instead of a popup window. This is how you inspect a surface HEADLESSLY, and it is applied automatically when a headless session refuses to open one. Same page and APIs, but no popup sizing and window.close() closes the tab. |
browser | string | no | Session browser; defaults to this project's live session | |
timeout | number | no | Command timeout in ms. When omitted, the default depends on the route: 30000 through the dev session's control channel, 10000 over the Firefox debugger protocol, and 15000 per command over the Chromium debug port. |
When it fails
- The call is refused because no session is live. Start one with
extension_devorextension_startand call again. - The control channel is off. The session was started with
allowControl: false. Start it again without that flag. - The answer depends on the network. This tool reaches the open web, so a refusal can be the network, not the project.
Next
- MCP server: install, the two groups and the session gates
- Install in your client
extension_eval: Evaluate an expression in a running extension context.extension_reload: Reload a running extension's background context, or a tab.extension_storage: Read or write chrome.storage in a running extension.