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.
- package/README.md +32 -35
- package/SETUP.md +20 -20
- package/dist/shared/protocol.d.ts +1 -1
- package/dist/shared/tab-border.d.ts +1 -1
- package/dist/shared/tab-border.js +1 -1
- package/dist/src/access.js +2 -1
- package/dist/src/auto-update.d.ts +6 -6
- package/dist/src/auto-update.js +9 -8
- package/dist/src/bridge/auth.d.ts +3 -3
- package/dist/src/bridge/auth.js +5 -4
- package/dist/src/bridge/datadir.d.ts +1 -1
- package/dist/src/bridge/datadir.js +1 -1
- package/dist/src/bridge/evict.d.ts +7 -7
- package/dist/src/bridge/evict.js +13 -13
- package/dist/src/bridge/peer.d.ts +4 -4
- package/dist/src/bridge/peer.js +4 -4
- package/dist/src/bridge/server.d.ts +6 -6
- package/dist/src/bridge/server.js +11 -11
- package/dist/src/cli.d.ts +1 -1
- package/dist/src/cli.js +13 -12
- package/dist/src/compat.d.ts +4 -0
- package/dist/src/compat.js +28 -0
- package/dist/src/config.d.ts +4 -4
- package/dist/src/config.js +27 -26
- package/dist/src/extension-command.js +3 -3
- package/dist/src/extension-install.d.ts +4 -4
- package/dist/src/extension-install.js +8 -6
- package/dist/src/mcp/log.js +2 -2
- package/dist/src/mcp/server.d.ts +1 -1
- package/dist/src/mcp/server.js +1 -1
- package/dist/src/mcp/tools.js +1 -1
- package/dist/src/native-host.d.ts +1 -1
- package/dist/src/native-host.js +1 -1
- package/dist/src/telemetry.d.ts +3 -3
- package/dist/src/telemetry.js +7 -6
- package/docs/BLUEPRINT.md +11 -11
- package/extension-dist/background.js +6 -6
- package/extension-dist/manifest.json +1 -1
- package/extension-dist/options.html +1 -1
- package/package.json +24 -5
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
* folders deep under `npm root -g`, and an npx run hides it in a cache. So on
|
|
8
8
|
* every boot (and on `--extension-path`) the server mirrors the bundled
|
|
9
9
|
* `extension-dist/` into a plain, visible folder directly under the home
|
|
10
|
-
* directory — `~/
|
|
10
|
+
* directory — `~/mcp-browser-extension` — and that is the folder the docs, the
|
|
11
11
|
* pairing file, and `--extension-path` all point at.
|
|
12
12
|
*
|
|
13
13
|
* The copy is a one-way mirror of top-level regular files, written only when
|
|
14
14
|
* content differs, so an unchanged boot touches nothing. It never deletes: the
|
|
15
15
|
* target may hold `pairing.json` (ours) and, if the operator pointed
|
|
16
|
-
*
|
|
16
|
+
* MCP_BROWSER_EXTENSION_EXTENSION_DIR somewhere of their own, files that are not ours to
|
|
17
17
|
* remove. It never throws — a read-only home just falls back to the bundled
|
|
18
18
|
* folder, which still works for Load unpacked.
|
|
19
19
|
*/
|
|
@@ -27,18 +27,20 @@ const node_os_1 = require("node:os");
|
|
|
27
27
|
const node_path_1 = require("node:path");
|
|
28
28
|
const node_fs_1 = require("node:fs");
|
|
29
29
|
const atomic_file_1 = require("./atomic-file");
|
|
30
|
+
const compat_1 = require("./compat");
|
|
30
31
|
/** Folder name under the home directory. */
|
|
31
|
-
exports.EXTENSION_DIR_NAME = '
|
|
32
|
+
exports.EXTENSION_DIR_NAME = 'mcp-browser-extension';
|
|
32
33
|
/** The auto-pairing file the server writes; never copied, never overwritten by the mirror. */
|
|
33
34
|
exports.PAIRING_FILE = 'pairing.json';
|
|
34
35
|
/** `dist/src/extension-install.js` -> `<pkg>/extension-dist`, which the tarball ships. */
|
|
35
36
|
function bundledExtensionDir() {
|
|
36
37
|
return (0, node_path_1.resolve)(__dirname, '..', '..', 'extension-dist');
|
|
37
38
|
}
|
|
38
|
-
/** Where the extension is mirrored for Load unpacked. `
|
|
39
|
+
/** Where the extension is mirrored for Load unpacked. `MCP_BROWSER_EXTENSION_EXTENSION_DIR` overrides. */
|
|
39
40
|
function extensionInstallDir() {
|
|
40
|
-
const override =
|
|
41
|
-
return override && override.trim() ? (0, node_path_1.resolve)(override.trim())
|
|
41
|
+
const override = (0, compat_1.runtimeEnv)('EXTENSION_DIR');
|
|
42
|
+
return override && override.trim() ? (0, node_path_1.resolve)(override.trim())
|
|
43
|
+
: (0, compat_1.renamedDirectory)((0, node_os_1.homedir)(), exports.EXTENSION_DIR_NAME, 'chrome-mcp-extension');
|
|
42
44
|
}
|
|
43
45
|
function readManifest(path) {
|
|
44
46
|
const value = JSON.parse((0, node_fs_1.readFileSync)(path, 'utf8'));
|
package/dist/src/mcp/log.js
CHANGED
|
@@ -32,12 +32,12 @@ function getLogLevel() {
|
|
|
32
32
|
function logErr(message) {
|
|
33
33
|
if (logLevel === 'silent')
|
|
34
34
|
return;
|
|
35
|
-
process.stderr.write(`[
|
|
35
|
+
process.stderr.write(`[mcp-browser-extension] ${message}\n`);
|
|
36
36
|
}
|
|
37
37
|
/** Verbose tracing: emitted only at `--log-level debug`. */
|
|
38
38
|
function logDebug(message) {
|
|
39
39
|
if (logLevel !== 'debug')
|
|
40
40
|
return;
|
|
41
|
-
process.stderr.write(`[
|
|
41
|
+
process.stderr.write(`[mcp-browser-extension] [debug] ${message}\n`);
|
|
42
42
|
}
|
|
43
43
|
//# sourceMappingURL=log.js.map
|
package/dist/src/mcp/server.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* src/mcp/server.ts — MCP server bootstrap over stdio.
|
|
3
3
|
*
|
|
4
4
|
* Wires the SDK `Server` to a `StdioServerTransport` so an MCP host (Claude)
|
|
5
|
-
* drives
|
|
5
|
+
* drives mcp-browser-extension over JSON-RPC on stdin/stdout. CRITICAL: in stdio mode
|
|
6
6
|
* NOTHING may be written to stdout except the JSON-RPC stream — all diagnostics
|
|
7
7
|
* go to stderr via `logErr`.
|
|
8
8
|
*/
|
package/dist/src/mcp/server.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* src/mcp/server.ts — MCP server bootstrap over stdio.
|
|
4
4
|
*
|
|
5
5
|
* Wires the SDK `Server` to a `StdioServerTransport` so an MCP host (Claude)
|
|
6
|
-
* drives
|
|
6
|
+
* drives mcp-browser-extension over JSON-RPC on stdin/stdout. CRITICAL: in stdio mode
|
|
7
7
|
* NOTHING may be written to stdout except the JSON-RPC stream — all diagnostics
|
|
8
8
|
* go to stderr via `logErr`.
|
|
9
9
|
*/
|
package/dist/src/mcp/tools.js
CHANGED
|
@@ -387,7 +387,7 @@ function capabilityStatus(policy) {
|
|
|
387
387
|
disabledCapabilities: off,
|
|
388
388
|
capabilityHint: 'These tools are not available in this session because their capability is off. ' +
|
|
389
389
|
'If the user asks for one of them, tell them to add the listed flag to the MCP Browser Extension ' +
|
|
390
|
-
"server's entry (
|
|
390
|
+
"server's entry (mcp-browser-extension) in their MCP config and restart the client.",
|
|
391
391
|
};
|
|
392
392
|
}
|
|
393
393
|
/** The names actually advertised, in catalog order. */
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* - `registerNativeHost()`: the server writes the host's launcher script and
|
|
15
15
|
* its manifest into each installed browser's NativeMessagingHosts folder
|
|
16
16
|
* (the registry on Windows). Best-effort and idempotent.
|
|
17
|
-
* - `runNativeHost()`: what `
|
|
17
|
+
* - `runNativeHost()`: what `mcp-browser-extension --native-host` runs when Chrome starts
|
|
18
18
|
* the host: read one message, answer with the pairing, exit.
|
|
19
19
|
*/
|
|
20
20
|
/** The host's name, as the extension addresses it. */
|
package/dist/src/native-host.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* - `registerNativeHost()`: the server writes the host's launcher script and
|
|
16
16
|
* its manifest into each installed browser's NativeMessagingHosts folder
|
|
17
17
|
* (the registry on Windows). Best-effort and idempotent.
|
|
18
|
-
* - `runNativeHost()`: what `
|
|
18
|
+
* - `runNativeHost()`: what `mcp-browser-extension --native-host` runs when Chrome starts
|
|
19
19
|
* the host: read one message, answer with the pairing, exit.
|
|
20
20
|
*/
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
package/dist/src/telemetry.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* src/telemetry.ts — anonymous usage statistics from the
|
|
2
|
+
* src/telemetry.ts — anonymous usage statistics from the mcp-browser-extension SERVER.
|
|
3
3
|
*
|
|
4
|
-
* What it sends, to PostHog: a random per-install id, the
|
|
4
|
+
* What it sends, to PostHog: a random per-install id, the mcp-browser-extension version,
|
|
5
5
|
* OS, CPU architecture and Node major version, whether this session owns the
|
|
6
6
|
* port or shares it, how many browsers are paired (and, when none, which of a
|
|
7
7
|
* few fixed reasons applies), per-tool call and error
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* The browser extension sends nothing; this lives only in the npm server.
|
|
13
13
|
*
|
|
14
14
|
* On by default with a one-time notice on first run. Off with
|
|
15
|
-
*
|
|
15
|
+
* MCP_BROWSER_EXTENSION_TELEMETRY=0 (or false/off), DO_NOT_TRACK=1, or --no-telemetry.
|
|
16
16
|
* Every failure is swallowed: telemetry can never break or slow a tool call.
|
|
17
17
|
*/
|
|
18
18
|
/** PostHog project key. Public by design: it can only WRITE events, never read them. */
|
package/dist/src/telemetry.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* src/telemetry.ts — anonymous usage statistics from the
|
|
3
|
+
* src/telemetry.ts — anonymous usage statistics from the mcp-browser-extension SERVER.
|
|
4
4
|
*
|
|
5
|
-
* What it sends, to PostHog: a random per-install id, the
|
|
5
|
+
* What it sends, to PostHog: a random per-install id, the mcp-browser-extension version,
|
|
6
6
|
* OS, CPU architecture and Node major version, whether this session owns the
|
|
7
7
|
* port or shares it, how many browsers are paired (and, when none, which of a
|
|
8
8
|
* few fixed reasons applies), per-tool call and error
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* The browser extension sends nothing; this lives only in the npm server.
|
|
14
14
|
*
|
|
15
15
|
* On by default with a one-time notice on first run. Off with
|
|
16
|
-
*
|
|
16
|
+
* MCP_BROWSER_EXTENSION_TELEMETRY=0 (or false/off), DO_NOT_TRACK=1, or --no-telemetry.
|
|
17
17
|
* Every failure is swallowed: telemetry can never break or slow a tool call.
|
|
18
18
|
*/
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -31,6 +31,7 @@ const node_fs_1 = require("node:fs");
|
|
|
31
31
|
const node_os_1 = require("node:os");
|
|
32
32
|
const node_path_1 = require("node:path");
|
|
33
33
|
const tool_categories_1 = require("./mcp/tool-categories");
|
|
34
|
+
const compat_1 = require("./compat");
|
|
34
35
|
/** PostHog project key. Public by design: it can only WRITE events, never read them. */
|
|
35
36
|
exports.POSTHOG_KEY = 'phc_CG5QX5JEkRokfUN87rZQnPa3URdLWePCZnfqW6MCyCdU';
|
|
36
37
|
exports.POSTHOG_HOST = 'https://us.i.posthog.com';
|
|
@@ -54,13 +55,13 @@ const MCP_SESSION_IDLE_MS = 30 * 60_000;
|
|
|
54
55
|
const SEND_TIMEOUT_MS = 3_000;
|
|
55
56
|
const STATE_FILE = 'telemetry.json';
|
|
56
57
|
exports.TELEMETRY_NOTICE = 'MCP Browser Extension collects anonymous usage statistics (version, OS, tool call and error counts; never URLs, ' +
|
|
57
|
-
'page content or arguments) to see how it is used. Turn it off with
|
|
58
|
-
'Details: https://github.com/Mehmoodqureshi/
|
|
58
|
+
'page content or arguments) to see how it is used. Turn it off with MCP_BROWSER_EXTENSION_TELEMETRY=0 or DO_NOT_TRACK=1. ' +
|
|
59
|
+
'Details: https://github.com/Mehmoodqureshi/mcp-browser-extension#telemetry';
|
|
59
60
|
/** Whether the user has turned telemetry off, by env or flag. */
|
|
60
61
|
function telemetryDisabled(env, disabledByFlag = false) {
|
|
61
62
|
if (disabledByFlag)
|
|
62
63
|
return true;
|
|
63
|
-
const own = (
|
|
64
|
+
const own = ((0, compat_1.runtimeEnv)('TELEMETRY', env) ?? '').trim().toLowerCase();
|
|
64
65
|
if (['0', 'false', 'off', 'no'].includes(own))
|
|
65
66
|
return true;
|
|
66
67
|
const dnt = (env.DO_NOT_TRACK ?? '').trim().toLowerCase();
|
package/docs/BLUEPRINT.md
CHANGED
|
@@ -21,11 +21,11 @@ over **stdio**; the extension speaks the canonical frame protocol over a
|
|
|
21
21
|
```
|
|
22
22
|
┌──────────────────────────────────────────────────────────────┐
|
|
23
23
|
WORLD 1 │ MCP HOST (Claude Desktop / Claude Code) │
|
|
24
|
-
(the model)│ spawns: npx
|
|
24
|
+
(the model)│ spawns: npx mcp-browser-extension │
|
|
25
25
|
└───────────────┬──────────────────────────────────────────────┘
|
|
26
26
|
│ JSON-RPC over stdio (stdout = SACRED)
|
|
27
27
|
┌───────────────▼──────────────────────────────────────────────┐
|
|
28
|
-
WORLD 2 │
|
|
28
|
+
WORLD 2 │ mcp-browser-extension CLI (one Node process) │
|
|
29
29
|
(server) │ │
|
|
30
30
|
│ ┌────────────┐ ┌──────────────────┐ ┌─────────────────┐ │
|
|
31
31
|
│ │ MCP Server │──▶│ tools.ts │──▶│ ExecutorManager │ │
|
|
@@ -70,13 +70,13 @@ takes over from CDP and vice-versa on disconnect.
|
|
|
70
70
|
|
|
71
71
|
## 2. Repository Layout
|
|
72
72
|
|
|
73
|
-
Single sibling repo `
|
|
73
|
+
Single sibling repo `mcp-browser-extension/` (NOT a workspace). Two build roots in one git
|
|
74
74
|
repo so the wire protocol version-locks between server and extension. The shared
|
|
75
75
|
`protocol.ts` lives at the top so both builds import the *same file*.
|
|
76
76
|
|
|
77
77
|
```
|
|
78
|
-
|
|
79
|
-
├── package.json # bin:
|
|
78
|
+
mcp-browser-extension/
|
|
79
|
+
├── package.json # bin: mcp-browser-extension -> dist/cli.js; deps sdk, ws, playwright
|
|
80
80
|
├── tsconfig.json
|
|
81
81
|
├── README.md
|
|
82
82
|
├── .gitignore # dist/, extension-dist/, test-targets.json, *.handshake
|
|
@@ -107,7 +107,7 @@ chrome-mcp/
|
|
|
107
107
|
│ │ ├── server.ts # BridgeServer: ws on 127.0.0.1, token gate, id-correlation, heartbeat
|
|
108
108
|
│ │ ├── connection.ts # ExtensionConnection: pending-map, timeouts, reject-all-on-close
|
|
109
109
|
│ │ ├── auth.ts # token gen, atomic 0600 handshake.json, hashed constant-time compare
|
|
110
|
-
│ │ └── datadir.ts # Electron-free
|
|
110
|
+
│ │ └── datadir.ts # Electron-free MCP_BROWSER_EXTENSION_DATA || ~/.mcp-browser-extension
|
|
111
111
|
│ └── security/
|
|
112
112
|
│ └── policy.ts # Policy type, loadPolicy, assertUrlAllowed (default-deny, gates reads)
|
|
113
113
|
│
|
|
@@ -331,8 +331,8 @@ export type ExecutorErrorCode =
|
|
|
331
331
|
```
|
|
332
332
|
|
|
333
333
|
**Auth handshake (the canonical, ONLY model):** [RESOLVED — security blocker 1, minor 7]
|
|
334
|
-
1. Server, at boot, generates a **fresh 256-bit token every boot**, never persisted/reused: `crypto.randomBytes(32).toString('base64url')`. It writes `{ v, port, token, pid, ts, expectedExtensionId? }` **atomically** (tmp + `rename`) to `$
|
|
335
|
-
2. The extension acquires `{port, token}` from the handshake file via a **native-messaging trampoline** (`extension/src/nm/`) — the only component that can read a 0600 file the model/attacker cannot. v1 ships a **manual fallback**: the user runs `npx
|
|
334
|
+
1. Server, at boot, generates a **fresh 256-bit token every boot**, never persisted/reused: `crypto.randomBytes(32).toString('base64url')`. It writes `{ v, port, token, pid, ts, expectedExtensionId? }` **atomically** (tmp + `rename`) to `$MCP_BROWSER_EXTENSION_DATA/handshake.json` with mode **0600**, verifies the mode after write, and **fails closed** if it cannot. The token is **never** written to stdout or stderr or any log. A test asserts this.
|
|
335
|
+
2. The extension acquires `{port, token}` from the handshake file via a **native-messaging trampoline** (`extension/src/nm/`) — the only component that can read a 0600 file the model/attacker cannot. v1 ships a **manual fallback**: the user runs `npx mcp-browser-extension --print-pairing` which prints a **redacted confirmation + the file path** (`handshake.json written to …; open the extension and click Pair`) and the trampoline reads it. **No token on stdout/stderr, no `/connect` HTTP endpoint.** [RESOLVED — security blocker 3]
|
|
336
336
|
3. Extension dials `ws://127.0.0.1:<port>` (port read from handshake via trampoline; see §6 for re-read-on-reconnect) and sends `hello` within 5000ms.
|
|
337
337
|
4. Server compares tokens by **hashing both sides to SHA-256 and `timingSafeEqual`-ing the digests** (no length precondition, no length leak). Match → `welcome`, flip to ACTIVE; mismatch / `v!==1` / timeout → send `unauthorized` then close **4401**. No `command`/`result`/`event` is processed before `welcome`.
|
|
338
338
|
|
|
@@ -456,7 +456,7 @@ truth). The extension learns both via the native-messaging trampoline. **Wheneve
|
|
|
456
456
|
a WS dial FAILS** (server restarted → fresh token + possibly fresh port), the SW
|
|
457
457
|
re-invokes the trampoline to re-read `{port, token}` before the next dial. This
|
|
458
458
|
makes ephemeral ports work: the extension never holds a stale port. The single
|
|
459
|
-
default fixed port is **`38017`** (override `
|
|
459
|
+
default fixed port is **`38017`** (override `MCP_BROWSER_EXTENSION_WS_PORT`); ephemeral
|
|
460
460
|
port `0` is supported precisely because the extension re-reads on failure. The
|
|
461
461
|
port is **not** a security boundary — the token is.
|
|
462
462
|
|
|
@@ -529,7 +529,7 @@ or `launchPersistentContext(userDataDir)` (self-spawn). **Lifted from
|
|
|
529
529
|
Decisions:
|
|
530
530
|
- **Ownership flag `launched`**: `dispose()` closes the context only when `launched===true`; attach mode drops refs only.
|
|
531
531
|
- **Do NOT set `PLAYWRIGHT_BROWSERS_PATH`** (rely on the postinstall cache; respect a pre-set override). Drop the Electron `useBundledBrowsersIfPackaged` branch.
|
|
532
|
-
- **Self-launch profile dir must NOT be the user's real Chrome profile** (`
|
|
532
|
+
- **Self-launch profile dir must NOT be the user's real Chrome profile** (`MCP_BROWSER_EXTENSION_USERDATA` || `~/.mcp-browser-extension/cdp-profile`) — it would conflict with the real Chrome the extension drives.
|
|
533
533
|
- `screenshot` → `page.screenshot({fullPage})` → base64; `eval` → `page.evaluate` wrapped so a page throw becomes `{ok:false}` not a transport-killing throw.
|
|
534
534
|
- **tabId stamping**: CDP guids are prefixed `cdp:<sessionId>:<guid>`; extension ids `ext:<sessionId>:<targetId>`. A handle whose prefix doesn't match the current backend/session → `STALE_TAB` ('call tabs_list again'). [RESOLVED — mv3 major tabId / integration]
|
|
535
535
|
|
|
@@ -588,7 +588,7 @@ Build: `manifest.json`, `sw/background.ts` (top-level listeners, keepalive inter
|
|
|
588
588
|
Build: server-side `extract_links`/`read_as_markdown`/`fill_form` over `Runtime.evaluate`; server-side CDP-fetch `download_file` with sanitized names/size cap; policy enforced at executor + router. *Verify:* `test/hitl/` (cloned harness, Executor handle) — read steps free; mutating steps (`download_file`, `fill_form+submit`, `eval`-side-effect) behind classification + `--include-mutating` + literal `yes` + `test-targets.json` allowlist. Human verdict gate; never CI.
|
|
589
589
|
|
|
590
590
|
**Phase 6 — Packaging & docs.**
|
|
591
|
-
Build: `files` whitelist incl. `extension-dist/`, `--print-pairing`/`--print-extension-path`, `.mcp.json` snippet, README (banner caveat, load-unpacked-only, policy/safe-mode defaults, kill switch). *Verify:* `npx
|
|
591
|
+
Build: `files` whitelist incl. `extension-dist/`, `--print-pairing`/`--print-extension-path`, `.mcp.json` snippet, README (banner caveat, load-unpacked-only, policy/safe-mode defaults, kill switch). *Verify:* `npx mcp-browser-extension` from a packed tarball boots, prints the pairing file path (no token leak), and a fresh Chrome load-unpacked round-trips one navigate→get_text.
|
|
592
592
|
|
|
593
593
|
---
|
|
594
594
|
|
|
@@ -2464,7 +2464,7 @@
|
|
|
2464
2464
|
},
|
|
2465
2465
|
onPolicy: (policy) => {
|
|
2466
2466
|
currentPolicy = policy;
|
|
2467
|
-
void syncObserverScript(policy, (m) => console.debug("[
|
|
2467
|
+
void syncObserverScript(policy, (m) => console.debug("[mcp-browser-extension]", m));
|
|
2468
2468
|
void onAllowlist(policy);
|
|
2469
2469
|
},
|
|
2470
2470
|
// Shown on the Options page, so you can tell which name this browser got.
|
|
@@ -2472,13 +2472,13 @@
|
|
|
2472
2472
|
onGranted: (granted) => void chrome.storage.local.set({ grantedSites: granted }),
|
|
2473
2473
|
onBlocked: (host, method) => void rememberBlocked(host, method),
|
|
2474
2474
|
onLatestExtension: (version) => void chrome.storage.local.set({ latestExtension: version }),
|
|
2475
|
-
log: (m) => console.debug("[
|
|
2475
|
+
log: (m) => console.debug("[mcp-browser-extension]", m)
|
|
2476
2476
|
});
|
|
2477
2477
|
var router = new CommandRouter({
|
|
2478
2478
|
exec: executor,
|
|
2479
2479
|
send: (frame) => ws.send(frame),
|
|
2480
2480
|
getPolicy: () => currentPolicy,
|
|
2481
|
-
log: (m) => console.debug("[
|
|
2481
|
+
log: (m) => console.debug("[mcp-browser-extension]", m),
|
|
2482
2482
|
border
|
|
2483
2483
|
});
|
|
2484
2484
|
async function readBundledPairing() {
|
|
@@ -2512,7 +2512,7 @@
|
|
|
2512
2512
|
const { reloadedFor } = await chrome.storage.local.get("reloadedFor");
|
|
2513
2513
|
if (reloadedFor === onDisk.version) return;
|
|
2514
2514
|
await chrome.storage.local.set({ reloadedFor: onDisk.version });
|
|
2515
|
-
console.info(`[
|
|
2515
|
+
console.info(`[mcp-browser-extension] extension files updated on disk (${loaded} -> ${onDisk.version}); reloading`);
|
|
2516
2516
|
chrome.runtime.reload();
|
|
2517
2517
|
} catch {
|
|
2518
2518
|
}
|
|
@@ -2677,9 +2677,9 @@
|
|
|
2677
2677
|
}
|
|
2678
2678
|
async function syncProxy() {
|
|
2679
2679
|
try {
|
|
2680
|
-
await applyProxy((m) => console.debug("[
|
|
2680
|
+
await applyProxy((m) => console.debug("[mcp-browser-extension]", m));
|
|
2681
2681
|
} catch (err) {
|
|
2682
|
-
console.warn("[
|
|
2682
|
+
console.warn("[mcp-browser-extension] could not apply the proxy setting", err);
|
|
2683
2683
|
}
|
|
2684
2684
|
}
|
|
2685
2685
|
async function bootstrap() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "MCP Browser Extension",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.26",
|
|
5
5
|
"description": "Lets your AI agent (Claude, Cursor, Codex) use the Chrome you are signed into, through a local MCP server. Deny-all by default.",
|
|
6
6
|
"homepage_url": "https://mcp-browser-extension.com",
|
|
7
7
|
"minimum_chrome_version": "116",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
<p class="hint" id="manual-intro">Or pair by hand:</p>
|
|
54
54
|
<p class="hint" id="source">Checking pairing source…</p>
|
|
55
55
|
<p class="hint">
|
|
56
|
-
Manual pairing: run <code>npx -y
|
|
56
|
+
Manual pairing: run <code>npx -y mcp-browser-extension@latest --print-pairing</code>,
|
|
57
57
|
open the printed <code>handshake.json</code>, and paste its <code>port</code>
|
|
58
58
|
and <code>token</code> below.
|
|
59
59
|
</p>
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-browser-extension",
|
|
3
|
-
"mcpName": "io.github.Mehmoodqureshi/
|
|
4
|
-
"version": "0.9.
|
|
5
|
-
"description": "Drive your real Chrome browser over MCP
|
|
3
|
+
"mcpName": "io.github.Mehmoodqureshi/mcp-browser-extension",
|
|
4
|
+
"version": "0.9.26",
|
|
5
|
+
"description": "Drive your real Chrome browser over MCP \u2014 real logins, real cookies. A stdio MCP server (CLI) plus an MV3 extension, driving Chrome via chrome.scripting/chrome.tabs. Multi-tab batch automation, accessibility snapshots, deny-all security by default.",
|
|
6
6
|
"author": "Mehmood Ur Rehman Qureshi",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"homepage": "https://mcp-browser-extension.com",
|
|
@@ -17,8 +17,7 @@
|
|
|
17
17
|
"access": "public"
|
|
18
18
|
},
|
|
19
19
|
"bin": {
|
|
20
|
-
"mcp-browser-extension": "dist/src/cli.js"
|
|
21
|
-
"chrome-mcp": "dist/src/cli.js"
|
|
20
|
+
"mcp-browser-extension": "dist/src/cli.js"
|
|
22
21
|
},
|
|
23
22
|
"files": [
|
|
24
23
|
"dist/src/**/*.js",
|
|
@@ -50,11 +49,31 @@
|
|
|
50
49
|
"claude",
|
|
51
50
|
"claude-code"
|
|
52
51
|
],
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "tsc -p tsconfig.json",
|
|
54
|
+
"build:ext": "node extension/scripts/build-ext.mjs",
|
|
55
|
+
"pack:ext": "npm run build:ext && node extension/scripts/pack-ext.mjs",
|
|
56
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
57
|
+
"typecheck:ext": "tsc -p tsconfig.ext.json",
|
|
58
|
+
"clean": "rimraf dist",
|
|
59
|
+
"test": "npm run clean && npm run build && npm run build:ext && node --test dist/test/*.test.js",
|
|
60
|
+
"test:hitl": "npm run build && node dist/hitl/index.js",
|
|
61
|
+
"prepack": "npm run clean && npm run build && npm run build:ext"
|
|
62
|
+
},
|
|
53
63
|
"dependencies": {
|
|
54
64
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
55
65
|
"ws": "^8.18.0",
|
|
56
66
|
"zod": "^4.4.3"
|
|
57
67
|
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@types/chrome": "^0.0.287",
|
|
70
|
+
"@types/node": "^20.17.10",
|
|
71
|
+
"@types/ws": "^8.5.13",
|
|
72
|
+
"esbuild": "^0.24.0",
|
|
73
|
+
"playwright": "^1.49.1",
|
|
74
|
+
"rimraf": "^5.0.10",
|
|
75
|
+
"typescript": "^5.7.2"
|
|
76
|
+
},
|
|
58
77
|
"engines": {
|
|
59
78
|
"node": ">=18.0.0"
|
|
60
79
|
}
|