@mehmoodqureshi/chrome-mcp 0.9.6 → 0.9.7
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 +25 -0
- package/dist/src/cli.js +11 -1
- package/dist/src/config.d.ts +2 -0
- package/dist/src/config.js +9 -0
- package/dist/src/mcp/tools.js +3 -0
- package/dist/src/telemetry.d.ts +53 -0
- package/dist/src/telemetry.js +207 -0
- package/extension-dist/manifest.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -520,6 +520,31 @@ group/other-accessible. Windows has no such bits — `chmod` there only toggles
|
|
|
520
520
|
read-only attribute — so the check is skipped and the token's confidentiality
|
|
521
521
|
rests on the per-user ACL of `%USERPROFILE%\.chrome-mcp`.
|
|
522
522
|
|
|
523
|
+
## Telemetry
|
|
524
|
+
|
|
525
|
+
The chrome-mcp **server** sends anonymous usage statistics to PostHog, so the
|
|
526
|
+
project can see how many installs are active, which versions and platforms are
|
|
527
|
+
in use, and which tools fail most. A notice is printed the first time it runs.
|
|
528
|
+
|
|
529
|
+
What is sent: a random install id (kept in `~/.chrome-mcp/telemetry.json`), the
|
|
530
|
+
chrome-mcp version, OS, CPU architecture and Node major version, whether the
|
|
531
|
+
session owns the bridge port or shares it, how many browsers are paired, and
|
|
532
|
+
per-tool call and error **counts** with error codes — batched every 10 minutes.
|
|
533
|
+
|
|
534
|
+
What is never sent: URLs, domains, tool arguments, page content, screenshots,
|
|
535
|
+
cookies, profile names, tokens, file paths, or anything you type. Events are
|
|
536
|
+
personless and GeoIP lookup is disabled.
|
|
537
|
+
|
|
538
|
+
The **browser extension sends nothing** — it only ever talks to `127.0.0.1`.
|
|
539
|
+
|
|
540
|
+
Turn it off with any of:
|
|
541
|
+
|
|
542
|
+
```bash
|
|
543
|
+
CHROME_MCP_TELEMETRY=0 # or false / off
|
|
544
|
+
DO_NOT_TRACK=1
|
|
545
|
+
--no-telemetry # server flag
|
|
546
|
+
```
|
|
547
|
+
|
|
523
548
|
## Develop
|
|
524
549
|
|
|
525
550
|
```
|
package/dist/src/cli.js
CHANGED
|
@@ -22,6 +22,7 @@ const workspace_1 = require("./bridge/workspace");
|
|
|
22
22
|
const auth_1 = require("./bridge/auth");
|
|
23
23
|
const server_2 = require("./mcp/server");
|
|
24
24
|
const tools_1 = require("./mcp/tools");
|
|
25
|
+
const telemetry_1 = require("./telemetry");
|
|
25
26
|
const extension_install_1 = require("./extension-install");
|
|
26
27
|
/** Hard deadline for clean shutdown before we force-exit (a stuck socket must not hang us). */
|
|
27
28
|
const SHUTDOWN_DEADLINE_MS = 3000;
|
|
@@ -242,6 +243,13 @@ async function main() {
|
|
|
242
243
|
};
|
|
243
244
|
const port = await bridge.start();
|
|
244
245
|
(0, tools_1.setProfileBridge)(bridge);
|
|
246
|
+
(0, telemetry_1.initTelemetry)({
|
|
247
|
+
dataDir,
|
|
248
|
+
version: version(),
|
|
249
|
+
disabledByFlag: cfg.noTelemetry,
|
|
250
|
+
log: (m) => (0, server_2.logErr)(m),
|
|
251
|
+
context: () => ({ role: bridge.role, browsers: bridge.connectedProfiles().length }),
|
|
252
|
+
});
|
|
245
253
|
// Never includes the pairing token — only the resolved, non-secret config.
|
|
246
254
|
(0, server_2.logDebug)(`resolved config: ${JSON.stringify({
|
|
247
255
|
wsPort: port,
|
|
@@ -309,7 +317,9 @@ async function main() {
|
|
|
309
317
|
return;
|
|
310
318
|
shuttingDown = true;
|
|
311
319
|
cleanup();
|
|
312
|
-
|
|
320
|
+
// Telemetry first: its final summary reads the bridge's role and paired
|
|
321
|
+
// browsers, which bridge.stop() clears synchronously.
|
|
322
|
+
exitWithDeadline(Promise.allSettled([(0, telemetry_1.stopTelemetry)(), (0, server_2.stopMcpServer)(), bridge.stop()]));
|
|
313
323
|
};
|
|
314
324
|
process.on('SIGINT', shutdown);
|
|
315
325
|
process.on('SIGTERM', shutdown);
|
package/dist/src/config.d.ts
CHANGED
|
@@ -34,6 +34,8 @@ export interface CliConfig {
|
|
|
34
34
|
showExtensionPath: boolean;
|
|
35
35
|
/** `--persist-token`: reuse a stable on-disk token so the extension never re-pairs. */
|
|
36
36
|
persistToken: boolean;
|
|
37
|
+
/** `--no-telemetry`: send no anonymous usage statistics (see src/telemetry.ts). */
|
|
38
|
+
noTelemetry: boolean;
|
|
37
39
|
/**
|
|
38
40
|
* `--tools`: advertise only these tools. `undefined` = the whole catalog.
|
|
39
41
|
* Names are validated against the catalog by `setToolAllowlist` at startup —
|
package/dist/src/config.js
CHANGED
|
@@ -78,6 +78,7 @@ function parseArgs(argv) {
|
|
|
78
78
|
let headless = false;
|
|
79
79
|
let printPairing = false;
|
|
80
80
|
let persistToken = false;
|
|
81
|
+
let noTelemetry = false;
|
|
81
82
|
let showHelp = false;
|
|
82
83
|
let showVersion = false;
|
|
83
84
|
let showExtensionPath = false;
|
|
@@ -178,6 +179,9 @@ function parseArgs(argv) {
|
|
|
178
179
|
case '--persist-token':
|
|
179
180
|
persistToken = true;
|
|
180
181
|
break;
|
|
182
|
+
case '--no-telemetry':
|
|
183
|
+
noTelemetry = true;
|
|
184
|
+
break;
|
|
181
185
|
case '--tools':
|
|
182
186
|
toolsFlagSeen = true;
|
|
183
187
|
for (const name of splitList(requireValue(argv[++i], '--tools')))
|
|
@@ -234,6 +238,7 @@ function parseArgs(argv) {
|
|
|
234
238
|
headless,
|
|
235
239
|
printPairing,
|
|
236
240
|
persistToken,
|
|
241
|
+
noTelemetry,
|
|
237
242
|
showHelp,
|
|
238
243
|
showVersion,
|
|
239
244
|
showExtensionPath,
|
|
@@ -309,6 +314,10 @@ Connection:
|
|
|
309
314
|
--persist-token Reuse a stable on-disk token across restarts so the
|
|
310
315
|
extension never has to re-pair (default: fresh per boot).
|
|
311
316
|
CHROME_MCP_TOKEN env, if set, pins the token explicitly.
|
|
317
|
+
--no-telemetry Send no anonymous usage statistics. Same as
|
|
318
|
+
CHROME_MCP_TELEMETRY=0 or DO_NOT_TRACK=1. Only counts are
|
|
319
|
+
ever sent (version, OS, tool calls, error codes) — never
|
|
320
|
+
URLs, page content or arguments.
|
|
312
321
|
|
|
313
322
|
Backend:
|
|
314
323
|
This build is EXTENSION-ONLY — it drives ONLY your real Chrome via the paired
|
package/dist/src/mcp/tools.js
CHANGED
|
@@ -38,6 +38,7 @@ const auth_wall_1 = require("../../shared/auth-wall");
|
|
|
38
38
|
const audit_1 = require("./audit");
|
|
39
39
|
const log_1 = require("./log");
|
|
40
40
|
const tasks_1 = require("../bridge/tasks");
|
|
41
|
+
const telemetry_1 = require("../telemetry");
|
|
41
42
|
const config_1 = require("../config");
|
|
42
43
|
const workspace_1 = require("../bridge/workspace");
|
|
43
44
|
const validators_1 = require("./validators");
|
|
@@ -1075,6 +1076,8 @@ function summarizeArgs(rawArgs) {
|
|
|
1075
1076
|
*/
|
|
1076
1077
|
function recordHistory(tool, rawArgs, ok, extra = {}) {
|
|
1077
1078
|
const a = extra.audit ?? {};
|
|
1079
|
+
// Counts only — the tool name and error code, never the args or URL below.
|
|
1080
|
+
(0, telemetry_1.noteToolCall)(tool, ok, extra.error);
|
|
1078
1081
|
(0, workspace_1.appendHistory)({
|
|
1079
1082
|
ts: new Date().toISOString(),
|
|
1080
1083
|
tool,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/telemetry.ts — anonymous usage statistics from the chrome-mcp SERVER.
|
|
3
|
+
*
|
|
4
|
+
* What it sends, to PostHog: a random per-install id, the chrome-mcp version,
|
|
5
|
+
* OS, CPU architecture and Node major version, whether this session owns the
|
|
6
|
+
* port or shares it, how many browsers are paired, and per-tool call and error
|
|
7
|
+
* COUNTS. Never URLs, domains, tool arguments, page content, profile names,
|
|
8
|
+
* tokens, file paths, or anything typed. Events are marked personless and ask
|
|
9
|
+
* PostHog not to geolocate them.
|
|
10
|
+
*
|
|
11
|
+
* The browser extension sends nothing; this lives only in the npm server.
|
|
12
|
+
*
|
|
13
|
+
* On by default with a one-time notice on first run. Off with
|
|
14
|
+
* CHROME_MCP_TELEMETRY=0 (or false/off), DO_NOT_TRACK=1, or --no-telemetry.
|
|
15
|
+
* Every failure is swallowed: telemetry can never break or slow a tool call.
|
|
16
|
+
*/
|
|
17
|
+
/** PostHog project key. Public by design: it can only WRITE events, never read them. */
|
|
18
|
+
export declare const POSTHOG_KEY = "phc_CG5QX5JEkRokfUN87rZQnPa3URdLWePCZnfqW6MCyCdU";
|
|
19
|
+
export declare const POSTHOG_HOST = "https://us.i.posthog.com";
|
|
20
|
+
export declare const TELEMETRY_NOTICE: string;
|
|
21
|
+
interface Event {
|
|
22
|
+
event: string;
|
|
23
|
+
distinct_id: string;
|
|
24
|
+
timestamp: string;
|
|
25
|
+
properties: Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
export interface TelemetryOptions {
|
|
28
|
+
dataDir: string;
|
|
29
|
+
version: string;
|
|
30
|
+
/** --no-telemetry */
|
|
31
|
+
disabledByFlag?: boolean;
|
|
32
|
+
env?: NodeJS.ProcessEnv;
|
|
33
|
+
/** Override the project key (tests, forks). Empty = telemetry off. */
|
|
34
|
+
key?: string;
|
|
35
|
+
log?: (message: string) => void;
|
|
36
|
+
/** Test seam: replaces the HTTP POST. */
|
|
37
|
+
send?: (events: Event[]) => Promise<void>;
|
|
38
|
+
/** Live context added to each summary (role, paired browsers). */
|
|
39
|
+
context?: () => Record<string, unknown>;
|
|
40
|
+
}
|
|
41
|
+
/** Whether the user has turned telemetry off, by env or flag. */
|
|
42
|
+
export declare function telemetryDisabled(env: NodeJS.ProcessEnv, disabledByFlag?: boolean): boolean;
|
|
43
|
+
/** Pull the `[CODE]` prefix off a tool error message, if any. */
|
|
44
|
+
export declare function errorCodeOf(message: string | undefined): string;
|
|
45
|
+
/** Start telemetry for this server process, unless turned off or unconfigured. */
|
|
46
|
+
export declare function initTelemetry(opts: TelemetryOptions): boolean;
|
|
47
|
+
/** Count one tool call. A no-op when telemetry is off. */
|
|
48
|
+
export declare function noteToolCall(tool: string, ok: boolean, error?: string): void;
|
|
49
|
+
/** Flush and send session_ended. Safe to call when telemetry is off. */
|
|
50
|
+
export declare function stopTelemetry(): Promise<void>;
|
|
51
|
+
/** Test seam: forget the active instance. */
|
|
52
|
+
export declare function resetTelemetryForTesting(): void;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* src/telemetry.ts — anonymous usage statistics from the chrome-mcp SERVER.
|
|
4
|
+
*
|
|
5
|
+
* What it sends, to PostHog: a random per-install id, the chrome-mcp version,
|
|
6
|
+
* OS, CPU architecture and Node major version, whether this session owns the
|
|
7
|
+
* port or shares it, how many browsers are paired, and per-tool call and error
|
|
8
|
+
* COUNTS. Never URLs, domains, tool arguments, page content, profile names,
|
|
9
|
+
* tokens, file paths, or anything typed. Events are marked personless and ask
|
|
10
|
+
* PostHog not to geolocate them.
|
|
11
|
+
*
|
|
12
|
+
* The browser extension sends nothing; this lives only in the npm server.
|
|
13
|
+
*
|
|
14
|
+
* On by default with a one-time notice on first run. Off with
|
|
15
|
+
* CHROME_MCP_TELEMETRY=0 (or false/off), DO_NOT_TRACK=1, or --no-telemetry.
|
|
16
|
+
* Every failure is swallowed: telemetry can never break or slow a tool call.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.TELEMETRY_NOTICE = exports.POSTHOG_HOST = exports.POSTHOG_KEY = void 0;
|
|
20
|
+
exports.telemetryDisabled = telemetryDisabled;
|
|
21
|
+
exports.errorCodeOf = errorCodeOf;
|
|
22
|
+
exports.initTelemetry = initTelemetry;
|
|
23
|
+
exports.noteToolCall = noteToolCall;
|
|
24
|
+
exports.stopTelemetry = stopTelemetry;
|
|
25
|
+
exports.resetTelemetryForTesting = resetTelemetryForTesting;
|
|
26
|
+
const node_crypto_1 = require("node:crypto");
|
|
27
|
+
const node_fs_1 = require("node:fs");
|
|
28
|
+
const node_os_1 = require("node:os");
|
|
29
|
+
const node_path_1 = require("node:path");
|
|
30
|
+
/** PostHog project key. Public by design: it can only WRITE events, never read them. */
|
|
31
|
+
exports.POSTHOG_KEY = 'phc_CG5QX5JEkRokfUN87rZQnPa3URdLWePCZnfqW6MCyCdU';
|
|
32
|
+
exports.POSTHOG_HOST = 'https://us.i.posthog.com';
|
|
33
|
+
/** How often the aggregated counts are sent while a session runs. */
|
|
34
|
+
const FLUSH_INTERVAL_MS = 10 * 60_000;
|
|
35
|
+
/** A send never holds up the process longer than this. */
|
|
36
|
+
const SEND_TIMEOUT_MS = 3_000;
|
|
37
|
+
const STATE_FILE = 'telemetry.json';
|
|
38
|
+
exports.TELEMETRY_NOTICE = 'chrome-mcp collects anonymous usage statistics (version, OS, tool call and error counts; never URLs, ' +
|
|
39
|
+
'page content or arguments) to see how it is used. Turn it off with CHROME_MCP_TELEMETRY=0 or DO_NOT_TRACK=1. ' +
|
|
40
|
+
'Details: https://github.com/Mehmoodqureshi/chrome-mcp#telemetry';
|
|
41
|
+
/** Whether the user has turned telemetry off, by env or flag. */
|
|
42
|
+
function telemetryDisabled(env, disabledByFlag = false) {
|
|
43
|
+
if (disabledByFlag)
|
|
44
|
+
return true;
|
|
45
|
+
const own = (env.CHROME_MCP_TELEMETRY ?? '').trim().toLowerCase();
|
|
46
|
+
if (['0', 'false', 'off', 'no'].includes(own))
|
|
47
|
+
return true;
|
|
48
|
+
const dnt = (env.DO_NOT_TRACK ?? '').trim().toLowerCase();
|
|
49
|
+
return dnt !== '' && dnt !== '0' && dnt !== 'false';
|
|
50
|
+
}
|
|
51
|
+
/** Pull the `[CODE]` prefix off a tool error message, if any. */
|
|
52
|
+
function errorCodeOf(message) {
|
|
53
|
+
const m = /^\[([A-Z_]+)\]/.exec(message ?? '');
|
|
54
|
+
return m ? m[1] : 'OTHER';
|
|
55
|
+
}
|
|
56
|
+
class Telemetry {
|
|
57
|
+
opts;
|
|
58
|
+
installId;
|
|
59
|
+
calls = new Map();
|
|
60
|
+
errorCodes = new Map();
|
|
61
|
+
timer = null;
|
|
62
|
+
base;
|
|
63
|
+
/** Sends still on the wire, so a quick exit doesn't cut session_started off. */
|
|
64
|
+
inflight = new Set();
|
|
65
|
+
constructor(opts) {
|
|
66
|
+
this.opts = opts;
|
|
67
|
+
this.installId = this.loadInstallId();
|
|
68
|
+
this.base = {
|
|
69
|
+
version: opts.version,
|
|
70
|
+
os: (0, node_os_1.platform)(),
|
|
71
|
+
arch: (0, node_os_1.arch)(),
|
|
72
|
+
node: process.versions.node.split('.')[0],
|
|
73
|
+
// Anonymous: no person profile, no GeoIP lookup from the request IP.
|
|
74
|
+
$process_person_profile: false,
|
|
75
|
+
$geoip_disable: true,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
start() {
|
|
79
|
+
void this.capture('session_started', this.opts.context?.() ?? {});
|
|
80
|
+
this.timer = setInterval(() => void this.flush(), FLUSH_INTERVAL_MS);
|
|
81
|
+
this.timer.unref();
|
|
82
|
+
}
|
|
83
|
+
noteCall(tool, ok, error) {
|
|
84
|
+
const c = this.calls.get(tool) ?? { calls: 0, errors: 0 };
|
|
85
|
+
c.calls++;
|
|
86
|
+
if (!ok) {
|
|
87
|
+
c.errors++;
|
|
88
|
+
const code = errorCodeOf(error);
|
|
89
|
+
this.errorCodes.set(code, (this.errorCodes.get(code) ?? 0) + 1);
|
|
90
|
+
}
|
|
91
|
+
this.calls.set(tool, c);
|
|
92
|
+
}
|
|
93
|
+
/** Send the counts gathered since the last flush (skipped when idle). */
|
|
94
|
+
async flush() {
|
|
95
|
+
const summary = this.takeSummary();
|
|
96
|
+
if (summary)
|
|
97
|
+
await this.send([summary]);
|
|
98
|
+
}
|
|
99
|
+
/** The counts since the last summary as an event, resetting them; null when idle. */
|
|
100
|
+
takeSummary() {
|
|
101
|
+
if (this.calls.size === 0)
|
|
102
|
+
return null;
|
|
103
|
+
const tools = Object.fromEntries(this.calls);
|
|
104
|
+
const errors = Object.fromEntries(this.errorCodes);
|
|
105
|
+
let total = 0;
|
|
106
|
+
let failed = 0;
|
|
107
|
+
for (const c of this.calls.values()) {
|
|
108
|
+
total += c.calls;
|
|
109
|
+
failed += c.errors;
|
|
110
|
+
}
|
|
111
|
+
this.calls = new Map();
|
|
112
|
+
this.errorCodes = new Map();
|
|
113
|
+
return this.event('usage_summary', { ...(this.opts.context?.() ?? {}), calls: total, errors: failed, tools, error_codes: errors });
|
|
114
|
+
}
|
|
115
|
+
/** Last summary and session_ended in ONE request, so both fit the shutdown deadline. */
|
|
116
|
+
async stop() {
|
|
117
|
+
if (this.timer)
|
|
118
|
+
clearInterval(this.timer);
|
|
119
|
+
this.timer = null;
|
|
120
|
+
const summary = this.takeSummary();
|
|
121
|
+
const final = this.send([...(summary ? [summary] : []), this.event('session_ended', {})]);
|
|
122
|
+
// Also wait for anything already sent (session_started on a short session).
|
|
123
|
+
await Promise.allSettled([...this.inflight, final]);
|
|
124
|
+
}
|
|
125
|
+
capture(event, props) {
|
|
126
|
+
return this.send([this.event(event, props)]);
|
|
127
|
+
}
|
|
128
|
+
event(event, props) {
|
|
129
|
+
return {
|
|
130
|
+
event,
|
|
131
|
+
distinct_id: this.installId,
|
|
132
|
+
timestamp: new Date().toISOString(),
|
|
133
|
+
properties: { ...this.base, ...props },
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
send(batch) {
|
|
137
|
+
const p = (async () => {
|
|
138
|
+
try {
|
|
139
|
+
await (this.opts.send ?? ((b) => this.post(b)))(batch);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
/* offline, blocked, or PostHog down — never matters to the user */
|
|
143
|
+
}
|
|
144
|
+
})();
|
|
145
|
+
this.inflight.add(p);
|
|
146
|
+
void p.finally(() => this.inflight.delete(p));
|
|
147
|
+
return p;
|
|
148
|
+
}
|
|
149
|
+
async post(batch) {
|
|
150
|
+
await fetch(`${exports.POSTHOG_HOST}/batch/`, {
|
|
151
|
+
method: 'POST',
|
|
152
|
+
headers: { 'content-type': 'application/json' },
|
|
153
|
+
body: JSON.stringify({ api_key: this.opts.key, batch }),
|
|
154
|
+
signal: AbortSignal.timeout(SEND_TIMEOUT_MS),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
/** The random install id, created (with the first-run notice) on first use. */
|
|
158
|
+
loadInstallId() {
|
|
159
|
+
const path = (0, node_path_1.join)(this.opts.dataDir, STATE_FILE);
|
|
160
|
+
try {
|
|
161
|
+
if ((0, node_fs_1.existsSync)(path)) {
|
|
162
|
+
const saved = JSON.parse((0, node_fs_1.readFileSync)(path, 'utf8'));
|
|
163
|
+
if (typeof saved.installId === 'string' && saved.installId.length > 0)
|
|
164
|
+
return saved.installId;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
/* unreadable: start over with a new id */
|
|
169
|
+
}
|
|
170
|
+
const installId = (0, node_crypto_1.randomUUID)();
|
|
171
|
+
this.opts.log?.(exports.TELEMETRY_NOTICE);
|
|
172
|
+
try {
|
|
173
|
+
const tmp = `${path}.tmp`;
|
|
174
|
+
(0, node_fs_1.writeFileSync)(tmp, JSON.stringify({ installId, noticeShownAt: new Date().toISOString() }, null, 2), { mode: 0o600 });
|
|
175
|
+
(0, node_fs_1.renameSync)(tmp, path);
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
/* read-only data dir: a new id (and notice) next boot is harmless */
|
|
179
|
+
}
|
|
180
|
+
return installId;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
let active = null;
|
|
184
|
+
/** Start telemetry for this server process, unless turned off or unconfigured. */
|
|
185
|
+
function initTelemetry(opts) {
|
|
186
|
+
const key = opts.key ?? exports.POSTHOG_KEY;
|
|
187
|
+
if (!key || telemetryDisabled(opts.env ?? process.env, opts.disabledByFlag))
|
|
188
|
+
return false;
|
|
189
|
+
active = new Telemetry({ ...opts, key });
|
|
190
|
+
active.start();
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
/** Count one tool call. A no-op when telemetry is off. */
|
|
194
|
+
function noteToolCall(tool, ok, error) {
|
|
195
|
+
active?.noteCall(tool, ok, error);
|
|
196
|
+
}
|
|
197
|
+
/** Flush and send session_ended. Safe to call when telemetry is off. */
|
|
198
|
+
async function stopTelemetry() {
|
|
199
|
+
const t = active;
|
|
200
|
+
active = null;
|
|
201
|
+
await t?.stop();
|
|
202
|
+
}
|
|
203
|
+
/** Test seam: forget the active instance. */
|
|
204
|
+
function resetTelemetryForTesting() {
|
|
205
|
+
active = null;
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=telemetry.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "MCP Extension for Chrome",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.7",
|
|
5
5
|
"description": "Lets a local chrome-mcp server drive this browser. Pair it with the server's handshake token.",
|
|
6
6
|
"homepage_url": "https://chrome-mcp-omega.vercel.app",
|
|
7
7
|
"minimum_chrome_version": "116",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mehmoodqureshi/chrome-mcp",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.7",
|
|
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",
|