@agent360/browser-mcp 1.29.0 → 1.29.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "Agent360 Browser MCP",
4
- "version": "1.29.0",
4
+ "version": "1.29.1",
5
5
  "description": "Give Claude Code your real logged-in Chrome. Two parts: this extension + one npx command. Multi-session, local, MIT.",
6
6
  "permissions": [
7
7
  "tabs",
@@ -14,12 +14,54 @@
14
14
  // samtidig den rigtige semantik: et dokument oprettet af en aeldre udgave baerer
15
15
  // den aeldre version, saa `offscreenSvarer()` kan se forskel paa "svarer" og
16
16
  // "er den udgave vi koerer nu".
17
+ // Plan 1.10 / R2 (Astra): versionsnummeret beviser ikke hvilken KODE der koerer - to kopier med samme nummer kan vaere
18
+ // forskellige, og udgivelsens flowtest kunne derfor godkendes mod gammel kode. Udvidelsen sender derfor et fingeraftryk af
19
+ // sin egen background.js. Kun et hash, og kun til 127.0.0.1: ingen kode forlader maskinen.
20
+ // MAALT 12/9: aftrykket daekkede kun background.js. Samme dag aendrede offscreen.js sig, og den aendring var USYNLIG for
21
+ // udgivelsens spaerre - en gammel kopi af broen kunne passere som kandidaten. Begge kodefiler taeller nu med, i fast
22
+ // raekkefoelge. Det er stadig en byggekontrol: filerne laeses fra den indlaeste udvidelses egen mappe, saa aftrykket
23
+ // beviser hvilke FILER der er indlaest - ikke hvilken kode der koerer i et gammelt offscreen-dokument.
24
+ const KODEFILER = ['background.js', 'offscreen.js'];
25
+ let kodeAftrykCache = null;
26
+ async function kodeAftryk() {
27
+ if (kodeAftrykCache) return kodeAftrykCache;
28
+ try {
29
+ const dele = [];
30
+ for (const fil of KODEFILER) {
31
+ const svar = await fetch(chrome.runtime.getURL(fil));
32
+ dele.push(new Uint8Array(await svar.arrayBuffer()));
33
+ }
34
+ const samlet = new Uint8Array(dele.reduce((n, d) => n + d.length, 0));
35
+ let i = 0;
36
+ for (const d of dele) { samlet.set(d, i); i += d.length; }
37
+ const bytes = new Uint8Array(await crypto.subtle.digest('SHA-256', samlet));
38
+ kodeAftrykCache = Array.from(bytes.slice(0, 6)).map((b) => b.toString(16).padStart(2, '0')).join('');
39
+ } catch (e) {
40
+ console.warn('[Offscreen] kunne ikke beregne kode-aftrykket:', e?.message || e);
41
+ }
42
+ return kodeAftrykCache;
43
+ }
44
+
17
45
  function minVersion() {
18
46
  try { return new URLSearchParams(location.search).get('v') || null; } catch { return null; }
19
47
  }
20
48
 
21
- const BASE_PORT = 9876;
22
- const MAX_PORT = 9895;
49
+ // Portomraadet kommer fra dokumentets egen adresse, sat af background.js ud fra chrome.storage.local.
50
+ // Standarden er 9876-9895. En isoleret testbrowser kan flytte den UDEN at repoets filer aendrer sig, saa
51
+ // kode-aftrykket - og dermed udgivelsens spaerre - er uroert. Vagten staar begge steder: en vaerdi er kun gyldig
52
+ // hvis den er to tal i et fornuftigt spaend. (Astra 12/9.)
53
+ function portOmraade() {
54
+ try {
55
+ const v = new URLSearchParams(location.search).get('porte');
56
+ const m = /^(\d{4,5})-(\d{4,5})$/.exec(v || '');
57
+ if (m) {
58
+ const fra = Number(m[1]), til = Number(m[2]);
59
+ if (fra >= 1024 && til <= 65535 && til >= fra && til - fra < 200) return [fra, til];
60
+ }
61
+ } catch {}
62
+ return [9876, 9895];
63
+ }
64
+ const [BASE_PORT, MAX_PORT] = portOmraade();
23
65
  const connections = new Map(); // port → WebSocket
24
66
 
25
67
  // ── Hvorfor porte foerst PROBES med fetch, og ikke bare aabnes (MAALT 22/8) ──────
@@ -122,7 +164,7 @@ function tryConnect(port) {
122
164
  if (ws.readyState !== WebSocket.OPEN) ws.close();
123
165
  }, 8000);
124
166
 
125
- ws.onopen = () => {
167
+ ws.onopen = async () => {
126
168
  clearTimeout(connectTimeout);
127
169
  connections.set(port, ws); // stadig vores? scanPorts har ikke lavet en nyere
128
170
 
@@ -141,9 +183,15 @@ function tryConnect(port) {
141
183
  // To rettelser: haandtrykket sendes nu UANSET om manifest-opslaget lykkes (det er
142
184
  // selve beskeden serveren har brug for, ikke felterne i den), og en fejl bliver
143
185
  // logget i stedet for at forsvinde.
144
- let hilsen = { type: 'hello', extensionId: null, version: minVersion(), name: null };
186
+ // MAALT 11/9 af Astra (e2e runde 2): haenger hentningen af background.js, blev haandtrykket ALDRIG sendt - og
187
+ // serveren saa en forbindelse uden version. Aftrykket er en bekvemmelighed for udgivelsens gate; hilsenen er ikke.
188
+ // MAALT 12/9 af Astra (efterproevning): fristen paa 1 s var et kaploeb. Tog hentningen 1,3 s, sendte vi `kode: null`,
189
+ // og udgivelsens gate afviste sin EGEN kandidat - et langsomt svar er ikke et forkert svar. Hilsenen sendes derfor
190
+ // med det aftryk der allerede ER beregnet (som regel intet ved foerste forbindelse), og aftrykket EFTERSENDES.
191
+ const kode = kodeAftrykCache;
192
+ let hilsen = { type: 'hello', extensionId: null, version: minVersion(), name: null, kode };
145
193
  try {
146
- hilsen = { type: 'hello', extensionId: chrome.runtime.id, version: minVersion(), name: null };
194
+ hilsen = { type: 'hello', extensionId: chrome.runtime.id, version: minVersion(), name: null, kode };
147
195
  } catch (e) {
148
196
  console.warn('[Offscreen] kunne ikke bygge haandtrykket:', e?.message || e);
149
197
  }
@@ -153,6 +201,15 @@ function tryConnect(port) {
153
201
  console.warn('[Offscreen] kunne ikke sende haandtrykket:', e?.message || e);
154
202
  }
155
203
 
204
+ // Eftersendelsen: naar aftrykket er beregnet, faar serveren det - uanset hvor lang tid hentningen tog.
205
+ if (!kode) {
206
+ kodeAftryk().then((k) => {
207
+ if (!k || ws.readyState !== WebSocket.OPEN) return;
208
+ try { ws.send(JSON.stringify({ type: 'kode', kode: k })); }
209
+ catch (e) { console.warn('[Offscreen] kunne ikke eftersende kode-aftrykket:', e?.message || e); }
210
+ });
211
+ }
212
+
156
213
  console.log(`[Offscreen] Connected to MCP server on port ${port} (${connections.size} total)`);
157
214
  updateStatus();
158
215
  };
@@ -37,16 +37,18 @@
37
37
  .color-purple { border-color: #a855f7; } .color-purple .session-header { color: #a855f7; }
38
38
  .color-cyan { border-color: #06b6d4; } .color-cyan .session-header { color: #06b6d4; }
39
39
  .color-orange { border-color: #f97316; } .color-orange .session-header { color: #f97316; }
40
- /* Shown only while the MCP server is missing the store can't install it for you */
40
+ /* Shown only while the MCP server is missing - the store can't install it for you */
41
41
  .setup { display: none; background: #1e293b; border: 1px solid #334155; border-left: 3px solid #f59e0b; border-radius: 8px; padding: 10px; margin-bottom: 8px; }
42
42
  .setup.show { display: block; }
43
43
  .setup p { font-size: 11px; line-height: 1.5; color: #94a3b8; margin-bottom: 8px; }
44
44
  .setup p b { color: #e2e8f0; }
45
45
  .setup code { display: block; background: #0f172a; border-radius: 6px; padding: 8px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10px; color: #22c55e; word-break: break-all; margin-bottom: 6px; }
46
+ /* De andre klienters kommandoer staar inde i en saetning - de maa ikke blive til blokke som hovedkommandoen. */
47
+ .setup p.clients code { display: inline; padding: 1px 5px; margin: 0; font-size: 10px; }
46
48
  .setup .row { display: flex; gap: 6px; }
47
49
  .setup .row button, .setup .row a { flex: 1; margin: 0; padding: 6px; border-radius: 6px; background: #334155; color: #e2e8f0; font-size: 11px; text-align: center; text-decoration: none; border: none; cursor: pointer; }
48
50
  .setup .row a:hover, .setup .row button:hover { background: #475569; }
49
- /* Shown once both halves are up but the agent has not touched a tab yet the
51
+ /* Shown once both halves are up but the agent has not touched a tab yet - the
50
52
  moment a new user checks "did it work?" and needs to know what to say next. */
51
53
  .try { display: none; background: #1e293b; border: 1px solid #334155; border-left: 3px solid #22c55e; border-radius: 8px; padding: 10px; margin-bottom: 8px; }
52
54
  .try.show { display: block; }
@@ -66,8 +68,11 @@
66
68
  </div>
67
69
 
68
70
  <div class="setup" id="setup">
69
- <p><b>This extension is only half of Browser MCP.</b> It needs a local MCP server to talk to the Chrome Web Store cannot install that part. Register it once, then restart your agent. Claude Code:</p>
71
+ <p><b>Already registered the server?</b> Then this is normal: the server only takes a port the first time your agent actually uses the browser. Ask it for a screenshot once, and this turns into "Connected".</p>
72
+ <p><b>Otherwise: this extension is only half of Browser MCP.</b> It needs a local MCP server to talk to - the Chrome Web Store cannot install that part. Register it once, then restart your agent. Claude Code:</p>
70
73
  <code id="setupCmd">claude mcp add --scope user browser-mcp -- npx @agent360/browser-mcp@latest</code>
74
+ <p class="clients">Codex: <code>codex mcp add browser-mcp -- npx @agent360/browser-mcp@latest</code><br>
75
+ Cursor, VS Code and the rest: run <code>npx @agent360/browser-mcp install</code> - it registers with the clients you have.</p>
71
76
  <div class="row">
72
77
  <button id="copyCmd">Copy command</button>
73
78
  <a href="https://browsermcp.dev/docs/install-claude-code/" target="_blank" rel="noopener">Setup guide</a>
@@ -75,7 +80,7 @@
75
80
  </div>
76
81
 
77
82
  <div class="try" id="try">
78
- <p><b>Connected you're ready.</b> Nothing happens until you ask your agent for something. Try saying:</p>
83
+ <p><b>Connected - you're ready.</b> Nothing happens until you ask your agent for something. Try saying:</p>
79
84
  <span class="prompt">"Take a screenshot of my current Chrome tab."</span>
80
85
  <span class="prompt">"Open my Gmail tab and tell me who sent my last 3 emails."</span>
81
86
  <a href="https://browsermcp.dev/#try" target="_blank" rel="noopener">More things to try</a>
@@ -1,17 +1,17 @@
1
1
  // ── Status ──────────────────────────────────────────────────────────────────
2
2
 
3
3
  // mcpCount = agent clients on the socket. `sessions` = agents that have actually claimed a
4
- // tab. They differ, and showing "Connected 1 session" above "No active sessions" read as a
4
+ // tab. They differ, and showing "Connected - 1 session" above "No active sessions" read as a
5
5
  // contradiction at exactly the moment a new user checks whether the install worked.
6
6
  function paintStatus(connected, count, sessionCount) {
7
7
  document.getElementById('dot').className = `dot ${connected ? 'on' : 'off'}`;
8
8
  document.getElementById('label').textContent = !connected
9
- ? 'Not connected no MCP server found'
9
+ ? 'Not connected - nothing on ports 9876-9895 yet'
10
10
  : sessionCount > 0
11
- ? `Connected ${sessionCount} active session${sessionCount === 1 ? '' : 's'}`
12
- : `Connected ready (${count} agent${count === 1 ? '' : 's'} listening)`;
11
+ ? `Connected - ${sessionCount} active session${sessionCount === 1 ? '' : 's'}`
12
+ : `Connected - ready (${count} agent${count === 1 ? '' : 's'} listening)`;
13
13
  // The Chrome Web Store can only install the extension. If nothing is listening on
14
- // ports 9876-9895, the user almost certainly never ran the npx install say so.
14
+ // ports 9876-9895, the user almost certainly never ran the npx install - say so.
15
15
  document.getElementById('setup').classList.toggle('show', !connected);
16
16
  // Connected but idle: they got it working and now need to know what to say.
17
17
  document.getElementById('try').classList.toggle('show', connected && sessionCount === 0);