mcp-browser-extension 0.9.25 → 0.9.26

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.
Files changed (40) hide show
  1. package/README.md +32 -35
  2. package/SETUP.md +20 -20
  3. package/dist/shared/protocol.d.ts +1 -1
  4. package/dist/shared/tab-border.d.ts +1 -1
  5. package/dist/shared/tab-border.js +1 -1
  6. package/dist/src/access.js +2 -1
  7. package/dist/src/auto-update.d.ts +6 -6
  8. package/dist/src/auto-update.js +9 -8
  9. package/dist/src/bridge/auth.d.ts +3 -3
  10. package/dist/src/bridge/auth.js +5 -4
  11. package/dist/src/bridge/datadir.d.ts +1 -1
  12. package/dist/src/bridge/datadir.js +1 -1
  13. package/dist/src/bridge/evict.d.ts +7 -7
  14. package/dist/src/bridge/evict.js +13 -13
  15. package/dist/src/bridge/peer.d.ts +4 -4
  16. package/dist/src/bridge/peer.js +4 -4
  17. package/dist/src/bridge/server.d.ts +6 -6
  18. package/dist/src/bridge/server.js +11 -11
  19. package/dist/src/cli.d.ts +1 -1
  20. package/dist/src/cli.js +13 -12
  21. package/dist/src/compat.d.ts +4 -0
  22. package/dist/src/compat.js +28 -0
  23. package/dist/src/config.d.ts +4 -4
  24. package/dist/src/config.js +27 -26
  25. package/dist/src/extension-command.js +3 -3
  26. package/dist/src/extension-install.d.ts +4 -4
  27. package/dist/src/extension-install.js +8 -6
  28. package/dist/src/mcp/log.js +2 -2
  29. package/dist/src/mcp/server.d.ts +1 -1
  30. package/dist/src/mcp/server.js +1 -1
  31. package/dist/src/mcp/tools.js +1 -1
  32. package/dist/src/native-host.d.ts +1 -1
  33. package/dist/src/native-host.js +1 -1
  34. package/dist/src/telemetry.d.ts +3 -3
  35. package/dist/src/telemetry.js +7 -6
  36. package/docs/BLUEPRINT.md +11 -11
  37. package/extension-dist/background.js +6 -6
  38. package/extension-dist/manifest.json +1 -1
  39. package/extension-dist/options.html +1 -1
  40. package/package.json +24 -5
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  /**
3
- * src/bridge/evict.ts — take a pinned port back from a stale chrome-mcp.
3
+ * src/bridge/evict.ts — take a pinned port back from a stale mcp-browser-extension.
4
4
  *
5
- * A second session normally JOINS the chrome-mcp holding the port as a peer
5
+ * A second session normally JOINS the mcp-browser-extension holding the port as a peer
6
6
  * (see ./peer) and nobody is stopped. This is the fallback for when joining
7
- * fails: an older chrome-mcp that can't share the port, or a hung one. It will
7
+ * fails: an older mcp-browser-extension that can't share the port, or a hung one. It will
8
8
  * never release the port on its own, so rather than fail with EADDRINUSE and
9
9
  * make the user kill it by hand, we do that for them.
10
10
  *
@@ -13,13 +13,13 @@
13
13
  * - the handshake names that port (so it describes *this* listener), and
14
14
  * - the pid is not us, and
15
15
  * - the pid is alive, and
16
- * - its command line mentions chrome-mcp.
16
+ * - its command line mentions mcp-browser-extension.
17
17
  * If any check fails we leave the process alone and let the caller surface the
18
18
  * plain-English port-busy error instead. Refusing to evict is always safe; a
19
19
  * wrong kill is not.
20
20
  */
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.looksLikeChromeMcp = looksLikeChromeMcp;
22
+ exports.looksLikeMcpBrowserExtension = looksLikeMcpBrowserExtension;
23
23
  exports.evictPortOwner = evictPortOwner;
24
24
  const node_child_process_1 = require("node:child_process");
25
25
  const auth_1 = require("./auth");
@@ -42,7 +42,7 @@ function isAlive(pid) {
42
42
  * Full command line of `pid`, or null if it can't be read.
43
43
  *
44
44
  * Windows needs PowerShell/CIM: `tasklist` reports only the image name
45
- * ("node.exe"), which can't distinguish chrome-mcp from any other Node process
45
+ * ("node.exe"), which can't distinguish mcp-browser-extension from any other Node process
46
46
  * — far too weak a signal to kill on.
47
47
  */
48
48
  function commandLine(pid) {
@@ -68,12 +68,12 @@ function commandLine(pid) {
68
68
  return null;
69
69
  }
70
70
  }
71
- /** Does this command line belong to a chrome-mcp server? */
72
- function looksLikeChromeMcp(cmdline) {
73
- return /chrome-mcp/i.test(cmdline);
71
+ /** Does this command line belong to a mcp-browser-extension server? */
72
+ function looksLikeMcpBrowserExtension(cmdline) {
73
+ return /(?:mcp-browser-extension|chrome-mcp)/i.test(cmdline);
74
74
  }
75
75
  /**
76
- * Try to free `port` by terminating the chrome-mcp that owns it.
76
+ * Try to free `port` by terminating the mcp-browser-extension that owns it.
77
77
  * Returns true only if an owner was found, killed, and confirmed gone.
78
78
  */
79
79
  async function evictPortOwner(dataDir, port, log, deps = {}) {
@@ -100,12 +100,12 @@ async function evictPortOwner(dataDir, port, log, deps = {}) {
100
100
  if (!alive(pid))
101
101
  return false;
102
102
  const cmdline = cmdOf(pid);
103
- if (!cmdline || !looksLikeChromeMcp(cmdline)) {
104
- log(`port ${port} is held by pid ${pid}, which does not look like chrome-mcp — ` +
103
+ if (!cmdline || !looksLikeMcpBrowserExtension(cmdline)) {
104
+ log(`port ${port} is held by pid ${pid}, which does not look like mcp-browser-extension — ` +
105
105
  `leaving it alone. Stop it yourself, or use a different --port.`);
106
106
  return false;
107
107
  }
108
- log(`port ${port} is held by chrome-mcp pid ${pid} (another session) — taking the port over`);
108
+ log(`port ${port} is held by mcp-browser-extension pid ${pid} (another session) — taking the port over`);
109
109
  try {
110
110
  kill(pid, 'SIGTERM');
111
111
  }
@@ -1,10 +1,10 @@
1
1
  /**
2
- * src/bridge/peer.ts — let several chrome-mcp servers share one Chrome.
2
+ * src/bridge/peer.ts — let several mcp-browser-extension servers share one Chrome.
3
3
  *
4
- * Every MCP host session (each Claude terminal/tab) spawns its own chrome-mcp,
4
+ * Every MCP host session (each Claude terminal/tab) spawns its own mcp-browser-extension,
5
5
  * but a browser's extension dials exactly one port. So the first server to bind
6
6
  * the port is the HUB: it owns the extension connections. A later server that
7
- * finds the port held by a live chrome-mcp joins it as a PEER over the same
7
+ * finds the port held by a live mcp-browser-extension joins it as a PEER over the same
8
8
  * port and relays its commands through the hub, instead of killing it. If the
9
9
  * hub exits, its peers race to bind the port; the winner becomes the new hub
10
10
  * (with the same token, so the extension re-pairs on its own) and the rest join
@@ -93,7 +93,7 @@ export declare class HubLink {
93
93
  private constructor();
94
94
  /**
95
95
  * Join the hub on `port` with `token`. Resolves null when nothing answers as a
96
- * chrome-mcp hub in time: a wrong token, an older server that doesn't speak
96
+ * mcp-browser-extension hub in time: a wrong token, an older server that doesn't speak
97
97
  * the peer protocol (it ignores the frame and times us out), or no listener.
98
98
  */
99
99
  static join(host: string, port: number, token: string, onClose: () => void, onGrant?: (host: string, allow: boolean) => void): Promise<HubLink | null>;
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  /**
3
- * src/bridge/peer.ts — let several chrome-mcp servers share one Chrome.
3
+ * src/bridge/peer.ts — let several mcp-browser-extension servers share one Chrome.
4
4
  *
5
- * Every MCP host session (each Claude terminal/tab) spawns its own chrome-mcp,
5
+ * Every MCP host session (each Claude terminal/tab) spawns its own mcp-browser-extension,
6
6
  * but a browser's extension dials exactly one port. So the first server to bind
7
7
  * the port is the HUB: it owns the extension connections. A later server that
8
- * finds the port held by a live chrome-mcp joins it as a PEER over the same
8
+ * finds the port held by a live mcp-browser-extension joins it as a PEER over the same
9
9
  * port and relays its commands through the hub, instead of killing it. If the
10
10
  * hub exits, its peers race to bind the port; the winner becomes the new hub
11
11
  * (with the same token, so the extension re-pairs on its own) and the rest join
@@ -64,7 +64,7 @@ class HubLink {
64
64
  }
65
65
  /**
66
66
  * Join the hub on `port` with `token`. Resolves null when nothing answers as a
67
- * chrome-mcp hub in time: a wrong token, an older server that doesn't speak
67
+ * mcp-browser-extension hub in time: a wrong token, an older server that doesn't speak
68
68
  * the peer protocol (it ignores the frame and times us out), or no listener.
69
69
  */
70
70
  static join(host, port, token, onClose, onGrant) {
@@ -10,7 +10,7 @@
10
10
  * 3. On success, send `welcome` and file the connection under its profile
11
11
  * (superseding only that profile's prior one — a security-relevant
12
12
  * displacement event).
13
- * Other chrome-mcp servers (one per Claude session) may join the same port as
13
+ * Other mcp-browser-extension servers (one per Claude session) may join the same port as
14
14
  * peers with `peer_hello` and relay their commands through us; see ./peer.
15
15
  */
16
16
  import { type WireEvent, type WireMethod, type WirePolicy } from '../../shared/protocol';
@@ -65,7 +65,7 @@ export interface BridgeOptions {
65
65
  host?: string;
66
66
  heartbeatMs?: number;
67
67
  /** Data dir holding the handshake. Enables reclaiming a pinned port from a
68
- * stale chrome-mcp (see ./evict). Omit to disable eviction entirely. */
68
+ * stale mcp-browser-extension (see ./evict). Omit to disable eviction entirely. */
69
69
  dataDir?: string;
70
70
  /** Diagnostics — MUST never receive the token (a test asserts this). */
71
71
  onLog?: (message: string) => void;
@@ -74,7 +74,7 @@ export interface BridgeOptions {
74
74
  /**
75
75
  * Called whenever this server takes a role on the port: 'hub' when it binds
76
76
  * it (publish the handshake + pairing files then), 'peer' when it joins the
77
- * chrome-mcp already holding it. Fires again after a failover.
77
+ * mcp-browser-extension already holding it. Fires again after a failover.
78
78
  */
79
79
  onRole?: (role: BridgeRole, info: {
80
80
  port: number;
@@ -103,7 +103,7 @@ export declare class BridgeServer {
103
103
  private token;
104
104
  /** Peer role: the link to the hub that owns the browsers. */
105
105
  private hub;
106
- /** Hub role: the other chrome-mcp servers relaying through us. */
106
+ /** Hub role: the other mcp-browser-extension servers relaying through us. */
107
107
  private readonly peers;
108
108
  private stopped;
109
109
  /** The last extension hello this hub turned away, for telling a stale token
@@ -133,12 +133,12 @@ export declare class BridgeServer {
133
133
  get role(): BridgeRole | null;
134
134
  /**
135
135
  * Bind and start listening, or — when a pinned port is held by another live
136
- * chrome-mcp — join it as a peer. Returns the port (useful with port 0).
136
+ * mcp-browser-extension — join it as a peer. Returns the port (useful with port 0).
137
137
  */
138
138
  start(): Promise<number>;
139
139
  private claim;
140
140
  /**
141
- * Join the chrome-mcp holding `port` as a peer. Tries the token in the
141
+ * Join the mcp-browser-extension holding `port` as a peer. Tries the token in the
142
142
  * handshake it published first (sessions without --persist-token each mint
143
143
  * their own), then ours.
144
144
  */
@@ -11,7 +11,7 @@
11
11
  * 3. On success, send `welcome` and file the connection under its profile
12
12
  * (superseding only that profile's prior one — a security-relevant
13
13
  * displacement event).
14
- * Other chrome-mcp servers (one per Claude session) may join the same port as
14
+ * Other mcp-browser-extension servers (one per Claude session) may join the same port as
15
15
  * peers with `peer_hello` and relay their commands through us; see ./peer.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -105,7 +105,7 @@ class BridgeServer {
105
105
  token;
106
106
  /** Peer role: the link to the hub that owns the browsers. */
107
107
  hub = null;
108
- /** Hub role: the other chrome-mcp servers relaying through us. */
108
+ /** Hub role: the other mcp-browser-extension servers relaying through us. */
109
109
  peers = new Set();
110
110
  stopped = false;
111
111
  /** The last extension hello this hub turned away, for telling a stale token
@@ -171,7 +171,7 @@ class BridgeServer {
171
171
  }
172
172
  /**
173
173
  * Bind and start listening, or — when a pinned port is held by another live
174
- * chrome-mcp — join it as a peer. Returns the port (useful with port 0).
174
+ * mcp-browser-extension — join it as a peer. Returns the port (useful with port 0).
175
175
  */
176
176
  async start() {
177
177
  if (this.wss || this.hub)
@@ -205,16 +205,16 @@ class BridgeServer {
205
205
  const inUse = err?.code === 'EADDRINUSE';
206
206
  if (!inUse || port === 0)
207
207
  throw inUse ? new Error(portBusyMessage(host, port)) : err;
208
- // Another Claude session's chrome-mcp owns the port: share it rather
208
+ // Another Claude session's mcp-browser-extension owns the port: share it rather
209
209
  // than kill it, so every session keeps working at once.
210
210
  if (!triedJoin) {
211
211
  triedJoin = true;
212
212
  if (await this.joinHub(host, port))
213
213
  return this.boundPort;
214
214
  }
215
- // Still busy after a failed join: an older chrome-mcp that can't share,
215
+ // Still busy after a failed join: an older mcp-browser-extension that can't share,
216
216
  // or a hung one. It will never release the port on its own, so take it
217
- // over (once). Only a verified chrome-mcp is ever killed; anything else
217
+ // over (once). Only a verified mcp-browser-extension is ever killed; anything else
218
218
  // falls through to the wait-and-retry below.
219
219
  if (!evicted && this.opts.dataDir) {
220
220
  evicted = true;
@@ -231,7 +231,7 @@ class BridgeServer {
231
231
  }
232
232
  }
233
233
  /**
234
- * Join the chrome-mcp holding `port` as a peer. Tries the token in the
234
+ * Join the mcp-browser-extension holding `port` as a peer. Tries the token in the
235
235
  * handshake it published first (sessions without --persist-token each mint
236
236
  * their own), then ours.
237
237
  */
@@ -252,7 +252,7 @@ class BridgeServer {
252
252
  this.hub = link;
253
253
  this.token = token;
254
254
  this.boundPort = port;
255
- this.log(`port ${host}:${port} is held by chrome-mcp pid ${link.hubPid || '?'} — sharing its browsers as a peer`);
255
+ this.log(`port ${host}:${port} is held by mcp-browser-extension pid ${link.hubPid || '?'} — sharing its browsers as a peer`);
256
256
  this.opts.onRole?.('peer', { port, token, hubPid: link.hubPid });
257
257
  return true;
258
258
  }
@@ -275,7 +275,7 @@ class BridgeServer {
275
275
  this.hub = null;
276
276
  if (this.stopped)
277
277
  return;
278
- this.log('the chrome-mcp sharing its browsers with us went away — taking over the port');
278
+ this.log('the mcp-browser-extension sharing its browsers with us went away — taking over the port');
279
279
  void this.failover();
280
280
  }
281
281
  async failover() {
@@ -565,7 +565,7 @@ class BridgeServer {
565
565
  return;
566
566
  }
567
567
  if (frame.type === 'peer_hello') {
568
- // Another chrome-mcp (a second Claude session) joining to share our browsers.
568
+ // Another mcp-browser-extension (a second Claude session) joining to share our browsers.
569
569
  const peer = frame;
570
570
  clearTimeout(helloTimer);
571
571
  if (peer.v !== protocol_1.PROTOCOL_VERSION)
@@ -632,7 +632,7 @@ class BridgeServer {
632
632
  /** Hub side: serve a joined peer's relayed commands against our browsers. */
633
633
  acceptPeer(ws, pid) {
634
634
  this.peers.add(ws);
635
- this.log(`chrome-mcp pid ${pid ?? '?'} joined as a peer (${this.peers.size} sharing these browsers)`);
635
+ this.log(`mcp-browser-extension pid ${pid ?? '?'} joined as a peer (${this.peers.size} sharing these browsers)`);
636
636
  this.sendPeer(ws, { type: 'peer_welcome', hubPid: process.pid });
637
637
  this.sendPeer(ws, { type: 'peer_state', profiles: this.pairedProfiles() });
638
638
  ws.on('message', (raw) => this.handlePeerFrame(ws, raw.toString()));
package/dist/src/cli.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * src/cli.ts — `npx chrome-mcp` entrypoint.
3
+ * src/cli.ts — `npx mcp-browser-extension` entrypoint.
4
4
  *
5
5
  * Boot order: resolve config → ensure data dir → generate a per-boot token →
6
6
  * start the loopback bridge → write the 0600 handshake → configure the manager
package/dist/src/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  /**
4
- * src/cli.ts — `npx chrome-mcp` entrypoint.
4
+ * src/cli.ts — `npx mcp-browser-extension` entrypoint.
5
5
  *
6
6
  * Boot order: resolve config → ensure data dir → generate a per-boot token →
7
7
  * start the loopback bridge → write the 0600 handshake → configure the manager
@@ -10,6 +10,7 @@
10
10
  * prints the handshake path (for manual pairing), never serving MCP.
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
+ const compat_1 = require("./compat");
13
14
  const node_fs_1 = require("node:fs");
14
15
  const node_path_1 = require("node:path");
15
16
  const config_1 = require("./config");
@@ -79,7 +80,7 @@ function bundledExtensionVersion() {
79
80
  }
80
81
  /**
81
82
  * Mirror the bundled extension into the visible install folder
82
- * (`~/chrome-mcp-extension`) and report where Chrome should load it from. On a
83
+ * (`~/mcp-browser-extension`) and report where Chrome should load it from. On a
83
84
  * read-only home the bundled folder is returned instead; both are loadable.
84
85
  */
85
86
  function installExtension() {
@@ -122,11 +123,11 @@ function flag(args, name) {
122
123
  function hasFlag(args, name) {
123
124
  return args.includes(name);
124
125
  }
125
- const TASKS_HELP = `chrome-mcp tasks — inspect and prune per-profile task workspaces.
126
+ const TASKS_HELP = `mcp-browser-extension tasks — inspect and prune per-profile task workspaces.
126
127
 
127
128
  Usage:
128
- chrome-mcp tasks list [--json] [--data-dir <path>]
129
- chrome-mcp tasks gc [--older-than <days>] [--keep <n>] [--profile <name>]
129
+ mcp-browser-extension tasks list [--json] [--data-dir <path>]
130
+ mcp-browser-extension tasks gc [--older-than <days>] [--keep <n>] [--profile <name>]
130
131
  [--dry-run] [--data-dir <path>]
131
132
 
132
133
  gc removes a task only when it is NOT among the newest --keep AND is older than
@@ -143,7 +144,7 @@ function runTasksCommand(argv) {
143
144
  const sub = args[0];
144
145
  const dataDirFlag = flag(args, '--data-dir');
145
146
  if (dataDirFlag)
146
- process.env.CHROME_MCP_DATA = dataDirFlag;
147
+ process.env.MCP_BROWSER_EXTENSION_DATA = dataDirFlag;
147
148
  const dataDir = (0, config_1.resolveDataDir)();
148
149
  if (sub === 'list') {
149
150
  const tasks = (0, tasks_1.listTasks)(dataDir);
@@ -238,7 +239,7 @@ async function main() {
238
239
  process.stdout.write(`${installExtension()}\n`);
239
240
  return;
240
241
  }
241
- // Before anything binds the port: if npm has a newer chrome-mcp, run that
242
+ // Before anything binds the port: if npm has a newer mcp-browser-extension, run that
242
243
  // instead (stdio passes straight through), so no install stays on an old copy.
243
244
  const handedOff = await (0, auto_update_1.maybeHandOff)({
244
245
  current: version(),
@@ -275,7 +276,7 @@ async function main() {
275
276
  if (role === 'hub')
276
277
  publishPairing(info.port, info.token);
277
278
  else {
278
- (0, server_2.logErr)(`sharing the browsers of the chrome-mcp already on port ${info.port} (pid ${info.hubPid || '?'}) — several sessions can drive Chrome at once`);
279
+ (0, server_2.logErr)(`sharing the browsers of the mcp-browser-extension already on port ${info.port} (pid ${info.hubPid || '?'}) — several sessions can drive Chrome at once`);
279
280
  // Refresh the unpacked extension folder from this session too: the hub
280
281
  // may be an old process from a window left open for days, and it would
281
282
  // keep the folder on its old files. The mirror never downgrades.
@@ -293,11 +294,11 @@ async function main() {
293
294
  // Drop the same port + token into the bundled extension folder so a Load
294
295
  // unpacked from there pairs itself. Best-effort: a read-only install just
295
296
  // falls back to the Options-page paste. Never take over a pairing file that
296
- // a different, still-running chrome-mcp published (a second server with its
297
+ // a different, still-running mcp-browser-extension published (a second server with its
297
298
  // own data dir or port would otherwise re-point the user's extension).
298
299
  const extDir = installExtension();
299
300
  if (await (0, auth_1.bundledPairingHeldByOther)(extDir, port)) {
300
- (0, server_2.logErr)(`auto-pairing file at ${extDir} belongs to another running chrome-mcp — left as is; pair this server from the extension Options page if you want it`);
301
+ (0, server_2.logErr)(`auto-pairing file at ${extDir} belongs to another running mcp-browser-extension — left as is; pair this server from the extension Options page if you want it`);
301
302
  return;
302
303
  }
303
304
  const bundled = (0, auth_1.writeBundledPairing)(extDir, { port, token: pairToken });
@@ -349,8 +350,8 @@ async function main() {
349
350
  policy: cfg.policy,
350
351
  })}`);
351
352
  const handshakePath = (0, datadir_1.handshakePath)(dataDir);
352
- if (process.env.CHROME_MCP_TOKEN) {
353
- (0, server_2.logErr)('token: pinned from CHROME_MCP_TOKEN (stable; pair once, never again).');
353
+ if ((0, compat_1.runtimeEnv)('TOKEN')) {
354
+ (0, server_2.logErr)('token: pinned from MCP_BROWSER_EXTENSION_TOKEN (stable; pair once, never again).');
354
355
  }
355
356
  else if (cfg.persistToken) {
356
357
  (0, server_2.logErr)('token: persisted across restarts (--persist-token; pair once, never again).');
@@ -0,0 +1,4 @@
1
+ /** New configuration names take precedence; existing installations still work. */
2
+ export declare function runtimeEnv(key: string, env?: NodeJS.ProcessEnv): string | undefined;
3
+ /** Expose the new path without moving files that a running browser still uses. */
4
+ export declare function renamedDirectory(home: string, name: string, legacyName: string): string;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runtimeEnv = runtimeEnv;
4
+ exports.renamedDirectory = renamedDirectory;
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ /** New configuration names take precedence; existing installations still work. */
8
+ function runtimeEnv(key, env = process.env) {
9
+ return env[`MCP_BROWSER_EXTENSION_${key}`] ?? env[`CHROME_MCP_${key}`];
10
+ }
11
+ /** Expose the new path without moving files that a running browser still uses. */
12
+ function renamedDirectory(home, name, legacyName) {
13
+ const current = (0, node_path_1.join)(home, name);
14
+ const legacy = (0, node_path_1.join)(home, legacyName);
15
+ if ((0, node_fs_1.existsSync)(current) || !(0, node_fs_1.existsSync)(legacy))
16
+ return current;
17
+ try {
18
+ if (!(0, node_fs_1.statSync)(legacy).isDirectory())
19
+ return current;
20
+ (0, node_fs_1.symlinkSync)(legacy, current, process.platform === 'win32' ? 'junction' : 'dir');
21
+ return current;
22
+ }
23
+ catch {
24
+ // Another process may have created the alias, or the home may be read-only.
25
+ return (0, node_fs_1.existsSync)(current) ? current : legacy;
26
+ }
27
+ }
28
+ //# sourceMappingURL=compat.js.map
@@ -41,7 +41,7 @@ export interface CliConfig {
41
41
  /** `--no-site-grants`: the allowlist is exactly what the flags say; the
42
42
  * extension's Options page cannot add sites at runtime. */
43
43
  noSiteGrants: boolean;
44
- /** `--no-auto-update`: run this copy even when npm has a newer chrome-mcp. */
44
+ /** `--no-auto-update`: run this copy even when npm has a newer mcp-browser-extension. */
45
45
  noAutoUpdate: boolean;
46
46
  /** `--no-native-host`: don't register the one-click pairing helper with Chrome. */
47
47
  noNativeHost: boolean;
@@ -63,7 +63,7 @@ export interface CliConfig {
63
63
  showVersion: boolean;
64
64
  logLevel: LogLevel;
65
65
  }
66
- /** Resolve the data dir: `$CHROME_MCP_DATA` or `~/.chrome-mcp`. */
66
+ /** Resolve the data dir: `$MCP_BROWSER_EXTENSION_DATA` or `~/.mcp-browser-extension`. */
67
67
  export declare function resolveDataDir(): string;
68
68
  /**
69
69
  * Reduce an arbitrary label to a single safe path segment: no separators, no
@@ -71,9 +71,9 @@ export declare function resolveDataDir(): string;
71
71
  * the data dir, so they must never escape it.
72
72
  */
73
73
  export declare function sanitizeName(name: string, kind: 'profile' | 'task'): string;
74
- /** Active profile: `$CHROME_MCP_PROFILE` (set by `--profile`) or "default". */
74
+ /** Active profile: `$MCP_BROWSER_EXTENSION_PROFILE` (set by `--profile`) or "default". */
75
75
  export declare function resolveProfile(): string;
76
- /** Active task: `$CHROME_MCP_TASK` (set by `--task`) or "default". */
76
+ /** Active task: `$MCP_BROWSER_EXTENSION_TASK` (set by `--task`) or "default". */
77
77
  export declare function resolveTask(): string;
78
78
  /** `profiles/<profile>/` — holds the Chrome user-data dir and this profile's tasks. */
79
79
  export declare function resolveProfileDir(dataDir: string, profile: string): string;
@@ -21,11 +21,12 @@ const node_path_1 = require("node:path");
21
21
  const node_fs_1 = require("node:fs");
22
22
  const protocol_1 = require("../shared/protocol");
23
23
  const policy_1 = require("./security/policy");
24
+ const compat_1 = require("./compat");
24
25
  /** Local port for `--http` (one above the bridge's). */
25
26
  exports.DEFAULT_HTTP_PORT = 38018;
26
- /** Resolve the data dir: `$CHROME_MCP_DATA` or `~/.chrome-mcp`. */
27
+ /** Resolve the data dir: `$MCP_BROWSER_EXTENSION_DATA` or `~/.mcp-browser-extension`. */
27
28
  function resolveDataDir() {
28
- return process.env.CHROME_MCP_DATA ?? (0, node_path_1.join)((0, node_os_1.homedir)(), '.chrome-mcp');
29
+ return (0, compat_1.runtimeEnv)('DATA') ?? (0, compat_1.renamedDirectory)((0, node_os_1.homedir)(), '.mcp-browser-extension', '.chrome-mcp');
29
30
  }
30
31
  const DEFAULT_PROFILE = 'default';
31
32
  const DEFAULT_TASK = 'default';
@@ -41,13 +42,13 @@ function sanitizeName(name, kind) {
41
42
  }
42
43
  return clean;
43
44
  }
44
- /** Active profile: `$CHROME_MCP_PROFILE` (set by `--profile`) or "default". */
45
+ /** Active profile: `$MCP_BROWSER_EXTENSION_PROFILE` (set by `--profile`) or "default". */
45
46
  function resolveProfile() {
46
- return sanitizeName(process.env.CHROME_MCP_PROFILE ?? DEFAULT_PROFILE, 'profile');
47
+ return sanitizeName((0, compat_1.runtimeEnv)('PROFILE') ?? DEFAULT_PROFILE, 'profile');
47
48
  }
48
- /** Active task: `$CHROME_MCP_TASK` (set by `--task`) or "default". */
49
+ /** Active task: `$MCP_BROWSER_EXTENSION_TASK` (set by `--task`) or "default". */
49
50
  function resolveTask() {
50
- return sanitizeName(process.env.CHROME_MCP_TASK ?? DEFAULT_TASK, 'task');
51
+ return sanitizeName((0, compat_1.runtimeEnv)('TASK') ?? DEFAULT_TASK, 'task');
51
52
  }
52
53
  /** `profiles/<profile>/` — holds the Chrome user-data dir and this profile's tasks. */
53
54
  function resolveProfileDir(dataDir, profile) {
@@ -71,7 +72,7 @@ function readPolicyFile(path) {
71
72
  * read triggered by `--policy <path>`.
72
73
  */
73
74
  function parseArgs(argv) {
74
- let wsPort = envInt('CHROME_MCP_WS_PORT') ?? protocol_1.DEFAULT_WS_PORT;
75
+ let wsPort = envInt('MCP_BROWSER_EXTENSION_WS_PORT') ?? protocol_1.DEFAULT_WS_PORT;
75
76
  // Extension-only by default: never launch/attach a Chromium of our own unless
76
77
  // the operator explicitly opts in with --cdp-fallback (or --prefer cdp / --cdp-endpoint).
77
78
  let cdpFallback = false;
@@ -85,7 +86,7 @@ function parseArgs(argv) {
85
86
  let noAutoUpdate = false;
86
87
  let noNativeHost = false;
87
88
  let http = false;
88
- let httpPort = envInt('CHROME_MCP_HTTP_PORT') ?? exports.DEFAULT_HTTP_PORT;
89
+ let httpPort = envInt('MCP_BROWSER_EXTENSION_HTTP_PORT') ?? exports.DEFAULT_HTTP_PORT;
89
90
  let tunnel = false;
90
91
  let rotateRemoteKey = false;
91
92
  let showHelp = false;
@@ -117,13 +118,13 @@ function parseArgs(argv) {
117
118
  wsPort = requireInt(argv[++i], '--port');
118
119
  break;
119
120
  case '--data-dir':
120
- process.env.CHROME_MCP_DATA = requireValue(argv[++i], '--data-dir');
121
+ process.env.MCP_BROWSER_EXTENSION_DATA = requireValue(argv[++i], '--data-dir');
121
122
  break;
122
123
  case '--profile':
123
- process.env.CHROME_MCP_PROFILE = requireValue(argv[++i], '--profile');
124
+ process.env.MCP_BROWSER_EXTENSION_PROFILE = requireValue(argv[++i], '--profile');
124
125
  break;
125
126
  case '--task':
126
- process.env.CHROME_MCP_TASK = requireValue(argv[++i], '--task');
127
+ process.env.MCP_BROWSER_EXTENSION_TASK = requireValue(argv[++i], '--task');
127
128
  break;
128
129
  case '--policy':
129
130
  policyFile = readPolicyFile(requireValue(argv[++i], '--policy'));
@@ -288,7 +289,7 @@ function parseArgs(argv) {
288
289
  // Small parsing helpers
289
290
  // ---------------------------------------------------------------------------
290
291
  function envInt(name) {
291
- const raw = process.env[name];
292
+ const raw = (0, compat_1.runtimeEnv)(name.replace(/^MCP_BROWSER_EXTENSION_/, ''));
292
293
  if (raw === undefined)
293
294
  return undefined;
294
295
  const n = Number.parseInt(raw, 10);
@@ -325,17 +326,17 @@ function requireLogLevel(value) {
325
326
  throw new Error('--log-level must be "silent", "info", or "debug"');
326
327
  }
327
328
  /** Help text for `--help`. */
328
- exports.HELP_TEXT = `chrome-mcp — the MCP Browser Extension server: drive your real Chrome over MCP.
329
+ exports.HELP_TEXT = `mcp-browser-extension — the MCP Browser Extension server: drive your real Chrome over MCP.
329
330
 
330
- Usage: chrome-mcp [options]
331
- chrome-mcp extension doctor [--json] [--user-data-dir <browser directory>]
332
- chrome-mcp extension repair [--apply] [--user-data-dir <browser directory>]
333
- chrome-mcp tasks list [--json]
334
- chrome-mcp tasks gc [--older-than <days>] [--keep <n>] [--profile <name>] [--dry-run]
331
+ Usage: mcp-browser-extension [options]
332
+ mcp-browser-extension extension doctor [--json] [--user-data-dir <browser directory>]
333
+ mcp-browser-extension extension repair [--apply] [--user-data-dir <browser directory>]
334
+ mcp-browser-extension tasks list [--json]
335
+ mcp-browser-extension tasks gc [--older-than <days>] [--keep <n>] [--profile <name>] [--dry-run]
335
336
 
336
337
  Connection:
337
338
  --port <n> WebSocket bridge port (default ${protocol_1.DEFAULT_WS_PORT}; 0 = ephemeral)
338
- --data-dir <path> Override the data dir (default ~/.chrome-mcp)
339
+ --data-dir <path> Override the data dir (default ~/.mcp-browser-extension)
339
340
  --profile <name> Default browser profile / identity (default "default").
340
341
  Artifacts live under profiles/<name>/. At runtime, switch
341
342
  with the profile_use tool. Several browsers can pair to the
@@ -347,31 +348,31 @@ Connection:
347
348
  land in profiles/<profile>/tasks/<task>/.
348
349
  --print-pairing Write the handshake, print its path, and keep the bridge
349
350
  up until Ctrl-C (manual pairing; never serves MCP)
350
- --extension-path Install the extension to ~/chrome-mcp-extension (or
351
- CHROME_MCP_EXTENSION_DIR) and print that path — the folder
351
+ --extension-path Install the extension to ~/mcp-browser-extension (or
352
+ MCP_BROWSER_EXTENSION_EXTENSION_DIR) and print that path — the folder
352
353
  to pick in chrome://extensions -> Load unpacked. The server
353
354
  also refreshes it on every boot.
354
355
  --persist-token Reuse a stable on-disk token across restarts so the
355
356
  extension never has to re-pair (default: fresh per boot).
356
- CHROME_MCP_TOKEN env, if set, pins the token explicitly.
357
+ MCP_BROWSER_EXTENSION_TOKEN env, if set, pins the token explicitly.
357
358
  --no-native-host Don't register the helper behind the extension's one-click
358
359
  Connect button (pairing is then by pasting port and token)
359
360
  --http Serve MCP over HTTP on 127.0.0.1 instead of stdio, so a
360
361
  client elsewhere can connect. Runs until Ctrl-C. Every
361
362
  request needs the remote key (kept in <data-dir>/remote-key):
362
363
  in the path, /mcp/<key>, or as Authorization: Bearer <key>.
363
- --http-port <n> Port for --http (default 38018; env CHROME_MCP_HTTP_PORT)
364
+ --http-port <n> Port for --http (default 38018; env MCP_BROWSER_EXTENSION_HTTP_PORT)
364
365
  --tunnel --http plus a Cloudflare quick tunnel, and print a public
365
366
  connector URL for claude.ai, ChatGPT or any MCP client.
366
367
  Needs cloudflared. The URL changes on every start.
367
368
  --rotate-remote-key Make a new remote key: every remote client is cut off and
368
369
  needs the new URL.
369
- --no-auto-update Run this copy even when a newer chrome-mcp is published.
370
+ --no-auto-update Run this copy even when a newer mcp-browser-extension is published.
370
371
  By default an installed copy (npx or global) checks npm at
371
372
  startup and hands off to the latest release, so you never
372
- run a stale version. Same as CHROME_MCP_AUTO_UPDATE=0.
373
+ run a stale version. Same as MCP_BROWSER_EXTENSION_AUTO_UPDATE=0.
373
374
  --no-telemetry Send no anonymous usage statistics. Same as
374
- CHROME_MCP_TELEMETRY=0 or DO_NOT_TRACK=1. Only counts are
375
+ MCP_BROWSER_EXTENSION_TELEMETRY=0 or DO_NOT_TRACK=1. Only counts are
375
376
  ever sent (version, OS, tool calls, error codes) — never
376
377
  URLs, page content or arguments.
377
378
 
@@ -4,10 +4,10 @@ exports.runExtensionCommand = runExtensionCommand;
4
4
  const node_path_1 = require("node:path");
5
5
  const config_1 = require("./config");
6
6
  const extension_repair_1 = require("./extension-repair");
7
- const HELP = `chrome-mcp extension — diagnose an extension missing after a browser restart.
7
+ const HELP = `mcp-browser-extension extension — diagnose an extension missing after a browser restart.
8
8
 
9
- chrome-mcp extension doctor [--json] [--user-data-dir <browser directory>]
10
- chrome-mcp extension repair [--apply] [--json] [--user-data-dir <browser directory>]
9
+ mcp-browser-extension extension doctor [--json] [--user-data-dir <browser directory>]
10
+ mcp-browser-extension extension repair [--apply] [--json] [--user-data-dir <browser directory>]
11
11
  [--data-dir <backup parent>]
12
12
 
13
13
  doctor is read-only and reports the actual Store/unpacked registration.
@@ -6,23 +6,23 @@
6
6
  * folders deep under `npm root -g`, and an npx run hides it in a cache. So on
7
7
  * every boot (and on `--extension-path`) the server mirrors the bundled
8
8
  * `extension-dist/` into a plain, visible folder directly under the home
9
- * directory — `~/chrome-mcp-extension` — and that is the folder the docs, the
9
+ * directory — `~/mcp-browser-extension` — and that is the folder the docs, the
10
10
  * pairing file, and `--extension-path` all point at.
11
11
  *
12
12
  * The copy is a one-way mirror of top-level regular files, written only when
13
13
  * content differs, so an unchanged boot touches nothing. It never deletes: the
14
14
  * target may hold `pairing.json` (ours) and, if the operator pointed
15
- * CHROME_MCP_EXTENSION_DIR somewhere of their own, files that are not ours to
15
+ * MCP_BROWSER_EXTENSION_EXTENSION_DIR somewhere of their own, files that are not ours to
16
16
  * remove. It never throws — a read-only home just falls back to the bundled
17
17
  * folder, which still works for Load unpacked.
18
18
  */
19
19
  /** Folder name under the home directory. */
20
- export declare const EXTENSION_DIR_NAME = "chrome-mcp-extension";
20
+ export declare const EXTENSION_DIR_NAME = "mcp-browser-extension";
21
21
  /** The auto-pairing file the server writes; never copied, never overwritten by the mirror. */
22
22
  export declare const PAIRING_FILE = "pairing.json";
23
23
  /** `dist/src/extension-install.js` -> `<pkg>/extension-dist`, which the tarball ships. */
24
24
  export declare function bundledExtensionDir(): string;
25
- /** Where the extension is mirrored for Load unpacked. `CHROME_MCP_EXTENSION_DIR` overrides. */
25
+ /** Where the extension is mirrored for Load unpacked. `MCP_BROWSER_EXTENSION_EXTENSION_DIR` overrides. */
26
26
  export declare function extensionInstallDir(): string;
27
27
  export interface SyncResult {
28
28
  /** The folder that now holds the extension (the target on success, the source on failure). */