codex-control-chrome-mcp 1.3.0 → 1.3.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 +11 -1
- package/package.json +1 -1
- package/src/cli.js +7 -0
- package/src/mcp-server.js +64 -32
package/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,17 @@ This project follows semantic versioning.
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
-
## [1.3.
|
|
9
|
+
## [1.3.2] - 2026-07-04
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `codex-control-chrome-mcp --version` (also `-v` and `version`) prints the package name and version. Previously the CLI had no way to report its own version, so `-v`/`--version` fell through to `Unknown command`.
|
|
14
|
+
|
|
15
|
+
## [1.3.1] - 2026-07-04
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- `chrome_evaluate`, `chrome_navigate`, and `chrome_screenshot` now self-heal a stale debugger attachment instead of dead-ending on `Debugger is not attached`. Each tool already attaches before sending CDP commands, but the extension tracks attachments in memory: when Chrome tears an attachment down out-of-band (a competing debugger client, DevTools, or a renderer/process swap), that flag can go stale, so a fresh `attach` short-circuits and reports success without actually re-attaching and the next command fails with `Debugger is not attached`. The tab then stayed wedged — `attach` kept reporting `ok` while every command failed — and only a new tab recovered. These tools now retry once on that specific error by issuing a `detach` (which clears the stale flag; it may itself report "not attached", which is expected and ignored) followed by a real `attach`, so a previously wedged tab recovers automatically. The self-heal wrapper is covered by regression tests. This addresses recovery in the bridge only; the underlying churn comes from multiple debugger clients contending for the same tab, so reducing competing browser-control stacks still helps.
|
|
10
20
|
|
|
11
21
|
### Changed
|
|
12
22
|
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { DEFAULT_BROWSER, SUPPORTED_BROWSERS } from "./constants.js";
|
|
11
11
|
import { listBridgeSockets } from "./bridge-client.js";
|
|
12
12
|
import { probeLengthPrefixedSocket } from "./probe.js";
|
|
13
|
+
import { PACKAGE_NAME, PACKAGE_VERSION } from "./package-meta.js";
|
|
13
14
|
|
|
14
15
|
export async function runCli(argv) {
|
|
15
16
|
const args = argv.slice(2);
|
|
@@ -65,6 +66,11 @@ export async function runCli(argv) {
|
|
|
65
66
|
printJson(await probeLengthPrefixedSocket(socketPath));
|
|
66
67
|
return;
|
|
67
68
|
}
|
|
69
|
+
case "version":
|
|
70
|
+
case "--version":
|
|
71
|
+
case "-v":
|
|
72
|
+
process.stdout.write(`${PACKAGE_NAME} ${PACKAGE_VERSION}\n`);
|
|
73
|
+
return;
|
|
68
74
|
case "help":
|
|
69
75
|
case "--help":
|
|
70
76
|
case "-h":
|
|
@@ -157,6 +163,7 @@ Usage:
|
|
|
157
163
|
codex-control-chrome-mcp uninstall-native-host [--force] [--browser <chrome|edge|all>]
|
|
158
164
|
codex-control-chrome-mcp status [--browser <chrome|edge|all>]
|
|
159
165
|
codex-control-chrome-mcp probe-socket <socket-path>
|
|
166
|
+
codex-control-chrome-mcp --version
|
|
160
167
|
|
|
161
168
|
Notes:
|
|
162
169
|
--stdio is the MCP server mode for Agent tools.
|
package/src/mcp-server.js
CHANGED
|
@@ -229,15 +229,15 @@ function registerTools(server, runtime) {
|
|
|
229
229
|
url: z.string().url(),
|
|
230
230
|
},
|
|
231
231
|
},
|
|
232
|
-
async ({ tabId, url }) =>
|
|
233
|
-
await runtime
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
232
|
+
async ({ tabId, url }) =>
|
|
233
|
+
toolResult(await withReattach(runtime, tabId, async () => {
|
|
234
|
+
await executeCdp(runtime, { tabId, method: "Page.enable", params: {} });
|
|
235
|
+
return await executeCdp(runtime, {
|
|
236
|
+
tabId,
|
|
237
|
+
method: "Page.navigate",
|
|
238
|
+
params: { url },
|
|
239
|
+
});
|
|
240
|
+
})),
|
|
241
241
|
);
|
|
242
242
|
|
|
243
243
|
server.registerTool(
|
|
@@ -250,19 +250,19 @@ function registerTools(server, runtime) {
|
|
|
250
250
|
awaitPromise: z.boolean().default(true),
|
|
251
251
|
},
|
|
252
252
|
},
|
|
253
|
-
async ({ tabId, expression, awaitPromise }) =>
|
|
254
|
-
await runtime
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
253
|
+
async ({ tabId, expression, awaitPromise }) =>
|
|
254
|
+
toolResult(await withReattach(runtime, tabId, async () => {
|
|
255
|
+
await executeCdp(runtime, { tabId, method: "Runtime.enable", params: {} });
|
|
256
|
+
return await executeCdp(runtime, {
|
|
257
|
+
tabId,
|
|
258
|
+
method: "Runtime.evaluate",
|
|
259
|
+
params: {
|
|
260
|
+
expression,
|
|
261
|
+
awaitPromise,
|
|
262
|
+
returnByValue: true,
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
})),
|
|
266
266
|
);
|
|
267
267
|
|
|
268
268
|
server.registerTool(
|
|
@@ -274,16 +274,16 @@ function registerTools(server, runtime) {
|
|
|
274
274
|
format: z.enum(["png", "jpeg", "webp"]).default("png"),
|
|
275
275
|
},
|
|
276
276
|
},
|
|
277
|
-
async ({ tabId, format }) =>
|
|
278
|
-
await runtime
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
277
|
+
async ({ tabId, format }) =>
|
|
278
|
+
toolResult(await withReattach(runtime, tabId, async () => {
|
|
279
|
+
await executeCdp(runtime, { tabId, method: "Page.enable", params: {} });
|
|
280
|
+
return await executeCdp(runtime, {
|
|
281
|
+
tabId,
|
|
282
|
+
method: "Page.captureScreenshot",
|
|
283
|
+
params: { format, captureBeyondViewport: true },
|
|
284
|
+
timeoutMs: 30_000,
|
|
285
|
+
});
|
|
286
|
+
})),
|
|
287
287
|
);
|
|
288
288
|
|
|
289
289
|
server.registerTool(
|
|
@@ -319,6 +319,38 @@ function registerTools(server, runtime) {
|
|
|
319
319
|
);
|
|
320
320
|
}
|
|
321
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Attach the debugger, run a CDP sequence, and self-heal a stale-attach state.
|
|
324
|
+
*
|
|
325
|
+
* The Codex Chrome extension tracks debugger attachments in memory. When Chrome
|
|
326
|
+
* tears an attachment down out-of-band (a competing debugger client, DevTools, a
|
|
327
|
+
* renderer/process swap), that flag can go stale: a fresh `attach` short-circuits
|
|
328
|
+
* and reports success without actually re-attaching, so the next CDP command
|
|
329
|
+
* fails with "Debugger is not attached". A `detach` clears the stale flag (it may
|
|
330
|
+
* itself throw "not attached" — expected, and ignored), after which `attach`
|
|
331
|
+
* re-attaches for real. We retry the sequence once on that specific error.
|
|
332
|
+
*/
|
|
333
|
+
export async function withReattach(runtime, tabId, run) {
|
|
334
|
+
await runtime.request("attach", { tabId });
|
|
335
|
+
try {
|
|
336
|
+
return await run();
|
|
337
|
+
} catch (error) {
|
|
338
|
+
if (!isNotAttachedError(error)) throw error;
|
|
339
|
+
try {
|
|
340
|
+
await runtime.request("detach", { tabId });
|
|
341
|
+
} catch {
|
|
342
|
+
// Detach throws when the debugger is already gone; we only need its side
|
|
343
|
+
// effect of clearing the extension's stale attach flag.
|
|
344
|
+
}
|
|
345
|
+
await runtime.request("attach", { tabId });
|
|
346
|
+
return await run();
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export function isNotAttachedError(error) {
|
|
351
|
+
return /not attached/i.test(error?.message ?? String(error ?? ""));
|
|
352
|
+
}
|
|
353
|
+
|
|
322
354
|
async function executeCdp(runtime, { tabId, method, params = {}, timeoutMs }) {
|
|
323
355
|
return await runtime.request(
|
|
324
356
|
"executeCdp",
|