@extension.dev/mcp
Summary: @extension.dev/mcp gives AI agents 35 MCP tools to scaffold, run, inspect, debug, test, and ship cross-browser extensions locally, plus a private-alpha platform lane for sharing and publishing.
Scaffold & learn —
extension_createbuilds a project from a template;extension_templatesbrowses 50+ templates and reads their source;extension_docs_searchsearches Extension.js/extension.dev docs;extension_add_featureplans a popup, sidebar, options, content script, devtools panel, newtab, or background surface.Run —
extension_devstarts a dev server with HMR in Chrome, Chromium, Edge, Brave, Opera, Firefox, and more (Safari on macOS without HMR);extension_startruns the production build;extension_wait,extension_stopmanage sessions.See & debug —
extension_manifest_validate(cross-browser manifest checks),extension_analyze(static analysis of built extension),extension_inspect(deep live DOM, closed shadow roots, probes),extension_dom_snapshot,extension_screenshot,extension_list_extensions,extension_logs(all contexts),extension_doctor(session diagnosis),extension_theme_verify(Chrome theme colors).Test —
extension_assertstates expectations about a running extension and returns pass/fail/inconclusive verdicts per check.Act —
extension_eval(must enableallowEval),extension_storage(read/write chrome.storage),extension_reload,extension_open(open surfaces, trigger action/commands).Browsers —
extension_browsersdetects, lists, installs, and uninstalls browser binaries.Platform (private alpha, off by default) —
extension_auth,extension_workspace_create,extension_project_create,extension_preview_web(share a build as a link),extension_shares(list/revoke links),extension_publish,extension_release_promote,extension_submit(store review for Chrome, Firefox, Edge, Safari),extension_release_status,extension_builds,extension_workspace.Flags/guardrails —
--features=local,platform,--no-ship(blocks publish/promote/submit/share/revoke),--projectpinning, telemetry opt-out viaEXTENSION_DEV_NO_TELEMETRYorDO_NOT_TRACK, plus human approval for store submissions and stable promotions.
Allows running and debugging extensions in the Brave browser during development.
Enables submitting extension builds to the Chrome Web Store for publication and release management.
Allows running and debugging extensions in Firefox during development.
Provides authentication via GitHub device-code flow for accessing platform tools such as publishing and promoting builds.
Allows running and debugging extensions in LibreWolf during development.
Allows running and debugging extensions in Opera during development.
Allows running and debugging extensions in Safari on macOS during development.
Allows running and debugging extensions in Vivaldi during development.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@extension.dev/mcpscaffold a new popup extension using React"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@extension.dev/mcp

Give your AI agent hands for browser extension development. 35 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.
claude mcp add extension-dev npx @extension.dev/mcpWorks 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 listAct: 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.
Related MCP server: @nimbus21.ai/chrome-devtools-mcp
Watch it work

Browsers
extension_dev opens the extension in the browser you name.
Google Chrome | Chromium | Microsoft Edge | Brave | Opera | Mozilla Firefox | Apple 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 |
Setup
Claude Code
claude mcp add extension-dev -- npx @extension.dev/mcp --features=local,platformOr 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-mcpCursor
Or paste the .mcp.json block below into .cursor/mcp.json.
VS Code
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
codex mcp add extension-dev -- npx @extension.dev/mcp --features=local,platformOr 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:
{
"mcpServers": {
"extension-dev": {
"command": "npx",
"args": [
"@extension.dev/mcp",
"--features=local,platform"
]
}
}
}Flags
By default the server exposes the 24 of its 35 tools that work on this machine (the 11 platform tools are off).
--features=local,platformadds the platform group. Env:EXTENSION_DEV_FEATURES.--no-shiprefuses 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.
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/.
npm i -D @extension.dev/skill
mkdir -p .claude/skills && cp -R node_modules/@extension.dev/skill/skills/extension-dev .claude/skills/Tools
On by default, the 24 that work on this machine:
Tier | Tool | Description |
build |
| Scaffold from a template |
build |
| Browse 50+ templates ( |
build |
| Search the Extension.js and extension.dev docs by keyword |
build |
| Plan an options page, popup, side panel, content script, devtools panel or new tab page for an existing project |
build |
| Build for production |
run |
| Dev server with HMR |
run |
| Build + launch the production build ( |
run |
| Poll the dev-server ready contract |
run |
| Stop a dev/start/preview session (server + browser) |
see |
| Cross-browser manifest validation |
see |
| Static analysis of the built extension on disk |
see |
| Deep live inspection of a running extension (closed shadow roots, probes) |
see |
| Shallow DOM snapshot of a chosen tab or extension surface over the agent bridge |
see |
| Screenshot of an open extension surface or page, saved as a .png over the session's debug port |
see |
| List loaded extensions (Chromium and Firefox) |
see |
| Stream logs from every context |
see |
| Diagnose the dev session leg by leg (ready contract, ports, token, executor, browser) |
see |
| Verify a Chrome theme manifest against the colors Chrome actually paints |
test |
| State expectations about a running extension and get one verdict each: pass, fail, or inconclusive |
act |
| Evaluate in a context (needs |
act |
| Read/write |
act |
| Reload extension or tab |
act |
| Open a surface (popup, options, sidebar, devtools panel, override pages) / trigger |
browsers |
| Detect, list, install, and uninstall browsers |
On with --features=local,platform, the 11 that reach the extension.dev platform (private alpha):
Tier | Tool | Description |
platform |
| Device login at extension.dev for one project or a list of them, plus login status and logout |
platform |
| Create an extension.dev workspace, headless, via device approval; the approver becomes its owner |
platform |
| Create the extension.dev project for a built extension, or several under one approval, headless, via device approval |
platform |
| Render a build in the web emulator, and share it as a link |
platform |
| List every link you have shared, share a platform build as a link, and revoke one permanently |
platform |
| Mint a shareable link for a build extension.dev already holds (nothing is uploaded) |
platform |
| Promote a build to a release channel, headless |
platform |
| Submit for store review: Chrome, Firefox, Edge and Safari, through extension.dev |
platform |
| Read release channels, release history, recent builds, and store configuration, submission and review state |
platform |
| Read the platform's builds (recent builds, one build's artifacts and integrity, its CI logs), start a rebuild, change build settings with an owner's approval, and add a release channel |
platform |
| Read 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.

{
"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" }
]
}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 eleven 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:
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.
Chrome Web Store | Firefox Add-ons | Edge Add-ons | App 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.
Available Tools
32 toolsextension_add_featureARead-onlyIdempotent
Plan a new feature surface for an existing extension. This returns step-by-step instructions, the manifest additions to make, and reference templates from the extension.dev catalog. It modifies no files: apply the returned plan yourself.
| Name | Required | Description | Default |
|---|---|---|---|
| feature | Yes | Feature surface to add | |
| framework | No | react | |
| projectPath | Yes | Extension project root |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description reinforces and clarifies the annotations: 'It modifies no files: apply the returned plan yourself' explains why readOnlyHint/destructiveHint=false hold for a tool whose name contains 'add'. It also enumerates what gets returned (instructions, manifest additions, templates), which goes beyond the annotation set.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with purpose and followed by return contents and the no-write constraint. No filler or restatement of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing return values, and it does so (step-by-step instructions, manifest additions, reference templates). Safety is covered by annotations and the explicit no-write statement. Only per-parameter clarifications are missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67% and the description adds no parameter-level detail. The 'feature surface' wording loosely echoes the feature enum but supplies no extra meaning for projectPath or framework beyond what the schema already encodes.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Plan a new feature surface for an existing extension.' That is clearly distinct from extension_build/extension_create in intent, though it never names a sibling explicitly. An agent can tell what the tool produces (a plan, not a build).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'for an existing extension' implies usage scope versus creation tools, and 'apply the returned plan yourself' tells the agent what to do next. However, there is no explicit when-not or named alternative (e.g., extension_templates, extension_build) to route between.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_analyzeARead-onlyIdempotent
Analyze a BUILT extension on disk: file sizes, declared entry points, permissions, bundle composition, and store-readiness checks. This is static only: it reads dist/ from the filesystem and never touches a browser, so build first with extension_build. Use extension_inspect for a running extension's live DOM and console.
| Name | Required | Description | Default |
|---|---|---|---|
| format | No | summary | |
| browser | No | Browser build to analyze | chrome |
| projectPath | Yes | Extension project root |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/closed-world, but the description adds genuinely new behavioral context: it is static only, reads dist/<browser> from the filesystem, never touches a browser, and therefore must be preceded by a build. That workflow prerequisite and scope boundary go well beyond the structured annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with what is analyzed and what it outputs, then the static-only constraint, then the sibling alternative. No filler and each sentence carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by listing the concrete outputs (sizes, entry points, permissions, bundle composition, store-readiness checks). Combined with the readOnly annotations and the build-first prerequisite, an agent has everything needed to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67% and the description adds little: it references 'dist/<browser>' which loosely maps to the browser parameter, but the format enum values (summary/tree/json) carry no description in either schema or prose. With the schema doing most of the work and coverage above the midpoint, a baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (analyze) against a precise resource (a BUILT extension on disk) and enumerates exactly what is reported: file sizes, entry points, permissions, bundle composition, and store-readiness. It also explicitly differentiates from the sibling extension_inspect, so an agent can pick between them without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit prerequisite ('build first with extension_build') and an explicit alternative plus its selection condition ('Use extension_inspect for a running extension's live DOM and console'). Both the when-to-use and the when-not-to-use path are spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_assertAIdempotent
Run a test stage against a live dev session: state expectations and read one verdict for each, instead of reading a blob and hand-rolling the judgement. Every expectation comes back pass, fail or inconclusive, where inconclusive means this platform cannot cover the question today and the verdict says what would settle it. An inconclusive check is never a pass. Start the session with extension_dev; use extension_inspect or extension_logs when you want the raw reading instead of a verdict.
| Name | Required | Description | Default |
|---|---|---|---|
| expect | 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). | |
| browser | No | Session browser; defaults to this project's live session | |
| timeout | 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. | |
| projectPath | Yes | Extension project root (needs a live dev session) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare the safety profile (non-readonly, idempotent, non-destructive), so the bar is lower, and the description adds genuinely new behavioral context: every check returns pass/fail/inconclusive, and inconclusive is never a pass. It does not disclose failure or timeout behavior of the overall run, which keeps it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each doing work: what it does, what the verdicts mean, and how to start/sidestep. The purpose is front-loaded and there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return semantics and does so adequately by defining the three verdict states and the inconclusive caveat. Prerequisite session state is also covered, so an agent can call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema itself enumerates the check ids, their args, browser defaults, and the route-dependent timeout values. The prose adds no parameter meaning beyond the schema, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Run a test stage against a live dev session') and clarifies the output shape ('one verdict for each' expectation). It explicitly separates itself from extension_inspect and extension_logs, which return raw readings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit prerequisites ('Start the session with extension_dev') and names the alternatives to use when a raw reading is wanted rather than a verdict. It also frames the when-to-use case: assertions instead of hand-rolling judgement over a blob.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_authADestructive
Sign this machine in to extension.dev, report that login, or clear it. Pass action:'status' (the default) to name the workspace and project the stored token is scoped to and when it expires, never the token itself; that identity comes from the stored token alone, and does not change with the current working directory or whichever project folder you are in. Status also asks the platform's whoami endpoint whether that credential actually resolves there: the answer rides value.server.verdict as confirmed, refused or unavailable (when the server could not be reached), with status logged-in for the first and last and refused-by-server for the second, so a local file claiming a login the server refused is never reported as logged in. Pass action:'login' for a two-phase flow: call with project to get a code plus a URL the user authorizes at extension.dev/device, then call again with the returned deviceCode. GitHub federation happens server-side, so no GitHub token lands on this machine. Minted tokens live at most 7 days, server-enforced, so CI must re-mint before expiry on the console's project settings, Access tokens page. Pass action:'logout' to delete the local credentials only (with project, just that project's login); the token stays valid server-side until it is revoked at the URL the response returns. Several logins live side by side on one machine, one per workspace/project, and status lists them all under logins. To sign in to several existing projects of one workspace at once, pass projects instead of project: one approval, one stored token per project.
| Name | Required | Description | Default |
|---|---|---|---|
| api | No | Platform base URL (default EXTENSION_DEV_API_URL, else https://www.extension.dev) | |
| action | No | status | |
| project | No | login: target project as '<workspace>/<project>'; the token is scoped to it. The slug pair is the console address bar: an existing project's page is console.extension.dev/<workspace>/<project>. Create one at extension.dev/new if none exists yet. Logins to several projects are all kept, the latest is the default; token-scoped tools take `project` to pick another. logout: remove only this project's login (omitted, every stored login goes). | |
| projects | No | login: sign in to several existing projects of one workspace with one approval, instead of one approval each. 1 to 20 names as '<workspace>/<project>', all in the same workspace, each by its exact slug (lowercase letters and digits joined by single dashes, at most 48 characters), none twice. Pass it instead of `project`, never beside it. The approval page lists every name; one missing project refuses the whole list and mints nothing. Resume with the returned `deviceCode` and the same list. Every token is stored as that project's own login and all expire within 7 days, so the same call renews them together. | |
| deviceCode | No | login: resume token from the prior call's `deviceCode`; omit on the first call. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only give a coarse destructiveHint=true/openWorldHint=true; the description supplies the real behavioral detail: status never returns the token, logout deletes credentials locally while the server token stays valid until revoked, tokens are capped at 7 days server-side, GitHub federation happens server-side so no GitHub token lands locally, and server verdict can downgrade a local login to refused-by-server.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose and organized in action order (status, login, logout, multi-login, projects), and nearly every clause carries load-bearing detail. It is, however, a single dense ~350-word paragraph with some redundant restatement, which costs it the top mark.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates fully by naming returned fields and their semantics (value.server.verdict with confirmed/refused/unavailable, status logged-in/refused-by-server, `logins`). Everything an agent needs to call and interpret this tool is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 80% and its per-parameter descriptions are detailed, so this is largely the baseline-3 territory; the description nonetheless adds genuine semantics the schema lacks, notably the two-phase login/deviceCode resume flow and the `projects`-instead-of-`project` exclusivity rule.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Starts with a specific verb+resource ('Sign this machine in to extension.dev, report that login, or clear it') and then enumerates the three action modes with distinct behaviors. An agent can distinguish it from every sibling (auth vs build/preview/publish) without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use each action (status as default read, login two-phase with project/deviceCode, logout local-only) and names alternatives: `projects` versus `project` with the constraint 'Pass it instead of `project`, never beside it.' It also routes to the console URL for re-minting CI tokens.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_browsersADestructive
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 sizes on disk. 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.
| Name | Required | Description | Default |
|---|---|---|---|
| all | No | uninstall: remove every managed binary. | |
| action | No | detect | |
| browser | No | install/uninstall: which managed binary. Required for install. | |
| browsers | No | detect: limit the scan to these. Omit to check all. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (destructive/openWorld/idempotent=false), the description disambiguates which action is destructive and its blast radius ('uninstall... never touches a system install'), and warns that install is a several-hundred-MB blocking call requiring a generous client timeout. That is exactly the operational context the structured hints cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four dense sentences, front-loaded with the overall purpose and default action, then one sentence per action. No filler; the timeout warning and uninstall-safety note are placed where they are actionable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description still tells the agent what detect and list return (binary path, version, engine, debugger support; cache sizes) and what install/uninstall do to disk. Combined with the annotations and a four-parameter schema, nothing essential for a correct call is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema documents 75% of parameters, but the 'action' enum itself carries no per-value description in the schema, so the description's explanation of each action and the stated default meaningfully extends it. It also confirms browser is required for install and that browsers limits the detect scan (omit to check all), though it says nothing about the 'all' uninstall flag beyond what schema already covers.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb set and resource ('Find, install and remove the browsers Extension.js tooling can launch') and then breaks the tool into four named actions, so the agent knows exactly what it operates on. It never references a sibling, though, so mapping this against launch-oriented siblings like extension_start is left to inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Each enum value is paired with the condition that selects it and its return shape: detect (default) scans system + managed and reports path/version/engine/debugger support; list shows cached downloads with sizes; install fetches a managed binary; uninstall removes managed binaries. Requirements (browser is required for install) and exclusions ('never touches a system install') are both stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_buildAIdempotent
Build a browser extension for production. The output lands in dist//. 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.
| Name | Required | Description | Default |
|---|---|---|---|
| zip | No | Create a .zip file for store distribution | |
| mode | No | Bundler mode override (also sets NODE_ENV) | production |
| silent | No | Suppress build output | |
| appName | No | Safari targets only: name of the generated macOS app, which also names the Xcode scheme and the .app on disk. Defaults to the manifest name. | |
| browser | No | chrome | |
| bundleId | No | Safari targets only: a reverse-DNS bundle identifier you own, such as com.acme.readinglist. Without one the app is packaged under a generated dev.extensionjs.* identifier derived from the app name, which two projects with the same name share, and the first team to register it takes it. | |
| polyfill | No | Apply cross-browser polyfill | |
| macOsOnly | No | Safari targets only: generate a macOS-only Xcode project. Pass false for a universal project that also targets iOS and iPadOS, which is what you want if the extension ships on iPhone or iPad. | |
| zipSource | No | Include source code zip (required by some stores) | |
| projectPath | Yes | Extension project root | |
| zipFilename | No | Custom .zip file name (defaults to name and version) | |
| skipValidation | No | Build even when extension_manifest_validate reports build-blocking errors. The build normally refuses: the engine itself stops only on missing scripts, icons, DNR rule files, default_locale and manifest_version, and ships a bundle over the rest. | |
| forceRegenerate | No | Safari targets only: regenerate the Xcode project even when the engine considers it up to date. Use it when an earlier packaging run left the project broken. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as a non-readonly but non-destructive, idempotent, closed-world operation; the description adds real behavioral context beyond that: where output lands, that validation failures block the build and why, that skipValidation can yield a broken bundle, and that Safari builds convert to a macOS app.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, front-loaded with the core action and output location, and each sentence carries distinct information rather than padding. The bundleId sentence is dense but earns its length given the collision warning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 13-param, no-output-schema tool, the description covers the highest-stakes behaviors (validation gating, Safari/Xcode path, store packaging) and leaves the low-stakes flags to the thorough schema. Adequate, though a note on return values or build-output differences would round it out.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 92%, so the baseline is 3, but the prose adds meaning beyond the schema: it explains the collision risk of omitting bundleId (shared generated dev.extensionjs.* identifier) and the exact consequence of skipValidation. It does not cover the remaining params (mode, silent, polyfill, forceRegenerate) in prose, so it isn't a full 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource+"for production" scope, immediately distinguishing it from sibling build-adjacent tools like extension_dev. An agent knows this produces a production bundle rather than running a dev server.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear conditional guidance for the flags that matter (zip:true for store packaging, skipValidation:true to bypass the validation refusal, browser:'safari' for Xcode conversion). It does not explicitly name a sibling alternative or state when NOT to build, so it stops short of the 5 bar.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_createA
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. Read the result's defaultsApplied block for the decisions this tool can read back: parent directory, template, package manager, target browser and whether a git repository was initialized by this call.
| Name | Required | Description | Default |
|---|---|---|---|
| install | No | Install dependencies after creation | |
| template | No | Template slug from the extension.dev catalog (e.g. 'react', 'ai-claude', 'content-vue'). extension_templates discovers them. | typescript |
| parentDir | No | Directory to create the project inside. Defaults to the MCP server process cwd, NOT the caller's cwd, so pass it whenever you care where the project lands. Aliases: parent, into. | |
| projectName | Yes | Name of the extension project (used as directory name). Alias: name. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare non-read-only, non-idempotent, open-world and non-destructive behavior, yet the description adds real side-effect detail beyond them: git repository initialization with a first commit, store metadata and a self-authored .gitignore. This is exactly the kind of disclosure that annotations cannot convey. It still omits failure/overwrite behavior, so not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then ordered instructions, then behavioral caveats, in four dense but non-redundant sentences. The final sentence is long but carries the readback contract, so every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a scaffolding mutation with no output schema, the description covers prerequisite, side effects, and how to read back applied defaults. It is largely complete; the notable gap is behavior on an existing target directory or failure, which the non-idempotent annotation hints at but the description never explains.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3; the schema already documents each parameter including parentDir's cwd caveat and aliases. The description's defaultsApplied note concerns output readback rather than parameter meaning, so it does not add much beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Create a browser extension project from a template in the extension.dev catalog.' An agent immediately knows this scaffolds a project. However, the description never distinguishes itself from the sibling extension_project_create, which is an apparent overlap it should address.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly gives a prerequisite and ordering: 'Call extension_templates first to see what is available.' That routes the agent correctly before invoking. It stops short of stating when-not to use it (e.g. versus extension_project_create) or what happens if the target directory already exists.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_devA
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". ONLY this tool unlocks the control channel that extension_storage, extension_reload, extension_open and extension_dom_snapshot need (allowControl:true) and the eval channel that extension_eval needs (allowEval:true, which implies allowControl, so you never need to pass both). Use extension_start instead to run the production build in a browser. The result carries the process info that extension_wait and extension_inspect need.
| Name | Required | Description | Default |
|---|---|---|---|
| host | No | Bind host, default 127.0.0.1. Use 0.0.0.0 in Docker or devcontainers. | |
| port | No | Dev server port (0 for auto-assign) | |
| browser | No | chrome | |
| carrier | No | Load the bundled Live Preview carrier beside your extension (Chromium only) so allowlisted pages (preview.extension.dev, localhost) can pair with the session and stream its real-lane chrome.* trace. Written into the auto-loaded ./extensions folder, gitignored, and removed on extension_stop or extension_build: never part of a release. | |
| profile | No | Profile path, or "false" to reuse the real user profile. Omit for a throwaway one. | |
| replace | No | Stop the live session for this projectPath first, reported as replacedSession. Without it a second call is refused rather than forking: two sessions fight over one profile and the newer browser dies on the lock. | |
| polyfill | No | Apply cross-browser polyfill | |
| allowEval | No | Enable extension_eval (runs code in a context; writes a 0600 session token). Implies allowControl, so you never need to pass both. | |
| noBrowser | No | Start the dev server without launching a browser | |
| extensions | No | Extra extension paths or store URLs to load alongside the project | |
| publicHost | No | Host the browser dials for HMR and reload when it differs from the bind host | |
| geckoBinary | No | Custom Gecko/Firefox binary to launch; `browser` still names the target family the engine builds for (gecko-based when none is given). | |
| projectPath | Yes | Extension project root | |
| startingUrl | No | URL the browser opens on launch | |
| allowControl | No | Enable the agent-bridge control channel that extension_storage/reload/open/dom_snapshot need | |
| chromiumBinary | No | Custom Chromium-based binary to launch; `browser` still names the target family the engine builds for (chromium-based when none is given). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint=false, destructiveHint=false, idempotentHint=false), so the description's value is the extra behavioral context it adds: the exclusive unlock of the allowControl/allowEval channels, the implication chain (allowEval implies allowControl), the 0600 session token, and the fact that the result carries process info needed by extension_wait/extension_inspect. It does not restate annotation claims, and it adds real coupling semantics that structured fields do not convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the primary purpose, then the disambiguating alternative, then the dependency semantics. Each sentence carries distinct information with no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 16-parameter, non-idempotent start tool with no output schema, the description supplies the missing pieces: when to use vs alternatives, what channels it uniquely enables, and what the result feeds into. Enough for correct invocation without further documentation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 94%, so the schema does the heavy lifting and baseline would be 3. The description adds value by explaining the allowControl/allowEval relationship in terms of which sibling tools consume each flag, clarifying why an agent would set them rather than just what they do.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('run the extension while you edit it') and enumerates the core capabilities: dev build, HMR, browser with extension loaded. It explicitly distinguishes itself from the sibling extension_start (production build), so an agent can pick between the two without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger ('Reach for this first when the ask is "run my extension"'), names the disambiguating alternative (extension_start for production), and states the downstream conditions this tool satisfies (it is the only tool that unlocks the control and eval channels required by extension_storage, extension_reload, extension_open, extension_dom_snapshot, and extension_eval). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_docs_searchARead-onlyIdempotent
Find pages in the Extension.js and extension.dev docs by keyword, each with a short excerpt. Use it before answering from memory on anything version-specific: a CLI flag, a manifest field across browsers, a store submission rule. Free and needs no login.
| Name | Required | Description | Default |
|---|---|---|---|
| api | No | Platform base URL (default EXTENSION_DEV_API_URL, else https://www.extension.dev) | |
| limit | No | How many pages to return, 1 to 8. | |
| query | Yes | What to look up, in a few words. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, openWorld, non-destructive), so the bar is low, and the description still adds two useful facts beyond them: the tool is free and requires no login. It also discloses the response shape (pages plus excerpts), though no pagination behavior is mentioned.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with zero filler; the purpose leads and the usage guidance follows. Every clause is load-bearing.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description signals the return format (pages with excerpts), and for a free read-only search it covers cost, auth, and when to call. Nothing needed to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all three parameters including defaults, bounds, and the platform-override URL. The description only restates the keyword-based lookup, adding no syntax or format detail beyond the schema. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Find) and resource (pages in the Extension.js and extension.dev docs), plus the return shape ('each with a short excerpt'). It is the only documentation-search tool among siblings, so no disambiguation ambiguity remains.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger: 'Use it before answering from memory on anything version-specific,' with three concrete examples (CLI flag, cross-browser manifest field, store submission rule). No alternative tool is named, but none exists for this capability, so the guidance is effectively complete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_doctorARead-onlyIdempotent
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 without allowControl comes back ok:true with status 'read-only', not as an error: its control channel is off by choice. Run this first when any act tool (storage, reload, eval, open) errors unexpectedly. Call it with no projectPath for a pre-flight environment check (node, the Extension.js CLI, the template cache) before any project exists.
| Name | Required | Description | Default |
|---|---|---|---|
| browser | No | Browser session to diagnose. Defaults to the active dev session's browser for this project. | |
| projectPath | No | Path to the extension project root. Omit for a pre-flight environment check with no project. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), yet the description adds real behavioral context: the per-leg {check, status, detail, remediation?} return shape, dependency ordering, that 'skip' means blocked rather than pass, and that a no-allowControl session returns ok:true with status 'read-only' instead of erroring. This is substantive disclosure beyond structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the scope, then the return shape, then the two key behavioral caveats, then the usage triggers. Dense but every clause earns its place; only slight length pressure keeps it from a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, but the description specifies the return shape (one {check, status, detail, remediation?} per leg) and the non-error read-only outcome, so an agent knows both what it will get and how to interpret it. Complete for a zero-required-param diagnostic tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description's param-relevant statements (browser defaults to the active session, omit projectPath for pre-flight) largely restate what the schema already documents, adding little syntax or format detail beyond it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (diagnose) and resource (dev session) and enumerates the exact legs checked (ready contract, dev-server process, control-port agreement, control channel, eval token, executor, browser liveness). This clearly separates it from the sibling act tools like extension_eval, extension_reload, and extension_storage.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use: 'Run this first when any act tool (storage, reload, eval, open) errors unexpectedly.' Also gives a distinct invocation mode: 'Call it with no projectPath for a pre-flight environment check.' Both the trigger and the alternative usage path are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_dom_snapshotARead-onlyIdempotent
Take a shallow structured DOM snapshot of one chosen surface through the agent bridge (localhost only; the snapshot itself needs no CDP, but listTargets and tabUrl resolution ask the browser directly and need the session's debug port: CDP page targets on Chromium, RDP tab descriptors on Firefox): 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 CDP targetIds and RDP tab actors, listTabs for numeric tab ids). An ambiguous tabUrl returns the candidates instead of guessing. It does not pierce closed shadow roots, run selector probes, or navigate: use extension_inspect for those, and for a deep read of an already-open web page. Start the session with allowControl:true (extension_dev).
| Name | Required | Description | Default |
|---|---|---|---|
| tab | No | Numeric chrome.tabs id, only to disambiguate when several tabs match. With neither `tab` nor `url`, content/page target the active tab. | |
| url | No | content/page: pick the tab by url (match pattern, then substring). Preferred over `tab`. | |
| tabUrl | No | Target the tab whose URL contains this substring (case-insensitive; titles checked only when no url matches). Resolved against the live browser first: exactly one match proceeds, zero or several return the candidates instead of a guess. Alternative to `url`. | |
| browser | No | Session browser; defaults to this project's live session | |
| context | No | content/page targets `url`, else the active tab; the rest must already be OPEN | content |
| include | No | What to include; html is byte-capped | |
| timeout | 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. | |
| listTabs | No | Enumerate open tabs as {tabId,url,title} and return, ignoring the other args. Use when you need a numeric tab id. | |
| maxBytes | No | ||
| listTargets | No | Enumerate live page targets and return, ignoring the other args. The discovery path for `tabUrl`. Chromium: {targetId,url,title,type}. Firefox: RDP tab descriptors {actor,url,title,type}. Neither id is a numeric chrome.tabs id; for those use listTabs. | |
| projectPath | Yes | Extension project root (needs a live dev session) | |
| withConsole | No | Also include recent console lines. A number is how many; true means 50. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), so the bar is lower. The description adds genuinely useful behavior: localhost-only, the snapshot needs no CDP but listTargets and tabUrl resolution do need the debug port, and the ambiguity policy (candidates returned instead of guessing). It does not describe pagination or output shape, but adds substantial context beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose is front-loaded, but the description is a dense run-on with nested parentheticals and backtick-heavy clause chains that slow comprehension. Every sentence carries information, yet the structure is not cleanly parsable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 12-parameter read tool with no output schema, the description sketches the return payload (element counts, extension roots, open shadow roots, optional byte-capped HTML, console lines) and covers the discovery paths, prerequisites, and exclusions. Only minor gaps remain, such as return shape details for the enumeration modes.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 92%, so the schema does most of the work and baseline is 3. The description nevertheless adds meaning beyond the schema: html is byte-capped, listTabs/listTargets ignore the other args and return a specific shape, tabUrl resolution order (live browser, substring, titles fallback). That is more than restating field definitions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Take a shallow structured DOM snapshot of one chosen surface') and immediately positions itself as the unique 'SURFACE PICKER' that reads open extension surfaces by name and is the only tool taking a numeric chrome.tabs id. It also names what it is unlike (extension_inspect), so an agent can differentiate it from all 30 siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use it (reading an open surface by context name, enumerating what is open via listTargets/listTabs) and when not to (it does not pierce closed shadow roots, run selector probes, or navigate — use extension_inspect for those). It also gives a prerequisite: start the session with allowControl:true.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_evalADestructive
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}.
| Name | Required | Description | Default |
|---|---|---|---|
| tab | No | Numeric chrome.tabs id, only to disambiguate when several tabs match. | |
| url | No | content/page: pick the tab by url (match pattern, then substring). Preferred over `tab`. | |
| browser | No | Session browser; defaults to this project's live session | |
| context | No | Where to evaluate. Default background, except Chromium MV3 sessions default to page (the active tab). | |
| timeout | 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. | |
| expression | Yes | JavaScript expression to evaluate in the target context | |
| projectPath | Yes | Extension project root (needs a live dev session) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite annotations already declaring destructive/openWorld/non-idempotent, the description adds substantial context beyond them: the 0600 session-token gate, that debug-port evaluates run with a user gesture so gesture-gated APIs behave differently, the CDP vs in-bundle relay routing, and the Firefox debugger-protocol fallback for eval-forbidding CSPs. That is exactly the behavioral detail an agent needs before calling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and the eval-disabled gate are strongly front-loaded, and most clauses carry genuine routing information. It does run long and dense, bundling many edge cases into a single block, so it is efficient but not maximally tight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter, multi-route tool with no output schema, it covers prerequisites, context resolution, timeouts, and surface/tab addressing thoroughly. It stops short of describing the returned result shape or error formats, but the operational guidance needed to invoke it correctly is nearly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so each parameter is already documented, including the context default, timeout defaults, and url-vs-tab precedence. The description largely restates those defaults rather than adding syntax or format meaning beyond the schema, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence gives a precise verb+resource: 'Evaluate an expression in a running extension context.' It immediately names the prerequisite tool (extension_dev with allowEval:true) and cooperates with extension_open and extension_dom_snapshot, leaving no ambiguity about what this tool does versus its siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states explicit when/when-not conditions: start the session with allowEval:true, otherwise every route answers eval-disabled; use extension_open before targeting a surface; pass url or tab to disambiguate content/page; context:'page' for the active tab. Alternatives and prerequisites are spelled out rather than inferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_inspectAIdempotent
Inspect a running extension deeply over the browser's debugger protocol: full HTML (open shadow roots of #extension-root and [data-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 and picks the first inspectable target, or the first whose url contains url; it cannot address an extension surface by name and takes no chrome.tabs id. Use extension_dom_snapshot to choose which tab or which open surface (popup, options, sidebar, devtools) to read, or to enumerate what is open. Use extension_analyze for a built extension's files and sizes on disk. Chromium rides the Chrome DevTools Protocol and needs the session's debug port, not allowControl. Firefox is fully paired: summary, meta, html, dom_snapshot, extension_roots and probes ride the agent bridge and need allowEval:true, console rides the RDP watcher replay on engine 4.0.15 and later, and deepDom needs an MV2 session with host permissions for the target url, because the Firefox MV3 background CSP blocks bridge evals. This requires an active dev or start session.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | URL to inspect; the tab is navigated there first | |
| probe | No | CSS selectors to query; returns counts and samples for each | |
| browser | No | Session browser; defaults to this project's live session | |
| deepDom | No | Pierce CLOSED shadow roots (open roots of the extension-root hosts are already inlined in html; other open roots are not read). Chromium: CDP DOM pierce. Firefox: a content-script walk via tabs.executeScript (MV2 only, needs host permissions for the target url); the answer says whether that context could see closed roots at all. | |
| include | No | What to include | |
| maxBytes | No | Truncate HTML output at this byte count (0 = unlimited) | |
| projectPath | Yes | Extension project root (needs a live dev session) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations covering the safety profile, the description still adds substantial behavioral context: it navigates the tab to `url` before reading, it cannot address an extension surface by name or accept a chrome.tabs id, and it lays out engine-specific requirements (bridge evals blocked by Firefox MV3 CSP, console replay needing engine 4.0.15+). This is exactly the auth/permission and side-effect disclosure the annotations don't carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose, exclusivity, and sibling routing are front-loaded in the first three sentences, and nearly every clause carries actionable information. It is dense and one unbroken paragraph, though, which makes the browser-matrix tail harder to parse than it needs to be.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter tool with no output schema and complex cross-browser execution paths, the description supplies the missing context an agent needs: session prerequisites, what each browser can and cannot do, which shadow roots the default reads cross, and how probe output is shaped. Nothing essential to invoking it correctly is omitted.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The prose largely restates what the schema already documents for `url`, `probe`, `deepDom`, and `include` (its deepDom browser notes closely mirror the schema text), adding little semantic detail beyond the structured fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Inspect a running extension deeply over the browser's debugger protocol') and enumerates exactly what is read: full HTML, DOM structure, content-script injection, console messages, and CSS selector probes. It explicitly differentiates from siblings ('This is the ONLY tool that pierces closed shadow roots...') and names extension_dom_snapshot and extension_analyze as the alternatives for adjacent jobs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states when to use each alternative ('Use extension_dom_snapshot to choose which tab... Use extension_analyze for a built extension's files on disk') and the gating precondition ('requires an active dev or start session'). It further gives per-browser conditions (Chromium needs the session's debug port, not allowControl; Firefox needs allowEval:true; deepDom needs an MV2 session with host permissions).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_list_extensionsARead-onlyIdempotent
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. Chromium rides the Chrome DevTools Protocol, so an entry needs at least one live context, and a dormant MV3 service worker may be absent until it wakes. 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.
| Name | Required | Description | Default |
|---|---|---|---|
| browser | No | Session browser; defaults to this project's live session | |
| projectPath | Yes | Extension project root (needs a live dev session) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly/idempotent/non-destructive), yet the description adds substantial behavior: Chromium's requirement of at least one live context, dormant MV3 service workers being absent until woken, the Firefox RDP listAddons mechanism and engine-version floor, and the temporaryInstallation marker. It also assures the agent that other extensions' contexts are never attached to or evaluated in, which is real scope disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and returned fields are front-loaded, and the browser-specific caveats follow in logical order with no filler sentences. It is dense and slightly run-on in places, but every sentence carries information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing results and does so: returned fields, the ownExtension flag, the temporarilyInstalled marker, and per-browser context presence. The session prerequisite and cross-browser divergence are both covered, leaving no gap an agent needs before calling it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters (browser, projectPath) are already documented in structured form. The description reinforces the session requirement but adds no new syntax, format, or defaulting detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the extensions in the running dev browser') and enumerates the returned fields (id, name, version, live contexts), which clearly separates it from siblings like extension_browsers or extension_inspect. The per-browser framing further pins down exactly what gets listed.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear precondition ('This requires an active dev or start session') and explains when entries appear differently on Chromium vs Firefox. It stops short of naming sibling alternatives or stating when not to use this tool, so it is strong context without explicit routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_logsARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| tab | No | Only events from this tab id. | |
| url | No | Only events whose url/hostname matches (glob or substring), e.g. https://shop.example/*. | |
| level | No | Minimum severity; a level includes everything more severe. | all |
| limit | No | How many of the most recent events to return. | |
| since | No | Only events with seq greater than this; the cursor for polling forward. | |
| follow | No | Collect from the live control channel for a bounded window instead of reading the file. | |
| browser | No | Which dist/extension-js/<browser>/ to read. Defaults to this project's live session, else chrome. | |
| context | No | Restrict to these contexts. Omit for all. | |
| followMs | No | How long to collect live frames when follow=true (clamped 500–15000ms). | |
| projectPath | Yes | Extension project root (needs a live dev session) | |
| signalsOnly | No | Only structured dx.signal diagnostics (code/status/remediation), no plain console lines. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing that this reads the agent-bridge plane used by the `extension logs` CLI, that one-shot reads logs.ndjson, that follow replays a broker ring of up to 5,000 events (counted in value.replayed) then live frames during followMs (value.live), and that an active dev session is required. This is rich operational context an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense but front-loaded sentences; the core purpose leads and mode specifics follow. Every sentence carries information, though the middle sentence is heavy with detail.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 11-parameter tool with no output schema, the description covers the prerequisite session, both operational modes, and the shape of returned counts (replayed/live). It misses only explicit return-format details for one-shot reads, which is minor given the strong annotation coverage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds meaning beyond the schema by explaining follow's replay/live split, the value.replayed and value.live outputs, and the followMs collection window. This enriches the follow and followMs parameters beyond their schema entries.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Read or stream logs') and resource ('logs from every context of a running dev session'), and enumerates the contexts explicitly. An agent can distinguish this from sibling tools like extension_inspect or extension_dev without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly explains the two modes (one-shot file read vs follow:true live channel) and states the prerequisite of an active extension_dev session. It lacks explicit when-not-to-use guidance or direct comparison to sibling tools, but the mode selection context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_manifest_validateARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| browser | No | Single browser to validate against; alias for browsers:[browser] to match the other tools. | |
| browsers | No | Browsers to validate against | |
| projectPath | No | Path to the extension project root; manifest.json is resolved from it (root or src/). Accepted in place of manifestPath. | |
| manifestPath | No | Path to manifest.json. Or pass projectPath and the manifest is located for you. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, closed-world, so the safety profile is covered. The description adds real behavioral substance beyond that: the four categories of findings it produces and the existence of a buildBlocking field that determines whether a build is refused. It does not mention severity levels, whether validation is fast/offline, or how findings are ordered, which keeps it out of 5 territory.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core action and scope, followed by the finding categories and then the downstream consequence. Nothing is redundant and the most decision-relevant clause ('across browsers') appears first.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by naming buildBlocking and the categories of findings an agent should expect. That is enough to call it correctly, but it does not sketch the overall result shape (e.g. per-browser grouping or pass/fail summary), leaving a small gap for a tool with an entirely undocumented return value.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and all four parameters (browser, browsers, projectPath, manifestPath) carry their own descriptions, including the aliasing relationship between browser and browsers and the projectPath/manifestPath substitution. The description text adds nothing about parameters, so the baseline of 3 is correct.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ('Validate a manifest.json') and immediately scopes it ('across browsers'), then enumerates the exact defect classes it surfaces (missing fields, invalid permissions, dangling file references, cross-browser issues). This is distinguishable from siblings like extension_build, extension_doctor, and extension_analyze without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear operative context by tying itself to extension_build ('the errors that make extension_build refuse') and pointing at the buildBlocking field, which tells an agent this is the pre-build gate. It stops short of explicit when-not guidance, e.g. why to choose this over extension_doctor or extension_analyze, so it falls one step short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_openA
Open an extension surface, or replay an event, in a running session. 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. Start the session with allowControl:true (extension_dev).
| Name | Required | Description | Default |
|---|---|---|---|
| tab | 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. | |
| url | 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. | |
| name | No | For surface 'command': the chrome.commands name to trigger. | |
| asTab | No | 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. | |
| panel | 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. | |
| reload | No | 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. | |
| waitMs | 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`. | |
| browser | No | Session browser; defaults to this project's live session | |
| surface | No | Which surface to open or event to replay. | |
| timeout | 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. | |
| projectPath | Yes | Extension project root (needs a live dev session) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it discloses Chromium-only sidebar fallback via synthetic click and tab rendering, the warnings channel, CDP Target.openDevTools usage, that action/command replay runs without a user gesture so activeTab does not apply, and that reload discards page state. This is exactly the extra side-effect and caveat context annotations do not carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded and each sentence conveys substantive behavioral detail rather than filler, but it is a single dense run-on block with heavy parenthetical asides that would read better as a per-surface breakdown. Appropriately sized for nine surfaces, slightly overpacked in structure.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 11-parameter tool with no output schema it covers the main intents, prerequisites, and fallback behaviors well, and even hints at the return shape for the devtools case. It is largely self-sufficient, though the return framing for the non-devtools surfaces is left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds cross-parameter meaning the schema does not: how `url` interacts with `tab`, that `panel` selects among multiple panels, and that the devtools result url is consumed by extension_eval with context 'page'. That linking value lifts it above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (open/replay) and resource (extension surface or event) and enumerates every surface value with its distinct effect. It also names related siblings (extension_dev for the allowControl session, extension_eval for reading the panel document), so an agent can place it precisely in the toolset.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It tells the agent which surface value to pass for each intent (UI surface vs chrome_url_overrides tab vs DevTools vs action/command replay) and gives a prerequisite (start the session with allowControl:true). It lacks explicit when-not-to-use guidance against alternatives like extension_reload or extension_inspect, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_preview_webA
Preview an in-progress extension in the web emulator, with no real browser. This builds the project (unless build:false) and previews dist/. Pass share:true unless you are working inside the extension.dev monorepo: it uploads the build and returns a link anyone can open, with no install, sign-in or dev server, and it is the only lane that works from an npm install of this server. Sharing also serves the build as a zip, so it hands over the built code; read the share property before using it. The default lane instead returns a deep link over the dev-only preview://build scheme, which resolves only against a preview.extension.dev dev server on this machine, so it is for people developing extension.dev itself. Call extension_shares to list and revoke every link shared this way, so one never vanishes with this response.
| Name | Required | Description | Default |
|---|---|---|---|
| open | No | Also open the deep link in a running session's browser, in a focus-safe background tab. Needs a live extension_dev/extension_start session. | |
| build | No | Build first. false previews the existing dist/<browser> as-is. | |
| probe | No | Fetch the surface's dev middleware first to confirm the artifact loads on the local host. With share:true it also checks the shared link the way a browser would, following the zip's redirects and asserting the final response allows the preview origin, and reports that as share.browserLoadable. | |
| share | No | Upload the built dist and return a public link (share.previewUrl) that renders those exact bytes for anyone: no install, sign-in or dev server. Uploading is metered against your plan's allowance on extension.dev; left false, the result's share property says what the local deepLink needs, what share:true spends, and the exact call to get a shareable link. It also serves the build as a zip (share.zipUrl), so sharing hands over the code. Needs a token scoped to an extension.dev project (extension_auth or EXTENSION_DEV_TOKEN); without one you get a login hint and the local preview still succeeds. Live until share.expiresAt; DELETE share.revokeUrl to kill it sooner. Revocation is permanent, and re-sharing an unchanged build returns the same link unless it was revoked, so each share is also appended to the project's gitignored .extension.dev/shared-previews.json. | |
| openIn | No | Which session's browser to open it in. Defaults to `browser`. | |
| browser | No | Which dist/<browser> output to preview. The emulator renders it as mocked Chrome either way. | chrome |
| hostUrl | No | Origin of the running preview.extension.dev dev server (default http://localhost:3110). | |
| project | No | Which stored login to use, as '<workspace>/<project>' (or a project slug that matches one login), when extension_auth has signed in to more than one project on this machine. Omitted, the most recent login is used, after EXTENSION_DEV_TOKEN when that is set. Named, it outranks EXTENSION_DEV_TOKEN. extension_auth (action: status) lists the stored logins. | |
| distPath | No | Preview this built directory instead of dist/<browser> under projectPath. Implies build:false. | |
| projectPath | Yes | Extension project root |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare the generic safety profile (writes, open-world, non-idempotent); the description adds substantial behavioral context beyond them: sharing uploads and hands over built code, is metered against a plan allowance, requires a scoped token or yields a login hint, is live until share.expiresAt, revocation is permanent, and each share is logged to a gitignored file. This is well past the bar set by annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and the no-real-browser qualifier are front-loaded, and the sentences are dense with decision-relevant information rather than filler. It is long for a single paragraph, and a couple of clauses (e.g. the gitignore log detail) border on optional, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 10 parameters, no output schema, and an open-world network write, the description does the heavy lifting: it names the returned fields an agent must inspect (share, share.previewUrl, share.zipUrl, share.expiresAt, share.revokeUrl, deepLink) and covers auth and cleanup. A tighter mapping of the default-lane result shape would make it fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the parameter descriptions are themselves extremely detailed, so the schema already carries the parameter burden. The body text adds nuance about the share/build interaction but largely restates what the schema properties say. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (preview an in-progress extension in a web emulator) and immediately scopes it against alternatives: 'with no real browser,' the share lane vs. the local deep-link lane. An agent can distinguish it from extension_dev, extension_start and extension_build without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells the agent when to pass share:true and when not to ('unless you are working inside the extension.dev monorepo'), explains which lane works from an npm install, and names extension_shares as the revocation path. When/when-not/alternative are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_project_createA
Create an extension.dev project for an extension that does not have one yet, without opening the console. Use it right after extension_create and extension_build, once the extension's source is pushed to a GitHub repository, and BEFORE extension_auth: extension_auth can only log in to a project that already exists, and this tool is what brings that project into existence. Ask for nothing but the project slug and the repo; the platform finds the GitHub App installation on the approving account itself, and if there is none it returns a connect link to open. Two-phase, like login: the first call returns a code and a URL where a signed-in member of the workspace approves creating exactly this project; call again with the returned deviceCode to finish. The approval mints a provisioning grant that lives minutes, can only create the one named project, and is never stored on this machine. On success the platform creates the project and its mirror repository, and dispatches the first build when it can: the answer says in firstBuild whether one was dispatched and, when none was, why (no commits, no build workflow, a spent build allowance, a paused dispatch). Then run extension_auth (action: login) against the new project, and extension_publish to share it. To create several projects in one workspace under one approval, pass projects instead of project and repo: the approval page lists every name, each project is created by its own request, and each one's 7-day token is stored as that project's login, so no extension_auth call is needed afterwards. A list takes a few calls to finish: while projects remain the answer is status 'creating' with the same deviceCode to call again, and the grant is held in this server's memory only. One approval creates at most 10 projects, the cap the platform states in its login config, because it creates at most 10 per hour for one approving account; the next 10 can start in a new call once that limit allows. A longer list is refused before any approval is asked for, never split silently, and so is any list on a platform that does not advertise batch onboarding.
| Name | Required | Description | Default |
|---|---|---|---|
| api | No | Platform base URL (default EXTENSION_DEV_API_URL, else https://www.extension.dev) | |
| repo | No | Source GitHub repository as '<owner>/<repo>'. The extension's code must be pushed there, and the owner must be the same GitHub account that approves the device code. | |
| project | No | Target project as '<workspace>/<project>'. The workspace is the GitHub login of the approving user for personal workspaces; the project slug is the new project's name and must not exist yet. | |
| browsers | No | Browsers the platform builds, each enabled with the same install and build command and its own output directory. Pass every browser the extension targets, for example ["chrome", "edge", "firefox"], so the project needs no console visit to go cross-browser. | |
| projects | No | Create several projects in one workspace under one approval, instead of `project` and `repo`. 1 to 10 entries (the platform's cap per approval; never more than 20), each { project: '<workspace>/<project>', repo: '<owner>/<repo>' }, all in the same workspace, each project named by its exact slug (lowercase letters and digits joined by single dashes, at most 48 characters), none twice and none existing yet. An entry may also carry displayName, description, installCommand, buildCommand, outputDirectory, browsers and outputDirectories for that project alone; the same inputs at the top level are the shared default for every entry that leaves them out. The answer carries one row per project: created and logged in, created with no token (run a batch extension_auth login), refused with the platform's code, or not attempted. A refusal on one project never hides the others. | |
| deviceCode | No | Resume token from the prior call's `deviceCode`; omit on the first call. A batch returns the same deviceCode until every listed project has an answer. | |
| description | No | Short project description. Defaults to a generic sentence naming the repo. | |
| displayName | No | Human name for the project. Defaults to the project slug. | |
| buildCommand | No | Build command producing the extension bundle. | npm run build |
| installCommand | No | Dependency install command the build runs first. | npm install |
| installationId | No | Optional override. Leave it out: the platform finds the extension.dev GitHub App installation on the approving account itself. Pass it only when an operator needs to name one explicitly, and it must still be an installation on that account or the platform refuses it. | |
| outputDirectory | No | Directory the build writes the loadable extension into. With more than one browser, `<browser>` in the path becomes each browser's name (Extension.js writes `dist/<browser>`), and when it is left out every browser defaults to `dist/<browser>`. | dist/chrome |
| outputDirectories | No | Per-browser output directory overrides, for example {"edge": "build/manifestv3"}. A browser named here wins over `outputDirectory`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the annotations: two-phase device-code approval flow, a provisioning grant that lives minutes, can create only the named project, and is never stored locally, plus project + mirror-repo creation, first-build dispatch with a `firstBuild` reason field, and server-memory-only grant retention for batches. Rate/lifecycle limits (10 per approval, 10 per hour, next batch after the hour allows) are disclosed, which annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and sequencing are front-loaded, and most sentences carry routing or behavioral information. It is long (~400 words) and restates the 10-per-approval cap twice across the batch paragraph, so it could be tightened, but there is little pure filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex 13-parameter, nested-object, no-output-schema creation tool, the description covers the two-phase protocol, the return shape (`firstBuild` status/reason, one row per project with created/no-token/refused/not-attempted), and failure modes (connect link, batch refusal on unsupported platforms). Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3 and the schema already documents each parameter. The description adds cross-parameter semantics the schema cannot: `projects` substituting for `project`+`repo`, sharing top-level inputs as defaults, the 1–10 cap, and that `deviceCode` is reused until every listed project has an answer. It is additive rather than redundant.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource ('Create an extension.dev project for an extension that does not have one yet, without opening the console') and immediately distinguishes itself from three siblings (extension_create, extension_build, extension_auth). An agent can identify exactly what this does and when it applies without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit sequencing: 'Use it right after extension_create and extension_build, once the extension's source is pushed to a GitHub repository, and BEFORE extension_auth', with the reason extension_auth cannot create the project. It also states the follow-up (extension_publish) and the batch alternative, so when-to-use and what-comes-next are both pinned down.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_publishA
Publish the project your stored token is scoped to (extension_auth, or EXTENSION_DEV_TOKEN) to extension.dev, and return its shareable URL. This is what "deploy" or "ship" an extension usually means; extension_submit is the separate store-review path. The target is the token's project: there is no projectPath, and no local file is uploaded. With several logins stored, pass project ('/') to pick which one; it outranks EXTENSION_DEV_TOKEN. For a public project the URL is the canonical public page and ttlHours does not apply. For a private one it is a fresh time-limited share link (?share=) whose lifetime is ttlHours.
| Name | Required | Description | Default |
|---|---|---|---|
| api | No | Platform base URL (default EXTENSION_DEV_API_URL, else https://www.extension.dev) | |
| project | No | Which stored login to use, as '<workspace>/<project>' (or a project slug that matches one login), when extension_auth has signed in to more than one project on this machine. Omitted, the most recent login is used, after EXTENSION_DEV_TOKEN when that is set. Named, it outranks EXTENSION_DEV_TOKEN. extension_auth (action: status) lists the stored logins. | |
| buildSha | No | Pin the URL to a build sha (7-40 hex chars). The platform rejects a sha missing from a readable build index; when its index cannot be read it echoes the sha back and a pin on a failed build is accepted, so value.buildSha is the platform's claim, not a verified build. extension_release_status lists the builds it knows. | |
| ttlHours | No | Private-project share-link lifetime in hours, 1-168 (default 24). Ignored for public projects. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite annotations covering the safety profile (readOnlyHint=false, openWorldHint=true, destructiveHint=false), the description adds substantial non-obvious behavior: the target is the token's project with no projectPath and no local file upload, public projects get a canonical URL where ttlHours is ignored while private ones get a time-limited ?share= link, and buildSha is an unverified platform claim the platform may echo back on a failed build. These are real gotchas that annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with verb, target and return value, then threading the alternative path, token precedence, and public/private URL semantics in order of relevance. The prose is dense and every sentence carries information, though the final paragraph is long enough that a reader must parse carefully.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description compensates by explaining the return value in both cases (canonical public URL vs fresh ?share= link with ttlHours lifetime). It also covers the auth model, multi-login disambiguation, and the buildSha verification caveat, which is everything needed to call a four-parameter, zero-required deploy tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is already 100%, so the schema fully documents api, project, buildSha and ttlHours. The description's parameter-relevant content (project precedence over EXTENSION_DEV_TOKEN, ttlHours ignored for public projects, absence of a projectPath) largely restates the schema rather than extending it, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Publish the project your stored token is scoped to ... to extension.dev') and names the concrete artifact returned (shareable URL). It also explicitly distinguishes itself from the sibling extension_submit by labeling that tool the 'separate store-review path', so an agent can route without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the when-to-use framing directly ('This is what "deploy" or "ship" an extension usually means') and names the alternative path (extension_submit) with the condition that selects it. It further states prerequisites for the multi-login case (pass `project`, which outranks EXTENSION_DEV_TOKEN), leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_release_promoteADestructive
Promote a built extension to a release channel (stable, preview, beta, …) on extension.dev, headless. This WRITES: it is the only verb that changes what a channel points at. It is auth-gated by your stored login (extension_auth) or a release token in EXTENSION_DEV_TOKEN, minted and revoked under project settings, Access tokens. Tokens live at most 7 days, so CI must re-mint before expiry. The project comes from the token; with several logins stored, project picks which one. Call extension_release_status to find a valid buildId. The status is 'promoted' only when the platform says every asked browser's release was dispatched and the channel pointer moved; 'promoted-partially' lists in its warnings what did not happen (a browser whose dispatch failed, a channel pointer that was not moved) and must not be repeated whole; 'promote-unconfirmed' means the platform's answer did not carry the result, so read extension_release_status before promoting again. Cutting a version-bump PR is not available headlessly, because it writes to your source repo and needs an interactive login.
| Name | Required | Description | Default |
|---|---|---|---|
| api | No | Platform base URL (default EXTENSION_DEV_API_URL, else https://www.extension.dev) | |
| buildId | Yes | Build commit SHA to promote (a 7-char short SHA is fine) | |
| channel | Yes | Target release channel, e.g. stable, preview, beta | |
| project | No | Which stored login to use, as '<workspace>/<project>' (or a project slug that matches one login), when extension_auth has signed in to more than one project on this machine. Omitted, the most recent login is used, after EXTENSION_DEV_TOKEN when that is set. Named, it outranks EXTENSION_DEV_TOKEN. extension_auth (action: status) lists the stored logins. | |
| version | No | Version label for the release (optional) | |
| browsers | No | Browsers to release. Optional: when omitted the platform reads the build's browsers from its index, and falls back to chrome alone when that index cannot be read, so pass them to be sure. | |
| approvalId | No | The approval handle returned by a prior approval-required response. Promoting changes what a public channel serves and is not reversible in place, so when the platform's approval gate is on this needs a human approval: call once without this to get an approval id and URL, have a human approve at extension.dev, then call again with the same id. | |
| releaseNotes | No | Release notes markdown (optional) | |
| sourceChannel | No | Channel to promote from (optional; inferred otherwise) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations by disclosing auth mechanisms (stored login or EXTENSION_DEV_TOKEN), the 7-day token lifetime and CI re-mint requirement, the human approval gate two-call flow, and that promotion is not reversible in place. The status semantics ('promoted', 'promoted-partially', 'promote-unconfirmed') add real operational context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the write/auth/safety facts and generally dense with useful content, but it is long and some status-handling detail could be trimmed. Nearly every sentence carries weight, so it stays efficient despite its size.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive mutation tool with nine parameters and no output schema, the description supplies the missing return semantics (status values), auth requirements, approval flow, and irreversibility. Nothing an agent needs to call it correctly appears absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and its field descriptions already cover approvalId's two-step flow, project precedence, browsers fallback, and buildId format. The description largely restates this, so it adds little parameter meaning beyond what the schema provides. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('promote a built extension to a release channel') and explicitly claims unique scope: 'the only verb that changes what a channel points at.' It is clearly distinguishable from siblings like extension_publish, extension_release_status, and extension_build.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: 'Call extension_release_status to find a valid buildId,' and names the exclusion ('Cutting a version-bump PR is not available headlessly'). It also states the recovery conditions for partial and unconfirmed outcomes.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_release_statusARead-onlyIdempotent
Read where a project stands on extension.dev, from the public registry (registry.extension.land). This is read-only: it dispatches nothing and promotes nothing. Pass include:'releases' for the release channels (channel to promoted build sha), recent builds, and a public build-page URL for each, which is how you find a valid sha for extension_release_promote, extension_submit or extension_publish. Pass include:'stores' for the per-store picture after an extension_submit (chrome, firefox, edge, safari): configured or not, the last credential health check, the last recorded submission, and the latest review status, read from stores/health.json, stores/status.json and stores/submissions.json. Both are included by default. This defaults to the logged-in project (extension_auth); pass workspace and project to read another. Private projects work when your stored login covers them. Registry state can lag the store dashboards by up to a polling interval.
| Name | Required | Description | Default |
|---|---|---|---|
| api | No | Platform base URL (default EXTENSION_DEV_API_URL, else https://www.extension.dev) | |
| include | No | Which sections to read. Both by default. | |
| project | No | Project slug override (default: the stored login's). | |
| workspace | No | Workspace slug override (default: the stored login's). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotentHint/destructiveHint=false, but the description adds real value beyond them: 'dispatches nothing and promotes nothing', the caveat that registry state can lag store dashboards, and that private projects work when the stored login covers them. This is strong disclosure, though return-shape detail leans on the include explanation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose then default behavior, section semantics, overrides, and caveats. Dense and information-rich; each sentence carries weight, though the middle is somewhat packed and could be split for easier scanning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-value burden and does so: it describes the release channels, build URLs, and per-store fields (configured state, credential health, last submission, review status) plus their source files. An agent has enough to call and interpret it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% (baseline 3), and the description adds meaning beyond the schema by enumerating what include:'releases' returns (channel→promoted sha, builds, build-page URL) and include:'stores' returns per store. It also clarifies workspace/project override the stored login default.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Read where a project stands on extension.dev, from the public registry (registry.extension.land).' It clearly positions itself as a status/read tool distinct from the mutation siblings it references.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells the agent when to use include:'releases' (to find a valid sha for extension_release_promote, extension_submit, extension_publish) and include:'stores' (after extension_submit). It names the alternative tools and the conditions that route to them rather than leaving it to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_reloadAIdempotent
Reload a running extension's background context, or a tab. Start the session with allowControl:true (extension_dev).
| Name | Required | Description | Default |
|---|---|---|---|
| tab | No | For content/page: a specific tab id | |
| browser | No | Session browser; defaults to this project's live session | |
| context | No | background | |
| timeout | 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. | |
| projectPath | Yes | Extension project root (needs a live dev session) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare non-read-only, idempotent, non-destructive behavior, and the description is consistent with them. It adds the session-control prerequisite (allowControl:true), which is useful behavioral context, but does not say what reload resets (background state, tab contents) or what auth/session it depends on beyond that.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with zero waste; the core action is front-loaded and the prerequisite follows immediately. Nothing is padded or redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a state-changing tool with no output schema, the description conveys the action and the session requirement but leaves the effect of the reload and any return signal unstated. Annotations carry some of the safety burden, so it is adequate but with clear gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is high (80%) and the timeout/browser/projectPath params are well documented in-schema. The description's 'background context, or a tab' loosely maps to the context and tab parameters but adds no format or selection detail beyond the schema. Baseline 3 when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (reload) and resource (a running extension's background context, or a tab), which cleanly separates it from siblings like extension_build, extension_start, and extension_stop. It doesn't explicitly name those siblings, but the action is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides a genuine precondition — the session must be started with allowControl:true via extension_dev — which tells the agent when this tool is callable. It stops short of saying when to prefer this over alternatives such as extension_start or restarting the session.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_startA
Run the PRODUCTION build in a browser: build the project, serve it, and launch. There is no hot module replacement and no control channel, so your edits are not picked up and extension_eval, extension_storage, extension_reload, extension_open and extension_dom_snapshot cannot attach to this session. Use extension_dev while writing code, and this to check what actually ships. Pass build:false to launch an existing dist/ without rebuilding, or outputPath to launch any prebuilt unpacked extension directory, one another toolchain produced included, which implies build:false.
| Name | Required | Description | Default |
|---|---|---|---|
| host | No | Bind host, default 127.0.0.1. Use 0.0.0.0 in Docker or devcontainers. | |
| port | 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. | |
| build | No | Build before serving. false serves the existing dist/<browser> as-is and fails when there is none. | |
| browser | No | chrome | |
| profile | No | Profile path, or "false" to reuse the real user profile. Omit for a throwaway one. | |
| polyfill | No | Apply cross-browser polyfill (build only) | |
| noBrowser | No | 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. | |
| extensions | No | Extra extension paths or store URLs to load alongside the project | |
| outputPath | 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. | |
| publicHost | No | Host the browser dials for HMR and reload when it differs from the bind host | |
| geckoBinary | No | Custom Gecko/Firefox binary to launch; `browser` still names the target family the engine builds for (gecko-based when none is given). | |
| projectPath | Yes | Extension project root | |
| startingUrl | No | URL the browser opens on launch | |
| chromiumBinary | No | Custom Chromium-based binary to launch; `browser` still names the target family the engine builds for (chromium-based when none is given). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing that there is no HMR and no control channel, enumerating exactly which sibling tools cannot attach (extension_eval, extension_storage, extension_reload, extension_open, extension_dom_snapshot), and explaining that a noBrowser production start ends when the build does.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose and free of filler, but the long multi-clause sentence chain is dense. Every clause does convey distinct behavior, so little is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 14-parameter launch tool with no output schema, the description covers build/serve/launch mechanics, session limitations, and the prebuilt-artifact path, which is everything an agent needs to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 93%, so the baseline is 3, but the description adds cross-parameter behavior: outputPath 'implies build:false' and build:false serves an existing dist or fails when none exists. That relational meaning is not in the schema itself.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Run the PRODUCTION build in a browser: build the project, serve it, and launch') and explicitly distinguishes itself from the sibling extension_dev, so an agent can route correctly without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use routing ('Use extension_dev while writing code, and this to check what actually ships') plus concrete conditional variants for build:false and outputPath. Alternatives and exclusions are named directly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_stopADestructiveIdempotent
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. 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.
| Name | Required | Description | Default |
|---|---|---|---|
| all | No | Stop every known session across projects and browsers, found from this server's registry AND the on-disk markers written by this server or by servers that are no longer running, so it still works after an MCP restart. A marker owned by another MCP server that is still running is left alone and listed under skippedForeign unless includeOtherServers is true. It also takes back every live-preview carrier still recorded on this machine, including one in a project whose session was never stopped. projectPath/browser are then ignored. | |
| browser | No | Browser of the session to stop. Defaults to the single live session for this project rather than assuming chrome. | |
| projectPath | No | Extension project root | |
| includeOtherServers | No | With all: true, also stop sessions whose markers belong to another MCP server that is still running (the markers sit in a per-user directory every server shares). Off by default, since those sessions are someone else's. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already carry destructiveHint=true and idempotentHint=true, so the safety profile is partly covered. The description still earns credit by specifying exactly what is destroyed (server + launched browser + live-preview carrier) and the preview-session edge case. It does not address failure behavior when no session exists, leaving a small gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the primary action and scoped by three tight sentences with no filler. The first sentence is dense but every clause (server, browser, carrier) carries distinct information. Slightly heavy for its length, but no sentence is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive lifecycle tool with no output schema and thorough annotations, the description covers purpose, scope of destruction, the preview-session variant, and the usage trigger. It omits the no-op/error case when no session is found, which is the only notable missing context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the parameter docs are unusually thorough (all, browser, projectPath, includeOtherServers). The description adds no parameter-level syntax or format detail beyond what the schema states, so the baseline 3 is appropriate when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb (stop) plus resource (session) and an explicit enumeration of what is terminated: the server, the launched browser, and the live-preview carrier. It names the sibling tools that create these sessions (extension_dev, extension_start) and even calls out the extension_start build:false preview variant, so an agent can distinguish it from launcher tools without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear triggering condition: 'Call it when you are done verifying, so sessions do not accumulate.' That establishes when to invoke it relative to the dev/start lifecycle. It does not state when *not* to call it (e.g. mid-verification, or while another server owns the session), so it falls short of explicit exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_storageADestructive
Read or write chrome.storage in a running extension. Every call runs in the extension's background (the engine honours 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 matches. Start the session with allowControl:true (extension_dev). Set one key per call: there is no bulk-object set.
| Name | Required | Description | Default |
|---|---|---|---|
| key | No | Key to get or set | |
| area | No | local | |
| value | No | Value to set (any JSON value); required for action=set | |
| action | Yes | get reads a key (or the whole area); set writes a key | |
| browser | No | Session browser; defaults to this project's live session | |
| timeout | 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. | |
| projectPath | Yes | Extension project root (needs a live dev session) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavior the annotations cannot express: every call runs in the background so it proves nothing about content-script or page reads, a set is read back and the answer reports whether the stored value matches, and there is no bulk-object set. These are real operational traits beyond the destructiveHint/non-idempotent flags, and nothing contradicts the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense and front-loaded: purpose first, then behavioral caveats, then setup requirement, then the key-per-call constraint. Every sentence carries information, though the phrasing is compact enough that some clauses read as terse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter tool with 86% schema coverage and no output schema, the description covers the non-obvious behavior well (background execution semantics, read-back verification, session prerequisite). It is nearly complete; only explicit alternative routing is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 86%, so the baseline is 3, but the description goes beyond the schema by imposing a genuine usage constraint: 'Set one key per call: there is no bulk-object set,' which clarifies how key/value must be used. It adds meaning on top of the documented parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names a specific verb pair and resource: 'Read or write chrome.storage in a running extension.' It is unambiguous about what the tool operates on. Sibling differentiation is only partial — it references extension_dev for session startup but never explicitly contrasts itself with extension_eval or extension_inspect.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete prerequisite ('Start the session with allowControl:true (extension_dev)') and a scoping caveat explaining what the call does and does not prove. It stops short of naming an alternative tool or an explicit when-not set of conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_submitADestructive
Submit a built extension for store REVIEW through extension.dev, which holds your store credentials and dispatches from your project's mirror CI: the Chrome Web Store, Firefox AMO, Edge Add-ons and the App Store (Safari). This is store review only. It does not push a build to the extension.dev platform, and it does not make a shareable link: that is extension_publish, which is what "deploy" or "ship" an extension almost always means. Reach for this only when the ask is explicitly a store submission. It defaults to a dry run that dispatches nothing: the platform verifies the token and project, finds the store workflow, reads the build from its index when that index is readable, reads store health itself and adds a Safari plan verdict; this tool re-reads the per-store health rows beside it. The dry run does not run the owner gate, the approval, the build quota, the dispatch pause or the submission-mode check, which the real run does first. Pass dryRun:false to actually submit, which is irreversible: only the workspace owner who issued the token may, and it dispatches the store workflow; a Chrome or Edge store with no saved submission mode is uploaded as a draft (absent_mode: safe) and does not enter review. A real submission answers 'submitted' only when the platform recorded a submission for every store asked; 'submitted-partially' names the stores it did not record, which are the only ones to submit again; 'submit-unconfirmed' means no usable answer came back, so read extension_release_status before submitting again, because a second call submits a second time. The project comes from your token (extension_auth or EXTENSION_DEV_TOKEN; tokens live at most 7 days, so CI must re-mint from the console's Access tokens page); with several logins stored, project picks which one. Store credentials are never arguments, and no local file is uploaded. Call extension_release_status for valid shas, and, after a real submission, for the recorded outcome and review state.
| Name | Required | Description | Default |
|---|---|---|---|
| api | No | Platform base URL (default EXTENSION_DEV_API_URL, else https://www.extension.dev) | |
| dryRun | No | Preflight only. Pass false to actually dispatch (irreversible, enters store review). | |
| channel | No | Release channel to submit from (default stable). | |
| project | No | Which stored login to use, as '<workspace>/<project>' (or a project slug that matches one login), when extension_auth has signed in to more than one project on this machine. Omitted, the most recent login is used, after EXTENSION_DEV_TOKEN when that is set. Named, it outranks EXTENSION_DEV_TOKEN. extension_auth (action: status) lists the stored logins. | |
| version | No | Version label for the submission record (optional). | |
| browsers | Yes | Stores to submit to. | |
| buildSha | Yes | The built commit SHA to submit. It needs a completed build in the project's build index; an unknown sha is rejected. | |
| approvalId | No | The approval handle returned by a prior approval-required response for a real submission. A real submission (dryRun:false) is irreversible and needs a human approval when the platform's approval gate is on: call once without this to get an approval id and URL, have a human approve at extension.dev, then call again with the same id. A dry run never needs it. | |
| projectPath | No | Path to the extension project root, read only for the local STORE.md advisory check. Nothing local is uploaded; without it the check falls back to the server's working directory. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive/non-idempotent/non-readonly/openWorld, and the description builds well past that: dry-run default and exactly which gates it skips vs. the real run, irreversibility, owner-only authorization, the approval loop, draft-upload behavior for Chrome/Edge without a saved mode, the submitted/partially/unconfirmed outcome vocabulary, and the 7-day token expiry. This is unusually rich disclosure for a destructive tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and the publish-vs-submit distinction are front-loaded, and the dry-run/real-run semantics follow logically. It is a dense, single long paragraph with some redundancy (irreversibility, token expiry and submission-mode checks are restated), but for a tool with this much behavior every clause mostly earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden and does: it describes return-state vocabulary, failure handling ('read extension_release_status before submitting again'), prerequisites (build index, token, owner gate), and irreversible side effects. Nothing needed to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and each parameter is already well documented, so the baseline is 3. The description adds real meaning beyond the schema: it explains where the project identity comes from (token vs. `project`), how approvalId is used across two calls, that credentials are never arguments, and that projectPath is only used for a local STORE.md advisory.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with scope: 'Submit a built extension for store REVIEW through extension.dev'. It explicitly names the sibling it is not (extension_publish) and clarifies that 'deploy' or 'ship' usually means the other tool, so an agent can distinguish them without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use ('only when the ask is explicitly a store submission'), when-not ('does not push a build to the platform, does not make a shareable link'), the alternative (extension_publish), and points to extension_release_status for valid shas and post-submission outcome. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_templatesARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | No | source: which template to read (e.g. 'ai-claude', 'content-react'). Required for source. | |
| tags | No | list: filter by tags, e.g. ['ai', 'chat']. | |
| files | No | source: paths to read (e.g. ['src/manifest.json']). Omit for the file listing. | |
| query | No | list: keyword search over slug, description, tags and useCases. Ranks by word matches, so a natural phrase works. | |
| action | No | list | |
| surface | No | list: filter by surface. For a popup/action starter use query:'action', not a surface. | |
| featured | No | list: only featured templates. | |
| framework | No | list: UI framework filter (empty string = vanilla JS). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this as a safe, idempotent, open-world read, so the bar is lower. The description still adds real context beyond them: 'list' returns metadata per template, 'source' returns a template's files, and it flags a non-obvious interpretation pitfall ('framework is the UI framework only, never the language'). It omits pagination/rate-limit behavior, so not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and the action modes, then the framework caveat, so the most important routing information comes first. The framework sentence is long but every clause carries a distinct slug/tag mapping, so it earns its space; only mild density cost.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 8 all-optional parameters, no required inputs, and no output schema, the description does the necessary work by explaining both modes and roughly what each returns. It does not describe the file-listing vs file-content return shape in detail, but it is complete enough for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 88%, so the baseline is 3, but the description adds genuine meaning the schema lacks: it clarifies that 'framework' is UI-framework-only and that TypeScript/JavaScript, shadcn variants, and provider AIs are reached via slug/tags rather than the framework enum. That disambiguation is exactly what an agent would otherwise get wrong.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names a specific verb and resource ('Browse the extension.dev template catalog'), then splits that resource into two concrete modes ('list' for search/filter/metadata, 'source' for reading one template's files). An agent can tell what this tool is and what it does without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is spelled out per action: 'list' is the default for searching/filtering, and 'source' is for 'learning a pattern before building something similar', which gives a clear motivating context. It stops short of naming sibling alternatives (e.g. extension_docs_search) or when-not-to-use, so it is strong context rather than full routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_theme_verifyARead-onlyIdempotent
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 pointing at the assert:theme and install-parity harnesses, never as passed.
| Name | Required | Description | Default |
|---|---|---|---|
| manifest | No | The Chrome theme manifest object (with a `theme` block). Pass this or manifestPath. | |
| manifestPath | No | Path to a theme manifest.json (or a { manifest } seed wrapper). Read in place of the inline manifest. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, yet the description adds substantial context beyond them: it verifies only and never authors or mutates, explains the D1/D3/D4 problem taxonomy (including keys Chrome silently discards), and discloses the headless limitation and that attended legs return needsAttended rather than passed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the purpose and remains a tight cluster of sentences, each carrying real information about scope, method, and return semantics. It leans heavily on domain jargon (four-leg, D1/D3/D4) that a fresh agent must infer, slightly reducing clarity per unit length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-value burden and does so by explaining the classification outputs and the needsAttended/passed distinction. It is nearly complete for an agent to call it correctly, missing only the explicit alternative sibling and any concrete invocation example.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters (manifest, manifestPath) are documented in the schema itself. The description adds no additional parameter syntax, format, or precedence detail beyond the schema's own 'pass this or that' guidance, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Verify a Chrome theme manifest before it ships') and richly characterizes scope: it settles the four-leg WYSIWYG contract headless and classifies problems into D1/D3/D4. The theme-specific framing implicitly distinguishes it from the general extension_manifest_validate sibling, though that sibling is never named.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear usage context ('before it ships') and explicitly scopes what it can cover headless versus what needs a browser, routing the app-rendered and real-pixel legs to the assert:theme and install-parity harnesses. It stops short of naming the obvious sibling alternative (extension_manifest_validate) by name.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_waitARead-onlyIdempotent
Wait for a running dev or start session to be ready. This polls the ready.json contract and reports compiled (the compiler finished), browserAttached (the runtime executor connected), and guestLoaded (the browser's own target list shows your extension). Read guestLoaded as the trustworthy load signal: it catches a silently rejected --load-extension that leaves ready.json stamped attached with empty logs. It is null when it could not be checked, for example a gecko session with no CDP port. Every result reports budgetMs and elapsedMs; on status 'timeout', call again to keep waiting on the same contract. In a noBrowser session this returns as soon as the compile lands, instead of waiting for a browser that will never attach. Ports come from the contract, so they match what the server actually bound.
| Name | Required | Description | Default |
|---|---|---|---|
| browser | No | Session browser; defaults to this project's live session | |
| timeout | No | Deprecated alias of timeoutMs, which wins when both are given. | |
| timeoutMs | No | Wait budget for this call. Default 45000, clamped to 1000-50000 so one call stays under the client's 60s request timeout. On timeout, call again to keep waiting. | |
| projectPath | Yes | Extension project root |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/idempotent annotations: it explains the ready.json polling contract, the three reported signals and which one (guestLoaded) to trust, why it can be null, timeout/retry semantics, and port sourcing. This is unusually rich behavioral disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: the core purpose leads, followed by signal meaning, null caveat, timeout retry, and noBrowser behavior. Nearly every sentence carries actionable information, though it is on the longer side.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by naming each returned field and its meaning. Combined with the annotations covering the safety profile, an agent has everything needed to call and interpret this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all four parameters including the deprecated alias and clamping range. The description adds little parameter-level detail beyond noting ports come from the contract, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: 'Wait for a running dev or start session to be ready.' It clearly positions itself as the waiting/polling tool among siblings like extension_start and extension_dev. An agent can distinguish it immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains the trigger context (a running dev or start session) and instructs to 'call again to keep waiting' on timeout, plus the noBrowser short-circuit. No explicit sibling alternative is named, but the usage condition is clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extension_workspace_createA
Create an extension.dev workspace that does not exist yet, without opening the console. Use it before extension_project_create when the project's workspace is not there: project creation can only target an existing workspace, and this tool is what brings one into existence. Two-phase, like login: the first call returns a code and a URL where a signed-in GitHub user approves creating exactly this workspace and becomes its owner; call again with the returned deviceCode to finish. Check ownerGithubLogin in the answer: whoever approved the code owns the workspace. The approval mints a grant that lives minutes, can only create the one named workspace, names no project, and is never stored on this machine. Then run extension_project_create against '/'.
| Name | Required | Description | Default |
|---|---|---|---|
| api | No | Platform base URL (default EXTENSION_DEV_API_URL, else https://www.extension.dev) | |
| workspace | Yes | Slug of the new workspace, lowercase letters, digits and hyphens, no slash. It must not exist yet; a personal workspace (the GitHub login) already exists for every signed-in user, so this is for a shared or organization-style workspace. | |
| deviceCode | No | Resume token from the prior call's `deviceCode`; omit on the first call. | |
| description | No | Short workspace description. Optional. | |
| displayName | No | Human name for the workspace. Defaults to the slug. | |
| developerUrl | No | Public URL for the workspace. Optional. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say it is a non-read-only, non-idempotent, open-world mutation. The description adds far more: a two-phase approval flow, that the first call returns a code and URL, that a signed-in GitHub user approves and becomes owner, that the grant is short-lived, single-purpose, names no project, and is never stored locally. This is exactly the behavioral context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and the sibling relationship, then flows into the two-phase mechanics. It is long, but nearly every sentence (ownership, grant lifetime, next call) carries information an agent needs; only mild trimming is possible.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex async, auth-gated creation tool with no output schema, the description covers the return values (code, URL, deviceCode, ownerGithubLogin), the sequencing, and the follow-up. Nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description goes further by tying deviceCode to the second call ('call again with the returned deviceCode to finish') and flagging ownerGithubLogin as the ownership signal, adding flow semantics the schema field descriptions do not fully convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Create an extension.dev workspace that does not exist yet, without opening the console') and distinguishes itself from extension_project_create by scope. An agent can tell what it does and when it applies without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly orders it before extension_project_create and explains why: 'project creation can only target an existing workspace.' It also notes that personal workspaces already exist, so this is for shared/org-style workspaces, and even prescribes the follow-up call ('run extension_project_create against <workspace>/<project>').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
20 tool updates
v10.10.13- Changed
extension_assert1 field changed- changed
Input schema / properties / timeout / descriptionPrevious value: -"Command timeout in ms (default 5000)"New value: +"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."
- Changed
extension_auth2 fields changed- changed
Input schema / properties / project / descriptionPrevious value: -"login: target project as '<workspace>/<project>'; the token is scoped to it. The slug pair is the console address bar: an existing project's page is console.extension.dev/<workspace>/<project>. Create one at extension.dev/new if none exists yet."New value: +"login: target project as '<workspace>/<project>'; the token is scoped to it. The slug pair is the console address bar: an existing project's page is console.extension.dev/<workspace>/<project>. Create one at extension.dev/new if none exists yet. Logins to several projects are all kept, the latest is the default; token-scoped tools take `project` to pick another. logout: remove only this project's login (omitted, every stored login goes)." - added
Input schema / properties / projectsAdded value: +{ + "description": "login: sign in to several existing projects of one workspace with one approval, instead of one approval each. 1 to 20 names as '<workspace>/<project>', all in the same workspace, each by its exact slug (lowercase letters and digits joined by single dashes, at most 48 characters), none twice. Pass it instead of `project`, never beside it. The approval page lists every name; one missing project refuses the whole list and mints nothing. Resume with the returned `deviceCode` and the same list. Every token is stored as that project's own login and all expire within 7 days, so the same call renews them together.", + "items": { + "type": "string" + }, + "type": "array" +}
- Changed
extension_build2 fields changed- changed
Input schema / properties / bundleId / descriptionPrevious value: -"Safari targets only: a reverse-DNS bundle identifier you own, such as com.acme.readinglist. Without one the app is packaged under a generated dev.extensionjs.* identifier derived from the app name, which every project built from the same template shares, and the first team to register it takes it."New value: +"Safari targets only: a reverse-DNS bundle identifier you own, such as com.acme.readinglist. Without one the app is packaged under a generated dev.extensionjs.* identifier derived from the app name, which two projects with the same name share, and the first team to register it takes it." - changed
Input schema / properties / skipValidation / descriptionPrevious value: -"Build even when extension_manifest_validate reports build-blocking errors. The build normally refuses: a manifest error yields a broken bundle the bundler itself never flags."New value: +"Build even when extension_manifest_validate reports build-blocking errors. The build normally refuses: the engine itself stops only on missing scripts, icons, DNR rule files, default_locale and manifest_version, and ships a bundle over the rest."
- Changed
extension_dev2 fields changed- changed
Input schema / properties / chromiumBinary / descriptionPrevious value: -"Custom Chromium-based binary (overrides browser)"New value: +"Custom Chromium-based binary to launch; `browser` still names the target family the engine builds for (chromium-based when none is given)." - changed
Input schema / properties / geckoBinary / descriptionPrevious value: -"Custom Gecko/Firefox binary (overrides browser)"New value: +"Custom Gecko/Firefox binary to launch; `browser` still names the target family the engine builds for (gecko-based when none is given)."
- Added
extension_docs_search - Changed
extension_dom_snapshot1 field changed- changed
Input schema / properties / timeout / descriptionPrevious value: -"Command timeout in ms (default 5000)"New value: +"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."
- Changed
extension_eval1 field changed- changed
Input schema / properties / timeout / descriptionPrevious value: -"Command timeout in ms (default 5000)"New value: +"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."
- Changed
extension_inspect1 field changed- changed
Input schema / properties / deepDom / descriptionPrevious value: -"Pierce CLOSED shadow roots; open ones are read anyway. Chromium: CDP DOM pierce. Firefox: a content-script walk via tabs.executeScript (MV2 only, needs host permissions for the target url)."New value: +"Pierce CLOSED shadow roots (open roots of the extension-root hosts are already inlined in html; other open roots are not read). Chromium: CDP DOM pierce. Firefox: a content-script walk via tabs.executeScript (MV2 only, needs host permissions for the target url); the answer says whether that context could see closed roots at all."
- Changed
extension_logs2 fields changed- changed
Input schema / properties / browser / descriptionPrevious value: -"Which dist/extension-js/<browser>/ to read. Defaults to this project's live session, else chromium."New value: +"Which dist/extension-js/<browser>/ to read. Defaults to this project's live session, else chrome." - changed
Input schema / properties / context / items / enumPrevious value: -[ - "background", - "content", - "page", - "sidebar", - "popup", - "options", - "devtools", - "newtab", - "history", - "bookmarks" -]New value: +[ + "background", + "content", + "sidebar", + "popup", + "options", + "devtools", + "newtab", + "history", + "bookmarks" +]
- Changed
extension_open3 fields changed- added
Input schema / properties / reloadAdded value: +{ + "default": false, + "description": "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.", + "type": "boolean" +} - changed
Input schema / properties / timeout / descriptionPrevious value: -"Command timeout in ms (default 5000)"New value: +"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." - added
Input schema / properties / waitMsAdded value: +{ + "description": "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`.", + "type": "number" +}
- Changed
extension_preview_web2 fields changed- added
Input schema / properties / projectAdded value: +{ + "description": "Which stored login to use, as '<workspace>/<project>' (or a project slug that matches one login), when extension_auth has signed in to more than one project on this machine. Omitted, the most recent login is used, after EXTENSION_DEV_TOKEN when that is set. Named, it outranks EXTENSION_DEV_TOKEN. extension_auth (action: status) lists the stored logins.", + "type": "string" +} - changed
Input schema / properties / share / descriptionPrevious value: -"Upload the built dist and return a public link (share.previewUrl) that renders those exact bytes for anyone: no install, sign-in or dev server. Uploading runs on extension.dev's machines and counts against your free allowance; left false, the result's share property says what the local deepLink needs, what share:true spends, and the exact call to get a shareable link. It also serves the build as a zip (share.zipUrl), so sharing hands over the code. Needs a token scoped to an extension.dev project (extension_auth or EXTENSION_DEV_TOKEN); without one you get a login hint and the local preview still succeeds. Live until share.expiresAt; DELETE share.revokeUrl to kill it sooner. Revocation is permanent, and re-sharing an unchanged build returns the same link unless it was revoked, so each share is also appended to the project's gitignored .extension.dev/shared-previews.json."New value: +"Upload the built dist and return a public link (share.previewUrl) that renders those exact bytes for anyone: no install, sign-in or dev server. Uploading is metered against your plan's allowance on extension.dev; left false, the result's share property says what the local deepLink needs, what share:true spends, and the exact call to get a shareable link. It also serves the build as a zip (share.zipUrl), so sharing hands over the code. Needs a token scoped to an extension.dev project (extension_auth or EXTENSION_DEV_TOKEN); without one you get a login hint and the local preview still succeeds. Live until share.expiresAt; DELETE share.revokeUrl to kill it sooner. Revocation is permanent, and re-sharing an unchanged build returns the same link unless it was revoked, so each share is also appended to the project's gitignored .extension.dev/shared-previews.json."
- Changed
extension_project_create3 fields changed- changed
Input schema / properties / deviceCode / descriptionPrevious value: -"Resume token from the prior call's `deviceCode`; omit on the first call."New value: +"Resume token from the prior call's `deviceCode`; omit on the first call. A batch returns the same deviceCode until every listed project has an answer." - added
Input schema / properties / projectsAdded value: +{ + "description": "Create several projects in one workspace under one approval, instead of `project` and `repo`. 1 to 10 entries (the platform's cap per approval; never more than 20), each { project: '<workspace>/<project>', repo: '<owner>/<repo>' }, all in the same workspace, each project named by its exact slug (lowercase letters and digits joined by single dashes, at most 48 characters), none twice and none existing yet. An entry may also carry displayName, description, installCommand, buildCommand, outputDirectory, browsers and outputDirectories for that project alone; the same inputs at the top level are the shared default for every entry that leaves them out. The answer carries one row per project: created and logged in, created with no token (run a batch extension_auth login), refused with the platform's code, or not attempted. A refusal on one project never hides the others.", + "items": { + "type": "object" + }, + "type": "array" +} - changed
Input schema / requiredPrevious value: -[ - "project", - "repo" -]New value: +[]
- Changed
extension_publish2 fields changed- changed
Input schema / properties / buildSha / descriptionPrevious value: -"Pin the URL to a build sha (7-40 hex chars). An unknown sha is rejected, so the returned URL always points at a real build."New value: +"Pin the URL to a build sha (7-40 hex chars). The platform rejects a sha missing from a readable build index; when its index cannot be read it echoes the sha back and a pin on a failed build is accepted, so value.buildSha is the platform's claim, not a verified build. extension_release_status lists the builds it knows." - added
Input schema / properties / projectAdded value: +{ + "description": "Which stored login to use, as '<workspace>/<project>' (or a project slug that matches one login), when extension_auth has signed in to more than one project on this machine. Omitted, the most recent login is used, after EXTENSION_DEV_TOKEN when that is set. Named, it outranks EXTENSION_DEV_TOKEN. extension_auth (action: status) lists the stored logins.", + "type": "string" +}
- Changed
extension_release_promote2 fields changed- changed
Input schema / properties / browsers / descriptionPrevious value: -"Browsers to release (optional; auto-detected from the build)"New value: +"Browsers to release. Optional: when omitted the platform reads the build's browsers from its index, and falls back to chrome alone when that index cannot be read, so pass them to be sure." - added
Input schema / properties / projectAdded value: +{ + "description": "Which stored login to use, as '<workspace>/<project>' (or a project slug that matches one login), when extension_auth has signed in to more than one project on this machine. Omitted, the most recent login is used, after EXTENSION_DEV_TOKEN when that is set. Named, it outranks EXTENSION_DEV_TOKEN. extension_auth (action: status) lists the stored logins.", + "type": "string" +}
- Changed
extension_reload1 field changed- changed
Input schema / properties / timeout / descriptionPrevious value: -"Command timeout in ms (default 5000)"New value: +"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."
- Changed
extension_shares2 fields changed- added
Input schema / properties / projectAdded value: +{ + "description": "Which stored login to use, as '<workspace>/<project>' (or a project slug that matches one login), when extension_auth has signed in to more than one project on this machine. Omitted, the most recent login is used, after EXTENSION_DEV_TOKEN when that is set. Named, it outranks EXTENSION_DEV_TOKEN. extension_auth (action: status) lists the stored logins.", + "type": "string" +} - changed
Input schema / properties / status / descriptionPrevious value: -"all (default) includes expired and revoked shares, which is what makes a dead link explainable; live returns only links that still resolve."New value: +"all (default) includes expired and revoked shares, which is what makes a dead link explainable; live returns only the links the platform reported resolving at list time (a 429 or 503 from the platform answers listed-local-only, which says nothing about any link)."
- Changed
extension_start4 fields changed- changed
Input schema / properties / chromiumBinary / descriptionPrevious value: -"Custom Chromium-based binary (overrides browser)"New value: +"Custom Chromium-based binary to launch; `browser` still names the target family the engine builds for (chromium-based when none is given)." - changed
Input schema / properties / geckoBinary / descriptionPrevious value: -"Custom Gecko/Firefox binary (overrides browser)"New value: +"Custom Gecko/Firefox binary to launch; `browser` still names the target family the engine builds for (gecko-based when none is given)." - changed
Input schema / properties / noBrowser / descriptionPrevious value: -"Serve without launching a browser"New value: +"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." - changed
Input schema / properties / port / descriptionPrevious value: -"Server port (0 for auto-assign)"New value: +"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."
- Changed
extension_stop2 fields changed- changed
Input schema / properties / all / descriptionPrevious value: -"Stop every known session across projects and browsers, found from this server's registry AND the on-disk markers earlier runs left, so it still works after an MCP restart. It also takes back every live-preview carrier still recorded on this machine, including one in a project whose session was never stopped. projectPath/browser are then ignored."New value: +"Stop every known session across projects and browsers, found from this server's registry AND the on-disk markers written by this server or by servers that are no longer running, so it still works after an MCP restart. A marker owned by another MCP server that is still running is left alone and listed under skippedForeign unless includeOtherServers is true. It also takes back every live-preview carrier still recorded on this machine, including one in a project whose session was never stopped. projectPath/browser are then ignored." - added
Input schema / properties / includeOtherServersAdded value: +{ + "default": false, + "description": "With all: true, also stop sessions whose markers belong to another MCP server that is still running (the markers sit in a per-user directory every server shares). Off by default, since those sessions are someone else's.", + "type": "boolean" +}
- Changed
extension_storage2 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "default": "background", - "enum": [ - "background", - "popup", - "options", - "sidebar", - "content" - ], - "type": "string" -} - changed
Input schema / properties / timeout / descriptionPrevious value: -"Command timeout in ms (default 5000)"New value: +"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."
- Changed
extension_submit1 field changed- added
Input schema / properties / projectAdded value: +{ + "description": "Which stored login to use, as '<workspace>/<project>' (or a project slug that matches one login), when extension_auth has signed in to more than one project on this machine. Omitted, the most recent login is used, after EXTENSION_DEV_TOKEN when that is set. Named, it outranks EXTENSION_DEV_TOKEN. extension_auth (action: status) lists the stored logins.", + "type": "string" +}
8 tool updates
v10.10.1- Changed
extension_browsers1 field changed- changed
Input schema / properties / browsers / items / enumPrevious value: -[ - "chrome", - "chromium", - "edge", - "brave", - "opera", - "vivaldi", - "yandex", - "firefox", - "waterfox", - "librewolf", - "safari" -]New value: +[ + "chrome", + "chromium", + "edge", + "brave", + "opera", + "vivaldi", + "yandex", + "firefox", + "waterfox", + "librewolf", + "zen", + "floorp", + "safari" +]
- Changed
extension_build1 field changed- changed
Input schema / properties / browser / enumPrevious value: -[ - "chrome", - "chromium", - "edge", - "brave", - "opera", - "vivaldi", - "yandex", - "firefox", - "waterfox", - "librewolf", - "safari", - "chromium-based", - "gecko-based", - "firefox-based", - "webkit-based" -]New value: +[ + "chrome", + "chromium", + "edge", + "brave", + "opera", + "vivaldi", + "yandex", + "firefox", + "waterfox", + "librewolf", + "zen", + "floorp", + "safari", + "chromium-based", + "gecko-based", + "firefox-based", + "webkit-based" +]
- Changed
extension_dev1 field changed- changed
Input schema / properties / browser / enumPrevious value: -[ - "chrome", - "chromium", - "edge", - "brave", - "opera", - "vivaldi", - "yandex", - "firefox", - "waterfox", - "librewolf", - "safari", - "chromium-based", - "gecko-based", - "firefox-based", - "webkit-based" -]New value: +[ + "chrome", + "chromium", + "edge", + "brave", + "opera", + "vivaldi", + "yandex", + "firefox", + "waterfox", + "librewolf", + "zen", + "floorp", + "safari", + "chromium-based", + "gecko-based", + "firefox-based", + "webkit-based" +]
- Changed
extension_open4 fields changed- added
Input schema / properties / panelAdded value: +{ + "description": "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.", + "type": "string" +} - changed
Input schema / properties / surface / enumPrevious value: -[ - "popup", - "options", - "sidebar", - "newtab", - "history", - "bookmarks", - "action", - "command" -]New value: +[ + "popup", + "options", + "sidebar", + "devtools", + "newtab", + "history", + "bookmarks", + "action", + "command" +] - added
Input schema / properties / tabAdded value: +{ + "description": "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.", + "type": "number" +} - changed
Input schema / properties / url / descriptionPrevious value: -"Navigate a real tab here instead of opening a surface (Firefox needs allowEval: true). Use for content-script test pages, or a surface as a page: chrome-extension://<id>/popup.html."New value: +"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."
- Changed
extension_preview_web2 fields changed- changed
Input schema / properties / browser / enumPrevious value: -[ - "chrome", - "chromium", - "edge", - "brave", - "opera", - "vivaldi", - "yandex", - "firefox", - "waterfox", - "librewolf", - "safari" -]New value: +[ + "chrome", + "chromium", + "edge", + "brave", + "opera", + "vivaldi", + "yandex", + "firefox", + "waterfox", + "librewolf", + "zen", + "floorp", + "safari" +] - changed
Input schema / properties / openIn / enumPrevious value: -[ - "chrome", - "chromium", - "edge", - "brave", - "opera", - "vivaldi", - "yandex", - "firefox", - "waterfox", - "librewolf", - "safari" -]New value: +[ + "chrome", + "chromium", + "edge", + "brave", + "opera", + "vivaldi", + "yandex", + "firefox", + "waterfox", + "librewolf", + "zen", + "floorp", + "safari" +]
- Changed
extension_project_create3 fields changed- added
Input schema / properties / browsersAdded value: +{ + "default": [ + "chrome" + ], + "description": "Browsers the platform builds, each enabled with the same install and build command and its own output directory. Pass every browser the extension targets, for example [\"chrome\", \"edge\", \"firefox\"], so the project needs no console visit to go cross-browser.", + "items": { + "enum": [ + "chrome", + "edge", + "firefox" + ], + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / outputDirectoriesAdded value: +{ + "description": "Per-browser output directory overrides, for example {\"edge\": \"build/manifestv3\"}. A browser named here wins over `outputDirectory`.", + "type": "object" +} - changed
Input schema / properties / outputDirectory / descriptionPrevious value: -"Directory the build writes the loadable extension into."New value: +"Directory the build writes the loadable extension into. With more than one browser, `<browser>` in the path becomes each browser's name (Extension.js writes `dist/<browser>`), and when it is left out every browser defaults to `dist/<browser>`."
- Changed
extension_start2 fields changed- changed
Input schema / properties / browser / enumPrevious value: -[ - "chrome", - "chromium", - "edge", - "brave", - "opera", - "vivaldi", - "yandex", - "firefox", - "waterfox", - "librewolf", - "safari", - "chromium-based", - "gecko-based", - "firefox-based", - "webkit-based" -]New value: +[ + "chrome", + "chromium", + "edge", + "brave", + "opera", + "vivaldi", + "yandex", + "firefox", + "waterfox", + "librewolf", + "zen", + "floorp", + "safari", + "chromium-based", + "gecko-based", + "firefox-based", + "webkit-based" +] - added
Input schema / properties / outputPathAdded value: +{ + "description": "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.", + "type": "string" +}
- Added
extension_workspace_create
1 tool update
v10.9.0- Changed
extension_preview_web1 field changed- changed
Input schema / properties / share / descriptionPrevious value: -"Upload the built dist and return a public link (share.previewUrl) that renders those exact bytes for anyone: no install, sign-in or dev server. It also serves the build as a zip (share.zipUrl), so sharing hands over the code. Needs a token scoped to an extension.dev project (extension_auth or EXTENSION_DEV_TOKEN); without one you get a login hint and the local preview still succeeds. Live until share.expiresAt; DELETE share.revokeUrl to kill it sooner. Revocation is permanent, and re-sharing an unchanged build returns the same link unless it was revoked, so each share is also appended to the project's gitignored .extension.dev/shared-previews.json."New value: +"Upload the built dist and return a public link (share.previewUrl) that renders those exact bytes for anyone: no install, sign-in or dev server. Uploading runs on extension.dev's machines and counts against your free allowance; left false, the result's share property says what the local deepLink needs, what share:true spends, and the exact call to get a shareable link. It also serves the build as a zip (share.zipUrl), so sharing hands over the code. Needs a token scoped to an extension.dev project (extension_auth or EXTENSION_DEV_TOKEN); without one you get a login hint and the local preview still succeeds. Live until share.expiresAt; DELETE share.revokeUrl to kill it sooner. Revocation is permanent, and re-sharing an unchanged build returns the same link unless it was revoked, so each share is also appended to the project's gitignored .extension.dev/shared-previews.json."
5 tool updates
v10.8.0- Added
extension_assert - Added
extension_project_create - Changed
extension_release_promote1 field changed- added
Input schema / properties / approvalIdAdded value: +{ + "description": "The approval handle returned by a prior approval-required response. Promoting changes what a public channel serves and is not reversible in place, so when the platform's approval gate is on this needs a human approval: call once without this to get an approval id and URL, have a human approve at extension.dev, then call again with the same id.", + "type": "string" +}
- Changed
extension_shares1 field changed- added
Input schema / properties / approvalIdAdded value: +{ + "description": "The approval handle returned by a prior approval-required response for a revoke. Revoking permanently burns a share and cannot be undone, so when the platform's approval gate is on this needs a human approval: call revoke once without this to get an approval id and URL, have a human approve at extension.dev, then call revoke again with the same id. Listing never needs it.", + "type": "string" +}
- Changed
extension_submit1 field changed- added
Input schema / properties / approvalIdAdded value: +{ + "description": "The approval handle returned by a prior approval-required response for a real submission. A real submission (dryRun:false) is irreversible and needs a human approval when the platform's approval gate is on: call once without this to get an approval id and URL, have a human approve at extension.dev, then call again with the same id. A dry run never needs it.", + "type": "string" +}
2 tool updates
v10.3.1- Changed
extension_auth1 field changed- changed
Input schema / properties / project / descriptionPrevious value: -"login: target project as '<workspace>/<project>'; the token is scoped to it."New value: +"login: target project as '<workspace>/<project>'; the token is scoped to it. The slug pair is the console address bar: an existing project's page is console.extension.dev/<workspace>/<project>. Create one at extension.dev/new if none exists yet."
- Changed
extension_build1 field changed- changed
Input schema / properties / bundleId / descriptionPrevious value: -"Safari targets only: a reverse-DNS bundle identifier you own, such as com.acme.readinglist. Without one the app is packaged under a generated dev.extensionjs.* identifier that Apple will not accept for distribution."New value: +"Safari targets only: a reverse-DNS bundle identifier you own, such as com.acme.readinglist. Without one the app is packaged under a generated dev.extensionjs.* identifier derived from the app name, which every project built from the same template shares, and the first team to register it takes it."
28 tool updates
v10.1.0- First observed
extension_add_feature - First observed
extension_analyze - First observed
extension_auth - First observed
extension_browsers - First observed
extension_build - First observed
extension_create - First observed
extension_dev - First observed
extension_doctor - First observed
extension_dom_snapshot - First observed
extension_eval - First observed
extension_inspect - First observed
extension_list_extensions - First observed
extension_logs - First observed
extension_manifest_validate - First observed
extension_open - First observed
extension_preview_web - First observed
extension_publish - First observed
extension_release_promote - First observed
extension_release_status - First observed
extension_reload - First observed
extension_shares - First observed
extension_start - First observed
extension_stop - First observed
extension_storage - First observed
extension_submit - First observed
extension_templates - First observed
extension_theme_verify - First observed
extension_wait
TDQS
Scored across 32 tools
There is heavy surface overlap between extension_build/extension_dev/extension_start/extension_preview_web and between extension_inspect/extension_dom_snapshot/extension_eval, but the descriptions explicitly delineate each (e.g. 'ONLY this tool pierces closed shadow roots', 'use extension_dom_snapshot to choose which tab'). An agent can generally pick correctly, though the sheer density of cross-references makes misselection plausible.
Every tool uses the extension_ prefix with snake_case, and most follow a predictable verb or verb_noun shape (extension_build, extension_create, extension_release_promote, extension_manifest_validate). A few noun-only names (extension_templates, extension_browsers, extension_shares) are exceptions but consistent within their purpose.
At 32 tools the set is heavy, exceeding the 25-tool 'too many' threshold, though the domain (full extension lifecycle: scaffold, build, dev, inspect, publish, store submit, auth, releases) is genuinely broad so most tools earn their place. It still leans toward being a lot of surface for an agent to navigate.
The surface covers the whole lifecycle: templating, scaffolding, build, dev/start/preview sessions, inspection, eval, storage, reload, stop, auth, workspace/project creation, publish, release promotion/status, store submission, manifest validation, diagnoses, and docs. No obvious dead ends or missing lifecycle operations.
Maintenance
Related MCP Connectors
Live browser debugging for AI assistants — DOM, console, network via MCP.
A paid remote MCP for AI agent browser DevTools MCP, built to return verdicts, receipts, usage logs,
Hosted MCP with 91 agent tools: X, domains, SEO, Maps, Trends, Search, YouTube, TikTok, and more.
Your org's AI agents, tasks, runs, search, and brain files as MCP tools and resources.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI agents to control the Google Chrome browser through a Node.js WebSocket bridge and a dedicated browser extension. It provides tools for capturing screenshots, executing JavaScript, managing tabs, and extracting page content via the MCP protocol.2-
- AlicenseNot gradedqualityCmaintenanceLets AI coding agents control and inspect a live Chrome browser via MCP, providing Chrome DevTools capabilities for automation, debugging, and performance analysis.7 npmApache 2.0
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to control and interact with a Chrome browser via MCP, providing tools for navigation, screenshots, clicking, form filling, content extraction, and tab management.-
- FlicenseNot gradedqualityBmaintenanceExposes your Chrome/Edge browser as MCP tools for AI agents, enabling browser automation through a Chrome extension with 47 tools for navigation, interaction, page reading, and more.12 npm-