Extensiondev

io.github.extensiondevPublished by GitHub account extensiondevv10.21.0Updated Nov 5, 2026

Build, run, inspect, and publish browser extensions from any MCP client. 38 tools, 13 browsers.

VerifiedSTDIODesktop onlyBrowser AutomationDeveloper Tools

Overview

AI-generated overview

Local MCP server that lets an assistant scaffold, run, inspect, debug, test and build cross-browser browser extensions on your machine.

What you can do
  • Scaffold projects from a template catalog, plan new surfaces, and search Extension.js docs
  • Run dev sessions with hot reload, launch production builds, and stop sessions
  • Inspect live extensions: DOM snapshots, screenshots, logs, loaded extension list, deep debugger inspection
  • Act on a running extension: evaluate code, read and write chrome.storage, reload, open surfaces or trigger commands
  • Test with stated expectations and per-check verdicts, validate manifests, verify themes, analyze built output
  • Detect, install and remove browsers the tooling can launch
When to use it
Useful when you are developing a browser extension and want the assistant to run it, see what the live browser shows, and debug from evidence instead of guessing. Also fits validating manifests and producing store-ready builds across Chrome, Firefox, Edge and Safari.
Requirements
Runs locally over stdio via npx from the npm package, so Node.js and network access for the package are needed. A browser supported by the tooling must be installed (detectable with the browsers tool); Safari needs macOS with Xcode. No API keys or environment variables are required for the default local tools.
Before you install
Tools write to disk: scaffolding creates a project and may initialize a git repository, and builds write output folders. Eval and storage tools can run code and change extension data; eval stays off until allowEval is enabled on the dev session. A scaffold sends a telemetry event to PostHog unless disabled by environment variable. The optional platform lane, off by default, can share, publish and submit to stores and needs a login.

Installation

In SourceWeft

  1. Open Extensiondev in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

@extension.dev/mcp [Version] [Downloads] [Discord]

Give your AI agent hands for browser extension development. 38 MCP tools that scaffold, run, inspect, debug, test, and build cross-browser extensions on your machine, plus a platform lane (private alpha) to share and publish them.

[Logo]
bash
claude mcp add extension-dev npx @extension.dev/mcp

Works with Claude Code, Claude Desktop, Cursor, and any MCP client.

extension.dev · Docs · Templates · Discord

Why an MCP server for extensions

Extensions fail silently: content scripts that never inject, panels that never open, permissions that return undefined with no error. These tools give the agent eyes on the live browser, so it debugs from evidence instead of guessing.

  • Scaffold from the 50+ templates behind templates.extension.dev, or add a popup, sidebar, or content script to an existing project
  • Run the dev server with HMR in Chrome, Firefox, Edge and every browser below, plus Safari on macOS (no HMR yet)
  • See the live DOM, logs from every extension context, chrome.storage, and the loaded-extension list
  • Act: evaluate code in any context, trigger the action button and commands, reload the extension
  • Test: state expectations about the running extension and get one verdict each
  • Ship: validate the manifest cross-browser and build for production. On the platform lane: share a preview link, promote a build, and submit to the stores

Built on Extension.js, the open source framework extension.dev sponsors. Every engine command runs the project's own node_modules/.bin/extension when the project has one, else npx extension@<pin> at the version this server pins (EXTENSION_MCP_CLI_VERSION changes the pin). To run a fix that has not shipped yet, set EXTENSION_MCP_ENGINE_DIR to a compiled Extension.js checkout root (the folder holding programs/extension/bin/extension.cjs) or to a built extension package folder (holding bin/extension.cjs): every spawn then runs node <that bin>, the project's engine and the pin are bypassed, extension_doctor's project-engine check names the path with its version, sha and branch, and a path with no bin refuses every spawn instead of falling back. EXTENSION_MCP_ENGINE_BIN names the exact bin file instead.

Watch it work

[Asked to run the extension, the agent starts the dev session, Chrome opens with it loaded, and the agent reports the session, from a real Claude Code session]

Browsers

extension_dev opens the extension in the browser you name.

[Chrome][Chromium][Edge][Brave][Opera][Firefox][Safari]
Google ChromeChromiumMicrosoft EdgeBraveOperaMozilla FirefoxApple Safari

The Chromium family and Firefox get HMR, control, eval, inspect and assert (Firefox over its debugger protocol and the agent bridge, no CDP). Safari gets dev and build on macOS, no HMR and no inspect; the full list of what works there is under Safari. Plus Vivaldi, Yandex, Waterfox, Zen and Floorp, and any Chromium or Gecko binary by path.

Clients

[Claude Code][Claude Desktop][Cursor][VS Code][Codex]
Claude CodeClaude DesktopCursorVS CodeCodex

Setup

Claude Code

bash
claude mcp add extension-dev -- npx @extension.dev/mcp --features=local,platform

Or install it as a plugin, the MCP server plus the /extension, /extension-add, /extension-debug, and /extension-publish commands in one step:

/plugin marketplace add extensiondev/mcp/plugin install extension-mcp@extensiondev-mcp

Cursor

[Install MCP Server]

Or paste the .mcp.json block below into .cursor/mcp.json.

VS Code

bash
code --add-mcp '{"name":"extension-dev","command":"npx","args":["@extension.dev/mcp","--features=local,platform"]}'

Or paste it into .vscode/mcp.json under servers, with "type": "stdio" on the entry.

Codex

bash
codex mcp add extension-dev -- npx @extension.dev/mcp --features=local,platform

Or write it into ~/.codex/config.toml as a [mcp_servers.extension-dev] table with the same command and args.

Other clients (Claude Desktop and .mcp.json)

.mcp.json:

json
{  "mcpServers": {    "extension-dev": {      "command": "npx",      "args": [        "@extension.dev/mcp",        "--features=local,platform"      ]    }  }}

Flags

  • By default the server exposes the 25 of its 38 tools that work on this machine (the 13 platform tools are off). --features=local,platform adds the platform group. Env: EXTENSION_DEV_FEATURES.
  • --no-ship refuses every call that puts something in front of other people (publish, promote, a real submit, a shared preview, a revoke). Env: EXTENSION_DEV_NO_SHIP=1.
  • --project <workspace>/<project> pins the server to one project. Env: EXTENSION_DEV_PROJECT.
  • When a platform act answers approval-required on a desktop (not headless, not CI, and on Linux with a display), the server opens the approval page once in the default browser. --no-ship or EXTENSION_DEV_NO_AUTO_OPEN=1 turns that off.

A refused call answers E_TOOL_DISABLED with the flag to change. Human approval for store submissions and stable promotions, the MCP annotations every tool carries, and the <untrusted-data-ID> fence around page-written text are described under Server flags.

Telemetry

extension_create sends one draft_seeded event to PostHog at us.i.posthog.com after a successful scaffold (template slug, source and commit, a random per-process session id, never a path or a name), and the platform tools send a per-install id header with their calls. EXTENSION_DEV_NO_TELEMETRY=1 or DO_NOT_TRACK=1 stops both. The full payload is listed under Telemetry.

Pair with the skill

This server gives agents hands; @extension.dev/skill gives them judgment: the cross-browser rules, silent-failure gotchas, debugging playbooks, and store checklist, in the open Agent Skills format. The package also ships Claude Code rules and the four slash commands under claude/.

bash
npm i -D @extension.dev/skillmkdir -p .claude/skills && cp -R node_modules/@extension.dev/skill/skills/extension-dev .claude/skills/

Tools

On by default, the 25 that work on this machine:

TierToolDescription
buildextension_createScaffold from a template
buildextension_templatesBrowse 50+ templates (list) and read one's source (source)
buildextension_docs_searchSearch the Extension.js and extension.dev docs by keyword
buildextension_add_featurePlan an options page, popup, side panel, content script, devtools panel or new tab page for an existing project
buildextension_buildBuild for production
runextension_devDev server with HMR
runextension_startBuild + launch the production build (build: false launches the existing dist; outputPath launches any prebuilt unpacked directory)
runextension_tryRun a published extension.dev build in a fresh local browser, use it once with a screenshot, and say what it can reach; action: "close" removes it
runextension_waitPoll the dev-server ready contract
runextension_stopStop a dev/start/preview session (server + browser)
seeextension_manifest_validateCross-browser manifest validation
seeextension_analyzeStatic analysis of the built extension on disk
seeextension_inspectDeep live inspection of a running extension (closed shadow roots, probes)
seeextension_dom_snapshotShallow DOM snapshot of a chosen tab or extension surface over the agent bridge
seeextension_screenshotScreenshot of an open extension surface or page, saved as a .png over the session's debug port
seeextension_list_extensionsList loaded extensions (Chromium and Firefox)
seeextension_logsStream logs from every context
seeextension_doctorDiagnose the dev session leg by leg (ready contract, ports, token, executor, browser)
seeextension_theme_verifyVerify a Chrome theme manifest against the colors Chrome actually paints
testextension_assertState expectations about a running extension and get one verdict each: pass, fail, or inconclusive
actextension_evalEvaluate in a context (needs allowEval: true on extension_dev)
actextension_storageRead/write chrome.storage
actextension_reloadReload extension or tab
actextension_openOpen a surface (popup, options, sidebar, devtools panel, override pages) / trigger action, command
browsersextension_browsersDetect, list, install, and uninstall browsers

On with --features=local,platform, the 12 that reach the extension.dev platform (private alpha):

TierToolDescription
platformextension_authDevice login at extension.dev for one project or a list of them, plus login status and logout
platformextension_workspace_createCreate an extension.dev workspace, headless, via device approval; the approver becomes its owner
platformextension_project_createCreate the extension.dev project for a built extension, or several under one approval, headless, via device approval
platformextension_preview_webRender a build in the web emulator, and share it as a link
platformextension_sharesList every link you have shared, share a platform build as a link, and revoke one permanently
platformextension_publishMint a shareable link for a build extension.dev already holds (nothing is uploaded)
platformextension_release_promoteRelease a build to a channel, headless
platformextension_submitSubmit for store review: Chrome, Firefox, Edge and Safari, through extension.dev
platformextension_submit_checkRead a store submission's readiness and status, rehearse it, and ask for its approval, under a read-only hint
platformextension_release_statusRead release channels, release history, recent builds, and store configuration, submission and review state
platformextension_approvalsRead one approval, or revoke a pending or approved and unused one so it never runs
platformextension_buildsRead the platform's builds (recent builds, one build's artifacts and integrity, its CI logs), save a build's package to disk verified against its integrity report, start a rebuild, change build settings as a plain call under the owner's token, and add a release channel
platformextension_workspaceRead a workspace with any of its project logins: plan and limits, projects and last builds, usage, and a project's settings

A dev session carries the control channel that extension_storage, extension_reload, extension_open and extension_dom_snapshot ride: it is local, same machine, same user, and on unless extension_dev is called with allowControl: false. extension_eval is the one gate that stays off until allowEval: true is passed on extension_dev (it implies control). A session does not change its gates on a second call: call extension_dev again with what you need plus replace: true, which stops the first session.

Asserting instead of guessing

Every other tool hands back a reading. extension_assert states the expectation and returns the verdict.

[Asked whether the extension works, the agent runs it, states expectations and reads one verdict each, from a real Claude Code session]

jsonc
{  "projectPath": "/path/to/extension",  "expect": [    { "assert": "background-worker-booted" },    { "assert": "surface-rendered", "surface": "popup", "selector": "[data-testid=root]" },    { "assert": "storage-key-present", "key": "settings", "area": "local" },    { "assert": "console-errors-empty", "context": ["background", "popup"] },    { "assert": "content-script-injected", "url": "https://shop.example/cart" },    { "assert": "no-outside-requests", "allow": ["api.shop.example"] }  ]}

Each check comes back pass, fail or inconclusive, and the run passes only when every check passed. inconclusive means this platform cannot cover the question today, and the check carries settledBy naming the evidence that would answer it: a content script passes only on a line it wrote itself, "no console errors" over a session that never built is inconclusive, and a read the session refuses (chrome.storage on a session started with allowControl: false) is inconclusive rather than a failure.

Safari

A Safari dev session runs on the same bridge as every other engine: on Extension.js 4.1.21 or newer, extension_dev with browser: "safari" (macOS with Xcode) builds the app, opens it, reloads it on every save and streams its logs. Safari's MV3 background CSP blocks eval, there is no CDP or RDP path for extension_inspect, and opening a tab needs a safaridriver session; the limits are listed under Safari.

Platform (private alpha)

The thirteen platform tools connect agents to extension.dev. They stay off until the server is started with --features=local,platform, and sharing, publishing, promoting and submitting need a login:

bash
npx @extension.dev/mcp login --project <workspace>/<project>

You approve a code at extension.dev/device; no GitHub token reaches your machine, and the project-scoped token is stored locally, never returned to the agent, and lives at most 7 days. extension_preview_web with share: true uploads the build it just made and returns a link that renders those bytes in the web emulator, with its expiresAt and a revokeUrl. extension_publish returns the shareable URL of a build extension.dev already holds; extension_submit sends a built extension into store review through extension.dev, which holds your store credentials, and defaults to a dry run.

extension_submit_check takes the calls that only read or ask under readOnlyHint: true, so a client's permission layer can tell them from a store act: preflight, status, the default dry run, and every approval request, the first call with no approvalId that executes nothing and only asks a workspace owner to approve the exact act on extension.dev (a submit with dryRun: false, publish, cancel, rollout, release, a sync-listing carrying a value the platform derives, and a configure-store to a submission mode that sends the next upload to a review that publishes it). It never sends a write or an approvalId to the platform. extension_submit takes the call that spends the approval, a plain sync-listing or configure-store, which writes at once, and every other store act, so it carries the destructive hint; it still accepts the read calls too. If you accept the approval page as the only gate for those acts as well, allow both tools by name, in Claude Code's .claude/settings.json:

json
{ "permissions": { "allow": ["mcp__extension-dev__extension_submit_check", "mcp__extension-dev__extension_submit"] } }
[Chrome Web Store][Firefox Add-ons][Edge Add-ons][App Store]
Chrome Web StoreFirefox Add-onsEdge Add-onsApp Store

The details, the approval flow and the batch login for several projects are under Share a build in progress, Publish is not submit and Login.

Community

  • Join the extension.dev Discord for help and feedback
  • Browse production-ready templates at templates.extension.dev
  • Follow the platform's public packages on GitHub
  • Report Extension.js framework issues on GitHub

License

Apache-2.0 (c) 2026 Cezar Augusto and the extension.dev collaborators. See LICENSE.

Source: README.md at commit 7843b2e

Tools

25

extension_create

Create an extension

Create a browser extension project from a template in the extension.dev catalog; call extension_templates first to see what is available. The scaffolder may initialize a git repository in the new project (with a first commit), and it also writes store metadata and a .gitignore of its own; the result's defaultsApplied block reads those decisions back. The result's `scripts` lists every package.json script that runs the engine, with the browser it targets and the folder it writes: the scaffolder passes no --browser to `dev`, `start` and `build`, so `npm run build` writes dist/chromium while `build:chrome` writes dist/chrome; read the folder from that list instead of assuming one. A scaffold that answers `created` is verified (its manifest was found and read): it needs no build to prove it, so do not run `npm run build` to check it; the next step is extension_dev with the answered projectPath. Not for a project that exists: extension_dev runs it, extension_project_create puts it on extension.dev. After a successful scaffold this tool sends one telemetry event, draft_seeded (template slug, source and commit, a random install id, never a path or a name), to PostHog; the Telemetry section of this package's readme names the two environment variables that turn it off.

ParametersinstalltemplateparentDirprojectNamerequired

extension_templates

List the templates

Browse the extension.dev template catalog. Pass action:'list' (the default) to search and filter it and get metadata per template. Pass action:'source' with a `slug` to read one template's files, for learning a pattern before building something similar. Read `framework` as the UI framework only, never the language: TypeScript and JavaScript templates live under slugs ('typescript', 'content-typescript'), shadcn is a React variant ('sidebar-shadcn'), and provider AIs carry the 'ai' tag ('ai-chatgpt', 'ai-claude'). Reach those through query, tags or slug.

Parametersslugtagsfilesqueryactionsurfacefeaturedframework

extension_build

Build the extension locally

Build a browser extension for production. This tool always passes --browser (chrome unless you set it), so the output lands in dist/<browser>/ (dist/chrome by default) and the answer's outputPath always names the folder that was written (the engine's reported path, else dist/<browser> under the package root, the same folder this tool checked for the manifest), with zipPath beside it when a zip was asked for: read those paths instead of assuming one. To know what is in the build (sizes, entry points, the checks a store reviewer runs) call extension_analyze on the same projectPath and browser instead of listing or reading the output folder by hand; the answer's hint says so. A scaffolded project's own `npm run build` runs `extension build` with no --browser, which the engine defaults to chromium, so that script writes dist/chromium/ instead. Pass zip:true to also package a .zip for store submission. With browser:'safari' the build converts the extension into a macOS app through Xcode, and bundleId sets the identifier it ships under. The build refuses a manifest with build-blocking errors unless you pass skipValidation:true, because such a manifest yields a broken bundle the bundler itself never flags.

ParameterszipmodesilentappNamebrowserbundleIdpolyfillmacOsOnlyzipSourceprojectPathrequiredzipFilenameskipValidation+2 more

extension_dev

Run the dev session

Run the extension while you edit it: dev build, hot module replacement, and a browser with the extension loaded. Reach for this first when the ask is "run my extension": by default it waits for the session to be ready and answers with the readiness and the first log lines, so one call covers the ask; pass wait:false to return as soon as the server is spawned. A dev session carries the control channel that extension_storage, extension_reload, extension_open and extension_dom_snapshot need (local, same machine, same user) unless you pass allowControl:false; the eval channel that extension_eval needs is the one gate that stays off until you pass allowEval:true (which implies control, so you never need to pass both). Use extension_start instead to run the production build in a browser. When the answer's ready.status is "ready" the session is up and nothing else needs calling before extension_logs, extension_inspect or the control verbs; extension_wait is only for wait:false, an answer whose ready.status was not ready, or a build-only session.

ParametershostportwaitappNamebrowserprofilereplacebundleIdheadlesspolyfillallowEvalmacOsOnly+11 more

extension_start

Start a browser

Run the PRODUCTION build in a browser: build, serve and launch. No hot module replacement, so edits are not picked up; use extension_dev while writing code, and this to check what ships. By default there is no control channel, so extension_eval, extension_storage, extension_reload, extension_open and extension_dom_snapshot cannot attach; pass allowControl:true (or allowEval:true, which implies it) to drive the run with them. Both flags need Extension.js 4.1.34 or later; an older engine is refused as engine-unsupported. build:false launches an existing dist/<browser>; outputPath launches any prebuilt unpacked extension directory. By default it waits for the build and the browser like extension_dev (up to 45 s) and answers build-ready with the session, the extension id and cdpPort, so no extension_wait is needed before extension_open or extension_assert; wait:false answers once the engine process is alive 5 s after spawn, and a wait that runs out answers started naming the extension_wait call. It says what a production session cannot do (no hot reload, no console stream for extension_logs, and the bridge verbs need allowControl); whether the browser loaded the extension is read over its debug port on Extension.js 4.1.34 or later, and only extension_dev proves it on an older engine.

ParametershostportwaitbuildbrowserprofilereplaceheadlesspolyfillallowEvalnoBrowserextensions+7 more

extension_try

Try a published extension

Run a published extension.dev build for the person in a fresh browser on this machine, so they see it work without downloading a package, turning on developer mode or running an installer. It downloads the build's package (newest by default), checks it against the platform's integrity record when there is one, unpacks it into a temporary folder and launches it with a new profile; on Extension.js 4.1.34 or later it then opens the popup or replays the toolbar action and saves a screenshot, and on an older engine it only launches and says the extension was not used. The answer names the version, the package size, what was confirmed and what was not, the screenshot, and what the extension can reach in plain words: warn the person about that. Nothing stays installed: call it again with action:'close' when done. For a project on disk use extension_dev or extension_start.

Parametersurlactionbrowserprojectrequiredversionheadless

extension_stop

Stop the session

Stop a session that extension_dev or extension_start is running: terminate the server and the browser it launched, and remove the live-preview carrier if extension_dev placed one. The answer names the server pid and the browser pid the launcher recorded, each with whether it is gone (serverGone, browserGone), so a "close its browser" ask is settled by this answer with no process check by hand. This covers extension_start build:false too, which the registry records as a preview session. Call it when you are done verifying, so sessions do not accumulate.

ParametersallbrowserconfirmprojectPathincludeOtherServers

extension_manifest_validate

Validate the manifest

Validate a manifest.json across browsers. This reports missing fields, invalid permissions, dangling file references, and cross-browser compatibility issues. Read buildBlocking for the errors that make extension_build refuse.

ParametersbrowserbrowsersprojectPathmanifestPath

extension_theme_verify

Verify a theme

Verify a Chrome theme manifest before it ships. This settles the four-leg WYSIWYG contract (app-shows == manifest-says == chrome-paints, plus chrome-accepts) as far as is possible headless: it derives every color current Chrome would paint from the manifest through the transcribed Chromium resolver, and classifies each problem as D1 fabrication, D3 parity gap, or D4 acceptance gap (keys Chrome silently discards: dead legacy, incognito, unknown, out-of-range). It verifies only, and never authors or mutates a theme. The app-rendered and real-pixel legs need a browser, so they come back as needsAttended with the step that settles each one (the theme editor at themes.extension.dev, and a dev session in Chrome), never as passed.

ParametersmanifestmanifestPath

extension_analyze

Analyze the extension

Analyze a BUILT extension on disk: sizes, entry points, permissions, bundle composition, store-readiness checks, and manifestByBrowser, the emitted manifest per built browser with the resolved keys (background, action, sidebar, permissions, host_permissions, chrome_url_overrides, browser_specific_settings) that differ; other dist folders are named, not read as browsers. Static: it reads dist/<browser> only. A dist extension_dev rewrote is a development build: buildType says so, store checks are skipped, extension_build makes the build to analyze. extension_inspect reads a running extension.

ParametersformatbrowserprojectPathrequired

extension_assert

Assert on a page

Run a test stage on an extension_dev or extension_start session: one verdict per expectation (see expect): pass, fail, not ready (a precondition; see settledBy) or inconclusive (a platform limit). page-world-clean, no-outside-requests and background-worker-booted read the debug port: meant for the production build (extension_start, allowControl:true). storage-key-present needs the control channel; content-script-injected and console-errors-empty read the dev log stream: extension_dev only.

ParametersexpectrequiredbrowsertimeoutprojectPathrequired

extension_inspect

Inspect a live page

Inspect a running extension deeply over the browser's debugger protocol: full HTML (open shadow roots of the extension-root hosts inlined; other shadow roots are not crossed by html, dom_snapshot or probe), DOM structure, content-script injection, console messages, and CSS selector queries through `probe`. This is the ONLY tool that pierces closed shadow roots (deepDom), runs selector probes, and navigates a tab to `url` before reading it. It reads a web or override page: the first inspectable target, the first whose url contains `url`, or the exact page `targetId` names (the target.targetId extension_open answers, or one from extension_dom_snapshot listTargets) without navigating. Not for an extension surface by name (popup, options, sidebar, devtools) or a chrome.tabs id, and not for enumerating what is open: that is extension_dom_snapshot. Not for a built extension's files on disk: that is extension_analyze. Chromium rides the Chrome DevTools Protocol and needs the session's debug port, not allowControl; on Firefox the reads ride the agent bridge and need allowEval:true (console rides the RDP watcher replay on engine 4.0.15 and later). This requires an active dev or start session.

ParametersurlprobebrowserdeepDomincludemaxBytestargetIdprojectPathrequired

extension_list_extensions

List the loaded extensions

List the extensions in the running dev browser: id, name, version, and, on Chromium, live contexts. This session's own extension carries ownExtension:true, with name and version from the ready contract even when the browser exposes no identity. On Chromium, entries come from the live CDP targets and from the session profile's installed set, so an extension whose MV3 service worker is dormant is still listed, with running:false and no contexts. Firefox rides the RDP root actor (listAddons, engine 4.0.15 and later), so entries are installed add-ons regardless of contexts, are marked temporarilyInstalled where relevant, and carry no contexts. Other extensions' contexts are never attached to or evaluated in. This requires an active dev or start session.

ParametersbrowserprojectPathrequired

extension_logs

Read the console

Read or stream logs from every context of a running dev session (service worker, content scripts, popup, options, sidebar, devtools, pages) in one ordered timeline. This reads the same agent-bridge plane as the `extension logs` CLI: a one-shot returns the most recent matching lines from logs.ndjson, and follow:true connects to the live control channel, receives the broker's replay of its recent ring (up to 5,000 events, counted in value.replayed) and then the frames that arrive during followMs (value.live). This requires an active extension_dev session.

ParameterstaburllevellimitsincefollowbrowsercontextfollowMsprojectPathrequiredsignalsOnly

extension_eval

Evaluate code in a context

Evaluate an expression in a running extension context: the background, an extension surface (popup, options, sidebar, devtools, newtab, history, bookmarks), a content script or a page, picked by context, url, tab or targetId. 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. A returned promise is awaited; a value that cannot be cloned (a DOM node, a function) comes back as its string form. To wait for a condition that is still settling (a model loading, an element appearing), pass until: {} (or {timeoutMs, intervalMs}) and the eval repeats until its value is truthy, answering that value, or the last one on timeout. 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. Naming a tab the browser refuses to script (page-not-scriptable, extension-page-unreachable) needs Extension.js 4.1.34 or later; on an older engine such a refusal still answers as a missing target. On Safari this tool reaches only page contexts, through the automation window's WebDriver session: the background and the extension surfaces are out of reach (extension_logs reads the background). Not for reading a page's structure: that is extension_dom_snapshot, which also lists tabs and targets. Pass `targetId` (the target.targetId extension_open answers, or one from extension_dom_snapshot listTargets:true) to evaluate in that exact page over the debug port; context, url and tab are then ignored.

ParameterstaburluntilbrowsercontexttimeouttargetIdexpressionrequiredprojectPathrequired

extension_storage

Read extension storage

Read or write chrome.storage in a running extension. Every call runs in the extension's background (the engine honors no context), so it proves nothing about what a content script or page can read. A set is read back and the answer says whether the stored value and its type match. Rides the dev session's control channel, on unless extension_dev was called with allowControl:false. One key per call.

ParameterskeyareavalueactionrequiredbrowsertimeoutvalueJsonprojectPathrequired

extension_reload

Reload the extension

Reload a running extension's background context, or a tab. Rides the dev session's control channel, on unless extension_dev was called with allowControl:false. A background reload answers once the engine's ready.json shows the new background attached to the dev server again (value.reattached, value.reattachedMs), so the next read or assertion meets the new generation and not the gap between them; if it has not come back within the budget (timeout, at most 5 seconds) the answer is status reloading with the contract's own stamps.

ParameterstabbrowsercontexttimeoutprojectPathrequired

extension_open

Open a surface

Open an extension surface (popup, options, sidebar, the newtab, history or bookmarks override page, or the extension's DevTools panel), navigate a tab to a url, or replay an event (the toolbar action, a chrome.commands shortcut) in a running session, over the dev session's control channel (on unless extension_dev was called with allowControl:false). Opening a url on Chromium answers target.targetId, the CDP target id of the tab it opened: pass it as `targetId` to extension_screenshot, extension_dom_snapshot, extension_inspect or extension_eval to address that exact tab (extension_dom_snapshot listTargets: true lists every targetId, on Firefox too). A url answer also carries tab {active, visibilityState}, viewport {width, height} and headless: an element below the viewport is not observed until it is scrolled into view. A url opens in a background tab unless foreground: true. Not for evaluating in the page once it is open: that is extension_eval. An action or command replay invokes your listener without a user gesture, so the gesture-derived activeTab grant does not apply.

ParameterstaburlnameasTabpanelreloadwaitMsbrowsersurfacetimeoutforegroundprojectPathrequired

extension_dom_snapshot

Snapshot the page

Take a shallow structured DOM snapshot of one chosen surface: element counts, extension roots, open shadow roots, optional byte-capped HTML, and optional recent console lines. This is the SURFACE PICKER: the only tool that reads an open extension surface by name (`context`: popup, options, sidebar, devtools) or an override page, the only one that takes a numeric chrome.tabs id, and the only one that enumerates what is open (listTargets for targetIds, listTabs for numeric tab ids). Pass `targetId` (the target.targetId extension_open answers, or one from listTargets) to read that exact page over the debug port. Not for closed shadow roots, selector probes, navigation or a deep read of an open web page: that is extension_inspect. Not for the pixels: that is extension_screenshot. The snapshot rides the agent bridge (localhost only, on unless extension_dev was called with allowControl:false) and needs no CDP; listTargets and `tabUrl` resolution ask the browser directly and need the session's debug port.

ParameterstaburltabUrlbrowsercontextincludetimeoutlistTabsmaxBytestargetIdlistTargetsprojectPathrequired+1 more

extension_screenshot

Take a screenshot

Take a screenshot of one open extension surface (popup, options, sidebar, newtab, history, bookmarks) or web page in a live extension_dev or extension_start session as a .png file. It asks the browser for the page's own pixels over the debug port (CDP on Chromium, the screenshot actor on Firefox, WebDriver on Safari, web pages only); it never captures the screen and never brings a window forward: on Chromium a page behind other windows or in a hidden tab is shown briefly for the capture (value.behindWindow, value.hiddenTab). Open the surface with extension_open first. `targetId` captures that exact page; a url matching several tabs of one page captures the most recently active one and warns. width and height set the Chromium viewport, resize the Safari window and crop from the top left on Firefox; deviceScaleFactor sets the pixel ratio. `store` captures a store listing screenshot at that store's size into store/screenshots/<store>/, where extension_submit sync-listing picks it up; `browserCapture` files a capture of the extension running in this browser under captures/<browser>/, where extension_publish sync-captures picks it up; one call per view. The file goes under dist/extension-js/<browser>/screenshots unless `path` names one; the answer gives path and pixel size.

ParametersurlpathstorewidthheightbrowsercontexttimeouttargetIdprojectPathrequiredbrowserCapturedeviceScaleFactor

extension_wait

Wait for the session

Wait for a running dev or start session to be ready, or for a rebuild after a source edit (for: "rebuild"). Call it for a session started with wait:false, after an extension_dev answer whose ready.status was not "ready", and for a build-only (noBrowser) session, which answers as soon as the compile lands; an extension_dev answer with ready.status "ready" already carries this result, so there is nothing left to wait for. It polls the ready.json contract and reports compiled, browserAttached and guestLoaded (the browser's own target list shows your extension, the trustworthy load signal; null when it could not be checked), every answer carries budgetMs and elapsedMs, and on status 'timeout' call again to keep waiting on the same contract. Every ready answer carries the ports the session bound: port (the dev server), controlPort (the control channel) and cdpPort (Chromium) or rdpPort (Gecko), or debugPortNote when the session opened no debug port, so a question about ports is answered here without a shell. The reload stamp a rebuild wait reads (reloadedAt) needs Extension.js 4.1.34 or later; a project on an older engine gets a brief watch for the background to reconnect instead, answering reattached, still-detached or not-stamped. Not for a condition in the page (a model loading, an element appearing): that is extension_eval with until. Never sleep or tail the session log in a shell to wait. A browser that is running while the extension's background went idle answers status "background-asleep" with how to wake it, not "browser-gone"; a Safari WebDriver session that Safari ended answers "webdriver-session-ended" with the restart that opens a new one.

ParametersforsincebrowsertimeouttimeoutMsprojectPathrequired

extension_add_feature

Plan a feature

Plan the surface before adding an options page, a popup, a side panel, a content script, a devtools panel, a new tab page or a background script to an existing extension. It answers with the manifest additions, the files to create and the catalog template to copy from, and modifies nothing: write what the plan says, then validate the manifest and run extension_dev.

ParametersfeaturerequiredframeworkprojectPathrequired

extension_browsers

List the browsers

Find, install and remove the browsers Extension.js tooling can launch. Pass action:'detect' (the default) to scan both system-installed and managed browsers, and report each one's binary path, version, engine and debugger support. Pass action:'list' for the managed cache this tool downloads into, with each binary's version and size on disk. Both report the version the binary itself carries (its bundle metadata, else --version), prerelease suffix included (159.0a1), never the cache folder's name. Pass action:'install' to download a managed binary: several hundred MB in one blocking call, so allow a generous client timeout. Pass action:'uninstall' to remove managed binaries; it never touches a system install.

Parametersallactionbrowserbrowsers

extension_doctor

Diagnose the session

Diagnose a dev session end to end: ready contract, dev-server process, control-port agreement, control channel, eval token, executor, browser liveness. This returns one {check, status, detail, remediation?} per leg, in dependency order. Read a 'skip' as blocked, not as a pass: it names the check that blocked it. A session started with allowControl: false comes back ok:true with status 'read-only', not as an error. On Chromium, value.capabilities reads each extension context's WebGPU adapter, crossOriginIsolated and headless. Run this first when any act tool errors unexpectedly. Call it with no projectPath for a pre-flight environment check (node, the Extension.js CLI, the template cache).

ParametersbrowserprojectPath

Version history

22
  1. v10.21.0LatestNov 5, 2026
  2. v10.20.0Nov 5, 2026
  3. v10.15.1Oct 29, 2026
  4. v10.14.1Oct 18, 2026
  5. v10.14.0Oct 18, 2026
  6. v10.13.0Oct 17, 2026
  7. v10.12.0Oct 15, 2026
  8. v10.11.6Oct 10, 2026
  9. v10.11.5Oct 10, 2026
  10. v10.11.4Oct 9, 2026
  11. v10.11.1Oct 9, 2026
  12. v10.11.0Oct 8, 2026
  13. v10.10.13Oct 7, 2026
  14. v10.10.12Oct 6, 2026
  15. v10.10.11Oct 6, 2026
  16. v10.10.9Oct 5, 2026
  17. v10.10.8Oct 5, 2026
  18. v10.10.4Oct 4, 2026
  19. v10.10.2Oct 3, 2026
  20. v10.10.1Oct 1, 2026
  21. v10.10.0Sep 26, 2026
  22. v10.9.0Sep 16, 2026

Score

90% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts
  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts