@extension.dev/mcp 10.10.10 → 10.10.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,7 @@
10
10
  "name": "extension-mcp",
11
11
  "source": "./",
12
12
  "description": "MCP tools for browser extension development: scaffold from 50+ templates, run the dev server with HMR, inspect the live DOM and logs, and publish store-ready builds for Chrome, Edge, and Firefox.",
13
- "version": "10.10.10",
13
+ "version": "10.10.12",
14
14
  "category": "development",
15
15
  "author": {
16
16
  "name": "Cezar Augusto"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "extension-mcp",
3
3
  "description": "MCP tools for browser extension development: scaffold from 50+ templates, run the dev server with HMR, inspect the live DOM and logs, and publish store-ready builds for Chrome, Edge, and Firefox. Ships /extension, /extension-add, /extension-debug, and /extension-publish commands.",
4
- "version": "10.10.10",
4
+ "version": "10.10.12",
5
5
  "author": {
6
6
  "name": "Cezar Augusto",
7
7
  "email": "hello@extension.dev",
package/CHANGELOG.md CHANGED
@@ -1,5 +1,49 @@
1
1
  # Changelog
2
2
 
3
+ ## 10.10.12
4
+
5
+ - `extension_stop` on Windows reads the Windows process table to find what
6
+ is left of a session, so a stop that ended the whole tree says
7
+ `stopped` instead of "survivors were not verified". Before this, every
8
+ Windows stop answered `stopped: false`, and `extension_dev` with
9
+ `replace: true` refused every time. A stop still says unverified when
10
+ the table cannot be read. Measured on a Windows runner.
11
+ - The lockfile raises `proxy-addr`, `source-map-js` and Vue past their
12
+ open advisories.
13
+
14
+ ## 10.10.11
15
+
16
+ The rest of the 2026-10-05 audit ledger, apart from the Safari WebDriver
17
+ fields that wait on the engine (entry 110h, Extension.js BUGS_TO_FIX 905).
18
+
19
+ - `extension_eval` says where it ran and what came back: the tab's url and
20
+ title on Firefox, a note when the value was not serializable, only real
21
+ background targets as the background, and `eval-lost` or
22
+ `eval-unsupported` when the answer never arrived. A woken worker is no
23
+ longer said to have idled when it may never have started.
24
+ - `extension_logs` and `extension_assert` report a cut stream: a follow
25
+ that closed early is a partial read, dropped-line markers are not
26
+ counted as events, and console-errors-empty is inconclusive when lines
27
+ were dropped. An unknown console `context` is refused as a bad request
28
+ instead of failing the whole call.
29
+ - `extension_wait` and `extension_start` report only what they observed:
30
+ a start session is `build-ready`, a build contract or a stopped session
31
+ is `no-session`, and start refuses Safari and preview-path hosts it
32
+ cannot serve.
33
+ - `extension_open` names the DevTools panel frame that appeared, and says
34
+ when the panel registry could not be read or the target was inferred.
35
+ - Platform answers of the wrong shape (channels, build index, shares,
36
+ login config) are unreadable, never empty, and an unpinned publish
37
+ matches the build the platform named.
38
+ - `extension_stop` counts a process as reaped only once it is gone, and
39
+ ends a Windows session through `taskkill /T /F`. A session marker that
40
+ could not be written is a warning on the started answer, and the
41
+ `release promote` command exits non-zero on an answer it cannot read.
42
+ - `extension_list_extensions` on Firefox marks a lone temporary add-on as
43
+ an inferred match.
44
+ - The scheduled test tier builds through the real pinned engine with
45
+ `--output json` and checks the fixtures against what it writes.
46
+
3
47
  ## 10.10.10
4
48
 
5
49
  Every sentence the server says is now backed by something it read
package/README.md CHANGED
@@ -151,7 +151,7 @@ Two flags (or environment variables) narrow the server before an agent sees it:
151
151
 
152
152
  A refused call answers `E_TOOL_DISABLED` with the flag to change.
153
153
 
154
- A real store submission, a promotion to stable and a share revoke also wait for a person by default: the first call answers `approval-required` with a link on extension.dev, a workspace member approves exactly that action, and the same call with the returned `approvalId` runs it once. `EXTENSION_DEV_APPROVAL_GATE=1` extends this to every promotion; `EXTENSION_DEV_APPROVAL_GATE=0` turns it off.
154
+ A real store submission, a promotion to stable and a share revoke also wait for a person by default: the first call answers `approval-required` with a link on extension.dev, a workspace member approves exactly that action (a store submission needs a workspace owner), and the same call with the returned `approvalId` runs it once. `EXTENSION_DEV_APPROVAL_GATE=1` extends this to every promotion; `EXTENSION_DEV_APPROVAL_GATE=0` turns it off.
155
155
 
156
156
  Every tool also carries MCP annotations (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`), so clients can auto-approve reads and ask before the rest.
157
157
 
@@ -304,7 +304,7 @@ Extension.js release records one, and that leg reads `skip`.
304
304
 
305
305
  ## Sharing a build in progress
306
306
 
307
- An unpacked extension is unusually hard to hand to someone: the only way to look at a colleague's work-in-progress has been to take their zip and run untrusted code with real browser permissions on your own machine. `extension_preview_web` with `share: true` uploads the `dist/` it just built and returns a link that renders those exact bytes in the emulator. Whoever opens it installs nothing and signs in to nothing, which is what lets a designer, a PM, or a reviewer into the loop at all. Those bytes run in an isolated sandbox origin or they do not run at all: preview refuses a shared build rather than serving it in its own renderer. Sharing needs auth (`extension_auth` or `EXTENSION_DEV_TOKEN`), the link lives 30 days, and `DELETE`ing the returned `revokeUrl` with the same token kills it early. Re-sharing an unchanged build returns that same link rather than a second one, and only a revoked link is replaced by a different one, because revocation is permanent: the address is burned and never resolves again. That makes `revokeUrl` the handle to the link you just made, so every share is also appended to `.extension.dev/shared-previews.json` in the project (gitignored) so it survives losing the tool output. The upload holds up to 2,000 files and about 64MB of text, or roughly 48MB when the build is mostly images, fonts or wasm, which travel base64-encoded. Without `share`, the tool returns a local-only deep link and uploads nothing.
307
+ An unpacked extension is unusually hard to hand to someone: the only way to look at a colleague's work-in-progress has been to take their zip and run untrusted code with real browser permissions on your own machine. `extension_preview_web` with `share: true` uploads the `dist/` it just built and returns a link that renders those exact bytes in the emulator. Whoever opens it installs nothing and signs in to nothing, which is what lets a designer, a PM, or a reviewer into the loop at all. Those bytes run in an isolated sandbox origin or they do not run at all: preview refuses a shared build rather than serving it in its own renderer. Sharing needs auth (`extension_auth` or `EXTENSION_DEV_TOKEN`), the link lives for the workspace plan's share window (30 days on Free, longer on Pro) and the answer carries its exact `expiresAt`, and `DELETE`ing the returned `revokeUrl` with the same token kills it early. Re-sharing an unchanged build returns that same link rather than a second one, and only a revoked link is replaced by a different one, because revocation is permanent: the address is burned and never resolves again. That makes `revokeUrl` the handle to the link you just made, so every share is also appended to `.extension.dev/shared-previews.json` in the project (gitignored) so it survives losing the tool output. The upload holds up to 2,000 files and about 64MB of text, or roughly 48MB when the build is mostly images, fonts or wasm, which travel base64-encoded. Without `share`, the tool returns a local-only deep link and uploads nothing.
308
308
 
309
309
  `extension_shares` is the other half of that: it lists every link the token has shared, live and dead, with the `previewUrl` and `revokeUrl` of each, and revokes one by `artifactId` or by pasting any of its URLs. Pass `projectPath` and it reconciles the platform's answer with the project's own record, so a link shared from another machine shows up as `remoteOnly` and a record with nothing behind it any more shows up under `localOnly`. It never rewrites the local file.
310
310
 
@@ -33,7 +33,7 @@ Run a test stage against a live dev session: state expectations and read one ver
33
33
  | `projectPath` | string | yes | | Extension project root (needs a live dev session) |
34
34
  | `expect` | array of object | yes | | One object per expectation, each { assert: <check id>, ...args }. background-worker-booted: no args. surface-rendered: surface (popup, options, sidebar, newtab, history, bookmarks), optional selector and minNodes. content-script-injected: url. storage-key-present: key, optional area (default local), equals, context. console-errors-empty: optional context (array), since (seq cursor), ignore (substrings). |
35
35
  | `browser` | string | no | | Session browser; defaults to this project's live session |
36
- | `timeout` | number | no | | Command timeout in ms (default 5000) |
36
+ | `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. |
37
37
 
38
38
  ## extension_auth
39
39
 
@@ -148,11 +148,11 @@ Take a shallow structured DOM snapshot of one chosen surface through the agent b
148
148
  | `maxBytes` | number | no | `262144` | |
149
149
  | `withConsole` | number \| boolean | no | | Also include recent console lines. A number is how many; true means 50. |
150
150
  | `browser` | string | no | | Session browser; defaults to this project's live session |
151
- | `timeout` | number | no | | Command timeout in ms (default 5000) |
151
+ | `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. |
152
152
 
153
153
  ## extension_eval
154
154
 
155
- Evaluate an expression in a running extension context. Start the session with allowEval:true (extension_dev), which writes a 0600 session token; without that token every route of this tool, the debug port included, answers eval-disabled. Context defaults to 'background', except on a Chromium MV3 session (the default template) where it defaults to 'page', the active tab, because the MV3 service worker CSP blocks eval; pass context:'background' to target the worker anyway and get that explanation back. For content and page, pass `url` to pick the tab, or omit both `url` and `tab` for the active tab; a numeric `tab` only disambiguates. Extension surfaces (popup, options, sidebar, devtools) and override pages (newtab, history, bookmarks) need no tab id but must already be open: open one with extension_open first, because a closed one returns an explicit error. On a Chromium MV3 session those pages, and context:'page' with a chrome-extension:// url, evaluate over CDP, the inspector path the extension page CSP does not govern; elsewhere they evaluate over the in-bundle relay. On Firefox a document whose content security policy forbids eval (the extension's own pages, or a site's) is evaluated over the debugger protocol instead, which takes one expression; a page inside the extension that is no declared surface (pages/*) is reached the same way by context:'page' and its moz-extension:// url once a tab shows it. Call extension_dom_snapshot with listTabs:true to enumerate {tabId, url, title}.
155
+ Evaluate an expression in a running extension context. Start the session with allowEval:true (extension_dev), which writes a 0600 session token; without that token every route of this tool, the debug port included, answers eval-disabled. Context defaults to 'background', except on a Chromium MV3 session (the default template) where it defaults to 'page', the active tab; pass context:'background' to evaluate in the service worker, which on Chromium goes over the debug port. Debug-port evaluates run with a user gesture, so gesture-gated APIs (permissions.request, sidePanel.open) can succeed here and still fail when the extension's own code calls them. For content and page, pass `url` to pick the tab, or omit both `url` and `tab` for the active tab; a numeric `tab` only disambiguates. Extension surfaces (popup, options, sidebar, devtools) and override pages (newtab, history, bookmarks) need no tab id but must already be open: open one with extension_open first, because a closed one returns an explicit error. On a Chromium MV3 session those pages, and context:'page' with a chrome-extension:// url, evaluate over CDP, the inspector path the extension page CSP does not govern; elsewhere they evaluate over the in-bundle relay. On Firefox a document whose content security policy forbids eval (the extension's own pages, or a site's) is evaluated over the debugger protocol instead, which takes one expression; a page inside the extension that is no declared surface (pages/*) is reached the same way by context:'page' and its moz-extension:// url once a tab shows it. Call extension_dom_snapshot with listTabs:true to enumerate {tabId, url, title}.
156
156
 
157
157
  | input | type | required | default | description |
158
158
  | --- | --- | --- | --- | --- |
@@ -162,7 +162,7 @@ Evaluate an expression in a running extension context. Start the session with al
162
162
  | `url` | string | no | | content/page: pick the tab by url (match pattern, then substring). Preferred over `tab`. |
163
163
  | `tab` | number | no | | Numeric chrome.tabs id, only to disambiguate when several tabs match. |
164
164
  | `browser` | string | no | | Session browser; defaults to this project's live session |
165
- | `timeout` | number | no | | Command timeout in ms (default 5000) |
165
+ | `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. |
166
166
 
167
167
  ## extension_inspect
168
168
 
@@ -232,7 +232,7 @@ Open an extension surface, or replay an event, in a running session. Pass surfac
232
232
  | `tab` | number | no | | With `url`: navigate this chrome.tabs id in place instead of opening a new tab (rides the engine's navigate verb, so the session needs allowControl: true). Without it an existing page is never taken over. |
233
233
  | `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. |
234
234
  | `browser` | string | no | | Session browser; defaults to this project's live session |
235
- | `timeout` | number | no | | Command timeout in ms (default 5000) |
235
+ | `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. |
236
236
 
237
237
  ## extension_preview_web
238
238
 
@@ -319,7 +319,7 @@ Reload a running extension's background context, or a tab. Start the session wit
319
319
  | `context` | "background" \| "content" \| "page" | no | `"background"` | |
320
320
  | `tab` | number | no | | For content/page: a specific tab id |
321
321
  | `browser` | string | no | | Session browser; defaults to this project's live session |
322
- | `timeout` | number | no | | Command timeout in ms (default 5000) |
322
+ | `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. |
323
323
 
324
324
  ## extension_shares
325
325
 
@@ -347,8 +347,8 @@ Run the PRODUCTION build in a browser: build the project, serve it, and launch.
347
347
  | `browser` | "chrome" \| "chromium" \| "edge" \| "brave" \| "opera" \| "vivaldi" \| "yandex" \| "firefox" \| "waterfox" \| "librewolf" \| "zen" \| "floorp" \| "safari" \| "chromium-based" \| "gecko-based" \| "firefox-based" \| "webkit-based" | no | `"chrome"` | |
348
348
  | `build` | boolean | no | `true` | Build before serving. false serves the existing dist/<browser> as-is and fails when there is none. |
349
349
  | `polyfill` | boolean | no | `true` | Apply cross-browser polyfill (build only) |
350
- | `port` | number | no | | Server port (0 for auto-assign) |
351
- | `noBrowser` | boolean | no | `false` | Serve without launching a browser |
350
+ | `port` | number | no | | Passed to the engine as --port (0 for auto-assign). A production start serves nothing over it today; it matters only to a toolchain that reads it. |
351
+ | `noBrowser` | boolean | no | `false` | Build (or, with build:false, check the dist) without launching a browser. A production start serves nothing, so with no browser the engine process ends once the build does; read the result with extension_build rather than a session. |
352
352
  | `outputPath` | string | no | | An existing unpacked extension directory to launch as it is (a manifest.json at its root), for an artifact built by another toolchain or an exact release candidate. Implies build:false; projectPath still names the project the session belongs to. Relative paths resolve against projectPath. |
353
353
  | `profile` | string | no | | Profile path, or "false" to reuse the real user profile. Omit for a throwaway one. |
354
354
  | `startingUrl` | string | no | | URL the browser opens on launch |
@@ -381,7 +381,7 @@ Read or write chrome.storage in a running extension. Every call runs in the exte
381
381
  | `key` | string | no | | Key to get or set |
382
382
  | `value` | any | no | | Value to set (any JSON value); required for action=set |
383
383
  | `browser` | string | no | | Session browser; defaults to this project's live session |
384
- | `timeout` | number | no | | Command timeout in ms (default 5000) |
384
+ | `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. |
385
385
 
386
386
  ## extension_submit
387
387