cdp-mcp 0.1.1 → 0.1.3

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/README.md CHANGED
@@ -4,7 +4,7 @@ A Model Context Protocol (MCP) server that exposes the Chrome DevTools Protocol
4
4
 
5
5
  Designed for agents running in CLIs (Claude Code, GitHub Copilot CLI) that have local source + source-map access. Coordinates flow in TS terms; the server translates to JS for CDP under the hood.
6
6
 
7
- **Status:** alpha (v0.1.0). **License:** [MIT](./LICENSE).
7
+ **Status:** alpha. **License:** [MIT](./LICENSE).
8
8
 
9
9
  ## What it gives an agent
10
10
 
@@ -22,6 +22,34 @@ Auto-attaches to iframes and workers via `Target.setAutoAttach({ flatten: true }
22
22
 
23
23
  ## Install / build
24
24
 
25
+ ### Runtime install from npm
26
+
27
+ Requires Node.js 20+ and a local Chrome/Chromium browser.
28
+
29
+ ```sh
30
+ npm install -g cdp-mcp
31
+ cdp-mcp # stdio MCP transport
32
+ cdp-mcp --port 9719 # SSE MCP transport on 127.0.0.1:9719
33
+ cdp-mcp --host 0.0.0.0 --port 9719 --allow-remote
34
+ ```
35
+
36
+ The npm package ships prebuilt `dist/`, so there is no build step for runtime
37
+ use. If `launch_chrome` cannot find Chrome/Chromium automatically, set
38
+ `CHROME_PATH` to the browser binary.
39
+
40
+ For MCP clients that support SSE, you can run `cdp-mcp` as a persistent local
41
+ service:
42
+
43
+ - [macOS launchd user service](docs/launchd-service.md)
44
+ - [Linux systemd user service](docs/systemd-service.md)
45
+
46
+ Persistent service mode keeps the `cdp-mcp` process and current browser/CDP
47
+ session alive across MCP client restarts or reconnects. It does **not** persist
48
+ state across service-process restarts. SSE mode is single-client today; if a
49
+ new client should start fresh, call `close_session` first.
50
+
51
+ ### Build from source
52
+
25
53
  ```sh
26
54
  npm install
27
55
  npm run build
@@ -62,11 +90,10 @@ Unit + L2 contract tests (~640ms, no browser, no LLM):
62
90
  npm test
63
91
  ```
64
92
 
65
- Currently 299 tests across 22 files. The `test/` tree is the L2 contract
66
- layer (every tool exercised against a fake CDP — see `test/fake-cdp.ts`);
67
- the inline `src/**/*.test.ts` files are L1 pure-data tests; `evals/**/
68
- *.test.ts` cover the L4 harness's grader/trace/oracle units (21 tests).
69
- See `docs/test-eval-plan.md` for the full pyramid.
93
+ The `test/` tree is the L2 contract layer (every tool exercised against a fake
94
+ CDP — see `test/fake-cdp.ts`); the inline `src/**/*.test.ts` files are L1
95
+ pure-data tests; `evals/**/*.test.ts` cover the L4 harness's
96
+ grader/trace/oracle units. See `docs/test-eval-plan.md` for the full pyramid.
70
97
 
71
98
  ### L3 — real-browser end-to-end
72
99
 
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createServer } from "node:http";
3
+ import { realpathSync } from "node:fs";
4
+ import { pathToFileURL } from "node:url";
3
5
  import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
4
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
7
  import { buildServer } from "./server.js";
@@ -93,6 +95,23 @@ function parsePort(raw) {
93
95
  }
94
96
  return port;
95
97
  }
98
+ const DEFAULT_SSE_KEEPALIVE_MS = 25_000;
99
+ // SSE streams sit idle between tool calls, and HTTP clients enforce a
100
+ // body-idle timeout (e.g. undici inside GitHub Copilot CLI tears the stream
101
+ // down after ~12 min with "Body Timeout Error"). A periodic SSE comment frame
102
+ // (`: ...\n\n`) is a no-op per the spec but resets that idle timer. Tunable via
103
+ // CDP_MCP_SSE_KEEPALIVE_MS (non-negative integer ms; 0 disables). See issue #1.
104
+ function getKeepaliveMs() {
105
+ const raw = process.env.CDP_MCP_SSE_KEEPALIVE_MS;
106
+ if (raw === undefined || raw === "")
107
+ return DEFAULT_SSE_KEEPALIVE_MS;
108
+ const value = Number(raw);
109
+ if (!Number.isInteger(value) || value < 0) {
110
+ log.warn("invalid CDP_MCP_SSE_KEEPALIVE_MS; using default", { value: raw, default: DEFAULT_SSE_KEEPALIVE_MS });
111
+ return DEFAULT_SSE_KEEPALIVE_MS;
112
+ }
113
+ return value;
114
+ }
96
115
  async function main() {
97
116
  const mode = parseArgs(process.argv.slice(2));
98
117
  if (mode.transport === "sse") {
@@ -191,7 +210,7 @@ function installProcessErrorHandlers() {
191
210
  log.error("unhandledRejection", { reason: String(reason) });
192
211
  });
193
212
  }
194
- async function handleSseRequest({ req, res, clients, host, port, validateHostOrigin, allowedHosts, allowedOrigins, }) {
213
+ export async function handleSseRequest({ req, res, clients, host, port, validateHostOrigin, allowedHosts, allowedOrigins, }) {
195
214
  try {
196
215
  // DNS-rebinding defense for loopback binds: validate Host (and
197
216
  // Origin if present) before the SDK touches the request. The MCP
@@ -262,7 +281,12 @@ function buildAllowedOrigins(bindHost, port) {
262
281
  async function startSseConnection({ res, clients, }) {
263
282
  const transport = new SSEServerTransport("/messages", res);
264
283
  const server = buildServer();
284
+ // Assigned after connect() (below) so the keepalive never writes before the
285
+ // SDK has sent the SSE response headers; cleared here on disconnect.
286
+ let keepalive;
265
287
  transport.onclose = () => {
288
+ if (keepalive)
289
+ clearInterval(keepalive);
266
290
  const client = clients.get(transport.sessionId);
267
291
  clients.delete(transport.sessionId);
268
292
  void client?.server.close().catch((e) => {
@@ -274,6 +298,23 @@ async function startSseConnection({ res, clients, }) {
274
298
  };
275
299
  clients.set(transport.sessionId, { server, transport });
276
300
  await server.connect(transport);
301
+ // connect() has now written the SSE headers + endpoint event, so it's safe
302
+ // to interleave keepalive comment frames on the stream.
303
+ const keepaliveMs = getKeepaliveMs();
304
+ if (keepaliveMs > 0) {
305
+ keepalive = setInterval(() => {
306
+ if (res.writableEnded)
307
+ return;
308
+ try {
309
+ res.write(": keepalive\n\n");
310
+ }
311
+ catch (e) {
312
+ log.warn("SSE keepalive write failed", { sessionId: transport.sessionId, error: String(e) });
313
+ }
314
+ }, keepaliveMs);
315
+ // Don't let the keepalive timer alone keep the process alive.
316
+ keepalive.unref();
317
+ }
277
318
  log.info("SSE client connected", { sessionId: transport.sessionId });
278
319
  }
279
320
  async function handleSseMessage({ req, res, clients, sessionId, }) {
@@ -338,8 +379,24 @@ function respondText(res, statusCode, body) {
338
379
  res.writeHead(statusCode, { "Content-Type": "text/plain; charset=utf-8" });
339
380
  res.end(body);
340
381
  }
341
- main().catch((err) => {
342
- log.error("fatal", { error: String(err), stack: err?.stack });
343
- process.exit(1);
344
- });
382
+ // Only run the server when executed as the CLI entry point — not when this
383
+ // module is imported (e.g. by the SSE transport tests). `realpathSync`
384
+ // resolves the npm bin symlink so the comparison holds for global installs.
385
+ function isRunAsMain() {
386
+ const entry = process.argv[1];
387
+ if (!entry)
388
+ return false;
389
+ try {
390
+ return import.meta.url === pathToFileURL(realpathSync(entry)).href;
391
+ }
392
+ catch {
393
+ return false;
394
+ }
395
+ }
396
+ if (isRunAsMain()) {
397
+ main().catch((err) => {
398
+ log.error("fatal", { error: String(err), stack: err?.stack });
399
+ process.exit(1);
400
+ });
401
+ }
345
402
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAwE,MAAM,WAAW,CAAC;AAC/G,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAapC,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;AAElE,SAAS,cAAc,CAAC,IAAY;IAClC,OAAO,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC;AASD,SAAS,SAAS,CAAC,IAAc;IAC/B,IAAI,IAAwB,CAAC;IAC7B,IAAI,IAAI,GAAG,WAAW,CAAC;IACvB,IAAI,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,GAAG,CAAC;IAE3D,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,SAAS;QACX,CAAC;QAED,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACrC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB;gBACE,QAAQ;gBACR,kEAAkE;gBAClE,kFAAkF;gBAClF,qDAAqD;gBACrD,EAAE;gBACF,mBAAmB;gBACnB,+DAA+D;gBAC/D,8DAA8D;gBAC9D,mDAAmD;gBACnD,iEAAiE;gBACjE,8DAA8D;gBAC9D,qDAAqD;gBACrD,8DAA8D;gBAC9D,oDAAoD;gBACpD,2DAA2D;gBAC3D,yDAAyD;gBACzD,0DAA0D;gBAC1D,4DAA4D;gBAC5D,+BAA+B;gBAC/B,EAAE;aACH,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAC9B,IAAI,CAAC,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YACvD,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;YACxB,KAAK,IAAI,CAAC,CAAC;YACX,SAAS;QACX,CAAC;QAED,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9B,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;YAC9C,SAAS;QACX,CAAC;QAED,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAC9B,IAAI,CAAC,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YACvD,IAAI,GAAG,KAAK,CAAC;YACb,KAAK,IAAI,CAAC,CAAC;YACX,SAAS;QACX,CAAC;QAED,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9B,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACnC,SAAS;QACX,CAAC;QAED,IAAI,GAAG,KAAK,gBAAgB,EAAE,CAAC;YAC7B,WAAW,GAAG,IAAI,CAAC;YACnB,SAAS;QACX,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;IAChC,CAAC;IAED,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,wDAAwD,IAAI,+IAA+I,CAC5M,CAAC;IACJ,CAAC;IAED,OAAO;QACL,SAAS,EAAE,KAAK;QAChB,IAAI;QACJ,IAAI;QACJ,WAAW;KACZ,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAExC,sEAAsE;AACtE,4EAA4E;AAC5E,8EAA8E;AAC9E,gFAAgF;AAChF,gFAAgF;AAChF,SAAS,cAAc;IACrB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;IACjD,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,wBAAwB,CAAC;IACrE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC1C,GAAG,CAAC,IAAI,CAAC,iDAAiD,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAAC,CAAC;QAC/G,OAAO,wBAAwB,CAAC;IAClC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9C,IAAI,IAAI,CAAC,SAAS,KAAK,KAAK,EAAE,CAAC;QAC7B,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;QACzB,OAAO;IACT,CAAC;IAED,MAAM,cAAc,EAAE,CAAC;AACzB,CAAC;AAED,KAAK,UAAU,cAAc;IAC3B,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;IAC7B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,GAAG,CAAC,IAAI,CAAC,wBAAwB,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAEzD,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAE,EAAE;QACxC,GAAG,CAAC,IAAI,CAAC,oBAAoB,MAAM,EAAE,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;YAC7B,IAAI,OAAO;gBAAE,MAAM,YAAY,CAAC,KAAK,EAAE,CAAC;QAC1C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IACtD,2BAA2B,EAAE,CAAC;AAChC,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,IAAa;IACvC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC7C,oEAAoE;IACpE,gEAAgE;IAChE,mEAAmE;IACnE,oEAAoE;IACpE,gEAAgE;IAChE,oEAAoE;IACpE,oDAAoD;IACpD,MAAM,kBAAkB,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrD,MAAM,YAAY,GAAG,kBAAkB,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAU,CAAC;IACtG,MAAM,cAAc,GAAG,kBAAkB,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAU,CAAC;IAC1G,MAAM,UAAU,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC3C,KAAK,gBAAgB,CAAC;YACpB,GAAG;YACH,GAAG;YACH,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,kBAAkB;YAClB,YAAY;YACZ,cAAc;SACf,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAC/B,GAAG,CAAC,IAAI,CAAC,4BAA4B,EAAE;QACrC,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,GAAG,EAAE,UAAU,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,MAAM;QAC3C,WAAW,EAAE,IAAI,CAAC,WAAW;KAC9B,CAAC,CAAC;IACH,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,GAAG,CAAC,IAAI,CACN,qIAAqI,EACrI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CACrC,CAAC;IACJ,CAAC;IAED,qEAAqE;IACrE,kEAAkE;IAClE,kEAAkE;IAClE,iCAAiC;IACjC,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAE,EAAE;QACxC,GAAG,CAAC,IAAI,CAAC,oBAAoB,MAAM,EAAE,CAAC,CAAC;QACvC,MAAM,eAAe,CAAC,OAAO,CAAC,CAAC;QAC/B,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;YAC7B,IAAI,OAAO;gBAAE,MAAM,YAAY,CAAC,KAAK,EAAE,CAAC;QAC1C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IACtD,2BAA2B,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,2BAA2B;IAClC,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,GAAG,EAAE,EAAE;QACtC,GAAG,CAAC,KAAK,CAAC,mBAAmB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE;QAC1C,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EACrC,GAAG,EACH,GAAG,EACH,OAAO,EACP,IAAI,EACJ,IAAI,EACJ,kBAAkB,EAClB,YAAY,EACZ,cAAc,GAUf;IACC,IAAI,CAAC;QACH,+DAA+D;QAC/D,iEAAiE;QACjE,mEAAmE;QACnE,kEAAkE;QAClE,IAAI,kBAAkB,EAAE,CAAC;YACvB,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;YACpC,IAAI,CAAC,UAAU,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;gBACjD,GAAG,CAAC,IAAI,CAAC,mDAAmD,EAAE;oBAC5D,IAAI,EAAE,UAAU;oBAChB,QAAQ,EAAE,IAAI;iBACf,CAAC,CAAC;gBACH,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC;gBACrC,OAAO;YACT,CAAC;YACD,+DAA+D;YAC/D,sDAAsD;YACtD,2DAA2D;YAC3D,4DAA4D;YAC5D,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;YACxC,IAAI,YAAY,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;gBACtD,GAAG,CAAC,IAAI,CAAC,qDAAqD,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;gBAC1F,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC;gBACrC,OAAO;YACT,CAAC;QACH,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;QAEvF,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YACpD,MAAM,kBAAkB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;YAC3C,OAAO;QACT,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC1D,MAAM,gBAAgB,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YAC5F,OAAO;QACT,CAAC;QAED,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YACrB,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,yBAAyB,CAAC,CAAC;QACnD,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;AACH,CAAC;AAED,uEAAuE;AACvE,yEAAyE;AACzE,iEAAiE;AACjE,SAAS,iBAAiB,CAAC,QAAgB,EAAE,IAAY;IACvD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAS;QAC5B,GAAG,QAAQ,IAAI,IAAI,EAAE;QACrB,aAAa,IAAI,EAAE;QACnB,aAAa,IAAI,EAAE;QACnB,SAAS,IAAI,EAAE;KAChB,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,mBAAmB,CAAC,QAAgB,EAAE,IAAY;IACzD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,QAAQ,IAAI,iBAAiB,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,UAAU,QAAQ,EAAE,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,WAAW,QAAQ,EAAE,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,EAChC,GAAG,EACH,OAAO,GAIR;IACC,MAAM,SAAS,GAAG,IAAI,kBAAkB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;IAE7B,4EAA4E;IAC5E,qEAAqE;IACrE,IAAI,SAAqD,CAAC;IAE1D,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE;QACvB,IAAI,SAAS;YAAE,aAAa,CAAC,SAAS,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAChD,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACpC,KAAK,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;YACtC,GAAG,CAAC,IAAI,CAAC,yCAAyC,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5G,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IACF,SAAS,CAAC,OAAO,GAAG,CAAC,CAAC,EAAE,EAAE;QACxB,GAAG,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IACxD,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,2EAA2E;IAC3E,wDAAwD;IACxD,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;QACpB,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;YAC3B,IAAI,GAAG,CAAC,aAAa;gBAAE,OAAO;YAC9B,IAAI,CAAC;gBACH,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;YAC/B,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,GAAG,CAAC,IAAI,CAAC,4BAA4B,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC/F,CAAC;QACH,CAAC,EAAE,WAAW,CAAC,CAAC;QAChB,8DAA8D;QAC9D,SAAS,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC;AACvE,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,EAC9B,GAAG,EACH,GAAG,EACH,OAAO,EACP,SAAS,GAMV;IACC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,qBAAqB,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,qBAAqB,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,MAAM,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACrD,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,MAAkB,EAAE,IAAa;IACrD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,OAAO,GAAG,CAAC,CAAQ,EAAE,EAAE;YAC3B,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;YACrC,MAAM,CAAC,CAAC,CAAC,CAAC;QACZ,CAAC,CAAC;QACF,MAAM,WAAW,GAAG,GAAG,EAAE;YACvB,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7B,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,MAAkB;IAC/C,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;YACjB,IAAI,CAAC,EAAE,CAAC;gBACN,MAAM,CAAC,CAAC,CAAC,CAAC;gBACV,OAAO;YACT,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE;QACtB,GAAG,CAAC,IAAI,CAAC,2BAA2B,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,OAA+B;IAC5D,MAAM,OAAO,GAAG,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACvC,OAAO,CAAC,KAAK,EAAE,CAAC;IAEhB,MAAM,OAAO,CAAC,GAAG,CACf,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,EAAE;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACjC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,GAAG,CAAC,IAAI,CAAC,6BAA6B,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC3E,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC9B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,GAAG,CAAC,IAAI,CAAC,0BAA0B,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACxE,CAAC;IACH,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,GAAmB,EAAE,UAAkB,EAAE,IAAY;IACxE,GAAG,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,cAAc,EAAE,2BAA2B,EAAE,CAAC,CAAC;IAC3E,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,2EAA2E;AAC3E,uEAAuE;AACvE,4EAA4E;AAC5E,SAAS,WAAW;IAClB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,aAAa,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,IAAI,WAAW,EAAE,EAAE,CAAC;IAClB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACnB,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
package/dist/server.js CHANGED
@@ -11,7 +11,7 @@ import { registerDomTools } from "./tools/dom.js";
11
11
  export function buildServer() {
12
12
  const server = new McpServer({
13
13
  name: "cdp-mcp",
14
- version: "0.1.0",
14
+ version: "0.1.2",
15
15
  });
16
16
  registerSessionTools(server);
17
17
  registerNavTools(server);
@@ -22,6 +22,16 @@ export function buildServer() {
22
22
  registerConsoleTools(server);
23
23
  registerNetworkTools(server);
24
24
  registerDomTools(server);
25
+ // The SDK advertises `tools: { listChanged: true }` as soon as any tool is
26
+ // registered, but never emits the matching notification on its own. Some
27
+ // clients (e.g. GitHub Copilot CLI over SSE) gate their first `tools/list`
28
+ // call on receiving a `notifications/tools/list_changed` and otherwise wait
29
+ // forever — registering zero tools. Emit it once, right after the client's
30
+ // `initialized` (so the transport is connected and the client is ready).
31
+ // Harmless for clients that already fetch eagerly. See issue #1.
32
+ server.server.oninitialized = () => {
33
+ server.sendToolListChanged();
34
+ };
25
35
  return server;
26
36
  }
27
37
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,UAAU,WAAW;IACzB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzB,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5B,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAEzB,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,UAAU,WAAW;IACzB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzB,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5B,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAEzB,2EAA2E;IAC3E,yEAAyE;IACzE,2EAA2E;IAC3E,4EAA4E;IAC5E,2EAA2E;IAC3E,yEAAyE;IACzE,iEAAiE;IACjE,MAAM,CAAC,MAAM,CAAC,aAAa,GAAG,GAAG,EAAE;QACjC,MAAM,CAAC,mBAAmB,EAAE,CAAC;IAC/B,CAAC,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,191 @@
1
+ # Chromium sandboxing
2
+
3
+ **Last updated: 2026-05-16**
4
+
5
+ This project launches Chromium in two different contexts:
6
+
7
+ - L3 e2e tests and L4 evals launch a real browser through `launch_chrome`.
8
+ - Agents then control that browser through CDP, including `Runtime.evaluate`,
9
+ `Debugger.*`, DOM interaction, console inspection, and network inspection.
10
+
11
+ That makes sandboxing a host setup and threat-model decision, not just a
12
+ Chrome flag. This document is the canonical reference for `--no-sandbox`,
13
+ AppArmor, unprivileged user namespaces, snap confinement, and Bubblewrap.
14
+
15
+ ## Current default
16
+
17
+ `launch_chrome` defaults to `sandbox: false`, which adds `--no-sandbox`.
18
+
19
+ The default exists because Ubuntu 23.10+ and 24.04 commonly restrict
20
+ unprivileged user namespaces through AppArmor. Playwright-bundled Chromium
21
+ does not ship with a SUID `chrome_sandbox` helper. On those hosts, launching
22
+ Chromium without `--no-sandbox` can fail before the DevTools port opens:
23
+
24
+ ```text
25
+ zygote_host_impl_linux.cc: No usable sandbox!
26
+ ```
27
+
28
+ From `chrome-launcher`, that often surfaces as a startup port poll timeout or
29
+ `ECONNREFUSED`.
30
+
31
+ Other Linux distributions may allow Chromium's unprivileged user namespace
32
+ sandbox path by default. Validate the actual host before assuming the Ubuntu
33
+ automation default is necessary there.
34
+
35
+ Use `sandbox: true` only when the host has a working Chromium sandbox path:
36
+
37
+ - An AppArmor policy that permits the specific Chromium binary to create the
38
+ unprivileged user namespace it needs.
39
+ - Or a working SUID `chrome_sandbox` helper installed alongside that binary.
40
+
41
+ ## Why the Chromium sandbox still matters
42
+
43
+ The MCP caller is already highly privileged relative to the page. It can ask
44
+ the server to evaluate JavaScript, drive the DOM, set breakpoints, inspect
45
+ scopes, and read browser-observed network activity. For that caller, the
46
+ Chromium renderer sandbox is not the primary trust boundary.
47
+
48
+ The Chromium sandbox still matters for hostile page content and browser
49
+ exploitation risk. With the sandbox enabled, Chromium isolates renderer, GPU,
50
+ and utility child processes from the browser process using mechanisms such as
51
+ namespaces, seccomp filters, brokered filesystem access, and per-process
52
+ capability reduction. With `--no-sandbox`, a compromised renderer has a much
53
+ larger blast radius inside the browser process tree.
54
+
55
+ So the project default is a pragmatic automation default, not a claim that
56
+ `--no-sandbox` is equally safe.
57
+
58
+ ## How the mechanisms relate
59
+
60
+ These mechanisms solve different problems:
61
+
62
+ - Chromium sandbox: Chromium's internal process sandbox. It is the boundary
63
+ between web content renderer processes and the rest of the browser.
64
+ - AppArmor: host-enforced mandatory access control. It can confine Chromium,
65
+ and on recent Ubuntu systems it can also restrict whether an unprivileged
66
+ process may create user namespaces.
67
+ - Snap confinement: the packaging sandbox used by snap-installed Chromium.
68
+ It can hide or remap filesystem locations and has caused DevTools port and
69
+ `userDataDir` friction in local runs.
70
+ - Bubblewrap (`bwrap`): a small Linux sandboxing tool that starts a process in
71
+ new namespaces with a controlled filesystem, process, and optional network
72
+ view.
73
+
74
+ Bubblewrap is useful defense-in-depth around a browser or eval job. For
75
+ example, it can run the whole MCP server plus browser process tree with only
76
+ the repository and selected temp/profile directories writable. That helps
77
+ prevent accidental or malicious access to unrelated files such as SSH keys,
78
+ cloud credentials, or the rest of the home directory.
79
+
80
+ Bubblewrap is not a clean substitute for Chromium's own sandbox. If Chromium
81
+ runs with `--no-sandbox` inside Bubblewrap, the entire browser process tree is
82
+ inside an outer container-like boundary, but Chromium's internal renderer
83
+ isolation is still disabled. A renderer compromise may be contained by the
84
+ outer Bubblewrap filesystem or network policy, but it is not contained in the
85
+ same way as Chromium's per-renderer sandbox.
86
+
87
+ ## Recommended posture
88
+
89
+ Local development:
90
+
91
+ - Treat the current default, `sandbox: false`, as a host-capability fallback:
92
+ it keeps work moving when Chromium sandbox setup is the blocker.
93
+ - Prefer `sandbox: true` once the host has a known-good Chromium sandbox path.
94
+
95
+ CI and L4 eval hosts:
96
+
97
+ - Keep the default working and deterministic. If `--no-sandbox` is needed for
98
+ Playwright-bundled Chromium on Ubuntu, document that in the host setup.
99
+ - Consider running the whole job inside an outer sandbox, VM, container, or
100
+ Bubblewrap profile with a throwaway browser profile and limited writable
101
+ paths.
102
+
103
+ Untrusted browsing:
104
+
105
+ - Prefer Chromium's sandbox on.
106
+ - Use a throwaway `userDataDir`.
107
+ - Add host-level confinement such as AppArmor, a container, VM, or Bubblewrap.
108
+ - Do not treat `bwrap + --no-sandbox` as equivalent to Chromium sandboxing.
109
+
110
+ ## Validated hosts
111
+
112
+ Hosts where `sandbox: true` has been verified working against this project, with the supporting posture:
113
+
114
+ | Host | OS | Arch | `sandbox: true` | AppArmor profile | Notes |
115
+ |---|---|---|---|---|---|
116
+ | Ubuntu 24.04 arm64 (Parallels VM) | Ubuntu 24.04 | arm64 | ✓ | `/etc/apparmor.d/cdp-mcp-chromium` (named-unconfined, mirrors Ubuntu's stock `chrome` / `msedge` / `brave`) | `kernel.apparmor_restrict_unprivileged_userns = 0` was set as a side effect of enabling Bubblewrap, so the kernel-level userns restriction is already off system-wide. The AppArmor profile gives Playwright Chromium a stable named label (instead of `unconfined`) and grants `userns,` explicitly, so `sandbox: true` keeps working even if a future kernel/package update flips the global knob back to `1`. |
117
+
118
+ When adding a new host to this table:
119
+
120
+ 1. Run the smoke tests below and capture the values.
121
+ 2. If `kernel.apparmor_restrict_unprivileged_userns` is `1` (Ubuntu's stock default) and `sandbox: true` is desired, install a profile under `/etc/apparmor.d/` mirroring Ubuntu's stock `chrome` / `msedge` / `brave` shape:
122
+ ```apparmor
123
+ abi <abi/4.0>,
124
+ include <tunables/global>
125
+
126
+ profile cdp-mcp-chromium /path/to/chromium flags=(unconfined) {
127
+ userns,
128
+ include if exists <local/cdp-mcp-chromium>
129
+ }
130
+ ```
131
+ Load with `sudo apparmor_parser -r /etc/apparmor.d/cdp-mcp-chromium`. The profile auto-loads at boot from `/etc/apparmor.d/`.
132
+ 3. Verify the running browser process is labelled correctly:
133
+ ```sh
134
+ cat /proc/<chromium-pid>/attr/current
135
+ ```
136
+ Expect the profile name (e.g. `cdp-mcp-chromium (unconfined)`), not `unconfined` alone.
137
+ 4. Add a row to the table above.
138
+
139
+ Other hosts to characterize as they come online: Fedora — Fedora uses SELinux rather than AppArmor and ships userns enabled by default, so `sandbox: true` is expected to work without host-side profile work. The `dnf install bubblewrap` path is also first-class on Fedora.
140
+
141
+ ## Smoke tests
142
+
143
+ Check whether unprivileged user namespaces are enabled:
144
+
145
+ ```sh
146
+ cat /proc/sys/kernel/unprivileged_userns_clone
147
+ cat /proc/sys/user/max_user_namespaces
148
+ ```
149
+
150
+ Expected working values are usually `1` for
151
+ `kernel.unprivileged_userns_clone` and a nonzero number for
152
+ `user.max_user_namespaces`.
153
+
154
+ On Ubuntu, AppArmor may still restrict unprivileged user namespaces:
155
+
156
+ ```sh
157
+ sysctl kernel.apparmor_restrict_unprivileged_userns
158
+ ```
159
+
160
+ Minimal Bubblewrap smoke tests:
161
+
162
+ ```sh
163
+ bwrap --unshare-user --uid 0 --gid 0 --ro-bind / / /usr/bin/true
164
+ bwrap --unshare-user --uid 0 --gid 0 --unshare-net --ro-bind / / /usr/bin/true
165
+ ```
166
+
167
+ If the first command fails with `setting up uid map: Permission denied`, the
168
+ host still blocks the user namespace setup Bubblewrap needs.
169
+
170
+ If the second command fails with `loopback: Failed RTM_NEWADDR: Operation not
171
+ permitted`, the network namespace setup is still blocked.
172
+
173
+ Project-level browser check:
174
+
175
+ ```sh
176
+ npm run test:e2e
177
+ ```
178
+
179
+ For a direct MCP check, call `launch_chrome` with `sandbox: true` on the host
180
+ you want to validate. If Chromium cannot create a usable sandbox, it will fail
181
+ before exposing its DevTools target.
182
+
183
+ ## Decision summary
184
+
185
+ - `--no-sandbox` remains the automation default because it keeps Ubuntu
186
+ Playwright-Chromium runs working.
187
+ - `sandbox: true` is the preferred security posture when the host supports it.
188
+ - AppArmor is the long-term host policy path for allowing Chromium's needed
189
+ user namespace behavior narrowly.
190
+ - Bubblewrap is an outer containment layer and is valuable defense-in-depth.
191
+ - Bubblewrap does not replace Chromium's internal renderer sandbox.
@@ -0,0 +1,138 @@
1
+ # Known Chromium gaps
2
+
3
+ Specs in the L3 e2e suite that fail (or fail intermittently) on Chromium but
4
+ pass on Chrome stable. Every entry below is a real coverage gap on Linux
5
+ ARM64 + Chromium (the day-1 primary target) — not a CI-only concession.
6
+
7
+ If the gap is mitigatable in production code, link the fix PR. If it's a CDP
8
+ protocol-version difference, link the Chromium release that includes the fix.
9
+
10
+ | Spec | Skip tag | CDP method missing/changed | Chromium version that fixes it | Tracking |
11
+ |---|---|---|---|---|
12
+ | _none yet — populate as L3 lands_ | | | | |
13
+
14
+ ## Pre-flagged risks (not yet observed; documented for triage)
15
+
16
+ These are known protocol-version-sensitive areas the test+eval plan flagged
17
+ as risky during planning. Add a row above when one of them actually fires
18
+ on the e2e suite.
19
+
20
+ - **`Network.loadNetworkResource`** — Used by `src/sourcemap/loader.ts:113`
21
+ to fetch source maps through the browser's network stack (so cookies/
22
+ origin/auth flow naturally). Older Chromium revisions ship a more limited
23
+ param set (no `options.includeCredentials`, no `options.disableCache`);
24
+ the production code already has a Node-fetch fallback, but verify the
25
+ fallback path is exercised under the older Chromium.
26
+
27
+ - **`Page.captureScreenshot`** flag set — `captureBeyondViewport` and
28
+ `quality` (when `format=jpeg`) gained options across versions. The
29
+ screenshot e2e spec asserts byte-shape, not flag-respect, so this is
30
+ most likely to surface as a "bytes don't match" assertion under older
31
+ Chromium.
32
+
33
+ ## Conventions
34
+
35
+ - Add a `// @chromium-skip — <gap-id>` comment on the spec's `it()` line.
36
+ - Set the spec to `it.skipIf(process.env.CDP_TEST_BROWSER === "chromium")` or
37
+ use vitest's `.skip` with a runtime check.
38
+ - Every skip MUST have a corresponding row in the table above. **Enforced** by
39
+ `scripts/check-chromium-skips.mjs` — runs as `pretest:e2e` on every PR and
40
+ also as `npm run lint:chromium-skips`. Greps `test/e2e/**/*.test.ts` for
41
+ `@chromium-skip` tags and `it.skipIf`/`describe.skipIf` Chromium guards,
42
+ parses the table above, exits 1 if any skip lacks a row OR any row points
43
+ at a spec that no longer exists. Zero-skip state (the current state) is
44
+ fine — the script is a no-op.
45
+
46
+ _(no entries below this line yet means no L3 specs needed a Chromium skip)_
47
+
48
+ ## Known host gaps (not Chromium-version issues)
49
+
50
+ These are host/library combinations where the e2e suite cannot run end-to-
51
+ end, separate from the per-Chromium-version skip mechanism above. Listed
52
+ here so future contributors don't waste a debug cycle.
53
+
54
+ - **Windows 11 + chrome-launcher 1.2.1.** `chrome-launcher.launch()`'s
55
+ internal startup-port poll always fails with `ECONNREFUSED` on this Win11
56
+ configuration, regardless of headless mode (`--headless=new`, classic
57
+ `--headless`, or non-headless), browser (Chrome stable from Program
58
+ Files, Playwright-bundled Chromium under `~/AppData/Local/ms-playwright/
59
+ chromium-XXXX/chrome-win64/chrome.exe`), or how the port is selected
60
+ (chrome-launcher-managed vs explicit). Spawning `chrome.exe` directly via
61
+ `Start-Process` and probing `/json/version` over HTTP works fine — only
62
+ chrome-launcher's launch path fails. The same code works on Linux (CI)
63
+ and is widely used elsewhere, so this is a Windows-host quirk rather
64
+ than a cdp-mcp issue. **Workaround**: run L3 changes under WSL2
65
+ (Ubuntu) or push and let CI validate (but see WSL2 caveat below). Unit
66
+ + L2 tests work fine on native Windows.
67
+
68
+ *Originally hit on agents/l3-impl during PR #11 implementation.
69
+ Cross-confirmed by Codex reviewer who diagnosed the on-CI failure
70
+ separately — turned out to be a different root cause (Codex blocker on
71
+ --remote-debugging-port=0 in chromeFlags overriding chrome-launcher's
72
+ own port). After that fix, CI on Linux is the live validation; Win11
73
+ local-host status remains as documented here.*
74
+
75
+ - **macOS arm64 + system unbranded Chromium (brew cask).** The `chromium`
76
+ Homebrew cask is **deprecated** ("does not pass the macOS Gatekeeper
77
+ check; will be disabled 2026-09-01"). Install completes and the wrapper
78
+ script lands at `/opt/homebrew/bin/chromium`, but on first launch
79
+ Gatekeeper rejects the `.app` as "damaged" and the binary is unusable
80
+ for unattended e2e/eval runs. Workaround for darwin-arm64: use Playwright
81
+ Chrome-for-Testing (`npx playwright install chromium`) — `resolveBrowser`
82
+ picks it up automatically from `~/Library/Caches/ms-playwright/chromium-
83
+ <rev>/chrome-mac-arm64/Google Chrome for Testing.app/Contents/MacOS/
84
+ Google Chrome for Testing` (CfT layout added to `pickPlaywrightExe` in
85
+ the same PR that landed this entry). The resolver also explicitly skips
86
+ the brew-cask wrapper on darwin (`isBrewCaskChromium`) so users who
87
+ tried the deprecated cask first — and then turn to Playwright per this
88
+ entry — fall through to the Playwright cache instead of getting the
89
+ Gatekeeper-rejected wrapper back from Step 2. Functionally Chromium-
90
+ channel at a fixed protocol revision, but Google-branded — call it out
91
+ if your eval needs *unbranded* Chromium. Building Chromium from source
92
+ on macOS is multi-hour + multi-GB ongoing maintenance; not a viable
93
+ automation path.
94
+
95
+ *Originally hit while validating set_breakpoint idempotency on a
96
+ macOS arm64 host.*
97
+
98
+ - **WSL2 (Ubuntu) + snap-installed chromium.** Default-template Ubuntu on
99
+ WSL2 ships chromium as a snap (`/snap/bin/chromium`), which runs in a
100
+ confined namespace. chrome-launcher launches the binary successfully
101
+ (visible window appears under WSLg) but its startup-port poll
102
+ `ECONNREFUSEs` on iter 1 and often iter 2 — the debug port either
103
+ binds to a different port than chrome-launcher polled (race) or is
104
+ invisible across the snap sandbox boundary. After 2-4 retries the
105
+ agent's tool-use loop eventually picks an instance that responds, so
106
+ the eval does run, but every trial pays an inflated cost in retry
107
+ iterations and the trace is contaminated with WARN entries that look
108
+ like real failures. Same chrome-launcher code path is clean on macOS,
109
+ Linux native, and Linux CI.
110
+
111
+ **Workaround options**: (a) **prefer macOS or Linux native** for
112
+ interactive eval iteration — a macOS arm64 host confirmed clean;
113
+ (b) install non-snap chromium in WSL2 via apt or
114
+ symlink Playwright's bundled chromium to `/usr/local/bin/chromium-browser`
115
+ before the snap path; (c) accept the noise and rely on CI for the
116
+ authoritative signal. Don't rely on WSL2 for eval validation runs.
117
+
118
+ *A re-run on the same commit (`f0ce92a`) on a native host showed 0
119
+ chrome-launcher errors, isolating the cause to the WSL2 + snap-chromium
120
+ combination rather than the harness.*
121
+
122
+ - **Ubuntu 23.10+ (incl. 24.04) + Playwright-bundled Chromium.** Recent
123
+ Ubuntu kernels restrict unprivileged user namespaces via AppArmor, and
124
+ Playwright-bundled Chromium ships without a SUID `chrome_sandbox`
125
+ helper. Without `--no-sandbox`, Chromium FATALs at startup
126
+ (`zygote_host_impl_linux.cc: No usable sandbox!`) before opening its
127
+ debug port — chrome-launcher's port-poll loop then times out with
128
+ ECONNREFUSED, looking exactly like the WSL2/snap gap above but with a
129
+ different root cause. **Mitigation:** `launchChrome` defaults
130
+ `sandbox: false` so `--no-sandbox` is added automatically; eval
131
+ pipelines on this host work out-of-the-box. For the full security model,
132
+ including `sandbox: true`, AppArmor, snap confinement, and Bubblewrap, see
133
+ [docs/chromium-sandboxing.md](./chromium-sandboxing.md).
134
+
135
+ *First observed on an Ubuntu 24.04 arm64 host (Parallels VM) while
136
+ validating the L4 eval suite. Quick eval went from FAIL/$0.34/445s
137
+ (chrome-launcher retry storm) to PASS/$0.31/107s once `--no-sandbox`
138
+ was the default.*
@@ -0,0 +1,217 @@
1
+ # macOS: Run as a Persistent Service (launchd)
2
+
3
+ Register `cdp-mcp` as a launchd user agent so it starts automatically on login
4
+ and exposes the MCP SSE endpoint on `127.0.0.1:9719`.
5
+
6
+ Persistent service mode is useful for MCP clients that support SSE because the
7
+ `cdp-mcp` process and its browser/CDP session can survive MCP client restarts or
8
+ reconnects. It does **not** persist state across service-process restarts.
9
+
10
+ > Security note: the local SSE endpoint has no authentication. MCP tools include
11
+ > in-page JavaScript evaluation and filesystem writes via screenshot paths. Only
12
+ > run a persistent service on trusted single-user machines, and do not bind it to
13
+ > non-loopback interfaces unless you understand the `--allow-remote` exposure.
14
+
15
+ ## Contents
16
+
17
+ - [1. Install the server](#1-install-the-server)
18
+ - [2. Create the plist](#2-create-the-plist)
19
+ - [3. Load and start](#3-load-and-start)
20
+ - [4. Verify](#4-verify)
21
+ - [5. Configure an MCP client](#5-configure-an-mcp-client)
22
+ - [6. Logs](#6-logs)
23
+ - [7. Stop / uninstall](#7-stop--uninstall)
24
+ - [8. Upgrade](#8-upgrade)
25
+ - [Troubleshooting](#troubleshooting)
26
+
27
+ ## 1. Install the server
28
+
29
+ Requires Node.js 20+ and a local Chrome/Chromium browser.
30
+
31
+ ```bash
32
+ npm install -g cdp-mcp
33
+ ```
34
+
35
+ Verify with `cdp-mcp --help`. The package ships prebuilt `dist/`, so there is no
36
+ build step and no repo checkout needed.
37
+
38
+ If `launch_chrome` cannot find Chrome/Chromium automatically, set `CHROME_PATH`
39
+ in the plist generated below.
40
+
41
+ ## 2. Create the plist
42
+
43
+ Run this from any directory:
44
+
45
+ ```bash
46
+ # If you use fnm, nvm, or another Node version manager, set these variables to
47
+ # stable paths before running this snippet. Example:
48
+ # NODE_BIN="$HOME/.local/share/fnm/aliases/default/bin/node"
49
+ # CDP_SCRIPT="$HOME/.local/share/fnm/aliases/default/bin/cdp-mcp"
50
+ NODE_BIN="${NODE_BIN:-$(command -v node)}"
51
+ CDP_SCRIPT="${CDP_SCRIPT:-$(command -v cdp-mcp)}"
52
+ CHROME_PATH="${CHROME_PATH:-}"
53
+
54
+ if [ -z "$NODE_BIN" ]; then
55
+ echo "Error: node not found in PATH. Install Node 20+ first." >&2
56
+ exit 1
57
+ fi
58
+ if [ -z "$CDP_SCRIPT" ]; then
59
+ echo "Error: cdp-mcp not found. Run 'npm install -g cdp-mcp' first." >&2
60
+ exit 1
61
+ fi
62
+
63
+ xml_escape() {
64
+ printf '%s' "$1" \
65
+ | sed \
66
+ -e 's/&/\&amp;/g' \
67
+ -e 's/</\&lt;/g' \
68
+ -e 's/>/\&gt;/g' \
69
+ -e 's/"/\&quot;/g' \
70
+ -e "s/'/\&apos;/g"
71
+ }
72
+
73
+ NODE_DIR="$(dirname "$NODE_BIN")"
74
+ mkdir -p ~/Library/LaunchAgents ~/Library/Logs/cdp-mcp
75
+ ESC_NODE=$(xml_escape "$NODE_BIN")
76
+ ESC_NODE_DIR=$(xml_escape "$NODE_DIR")
77
+ ESC_CDP=$(xml_escape "$CDP_SCRIPT")
78
+ ESC_HOME=$(xml_escape "$HOME")
79
+ ESC_CHROME=$(xml_escape "$CHROME_PATH")
80
+ cat > ~/Library/LaunchAgents/io.github.lcjanke2020.cdp-mcp.plist <<PLIST
81
+ <?xml version="1.0" encoding="UTF-8"?>
82
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
83
+ "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
84
+ <plist version="1.0">
85
+ <dict>
86
+ <key>Label</key>
87
+ <string>io.github.lcjanke2020.cdp-mcp</string>
88
+ <key>ProgramArguments</key>
89
+ <array>
90
+ <string>$ESC_NODE</string>
91
+ <string>$ESC_CDP</string>
92
+ <string>--port</string>
93
+ <string>9719</string>
94
+ </array>
95
+ <key>RunAtLoad</key>
96
+ <true/>
97
+ <key>KeepAlive</key>
98
+ <true/>
99
+ <key>StandardOutPath</key>
100
+ <string>$ESC_HOME/Library/Logs/cdp-mcp/server.stdout.log</string>
101
+ <key>StandardErrorPath</key>
102
+ <string>$ESC_HOME/Library/Logs/cdp-mcp/server.stderr.log</string>
103
+ <key>EnvironmentVariables</key>
104
+ <dict>
105
+ <key>PATH</key>
106
+ <string>$ESC_NODE_DIR:/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin</string>
107
+ $(if [ -n "$CHROME_PATH" ]; then printf ' <key>CHROME_PATH</key>\n <string>%s</string>\n' "$ESC_CHROME"; fi)
108
+ </dict>
109
+ </dict>
110
+ </plist>
111
+ PLIST
112
+ ```
113
+
114
+ The plist invokes `node` directly with the `cdp-mcp` script path. That makes the
115
+ `NODE_BIN` override authoritative even when your shell uses a Node version
116
+ manager.
117
+
118
+ ## 3. Load and start
119
+
120
+ On macOS 10.15+, use:
121
+
122
+ ```bash
123
+ launchctl bootstrap gui/$UID ~/Library/LaunchAgents/io.github.lcjanke2020.cdp-mcp.plist
124
+ launchctl kickstart -k gui/$UID/io.github.lcjanke2020.cdp-mcp
125
+ ```
126
+
127
+ Older macOS releases also support:
128
+
129
+ ```bash
130
+ launchctl load ~/Library/LaunchAgents/io.github.lcjanke2020.cdp-mcp.plist
131
+ ```
132
+
133
+ ## 4. Verify
134
+
135
+ ```bash
136
+ launchctl print gui/$UID/io.github.lcjanke2020.cdp-mcp
137
+ lsof -i :9719
138
+ curl -v --max-time 2 http://127.0.0.1:9719/sse 2>&1 | head -20
139
+ ```
140
+
141
+ The `curl` command should show a `200 OK` response and SSE event output. A
142
+ timeout after the first event is expected because `/sse` keeps the connection
143
+ open. The server also sends periodic SSE keepalive comments by default; tune
144
+ with `CDP_MCP_SSE_KEEPALIVE_MS` only if your MCP client needs a different idle
145
+ interval.
146
+
147
+ ## 5. Configure an MCP client
148
+
149
+ Point an SSE-capable MCP client at:
150
+
151
+ ```text
152
+ http://127.0.0.1:9719/sse
153
+ ```
154
+
155
+ For example, clients that use JSON MCP server config commonly use:
156
+
157
+ ```json
158
+ {
159
+ "mcpServers": {
160
+ "cdp-mcp": {
161
+ "type": "sse",
162
+ "url": "http://127.0.0.1:9719/sse"
163
+ }
164
+ }
165
+ }
166
+ ```
167
+
168
+ SSE mode is single-client today. Multiple MCP clients connected to the same
169
+ service share one process-global browser/CDP session and can interfere with each
170
+ other. Use one active debugging client per service, or run separate services on
171
+ separate ports.
172
+
173
+ A reconnecting client resumes the prior session. If you want a clean browser
174
+ session after reconnecting, call `close_session` before launching or attaching
175
+ again.
176
+
177
+ ## 6. Logs
178
+
179
+ ```bash
180
+ tail -f ~/Library/Logs/cdp-mcp/server.stderr.log
181
+ ```
182
+
183
+ ## 7. Stop / uninstall
184
+
185
+ ```bash
186
+ launchctl bootout gui/$UID/io.github.lcjanke2020.cdp-mcp
187
+ rm ~/Library/LaunchAgents/io.github.lcjanke2020.cdp-mcp.plist
188
+ ```
189
+
190
+ Older macOS releases also support:
191
+
192
+ ```bash
193
+ launchctl unload ~/Library/LaunchAgents/io.github.lcjanke2020.cdp-mcp.plist
194
+ ```
195
+
196
+ ## 8. Upgrade
197
+
198
+ ```bash
199
+ npm install -g cdp-mcp@latest
200
+ launchctl kickstart -k gui/$UID/io.github.lcjanke2020.cdp-mcp
201
+ ```
202
+
203
+ Restart or reconnect your MCP client after a server upgrade so it reloads tool
204
+ schemas.
205
+
206
+ ## Troubleshooting
207
+
208
+ | Symptom | Fix |
209
+ |---|---|
210
+ | `bootstrap` says service already loaded | Run `launchctl bootout gui/$UID/io.github.lcjanke2020.cdp-mcp`, then bootstrap again |
211
+ | Service exits immediately | Check `~/Library/Logs/cdp-mcp/server.stderr.log`; usually `cdp-mcp` is not installed, Node is too old, or a version-manager path moved |
212
+ | Port 9719 is already in use | Check `lsof -i :9719`, then stop the other process or change the port in the plist |
213
+ | MCP client rejects the config | Confirm the client supports SSE MCP servers and include both `"type": "sse"` and the `/sse` URL if your client uses JSON config |
214
+ | `launch_chrome` cannot find Chrome | Set `CHROME_PATH` before generating the plist, or edit the plist environment and reload the service |
215
+ | Service not starting after reboot | Verify the plist is in `~/Library/LaunchAgents/`, not `LaunchDaemons` |
216
+ | Service not starting after reboot with fnm/nvm | Version-manager shell paths can be ephemeral. Recreate the plist with stable `NODE_BIN` and `CDP_SCRIPT` paths, or install with a system Node |
217
+ | `already_session` after reconnecting | The prior browser/CDP session is still alive. Resume it, or call `close_session` before starting fresh |
@@ -0,0 +1,233 @@
1
+ # Linux: Run as a Persistent Service (systemd)
2
+
3
+ Register `cdp-mcp` as a systemd user service so it starts automatically on login
4
+ and exposes the MCP SSE endpoint on `127.0.0.1:9719`. If you enable lingering,
5
+ the service can also start at boot before an interactive login.
6
+
7
+ Persistent service mode is useful for MCP clients that support SSE because the
8
+ `cdp-mcp` process and its browser/CDP session can survive MCP client restarts or
9
+ reconnects. It does **not** persist state across service-process restarts.
10
+
11
+ > Security note: the local SSE endpoint has no authentication. MCP tools include
12
+ > in-page JavaScript evaluation and filesystem writes via screenshot paths. Only
13
+ > run a persistent service on trusted single-user machines. Be especially careful
14
+ > with `loginctl enable-linger` on shared hosts because it widens the service's
15
+ > exposure window beyond your interactive login session.
16
+
17
+ ## Contents
18
+
19
+ - [1. Install the server](#1-install-the-server)
20
+ - [2. Optional: enable lingering](#2-optional-enable-lingering)
21
+ - [3. Create the unit file](#3-create-the-unit-file)
22
+ - [4. Enable and start the service](#4-enable-and-start-the-service)
23
+ - [5. Verify](#5-verify)
24
+ - [6. Configure an MCP client](#6-configure-an-mcp-client)
25
+ - [7. Logs](#7-logs)
26
+ - [8. Stop / uninstall](#8-stop--uninstall)
27
+ - [9. Upgrade](#9-upgrade)
28
+ - [Linux ARM64 / Chromium](#linux-arm64--chromium)
29
+ - [Troubleshooting](#troubleshooting)
30
+
31
+ ## 1. Install the server
32
+
33
+ Requires Node.js 20+ and a local Chrome/Chromium browser.
34
+
35
+ ```bash
36
+ npm install -g cdp-mcp
37
+ ```
38
+
39
+ Verify with `cdp-mcp --help`. The package ships prebuilt `dist/`, so there is no
40
+ build step and no repo checkout needed.
41
+
42
+ If `launch_chrome` cannot find Chrome/Chromium automatically, set `CHROME_PATH`
43
+ when generating the unit file below.
44
+
45
+ ## 2. Optional: enable lingering
46
+
47
+ Enable lingering only if you want the user service to start at boot even before
48
+ you log in:
49
+
50
+ ```bash
51
+ sudo loginctl enable-linger "$USER"
52
+ ```
53
+
54
+ You only need to run this once per machine. Check with:
55
+
56
+ ```bash
57
+ loginctl show-user "$USER" --property=Linger
58
+ ```
59
+
60
+ Skip this step if starting the service during your login session is enough.
61
+
62
+ ## 3. Create the unit file
63
+
64
+ Run this from any directory:
65
+
66
+ ```bash
67
+ # If you use fnm, nvm, or another Node version manager, set these variables to
68
+ # stable paths before running this snippet. Example:
69
+ # NODE_BIN="$HOME/.local/share/fnm/aliases/default/bin/node"
70
+ # CDP_SCRIPT="$HOME/.local/share/fnm/aliases/default/bin/cdp-mcp"
71
+ NODE_BIN="${NODE_BIN:-$(command -v node)}"
72
+ CDP_SCRIPT="${CDP_SCRIPT:-$(command -v cdp-mcp)}"
73
+ CHROME_PATH="${CHROME_PATH:-}"
74
+
75
+ if [ -z "$NODE_BIN" ]; then
76
+ echo "Error: node not found in PATH. Install Node 20+ first." >&2
77
+ exit 1
78
+ fi
79
+ if [ -z "$CDP_SCRIPT" ]; then
80
+ echo "Error: cdp-mcp not found. Run 'npm install -g cdp-mcp' first." >&2
81
+ exit 1
82
+ fi
83
+
84
+ NODE_DIR="$(dirname "$NODE_BIN")"
85
+ mkdir -p ~/.config/systemd/user
86
+ cat > ~/.config/systemd/user/cdp-mcp.service << EOF
87
+ [Unit]
88
+ Description=cdp-mcp browser MCP server (SSE on port 9719)
89
+ After=network.target
90
+
91
+ [Service]
92
+ Type=simple
93
+ ExecStart="${NODE_BIN}" "${CDP_SCRIPT}" --port 9719
94
+ Restart=on-failure
95
+ RestartSec=5
96
+ Environment="PATH=${NODE_DIR}:/usr/local/bin:/usr/bin:/bin"
97
+ $(if [ -n "$CHROME_PATH" ]; then printf 'Environment="CHROME_PATH=%s"\n' "$CHROME_PATH"; else printf '# Optional: set CHROME_PATH if launch_chrome cannot find Chrome/Chromium.\n# Environment="CHROME_PATH=/path/to/chrome"\n'; fi)
98
+
99
+ [Install]
100
+ WantedBy=default.target
101
+ EOF
102
+ ```
103
+
104
+ The unit invokes `node` directly with the `cdp-mcp` script path. That makes the
105
+ `NODE_BIN` override authoritative even when your shell uses a Node version
106
+ manager. The `ExecStart` and `Environment` values are double-quoted so systemd
107
+ treats a path containing spaces as a single token rather than splitting it.
108
+
109
+ ## 4. Enable and start the service
110
+
111
+ ```bash
112
+ systemctl --user daemon-reload
113
+ systemctl --user enable --now cdp-mcp.service
114
+ ```
115
+
116
+ ## 5. Verify
117
+
118
+ ```bash
119
+ systemctl --user status cdp-mcp.service
120
+ ss -tlnp | grep 9719
121
+ curl -s --max-time 2 http://127.0.0.1:9719/sse | head -1
122
+ ```
123
+
124
+ The `curl` command should print an SSE `event:` line. The stream stays open by
125
+ design. The server also sends periodic SSE keepalive comments by default; tune
126
+ with `CDP_MCP_SSE_KEEPALIVE_MS` only if your MCP client needs a different idle
127
+ interval.
128
+
129
+ ## 6. Configure an MCP client
130
+
131
+ Point an SSE-capable MCP client at:
132
+
133
+ ```text
134
+ http://127.0.0.1:9719/sse
135
+ ```
136
+
137
+ For example, clients that use JSON MCP server config commonly use:
138
+
139
+ ```json
140
+ {
141
+ "mcpServers": {
142
+ "cdp-mcp": {
143
+ "type": "sse",
144
+ "url": "http://127.0.0.1:9719/sse"
145
+ }
146
+ }
147
+ }
148
+ ```
149
+
150
+ SSE mode is single-client today. Multiple MCP clients connected to the same
151
+ service share one process-global browser/CDP session and can interfere with each
152
+ other. Use one active debugging client per service, or run separate services on
153
+ separate ports.
154
+
155
+ A reconnecting client resumes the prior session. If you want a clean browser
156
+ session after reconnecting, call `close_session` before launching or attaching
157
+ again.
158
+
159
+ ## 7. Logs
160
+
161
+ ```bash
162
+ journalctl --user -u cdp-mcp.service -f
163
+ journalctl --user -u cdp-mcp.service -n 100
164
+ ```
165
+
166
+ ## 8. Stop / uninstall
167
+
168
+ ```bash
169
+ systemctl --user stop cdp-mcp.service
170
+ systemctl --user disable cdp-mcp.service
171
+ rm ~/.config/systemd/user/cdp-mcp.service
172
+ systemctl --user daemon-reload
173
+ ```
174
+
175
+ ## 9. Upgrade
176
+
177
+ ```bash
178
+ npm install -g cdp-mcp@latest
179
+ systemctl --user restart cdp-mcp.service
180
+ ```
181
+
182
+ Restart or reconnect your MCP client after a server upgrade so it reloads tool
183
+ schemas.
184
+
185
+ ## Linux ARM64 / Chromium
186
+
187
+ Google does not publish official Chrome builds for Linux ARM64. If your distro's
188
+ Chromium package is unreliable for DevTools Protocol launches, use a
189
+ Playwright-cached Chromium binary and set `CHROME_PATH` when generating the
190
+ unit:
191
+
192
+ ```bash
193
+ # Install Playwright's Chromium (one-time):
194
+ npx playwright install chromium
195
+
196
+ # Set CHROME_PATH to the latest revision before running the unit-file script:
197
+ export CHROME_PATH="$HOME/.cache/ms-playwright/chromium-1223/chrome-linux/chrome"
198
+ ```
199
+
200
+ Snap Chromium (`/snap/bin/chromium`) can be unreliable for persistent services
201
+ because snap confinement may interfere with `--remote-debugging-port`, headless
202
+ flags, and process lifecycle management. A Playwright-cached Chromium is often
203
+ more predictable for CDP-based debugging sessions. The generated unit's `PATH`
204
+ does not include `/snap/bin`, so if you do use snap Chromium you must set
205
+ `CHROME_PATH=/snap/bin/chromium` explicitly — `launch_chrome` will not
206
+ auto-detect it under the service environment.
207
+
208
+ Playwright upgrades may relocate the binary. After running
209
+ `npx playwright install chromium`, check the new revision directory name (for
210
+ example, `chromium-1223` to `chromium-1250`), update `CHROME_PATH` in the unit
211
+ file, and run:
212
+
213
+ ```bash
214
+ systemctl --user daemon-reload
215
+ systemctl --user restart cdp-mcp.service
216
+ ```
217
+
218
+ For Chromium sandbox flags (`--no-sandbox`, AppArmor, snap confinement) and known
219
+ host-OS launch gaps, see [chromium-sandboxing.md](./chromium-sandboxing.md) and
220
+ [known-chromium-gaps.md](./known-chromium-gaps.md).
221
+
222
+ ## Troubleshooting
223
+
224
+ | Symptom | Fix |
225
+ |---|---|
226
+ | Service exits immediately | Check `journalctl --user -u cdp-mcp.service -n 100`; usually `cdp-mcp` is not installed, Node is too old, or a version-manager path moved |
227
+ | Port 9719 is already in use | Compare `systemctl --user show -p MainPID --value cdp-mcp.service` with `ss -tlnp \| grep 9719`, then stop the other process or change the port |
228
+ | MCP client rejects the config | Confirm the client supports SSE MCP servers and include both `"type": "sse"` and the `/sse` URL if your client uses JSON config |
229
+ | `launch_chrome` cannot find Chrome | Set `CHROME_PATH` in the unit file and restart the service; on Linux ARM64, try Playwright-cached Chromium (`~/.cache/ms-playwright/chromium-*/chrome-linux/chrome`) |
230
+ | Service not starting after reboot | Enable lingering with `sudo loginctl enable-linger "$USER"` |
231
+ | Node not found after reboot with fnm/nvm | Version-manager shell paths can be ephemeral. Recreate the unit with stable `NODE_BIN` and `CDP_SCRIPT` paths, or install with a system Node |
232
+ | `Failed to connect to bus` over SSH | Run `export XDG_RUNTIME_DIR=/run/user/$(id -u)` before using `systemctl --user` |
233
+ | `already_session` after reconnecting | The prior browser/CDP session is still alive. Resume it, or call `close_session` before starting fresh |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdp-mcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Chrome DevTools Protocol MCP server — a TypeScript-aware frontend debugger for AI agents.",
5
5
  "license": "MIT",
6
6
  "author": "Leonard Janke",
@@ -29,7 +29,11 @@
29
29
  },
30
30
  "main": "dist/index.js",
31
31
  "files": [
32
- "dist"
32
+ "dist",
33
+ "docs/launchd-service.md",
34
+ "docs/systemd-service.md",
35
+ "docs/chromium-sandboxing.md",
36
+ "docs/known-chromium-gaps.md"
33
37
  ],
34
38
  "scripts": {
35
39
  "build": "tsc -p tsconfig.json",