@extension.dev/mcp 4.2.1 → 4.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/README.md +1 -1
- package/bin/extension-mcp.js +0 -0
- package/dist/module.js +127 -35
- package/dist/src/lib/act.d.ts +12 -0
- package/dist/src/lib/session-browser.d.ts +7 -0
- package/dist/src/tools/dom-inspect.d.ts +1 -1
- package/dist/src/tools/eval.d.ts +1 -1
- package/dist/src/tools/list-extensions.d.ts +1 -1
- package/dist/src/tools/logs-schema.d.ts +0 -1
- package/dist/src/tools/open.d.ts +1 -1
- package/dist/src/tools/reload.d.ts +1 -1
- package/dist/src/tools/source-inspect.d.ts +1 -1
- package/dist/src/tools/storage.d.ts +1 -1
- package/dist/src/tools/wait.d.ts +0 -1
- package/package.json +10 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.2.2
|
|
4
|
+
|
|
5
|
+
Agent-ergonomics release from the 4.2.1 fresh-eyes walk: the two changes
|
|
6
|
+
that removed nearly all friction a real MCP client hit.
|
|
7
|
+
|
|
8
|
+
- Session-aware browser default. Tools that target a running session
|
|
9
|
+
(`extension_logs`, `extension_reload`, `extension_eval`,
|
|
10
|
+
`extension_storage`, `extension_open`, `extension_dom_inspect`,
|
|
11
|
+
`extension_list_extensions`, `extension_source_inspect`,
|
|
12
|
+
`extension_wait`) no longer hard-default `browser` to a constant that
|
|
13
|
+
could disagree with the session `extension_dev` actually started.
|
|
14
|
+
Omitting `browser` now resolves to the active session's browser:
|
|
15
|
+
in-memory registry first, then the freshest live `ready.json` contract
|
|
16
|
+
on disk (dead pids ignored), then the old constant. Starting a session
|
|
17
|
+
with `browser: "chrome"` and calling `extension_logs` with no args now
|
|
18
|
+
just works instead of erroring about a missing chromium channel.
|
|
19
|
+
- Error hints speak the MCP tool surface, not the CLI. Act-verb error
|
|
20
|
+
prose is rewritten before returning: `` `extension dev
|
|
21
|
+
--browser=chromium --allow-control` `` becomes `extension_dev with
|
|
22
|
+
{ browser: "chromium", allowControl: true }`, and stray
|
|
23
|
+
`--allow-control` / `--allow-eval` / `--browser=<x>` mentions become
|
|
24
|
+
their tool-argument names. Result data is never touched — only
|
|
25
|
+
error/hint prose. Tool descriptions now name `allowControl` /
|
|
26
|
+
`allowEval` directly, so agents no longer discover the gates by
|
|
27
|
+
fuzzing the schema.
|
|
28
|
+
- The no-channel error now names the session that IS running ("Active
|
|
29
|
+
session browser(s) for this project: chrome — pass that as `browser`"),
|
|
30
|
+
so an agent retargets instead of spawning a second, conflicting
|
|
31
|
+
session. Same for the `extension_logs` follow miss.
|
|
32
|
+
- `extension_list_extensions` / `extension_source_inspect` accept
|
|
33
|
+
`browser: "chromium"` (the default dev target) instead of rejecting it
|
|
34
|
+
as non-Chromium.
|
|
35
|
+
- Tests: session-browser resolution + hint-translation suite (137 total).
|
|
36
|
+
|
|
37
|
+
## 4.2.1
|
|
38
|
+
|
|
39
|
+
`extension_build` failures no longer kill the MCP server process
|
|
40
|
+
(fatal-error path returned a rejected promise the server didn't catch).
|
|
41
|
+
CDP-dependent tools resolve the debug port from the session's ready
|
|
42
|
+
contract instead of assuming 9222 (plus a test-only engine pin
|
|
43
|
+
override, `EXTENSION_MCP_CLI_VERSION`).
|
|
44
|
+
|
|
3
45
|
## 4.2.0
|
|
4
46
|
|
|
5
47
|
Session lifecycle + determinism release. Tool count 27 -> 28.
|
package/README.md
CHANGED
|
@@ -96,7 +96,7 @@ cp node_modules/@extension.dev/mcp/claude/commands/*.md ~/my-extension/.claude/c
|
|
|
96
96
|
| see | `extension_dom_inspect` | CDP-free DOM snapshot |
|
|
97
97
|
| see | `extension_list_extensions` | List loaded extensions (Chromium) |
|
|
98
98
|
| see | `extension_logs` | Stream logs from every context |
|
|
99
|
-
| act | `extension_eval` | Evaluate in a context (
|
|
99
|
+
| act | `extension_eval` | Evaluate in a context (needs `allowEval: true` on `extension_dev`) |
|
|
100
100
|
| act | `extension_storage` | Read/write `chrome.storage` |
|
|
101
101
|
| act | `extension_reload` | Reload extension or tab |
|
|
102
102
|
| act | `extension_open` | Open a surface / trigger `action`, `command` |
|
package/bin/extension-mcp.js
CHANGED
|
File without changes
|
package/dist/module.js
CHANGED
|
@@ -183,7 +183,7 @@ __webpack_require__.d(whoami_namespaceObject, {
|
|
|
183
183
|
handler: ()=>whoami_handler,
|
|
184
184
|
schema: ()=>whoami_schema
|
|
185
185
|
});
|
|
186
|
-
var package_namespaceObject = JSON.parse('{"rE":"4.2.
|
|
186
|
+
var package_namespaceObject = JSON.parse('{"rE":"4.2.2","El":{"OP":"^4.0.8"}}');
|
|
187
187
|
const create_schema = {
|
|
188
188
|
name: "extension_create",
|
|
189
189
|
description: "Create a new browser extension project from a template in the extension.dev template catalog. Use extension_list_templates to see available options.",
|
|
@@ -1620,6 +1620,66 @@ function isCdpEndpoint(port) {
|
|
|
1620
1620
|
});
|
|
1621
1621
|
});
|
|
1622
1622
|
}
|
|
1623
|
+
function contractSightings(projectPath) {
|
|
1624
|
+
const root = node_path.resolve(projectPath, "dist", "extension-js");
|
|
1625
|
+
let dirs;
|
|
1626
|
+
try {
|
|
1627
|
+
dirs = node_fs.readdirSync(root);
|
|
1628
|
+
} catch {
|
|
1629
|
+
return [];
|
|
1630
|
+
}
|
|
1631
|
+
const sightings = [];
|
|
1632
|
+
for (const dir of dirs){
|
|
1633
|
+
const readyPath = node_path.join(root, dir, "ready.json");
|
|
1634
|
+
try {
|
|
1635
|
+
const stat = node_fs.statSync(readyPath);
|
|
1636
|
+
const contract = JSON.parse(node_fs.readFileSync(readyPath, "utf8"));
|
|
1637
|
+
if (contract?.status !== "ready") continue;
|
|
1638
|
+
sightings.push({
|
|
1639
|
+
browser: dir,
|
|
1640
|
+
mtimeMs: stat.mtimeMs,
|
|
1641
|
+
pid: "number" == typeof contract.pid ? contract.pid : void 0
|
|
1642
|
+
});
|
|
1643
|
+
} catch {}
|
|
1644
|
+
}
|
|
1645
|
+
return sightings;
|
|
1646
|
+
}
|
|
1647
|
+
function pidAlive(pid) {
|
|
1648
|
+
try {
|
|
1649
|
+
process.kill(pid, 0);
|
|
1650
|
+
return true;
|
|
1651
|
+
} catch {
|
|
1652
|
+
return false;
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
function knownSessionBrowsers(projectPath) {
|
|
1656
|
+
const resolved = node_path.resolve(projectPath);
|
|
1657
|
+
const browsers = [];
|
|
1658
|
+
for (const session of listSessions())if (node_path.resolve(session.projectPath) === resolved) browsers.push(session.browser);
|
|
1659
|
+
for (const sighting of contractSightings(projectPath))if (void 0 === sighting.pid || pidAlive(sighting.pid)) browsers.push(sighting.browser);
|
|
1660
|
+
return Array.from(new Set(browsers));
|
|
1661
|
+
}
|
|
1662
|
+
function resolveSessionBrowser(projectPath, explicit, fallback = "chromium") {
|
|
1663
|
+
if (explicit) return {
|
|
1664
|
+
browser: explicit,
|
|
1665
|
+
source: "explicit"
|
|
1666
|
+
};
|
|
1667
|
+
const resolved = node_path.resolve(projectPath);
|
|
1668
|
+
const mine = listSessions().filter((s)=>node_path.resolve(s.projectPath) === resolved);
|
|
1669
|
+
if (mine.length > 0) return {
|
|
1670
|
+
browser: mine[mine.length - 1].browser,
|
|
1671
|
+
source: "session"
|
|
1672
|
+
};
|
|
1673
|
+
const sightings = contractSightings(projectPath).filter((s)=>void 0 === s.pid || pidAlive(s.pid)).sort((a, b)=>b.mtimeMs - a.mtimeMs);
|
|
1674
|
+
if (sightings.length > 0) return {
|
|
1675
|
+
browser: sightings[0].browser,
|
|
1676
|
+
source: "contract"
|
|
1677
|
+
};
|
|
1678
|
+
return {
|
|
1679
|
+
browser: fallback,
|
|
1680
|
+
source: "fallback"
|
|
1681
|
+
};
|
|
1682
|
+
}
|
|
1623
1683
|
const source_inspect_schema = {
|
|
1624
1684
|
name: "extension_source_inspect",
|
|
1625
1685
|
description: "Inspect a running extension's live state via Chrome DevTools Protocol: full HTML (with shadow DOM), DOM structure, content script injection, console messages, and CSS selector queries. Requires an active dev or start session.",
|
|
@@ -1663,7 +1723,7 @@ const source_inspect_schema = {
|
|
|
1663
1723
|
},
|
|
1664
1724
|
browser: {
|
|
1665
1725
|
type: "string",
|
|
1666
|
-
|
|
1726
|
+
description: "Browser session to target. Defaults to the active dev session's browser for this project."
|
|
1667
1727
|
},
|
|
1668
1728
|
maxBytes: {
|
|
1669
1729
|
type: "number",
|
|
@@ -1682,7 +1742,7 @@ const source_inspect_schema = {
|
|
|
1682
1742
|
}
|
|
1683
1743
|
};
|
|
1684
1744
|
async function source_inspect_handler(args) {
|
|
1685
|
-
const browser = args.browser
|
|
1745
|
+
const { browser } = resolveSessionBrowser(args.projectPath, args.browser, "chrome");
|
|
1686
1746
|
const include = new Set(args.include ?? [
|
|
1687
1747
|
"summary",
|
|
1688
1748
|
"meta",
|
|
@@ -1691,12 +1751,13 @@ async function source_inspect_handler(args) {
|
|
|
1691
1751
|
const maxBytes = args.maxBytes ?? 262144;
|
|
1692
1752
|
const isChromium = [
|
|
1693
1753
|
"chrome",
|
|
1754
|
+
"chromium",
|
|
1694
1755
|
"edge",
|
|
1695
1756
|
"chromium-based"
|
|
1696
1757
|
].includes(browser);
|
|
1697
1758
|
if (!isChromium) return JSON.stringify({
|
|
1698
1759
|
error: `Source inspection for ${browser} uses RDP (Remote Debug Protocol). Currently only Chromium CDP is supported.`,
|
|
1699
|
-
hint:
|
|
1760
|
+
hint: 'Pass browser: "chrome" (against a Chromium-family dev session).'
|
|
1700
1761
|
});
|
|
1701
1762
|
const resolved = await resolveCdpPort(args.projectPath, browser);
|
|
1702
1763
|
if (!resolved) return JSON.stringify({
|
|
@@ -1797,7 +1858,7 @@ const list_extensions_schema = {
|
|
|
1797
1858
|
},
|
|
1798
1859
|
browser: {
|
|
1799
1860
|
type: "string",
|
|
1800
|
-
|
|
1861
|
+
description: "Browser session to target. Defaults to the active dev session's browser for this project."
|
|
1801
1862
|
}
|
|
1802
1863
|
},
|
|
1803
1864
|
required: [
|
|
@@ -1806,15 +1867,16 @@ const list_extensions_schema = {
|
|
|
1806
1867
|
}
|
|
1807
1868
|
};
|
|
1808
1869
|
async function list_extensions_handler(args) {
|
|
1809
|
-
const browser = args.browser
|
|
1870
|
+
const { browser } = resolveSessionBrowser(args.projectPath, args.browser, "chrome");
|
|
1810
1871
|
const isChromium = [
|
|
1811
1872
|
"chrome",
|
|
1873
|
+
"chromium",
|
|
1812
1874
|
"edge",
|
|
1813
1875
|
"chromium-based"
|
|
1814
1876
|
].includes(browser);
|
|
1815
1877
|
if (!isChromium) return JSON.stringify({
|
|
1816
1878
|
error: `Listing extensions for ${browser} uses RDP (Remote Debug Protocol). Currently only Chromium CDP is supported.`,
|
|
1817
|
-
hint:
|
|
1879
|
+
hint: 'Pass browser: "chrome" (against a Chromium-family dev session).'
|
|
1818
1880
|
});
|
|
1819
1881
|
const resolved = await resolveCdpPort(args.projectPath, browser);
|
|
1820
1882
|
if (!resolved) return JSON.stringify({
|
|
@@ -1950,8 +2012,7 @@ const logs_schema_schema = {
|
|
|
1950
2012
|
},
|
|
1951
2013
|
browser: {
|
|
1952
2014
|
type: "string",
|
|
1953
|
-
|
|
1954
|
-
description: "Which dist/extension-js/<browser>/ to read. Defaults to chromium (the default dev target)."
|
|
2015
|
+
description: "Which dist/extension-js/<browser>/ to read. Defaults to the active dev session's browser for this project (falls back to chromium)."
|
|
1955
2016
|
},
|
|
1956
2017
|
level: {
|
|
1957
2018
|
type: "string",
|
|
@@ -2092,10 +2153,14 @@ async function readFromFile(args, browser, limit) {
|
|
|
2092
2153
|
}
|
|
2093
2154
|
async function readFromStream(args, browser, limit) {
|
|
2094
2155
|
const ready = readReadyContract(args.projectPath, browser);
|
|
2095
|
-
if (!ready)
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2156
|
+
if (!ready) {
|
|
2157
|
+
const running = knownSessionBrowsers(args.projectPath).filter((b)=>b !== browser);
|
|
2158
|
+
const retarget = running.length ? `An active session exists for browser(s): ${running.join(", ")} — pass that as \`browser\`. Otherwise run` : "Run";
|
|
2159
|
+
return JSON.stringify({
|
|
2160
|
+
error: `No active control channel found for ${browser}.`,
|
|
2161
|
+
hint: `${retarget} extension_dev (browser: ${browser}) and wait for it to be ready, then retry. For past logs without a live channel, call without follow.`
|
|
2162
|
+
});
|
|
2163
|
+
}
|
|
2099
2164
|
const followMs = Math.min(Math.max(args.followMs ?? 4000, 500), 15000);
|
|
2100
2165
|
const matches = makeFilter(args);
|
|
2101
2166
|
const events = [];
|
|
@@ -2158,11 +2223,27 @@ async function readFromStream(args, browser, limit) {
|
|
|
2158
2223
|
});
|
|
2159
2224
|
}
|
|
2160
2225
|
async function logs_handler(args) {
|
|
2161
|
-
const browser = args.browser
|
|
2226
|
+
const { browser } = resolveSessionBrowser(args.projectPath, args.browser);
|
|
2162
2227
|
const limit = args.limit && args.limit > 0 ? args.limit : 200;
|
|
2163
2228
|
if (args.follow) return readFromStream(args, browser, limit);
|
|
2164
2229
|
return readFromFile(args, browser, limit);
|
|
2165
2230
|
}
|
|
2231
|
+
function toMcpSpeak(text) {
|
|
2232
|
+
return text.replace(/`?extension dev(?: [^\s`]*)? --browser[= ]([\w-]+) --allow-control`?/g, 'extension_dev with { browser: "$1", allowControl: true }').replace(/--allow-control/g, "allowControl: true (extension_dev)").replace(/--allow-eval/g, "allowEval: true (extension_dev)").replace(/--browser[= ]([\w-]+)/g, 'browser: "$1"').replace(/`extension dev`/g, "extension_dev").replace(/\bextension dev\b/g, "extension_dev");
|
|
2233
|
+
}
|
|
2234
|
+
function withSessionContext(message, projectPath) {
|
|
2235
|
+
if (!/no active control channel/i.test(message)) return message;
|
|
2236
|
+
const running = knownSessionBrowsers(projectPath);
|
|
2237
|
+
if (0 === running.length) return message;
|
|
2238
|
+
return `${message} Active session browser(s) for this project: ${running.join(", ")} — pass that as \`browser\`, or restart it via extension_dev with allowControl: true if the control channel is off.`;
|
|
2239
|
+
}
|
|
2240
|
+
function translateFrame(frame, projectPath) {
|
|
2241
|
+
if (!frame || false !== frame.ok) return frame;
|
|
2242
|
+
if (frame.error && "string" == typeof frame.error.message) frame.error.message = withSessionContext(toMcpSpeak(frame.error.message), projectPath);
|
|
2243
|
+
if ("string" == typeof frame.error?.hint) frame.error.hint = toMcpSpeak(frame.error.hint);
|
|
2244
|
+
if ("string" == typeof frame.hint) frame.hint = toMcpSpeak(frame.hint);
|
|
2245
|
+
return frame;
|
|
2246
|
+
}
|
|
2166
2247
|
async function runActVerb(args, projectPath, timeoutMs) {
|
|
2167
2248
|
const { code, stdout, stderr } = await runExtensionCli([
|
|
2168
2249
|
...args,
|
|
@@ -2174,14 +2255,16 @@ async function runActVerb(args, projectPath, timeoutMs) {
|
|
|
2174
2255
|
});
|
|
2175
2256
|
const out = stdout.trim();
|
|
2176
2257
|
if (out) try {
|
|
2177
|
-
JSON.parse(out);
|
|
2258
|
+
const frame = JSON.parse(out);
|
|
2259
|
+
if (frame && false === frame.ok) return JSON.stringify(translateFrame(frame, projectPath));
|
|
2178
2260
|
return out;
|
|
2179
2261
|
} catch {}
|
|
2262
|
+
const message = stderr.trim() || `extension exited with code ${code}`;
|
|
2180
2263
|
return JSON.stringify({
|
|
2181
2264
|
ok: false,
|
|
2182
2265
|
error: {
|
|
2183
2266
|
name: "CliError",
|
|
2184
|
-
message:
|
|
2267
|
+
message: withSessionContext(toMcpSpeak(message), projectPath)
|
|
2185
2268
|
}
|
|
2186
2269
|
});
|
|
2187
2270
|
}
|
|
@@ -2196,7 +2279,7 @@ function commonFlags(args) {
|
|
|
2196
2279
|
}
|
|
2197
2280
|
const eval_schema = {
|
|
2198
2281
|
name: "extension_eval",
|
|
2199
|
-
description: "Evaluate an expression in a running extension context (service worker, content script, popup, options, sidebar). Requires the dev session to be started with
|
|
2282
|
+
description: "Evaluate an expression in a running extension context (service worker, content script, popup, options, sidebar). Requires the dev session to be started with allowEval: true (extension_dev; writes a 0600 session token the CLI reads). Wraps `extension eval`.",
|
|
2200
2283
|
inputSchema: {
|
|
2201
2284
|
type: "object",
|
|
2202
2285
|
properties: {
|
|
@@ -2232,7 +2315,7 @@ const eval_schema = {
|
|
|
2232
2315
|
},
|
|
2233
2316
|
browser: {
|
|
2234
2317
|
type: "string",
|
|
2235
|
-
|
|
2318
|
+
description: "Browser session to target. Defaults to the active dev session's browser for this project."
|
|
2236
2319
|
},
|
|
2237
2320
|
timeout: {
|
|
2238
2321
|
type: "number",
|
|
@@ -2246,16 +2329,20 @@ const eval_schema = {
|
|
|
2246
2329
|
}
|
|
2247
2330
|
};
|
|
2248
2331
|
async function eval_handler(args) {
|
|
2332
|
+
const { browser } = resolveSessionBrowser(args.projectPath, args.browser);
|
|
2249
2333
|
return runActVerb([
|
|
2250
2334
|
"eval",
|
|
2251
2335
|
args.expression,
|
|
2252
2336
|
args.projectPath,
|
|
2253
|
-
...commonFlags(
|
|
2337
|
+
...commonFlags({
|
|
2338
|
+
...args,
|
|
2339
|
+
browser
|
|
2340
|
+
})
|
|
2254
2341
|
], args.projectPath, args.timeout);
|
|
2255
2342
|
}
|
|
2256
2343
|
const storage_schema = {
|
|
2257
2344
|
name: "extension_storage",
|
|
2258
|
-
description: "Read or write chrome.storage in a running extension. Requires the dev session to be started with
|
|
2345
|
+
description: "Read or write chrome.storage in a running extension. Requires the dev session to be started with allowControl: true (extension_dev). Wraps `extension storage get|set`.",
|
|
2259
2346
|
inputSchema: {
|
|
2260
2347
|
type: "object",
|
|
2261
2348
|
properties: {
|
|
@@ -2301,7 +2388,7 @@ const storage_schema = {
|
|
|
2301
2388
|
},
|
|
2302
2389
|
browser: {
|
|
2303
2390
|
type: "string",
|
|
2304
|
-
|
|
2391
|
+
description: "Browser session to target. Defaults to the active dev session's browser for this project."
|
|
2305
2392
|
},
|
|
2306
2393
|
timeout: {
|
|
2307
2394
|
type: "number",
|
|
@@ -2315,6 +2402,7 @@ const storage_schema = {
|
|
|
2315
2402
|
}
|
|
2316
2403
|
};
|
|
2317
2404
|
async function storage_handler(args) {
|
|
2405
|
+
const { browser } = resolveSessionBrowser(args.projectPath, args.browser);
|
|
2318
2406
|
const cli = [
|
|
2319
2407
|
"storage",
|
|
2320
2408
|
args.action,
|
|
@@ -2333,13 +2421,13 @@ async function storage_handler(args) {
|
|
|
2333
2421
|
cli.push("--value", JSON.stringify(args.value));
|
|
2334
2422
|
}
|
|
2335
2423
|
if (args.context) cli.push("--context", args.context);
|
|
2336
|
-
|
|
2424
|
+
cli.push("--browser", browser);
|
|
2337
2425
|
if (null != args.timeout) cli.push("--timeout", String(args.timeout));
|
|
2338
2426
|
return runActVerb(cli, args.projectPath, args.timeout);
|
|
2339
2427
|
}
|
|
2340
2428
|
const reload_schema = {
|
|
2341
2429
|
name: "extension_reload",
|
|
2342
|
-
description: "Reload a running extension (background) or a tab. Requires the dev session to be started with
|
|
2430
|
+
description: "Reload a running extension (background) or a tab. Requires the dev session to be started with allowControl: true (extension_dev). Wraps `extension reload`.",
|
|
2343
2431
|
inputSchema: {
|
|
2344
2432
|
type: "object",
|
|
2345
2433
|
properties: {
|
|
@@ -2362,7 +2450,7 @@ const reload_schema = {
|
|
|
2362
2450
|
},
|
|
2363
2451
|
browser: {
|
|
2364
2452
|
type: "string",
|
|
2365
|
-
|
|
2453
|
+
description: "Browser session to target. Defaults to the active dev session's browser for this project."
|
|
2366
2454
|
},
|
|
2367
2455
|
timeout: {
|
|
2368
2456
|
type: "number",
|
|
@@ -2375,15 +2463,19 @@ const reload_schema = {
|
|
|
2375
2463
|
}
|
|
2376
2464
|
};
|
|
2377
2465
|
async function reload_handler(args) {
|
|
2466
|
+
const { browser } = resolveSessionBrowser(args.projectPath, args.browser);
|
|
2378
2467
|
return runActVerb([
|
|
2379
2468
|
"reload",
|
|
2380
2469
|
args.projectPath,
|
|
2381
|
-
...commonFlags(
|
|
2470
|
+
...commonFlags({
|
|
2471
|
+
...args,
|
|
2472
|
+
browser
|
|
2473
|
+
})
|
|
2382
2474
|
], args.projectPath, args.timeout);
|
|
2383
2475
|
}
|
|
2384
2476
|
const open_schema = {
|
|
2385
2477
|
name: "extension_open",
|
|
2386
|
-
description: "Open an extension surface or replay an event in a running session. 'popup'/'options'/'sidebar' open UI surfaces. 'action' triggers the toolbar action: opens the action's popup, or (no popup) replays chrome.action.onClicked. 'command' replays a chrome.commands.onCommand keyboard shortcut (pass `name`). NOTE: action/command replay invokes your listener WITHOUT a user gesture, so the gesture-derived activeTab grant does not apply (the result includes gesture:false and a warning when activeTab is declared). Requires
|
|
2478
|
+
description: "Open an extension surface or replay an event in a running session. 'popup'/'options'/'sidebar' open UI surfaces. 'action' triggers the toolbar action: opens the action's popup, or (no popup) replays chrome.action.onClicked. 'command' replays a chrome.commands.onCommand keyboard shortcut (pass `name`). NOTE: action/command replay invokes your listener WITHOUT a user gesture, so the gesture-derived activeTab grant does not apply (the result includes gesture:false and a warning when activeTab is declared). Requires the dev session to be started with allowControl: true (extension_dev). Wraps `extension open`.",
|
|
2387
2479
|
inputSchema: {
|
|
2388
2480
|
type: "object",
|
|
2389
2481
|
properties: {
|
|
@@ -2408,7 +2500,7 @@ const open_schema = {
|
|
|
2408
2500
|
},
|
|
2409
2501
|
browser: {
|
|
2410
2502
|
type: "string",
|
|
2411
|
-
|
|
2503
|
+
description: "Browser session to target. Defaults to the active dev session's browser for this project."
|
|
2412
2504
|
},
|
|
2413
2505
|
timeout: {
|
|
2414
2506
|
type: "number",
|
|
@@ -2422,19 +2514,20 @@ const open_schema = {
|
|
|
2422
2514
|
}
|
|
2423
2515
|
};
|
|
2424
2516
|
async function open_handler(args) {
|
|
2517
|
+
const { browser } = resolveSessionBrowser(args.projectPath, args.browser);
|
|
2425
2518
|
const cli = [
|
|
2426
2519
|
"open",
|
|
2427
2520
|
args.surface,
|
|
2428
2521
|
args.projectPath
|
|
2429
2522
|
];
|
|
2430
2523
|
if ("command" === args.surface && args.name) cli.push("--name", args.name);
|
|
2431
|
-
|
|
2524
|
+
cli.push("--browser", browser);
|
|
2432
2525
|
if (null != args.timeout) cli.push("--timeout", String(args.timeout));
|
|
2433
2526
|
return runActVerb(cli, args.projectPath, args.timeout);
|
|
2434
2527
|
}
|
|
2435
2528
|
const dom_inspect_schema = {
|
|
2436
2529
|
name: "extension_dom_inspect",
|
|
2437
|
-
description: "Inspect a page/content-script DOM via the agent bridge (CDP-free, localhost). Returns a structured snapshot (counts, extension roots, open shadow roots, optional capped HTML). Requires
|
|
2530
|
+
description: "Inspect a page/content-script DOM via the agent bridge (CDP-free, localhost). Returns a structured snapshot (counts, extension roots, open shadow roots, optional capped HTML). Requires the dev session to be started with allowControl: true (extension_dev). For closed shadow roots or deep CDP inspection use extension_source_inspect. Wraps `extension inspect`.",
|
|
2438
2531
|
inputSchema: {
|
|
2439
2532
|
type: "object",
|
|
2440
2533
|
properties: {
|
|
@@ -2483,7 +2576,7 @@ const dom_inspect_schema = {
|
|
|
2483
2576
|
},
|
|
2484
2577
|
browser: {
|
|
2485
2578
|
type: "string",
|
|
2486
|
-
|
|
2579
|
+
description: "Browser session to target. Defaults to the active dev session's browser for this project."
|
|
2487
2580
|
},
|
|
2488
2581
|
timeout: {
|
|
2489
2582
|
type: "number",
|
|
@@ -2519,7 +2612,7 @@ async function dom_inspect_handler(args) {
|
|
|
2519
2612
|
if (args.include?.length) cli.push("--include", args.include.join(","));
|
|
2520
2613
|
if (null != args.maxBytes) cli.push("--max-bytes", String(args.maxBytes));
|
|
2521
2614
|
if (null != args.withConsole) cli.push("--with-console", String(args.withConsole));
|
|
2522
|
-
|
|
2615
|
+
cli.push("--browser", resolveSessionBrowser(args.projectPath, args.browser).browser);
|
|
2523
2616
|
if (null != args.timeout) cli.push("--timeout", String(args.timeout));
|
|
2524
2617
|
return runActVerb(cli, args.projectPath, args.timeout);
|
|
2525
2618
|
}
|
|
@@ -2676,8 +2769,7 @@ const wait_schema = {
|
|
|
2676
2769
|
},
|
|
2677
2770
|
browser: {
|
|
2678
2771
|
type: "string",
|
|
2679
|
-
|
|
2680
|
-
description: "Browser to check readiness for"
|
|
2772
|
+
description: "Browser to check readiness for. Defaults to the active dev session's browser for this project."
|
|
2681
2773
|
},
|
|
2682
2774
|
timeout: {
|
|
2683
2775
|
type: "number",
|
|
@@ -2691,7 +2783,7 @@ const wait_schema = {
|
|
|
2691
2783
|
}
|
|
2692
2784
|
};
|
|
2693
2785
|
async function wait_handler(args) {
|
|
2694
|
-
const browser = args.browser
|
|
2786
|
+
const { browser } = resolveSessionBrowser(args.projectPath, args.browser, "chrome");
|
|
2695
2787
|
const timeout = args.timeout ?? 60000;
|
|
2696
2788
|
const readyPath = node_path.resolve(args.projectPath, "dist", "extension-js", browser, "ready.json");
|
|
2697
2789
|
const start = Date.now();
|
|
@@ -3156,7 +3248,7 @@ async function install_browser_handler(args) {
|
|
|
3156
3248
|
status: "installed",
|
|
3157
3249
|
browser: args.browser,
|
|
3158
3250
|
duration: Date.now() - start,
|
|
3159
|
-
hint: `Browser "${args.browser}" is now available. Use extension_dev or extension_start with
|
|
3251
|
+
hint: `Browser "${args.browser}" is now available. Use extension_dev or extension_start with browser: "${args.browser}".`
|
|
3160
3252
|
});
|
|
3161
3253
|
} catch (err) {
|
|
3162
3254
|
return JSON.stringify({
|
package/dist/src/lib/act.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translate CLI-speak in an error message into the MCP tool surface
|
|
3
|
+
* (fresh-eyes walk, friction #2). The CLI's hints say things like
|
|
4
|
+
* "Run `extension dev --browser=chromium --allow-control` first" — correct
|
|
5
|
+
* for a human at a terminal, a dead end for an agent that only has the MCP
|
|
6
|
+
* tools. Rewrite flags to their tool-argument names so the hint is actionable
|
|
7
|
+
* on the surface the caller is actually using. Result data is never touched —
|
|
8
|
+
* only error/hint prose.
|
|
9
|
+
*/
|
|
10
|
+
export declare function toMcpSpeak(text: string): string;
|
|
1
11
|
/**
|
|
2
12
|
* Run an `extension <verb> … --output json` act command and return its result
|
|
3
13
|
* JSON as a string (the MCP tool payload). The CLI prints the control-channel
|
|
@@ -6,6 +16,8 @@
|
|
|
6
16
|
*
|
|
7
17
|
* Per lockstep invariant #1 the act tools wrap the CLI verb rather than talking
|
|
8
18
|
* to the control WS directly — so MCP behavior can never drift from the CLI.
|
|
19
|
+
* Error PROSE is the one exception: hints are rewritten from CLI flags to MCP
|
|
20
|
+
* tool arguments before returning (see toMcpSpeak).
|
|
9
21
|
*/
|
|
10
22
|
export declare function runActVerb(args: string[], projectPath: string, timeoutMs?: number): Promise<string>;
|
|
11
23
|
/** Shared input fields for act tools. */
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface ResolvedBrowser {
|
|
2
|
+
browser: string;
|
|
3
|
+
source: "explicit" | "session" | "contract" | "fallback";
|
|
4
|
+
}
|
|
5
|
+
/** Browsers with a live session for this project (registry + disk contracts). */
|
|
6
|
+
export declare function knownSessionBrowsers(projectPath: string): string[];
|
|
7
|
+
export declare function resolveSessionBrowser(projectPath: string, explicit: string | undefined, fallback?: string): ResolvedBrowser;
|
package/dist/src/tools/eval.d.ts
CHANGED
package/dist/src/tools/open.d.ts
CHANGED
package/dist/src/tools/wait.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@extension.dev/mcp",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.2.
|
|
4
|
+
"version": "4.2.2",
|
|
5
5
|
"description": "MCP server that lets AI agents build, run, inspect, and publish browser extensions. 28 tools for scaffolding, live DOM inspection, log streaming, and store-ready builds across Chrome, Edge, and Firefox.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": {
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
"engines": {
|
|
21
21
|
"node": ">=20.18"
|
|
22
22
|
},
|
|
23
|
-
"packageManager": "pnpm@10.19.0",
|
|
24
23
|
"exports": {
|
|
25
24
|
".": {
|
|
26
25
|
"types": "./dist/module.d.ts",
|
|
@@ -40,15 +39,6 @@
|
|
|
40
39
|
"CHANGELOG.md",
|
|
41
40
|
"LICENSE"
|
|
42
41
|
],
|
|
43
|
-
"scripts": {
|
|
44
|
-
"clean": "rm -rf dist",
|
|
45
|
-
"watch": "rslib build --watch",
|
|
46
|
-
"compile": "rslib build",
|
|
47
|
-
"build": "pnpm run compile",
|
|
48
|
-
"start": "node bin/extension-mcp.js",
|
|
49
|
-
"test": "vitest run",
|
|
50
|
-
"prepublishOnly": "pnpm run test && pnpm run compile"
|
|
51
|
-
},
|
|
52
42
|
"publishConfig": {
|
|
53
43
|
"access": "public",
|
|
54
44
|
"registry": "https://registry.npmjs.org"
|
|
@@ -87,5 +77,13 @@
|
|
|
87
77
|
"@types/ws": "^8.18.1",
|
|
88
78
|
"typescript": "6.0.2",
|
|
89
79
|
"vitest": "^4.1.3"
|
|
80
|
+
},
|
|
81
|
+
"scripts": {
|
|
82
|
+
"clean": "rm -rf dist",
|
|
83
|
+
"watch": "rslib build --watch",
|
|
84
|
+
"compile": "rslib build",
|
|
85
|
+
"build": "pnpm run compile",
|
|
86
|
+
"start": "node bin/extension-mcp.js",
|
|
87
|
+
"test": "vitest run"
|
|
90
88
|
}
|
|
91
|
-
}
|
|
89
|
+
}
|