@mehmoodqureshi/chrome-mcp 0.9.0 → 0.9.1
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 +3 -3
- package/SETUP.md +6 -5
- package/dist/src/cli.js +1 -1
- package/extension-dist/background.js +21 -4
- package/extension-dist/icon128.png +0 -0
- package/extension-dist/icon16.png +0 -0
- package/extension-dist/icon32.png +0 -0
- package/extension-dist/icon48.png +0 -0
- package/extension-dist/manifest.json +16 -3
- package/extension-dist/options.html +1 -1
- package/extension-dist/options.js +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -126,8 +126,8 @@ npx -y @mehmoodqureshi/chrome-mcp --extension-path
|
|
|
126
126
|
|
|
127
127
|
Then `chrome://extensions` → enable **Developer mode** → **Load unpacked** →
|
|
128
128
|
pick `chrome-mcp-extension` in your home folder. After upgrading the package the
|
|
129
|
-
server refreshes the files on its next boot
|
|
130
|
-
|
|
129
|
+
server refreshes the files on its next boot and the extension reloads itself
|
|
130
|
+
within 30 seconds; nothing to click. `CHROME_MCP_EXTENSION_DIR` moves the
|
|
131
131
|
folder somewhere else. (Working from a git clone instead? Run
|
|
132
132
|
`npm install && npm run build:ext` first — `extension-dist/` is gitignored, and
|
|
133
133
|
the server mirrors it to the same home folder.)
|
|
@@ -142,7 +142,7 @@ run? It re-checks every 30 seconds and pairs as soon as the file appears.
|
|
|
142
142
|
**Where to see the badge:** it sits on the extension's icon in Chrome's
|
|
143
143
|
toolbar, not on the `chrome://extensions` page. Chrome hides new extensions
|
|
144
144
|
behind the puzzle-piece button at the right of the address bar, so click that,
|
|
145
|
-
find **
|
|
145
|
+
find **MCP Extension for Chrome**, and click the pin next to it once; the icon then
|
|
146
146
|
stays in the toolbar. Hover it for the status in words.
|
|
147
147
|
|
|
148
148
|
| Badge | Meaning |
|
package/SETUP.md
CHANGED
|
@@ -47,8 +47,9 @@ It prints `~/chrome-mcp-extension` (on Windows `%USERPROFILE%\chrome-mcp-extensi
|
|
|
47
47
|
Verify with `ls` (or `dir`) that the folder holds `manifest.json` and
|
|
48
48
|
`background.js`. Record the path; the human needs it in step 4. The install is
|
|
49
49
|
small and downloads no browser: the server drives the Chrome the human already
|
|
50
|
-
has. The server refreshes this folder on every boot
|
|
51
|
-
|
|
50
|
+
has. The server refreshes this folder on every boot and the loaded extension
|
|
51
|
+
reloads itself when the version changes, so upgrades need nothing from the
|
|
52
|
+
human.
|
|
52
53
|
|
|
53
54
|
## Step 3 — Wire the server into this MCP client
|
|
54
55
|
|
|
@@ -107,7 +108,7 @@ You cannot do this step yourself. Give the human these exact instructions:
|
|
|
107
108
|
2. Turn on **Developer mode** (top right).
|
|
108
109
|
3. Click **Load unpacked** and choose the `chrome-mcp-extension` folder in
|
|
109
110
|
their home directory (the path from step 2).
|
|
110
|
-
4. Confirm an extension named **
|
|
111
|
+
4. Confirm an extension named **MCP Extension for Chrome** now appears in the list.
|
|
111
112
|
|
|
112
113
|
Wait for the human to confirm before continuing.
|
|
113
114
|
|
|
@@ -137,7 +138,7 @@ new extensions behind the puzzle-piece button at the right of the address bar,
|
|
|
137
138
|
so give them these exact steps:
|
|
138
139
|
|
|
139
140
|
1. Click the puzzle-piece button at the right of the address bar.
|
|
140
|
-
2. Find **
|
|
141
|
+
2. Find **MCP Extension for Chrome** in the list and click the pin icon next to it.
|
|
141
142
|
The extension icon now stays in the toolbar.
|
|
142
143
|
3. Look at the small badge on that icon. Hovering it shows the status in words.
|
|
143
144
|
|
|
@@ -158,7 +159,7 @@ printing the token,
|
|
|
158
159
|
node -e "console.log(require(require('os').homedir()+'/.chrome-mcp/handshake.json').port)"
|
|
159
160
|
```
|
|
160
161
|
|
|
161
|
-
then have the human open **Details** on
|
|
162
|
+
then have the human open **Details** on MCP Extension for Chrome, then **Extension
|
|
162
163
|
options**, enter that **Port**, open `~/.chrome-mcp/handshake.json` in a text
|
|
163
164
|
editor and paste its `token` into the **Token** field, leave **Profile** as
|
|
164
165
|
`default`, and click **Save**. The status line should read **connected** within
|
package/dist/src/cli.js
CHANGED
|
@@ -67,7 +67,7 @@ function installExtension() {
|
|
|
67
67
|
(0, server_2.logErr)(`extension installed at ${r.dir} — chrome://extensions -> Load unpacked -> pick that folder`);
|
|
68
68
|
}
|
|
69
69
|
else if (r.copied.length > 0) {
|
|
70
|
-
(0, server_2.logErr)(`extension files updated at ${r.dir} —
|
|
70
|
+
(0, server_2.logErr)(`extension files updated at ${r.dir} — a loaded extension reloads itself within 30 s`);
|
|
71
71
|
}
|
|
72
72
|
return r.dir;
|
|
73
73
|
}
|
|
@@ -1609,6 +1609,21 @@
|
|
|
1609
1609
|
await chrome.storage.local.set({ wsPort: bundled.wsPort, token: bundled.token, pairingSource: "auto" });
|
|
1610
1610
|
return true;
|
|
1611
1611
|
}
|
|
1612
|
+
async function reloadIfFilesChanged() {
|
|
1613
|
+
try {
|
|
1614
|
+
const res = await fetch(chrome.runtime.getURL("manifest.json"), { cache: "no-store" });
|
|
1615
|
+
if (!res.ok) return;
|
|
1616
|
+
const onDisk = await res.json();
|
|
1617
|
+
const loaded = chrome.runtime.getManifest().version;
|
|
1618
|
+
if (typeof onDisk.version !== "string" || onDisk.version === loaded) return;
|
|
1619
|
+
const { reloadedFor } = await chrome.storage.local.get("reloadedFor");
|
|
1620
|
+
if (reloadedFor === onDisk.version) return;
|
|
1621
|
+
await chrome.storage.local.set({ reloadedFor: onDisk.version });
|
|
1622
|
+
console.info(`[chrome-mcp] extension files updated on disk (${loaded} -> ${onDisk.version}); reloading`);
|
|
1623
|
+
chrome.runtime.reload();
|
|
1624
|
+
} catch {
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1612
1627
|
async function getConfig() {
|
|
1613
1628
|
const { wsPort, token, profile } = await chrome.storage.local.get(["wsPort", "token", "profile"]);
|
|
1614
1629
|
if (typeof wsPort === "number" && wsPort > 0 && typeof token === "string" && token.length > 0) {
|
|
@@ -1618,10 +1633,10 @@
|
|
|
1618
1633
|
return null;
|
|
1619
1634
|
}
|
|
1620
1635
|
var BADGE = {
|
|
1621
|
-
connected: { text: "\u25CF", color: "#16a34a", title: "Chrome
|
|
1622
|
-
connecting: { text: "\u2026", color: "#ca8a04", title: "Chrome
|
|
1623
|
-
unauthorized: { text: "!", color: "#dc2626", title: "Chrome
|
|
1624
|
-
idle: { text: "\u25CB", color: "#6b7280", title: "Chrome
|
|
1636
|
+
connected: { text: "\u25CF", color: "#16a34a", title: "MCP Extension for Chrome \u2014 connected" },
|
|
1637
|
+
connecting: { text: "\u2026", color: "#ca8a04", title: "MCP Extension for Chrome \u2014 connecting" },
|
|
1638
|
+
unauthorized: { text: "!", color: "#dc2626", title: "MCP Extension for Chrome \u2014 rejected (bad/stale token; re-pair)" },
|
|
1639
|
+
idle: { text: "\u25CB", color: "#6b7280", title: "MCP Extension for Chrome \u2014 not connected (open options to pair)" }
|
|
1625
1640
|
};
|
|
1626
1641
|
function reflectBadge(state) {
|
|
1627
1642
|
const b = BADGE[state] ?? BADGE.idle;
|
|
@@ -1644,6 +1659,7 @@
|
|
|
1644
1659
|
}
|
|
1645
1660
|
async function keepalivePulse() {
|
|
1646
1661
|
await chrome.storage.local.get("connState");
|
|
1662
|
+
await reloadIfFilesChanged();
|
|
1647
1663
|
if (!ws.isConnected() && !await getConfig()) await adoptBundledPairing();
|
|
1648
1664
|
await ensureConnected();
|
|
1649
1665
|
}
|
|
@@ -1668,6 +1684,7 @@
|
|
|
1668
1684
|
});
|
|
1669
1685
|
async function bootstrap() {
|
|
1670
1686
|
await chrome.alarms.create(KEEPALIVE_ALARM, { periodInMinutes: 0.5 });
|
|
1687
|
+
await reloadIfFilesChanged();
|
|
1671
1688
|
if (!await adoptBundledPairing()) await ensureConnected();
|
|
1672
1689
|
}
|
|
1673
1690
|
void bootstrap();
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
|
-
"name": "
|
|
4
|
-
"version": "0.9.
|
|
3
|
+
"name": "MCP Extension for Chrome",
|
|
4
|
+
"version": "0.9.1",
|
|
5
5
|
"description": "Lets a local chrome-mcp server drive this browser. Pair it with the server's handshake token.",
|
|
6
|
+
"homepage_url": "https://github.com/Mehmoodqureshi/chrome-mcp",
|
|
6
7
|
"minimum_chrome_version": "116",
|
|
8
|
+
"icons": {
|
|
9
|
+
"16": "icon16.png",
|
|
10
|
+
"32": "icon32.png",
|
|
11
|
+
"48": "icon48.png",
|
|
12
|
+
"128": "icon128.png"
|
|
13
|
+
},
|
|
7
14
|
"background": {
|
|
8
15
|
"service_worker": "background.js"
|
|
9
16
|
},
|
|
@@ -22,6 +29,12 @@
|
|
|
22
29
|
],
|
|
23
30
|
"options_page": "options.html",
|
|
24
31
|
"action": {
|
|
25
|
-
"default_title": "Chrome
|
|
32
|
+
"default_title": "MCP Extension for Chrome — open options to pair",
|
|
33
|
+
"default_icon": {
|
|
34
|
+
"16": "icon16.png",
|
|
35
|
+
"32": "icon32.png",
|
|
36
|
+
"48": "icon48.png",
|
|
37
|
+
"128": "icon128.png"
|
|
38
|
+
}
|
|
26
39
|
}
|
|
27
40
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
|
-
<title>Chrome
|
|
5
|
+
<title>MCP Extension for Chrome — Pairing</title>
|
|
6
6
|
<style>
|
|
7
7
|
body { font: 14px/1.5 system-ui, sans-serif; max-width: 32rem; margin: 2rem auto; padding: 0 1rem; }
|
|
8
8
|
h1 { font-size: 1.2rem; }
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"connState",
|
|
18
18
|
"pairingSource"
|
|
19
19
|
]);
|
|
20
|
-
sourceEl.textContent = pairingSource === "auto" ? "Paired automatically from the pairing.json the server wrote into this extension folder. Saving here overrides it." : pairingSource === "manual" ? "Paired by hand. Saved values take precedence over the bundled pairing.json." : "Not paired yet. If you loaded this extension from the chrome-mcp package folder, start the server once and it pairs itself; otherwise paste the values below.";
|
|
20
|
+
sourceEl.textContent = pairingSource === "auto" ? "Paired automatically from the pairing.json the server wrote into this extension folder. Saving here overrides it." : pairingSource === "manual" ? "Paired by hand. Saved values take precedence over the bundled pairing.json." : typeof wsPort === "number" && wsPort > 0 && connState !== "idle" ? "Paired with values saved by an earlier version. Saving here keeps them manual." : "Not paired yet. If you loaded this extension from the chrome-mcp package folder, start the server once and it pairs itself; otherwise paste the values below.";
|
|
21
21
|
portEl.value = typeof wsPort === "number" && wsPort > 0 ? String(wsPort) : String(DEFAULT_WS_PORT);
|
|
22
22
|
profileEl.value = typeof profile === "string" ? profile : "";
|
|
23
23
|
render(typeof connState === "string" ? connState : "idle");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mehmoodqureshi/chrome-mcp",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Drive your real Chrome browser over MCP — 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.",
|
|
5
5
|
"author": "Mehmood Ur Rehman Qureshi",
|
|
6
6
|
"license": "MIT",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"scripts": {
|
|
52
52
|
"build": "tsc -p tsconfig.json",
|
|
53
53
|
"build:ext": "node extension/scripts/build-ext.mjs",
|
|
54
|
+
"pack:ext": "npm run build:ext && rm -f chrome-mcp-extension-$npm_package_version.zip && cd extension-dist && zip -q -r ../chrome-mcp-extension-$npm_package_version.zip . -x pairing.json '.*' && cd .. && ls -la chrome-mcp-extension-$npm_package_version.zip",
|
|
54
55
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
55
56
|
"typecheck:ext": "tsc -p tsconfig.ext.json",
|
|
56
57
|
"clean": "rimraf dist extension-dist",
|