cdp-mcp-server 5.0.3 → 5.1.0
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 +14 -0
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/connection/capabilities.d.ts +58 -0
- package/dist/connection/capabilities.js +126 -0
- package/dist/connection/capabilities.js.map +1 -0
- package/dist/connection/index.d.ts +1 -0
- package/dist/connection/index.js +1 -0
- package/dist/connection/index.js.map +1 -1
- package/dist/connection/tab-session-service.d.ts +12 -2
- package/dist/connection/tab-session-service.js +48 -14
- package/dist/connection/tab-session-service.js.map +1 -1
- package/dist/index.js +44 -4
- package/dist/index.js.map +1 -1
- package/dist/snapshot/accessibility.d.ts +2 -0
- package/dist/snapshot/accessibility.js +1 -1
- package/dist/snapshot/accessibility.js.map +1 -1
- package/dist/tools/device-presets.d.ts +24 -0
- package/dist/tools/device-presets.js +62 -0
- package/dist/tools/device-presets.js.map +1 -0
- package/dist/tools/emulate.js +79 -0
- package/dist/tools/emulate.js.map +1 -1
- package/dist/tools/interact.js +191 -31
- package/dist/tools/interact.js.map +1 -1
- package/dist/tools/observe.js +201 -27
- package/dist/tools/observe.js.map +1 -1
- package/dist/tools/page.d.ts +52 -1
- package/dist/tools/page.js +242 -25
- package/dist/tools/page.js.map +1 -1
- package/dist/tools/storage.d.ts +1 -1
- package/dist/tools/storage.js +115 -3
- package/dist/tools/storage.js.map +1 -1
- package/dist/tools/tabs.js +4 -2
- package/dist/tools/tabs.js.map +1 -1
- package/dist/types.d.ts +14 -0
- package/dist/utils/actionability.d.ts +62 -0
- package/dist/utils/actionability.js +190 -0
- package/dist/utils/actionability.js.map +1 -0
- package/dist/utils/wait.d.ts +0 -25
- package/dist/utils/wait.js +0 -76
- package/dist/utils/wait.js.map +1 -1
- package/package.json +1 -1
- package/dist/utils/retry.d.ts +0 -40
- package/dist/utils/retry.js +0 -75
- package/dist/utils/retry.js.map +0 -1
package/README.md
CHANGED
|
@@ -64,6 +64,20 @@ command lines are never logged — disable with `CDP_PROCESS_SCAN=false`), and
|
|
|
64
64
|
can connect via the `chrome://inspect` toggle by reading `DevToolsActivePort`.
|
|
65
65
|
`ping`/`status` report the connection mode (`legacy` | `approval`).
|
|
66
66
|
|
|
67
|
+
## Browser compatibility
|
|
68
|
+
|
|
69
|
+
| Browser | Flag mode | Toggle (approval) | Process scan | Notes |
|
|
70
|
+
|---------|-----------|-------------------|--------------|-------|
|
|
71
|
+
| Chrome 136+ | ✅ requires non-default `--user-data-dir` | ✅ Chrome 144+ | ✅ | default-profile restriction since Chrome 136 |
|
|
72
|
+
| Brave | ✅ | ✅ (verified on 153) | ✅ (verified on 153) | portapps wrappers: launch inner `app\brave.exe`, not wrapper shortcut |
|
|
73
|
+
| Edge | ✅ | ✅ Chrome 144+ | ✅ | same Chromium behavior |
|
|
74
|
+
| Chromium | ✅ | ✅ Chrome 144+ | ✅ | restriction is Chrome-branding-gated |
|
|
75
|
+
| Vivaldi | ✅ | ✅ Chrome 144+ | ✅ | discovery path added in 5.0.3 |
|
|
76
|
+
| Opera | ✅ | ✅ Chrome 144+ | ✅ | discovery path added in 5.0.3 |
|
|
77
|
+
| Chrome for Testing | ✅ no restriction | — | ✅ | recommended automated/CI setups |
|
|
78
|
+
|
|
79
|
+
Connection failures auto-detect the failure mode and print the exact fix — see Troubleshooting above.
|
|
80
|
+
|
|
67
81
|
## Environment variables
|
|
68
82
|
|
|
69
83
|
| Variable | Default | Description |
|
package/dist/config.js
CHANGED
|
@@ -33,6 +33,8 @@ export function loadConfig() {
|
|
|
33
33
|
userDataDir: process.env.CDP_USER_DATA || '',
|
|
34
34
|
/** Process command-line scan on discovery failure (default ON). */
|
|
35
35
|
processScan: process.env.CDP_PROCESS_SCAN !== 'false',
|
|
36
|
+
/** Actionability gate before element interactions (default ON). */
|
|
37
|
+
autoWait: process.env.CDP_AUTO_WAIT !== 'false',
|
|
36
38
|
slimMode: process.env.CDP_SLIM_MODE === 'true',
|
|
37
39
|
};
|
|
38
40
|
}
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;;;GAMG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,WAAW;QAC5C,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,MAAM,EAAE,EAAE,CAAC;QAErD,kBAAkB;QAClB,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,OAAO,EAAE,EAAE,CAAC;QACtE,iBAAiB,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,OAAO,EAAE,EAAE,CAAC;QAC9E,eAAe,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO,EAAE,EAAE,CAAC;QAC1E,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO,EAAE,EAAE,CAAC;QAE/D,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,QAAQ,EAAE,EAAE,CAAC;QACjE,eAAe,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO,EAAE,EAAE,CAAC;QAE1E,mEAAmE;QACnE,sBAAsB,EACnB,OAAO,CAAC,GAAG,CAAC,oBAAwC,IAAI,QAAQ;QAEnE,YAAY,EAAE,MAAM;QACpB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,EAAE,sBAAsB;QAC/D,YAAY,EAAE,EAAE;QAChB,YAAY,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,aAAa;QAE3C,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE;QAEjD,0EAA0E;QAC1E,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE;QAE5C,mEAAmE;QACnE,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,OAAO;QAErD,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,MAAM;KAC/C,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;;;GAMG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,WAAW;QAC5C,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,MAAM,EAAE,EAAE,CAAC;QAErD,kBAAkB;QAClB,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,OAAO,EAAE,EAAE,CAAC;QACtE,iBAAiB,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,OAAO,EAAE,EAAE,CAAC;QAC9E,eAAe,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO,EAAE,EAAE,CAAC;QAC1E,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO,EAAE,EAAE,CAAC;QAE/D,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,QAAQ,EAAE,EAAE,CAAC;QACjE,eAAe,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO,EAAE,EAAE,CAAC;QAE1E,mEAAmE;QACnE,sBAAsB,EACnB,OAAO,CAAC,GAAG,CAAC,oBAAwC,IAAI,QAAQ;QAEnE,YAAY,EAAE,MAAM;QACpB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,EAAE,sBAAsB;QAC/D,YAAY,EAAE,EAAE;QAChB,YAAY,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,aAAa;QAE3C,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE;QAEjD,0EAA0E;QAC1E,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE;QAE5C,mEAAmE;QACnE,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,OAAO;QAErD,mEAAmE;QACnE,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,OAAO;QAE/C,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,MAAM;KAC/C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CDP domain capability report (5.1.0 B1, redesigned as multi-canary probing).
|
|
3
|
+
*
|
|
4
|
+
* `Schema.getDomains` — the original probe — was removed from Chrome years ago:
|
|
5
|
+
* on any modern Chrome/Brave it replies "'Schema.getDomains' wasn't found"
|
|
6
|
+
* (confirmed live on Brave 153, approval mode). There is no domain-enumeration
|
|
7
|
+
* command anymore, so presence is now probed per domain with a real canary
|
|
8
|
+
* command whose empty-params call is either read-only or rejected by parameter
|
|
9
|
+
* validation before any handler runs — a probe never mutates meaningful state.
|
|
10
|
+
*
|
|
11
|
+
* Classification:
|
|
12
|
+
* - `"'X' wasn't found"` → domain/method absent
|
|
13
|
+
* - any other outcome (success / Invalid parameters / domain-specific error)
|
|
14
|
+
* → domain present
|
|
15
|
+
*
|
|
16
|
+
* Cache lives on the instance and is invalidated on disconnect
|
|
17
|
+
* (wired in index.ts next to the other per-connection caches).
|
|
18
|
+
*/
|
|
19
|
+
import type { CDPClient } from './cdp-client.js';
|
|
20
|
+
/** Domains whose absence is worth surfacing in `status` output. */
|
|
21
|
+
export declare const NOTABLE_DOMAINS: readonly ["WebAuthn", "FedCm", "WebMCP", "Preload", "Ads", "Extensions", "PWA", "FindInPage", "Tracing", "Overlay"];
|
|
22
|
+
export type NotableDomain = (typeof NOTABLE_DOMAINS)[number];
|
|
23
|
+
/** True when a CDP error means "domain or method not implemented". */
|
|
24
|
+
export declare function isMethodMissingError(err: unknown): boolean;
|
|
25
|
+
export declare class DomainCapabilities {
|
|
26
|
+
/** Probe key (domain or Domain.method) → present? */
|
|
27
|
+
private cache;
|
|
28
|
+
private inFlight;
|
|
29
|
+
/**
|
|
30
|
+
* Probe a single canary / method. Empty params on purpose:
|
|
31
|
+
* required-params canaries fail validation (proving presence), read-only
|
|
32
|
+
* canaries succeed (proving presence), unknown methods report "wasn't found".
|
|
33
|
+
*
|
|
34
|
+
* Pass a page-session id when probing page-scoped domains: the browser-level
|
|
35
|
+
* endpoint only serves browser-wide domains (Target/Browser/SystemInfo/
|
|
36
|
+
* Tracing/Extensions...), so page-scoped domains report "wasn't found"
|
|
37
|
+
* without a session (live-confirmed: browser-level probes said 2/10).
|
|
38
|
+
*/
|
|
39
|
+
hasMethod(client: CDPClient, method: string, sessionId?: string): Promise<boolean>;
|
|
40
|
+
/**
|
|
41
|
+
* True when the connected browser supports the given domain. Domain names
|
|
42
|
+
* resolve through their canary; dotted "Domain.method" keys probe directly
|
|
43
|
+
* (useful for version-gated methods like Emulation.setCPUPerformanceOverride).
|
|
44
|
+
*/
|
|
45
|
+
has(client: CDPClient, key: string, sessionId?: string): Promise<boolean>;
|
|
46
|
+
/** Feature-gate helper: throws an actionable error when absent. */
|
|
47
|
+
require(client: CDPClient, key: string, minChrome?: string, sessionId?: string): Promise<void>;
|
|
48
|
+
/** Invalidate on disconnect/reconnect. */
|
|
49
|
+
clear(): void;
|
|
50
|
+
/**
|
|
51
|
+
* Summary for the `status` tool: how many of the notable domains are
|
|
52
|
+
* present, and which are missing. Every entry is individually probed.
|
|
53
|
+
*/
|
|
54
|
+
summarize(client: CDPClient, sessionId?: string): Promise<{
|
|
55
|
+
count: number;
|
|
56
|
+
missing: string[];
|
|
57
|
+
}>;
|
|
58
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/** Domains whose absence is worth surfacing in `status` output. */
|
|
2
|
+
export const NOTABLE_DOMAINS = [
|
|
3
|
+
'WebAuthn',
|
|
4
|
+
'FedCm',
|
|
5
|
+
'WebMCP',
|
|
6
|
+
'Preload',
|
|
7
|
+
'Ads',
|
|
8
|
+
'Extensions',
|
|
9
|
+
'PWA',
|
|
10
|
+
'FindInPage',
|
|
11
|
+
'Tracing',
|
|
12
|
+
'Overlay',
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* Canary command per domain (method names verified against the Chromium
|
|
16
|
+
* browser-protocol surface shipped with Playwright 1.65):
|
|
17
|
+
*
|
|
18
|
+
* - requires parameters → `{}` is rejected with "Invalid parameters" before
|
|
19
|
+
* the handler runs (zero side effect): WebAuthn.addVirtualAuthenticator
|
|
20
|
+
* (options), FedCm.selectAccount (dialogId+accountIndex),
|
|
21
|
+
* WebMCP.invokeTool (frameId+toolName+input), Extensions.loadUnpacked
|
|
22
|
+
* (path), PWA.getOsAppState (manifestId), FindInPage.findFirst (query),
|
|
23
|
+
* Overlay.setInspectMode (mode)
|
|
24
|
+
* - read-only with no required params → succeeds harmlessly:
|
|
25
|
+
* Ads.getAdScripts, Tracing.getCategories
|
|
26
|
+
* - Preload.enable is the one intentional soft exception: it succeeds and
|
|
27
|
+
* merely enables speculative preloading for the session (the browser's
|
|
28
|
+
* own default behavior).
|
|
29
|
+
*/
|
|
30
|
+
const CANARIES = {
|
|
31
|
+
WebAuthn: 'WebAuthn.addVirtualAuthenticator',
|
|
32
|
+
FedCm: 'FedCm.selectAccount',
|
|
33
|
+
WebMCP: 'WebMCP.invokeTool',
|
|
34
|
+
Preload: 'Preload.enable',
|
|
35
|
+
Ads: 'Ads.getAdScripts',
|
|
36
|
+
Extensions: 'Extensions.loadUnpacked',
|
|
37
|
+
PWA: 'PWA.getOsAppState',
|
|
38
|
+
FindInPage: 'FindInPage.findFirst',
|
|
39
|
+
Overlay: 'Overlay.setInspectMode',
|
|
40
|
+
Tracing: 'Tracing.getCategories',
|
|
41
|
+
};
|
|
42
|
+
/** True when a CDP error means "domain or method not implemented". */
|
|
43
|
+
export function isMethodMissingError(err) {
|
|
44
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
45
|
+
return /wasn'?t found|not found/i.test(msg);
|
|
46
|
+
}
|
|
47
|
+
export class DomainCapabilities {
|
|
48
|
+
/** Probe key (domain or Domain.method) → present? */
|
|
49
|
+
cache = new Map();
|
|
50
|
+
inFlight = new Map();
|
|
51
|
+
/**
|
|
52
|
+
* Probe a single canary / method. Empty params on purpose:
|
|
53
|
+
* required-params canaries fail validation (proving presence), read-only
|
|
54
|
+
* canaries succeed (proving presence), unknown methods report "wasn't found".
|
|
55
|
+
*
|
|
56
|
+
* Pass a page-session id when probing page-scoped domains: the browser-level
|
|
57
|
+
* endpoint only serves browser-wide domains (Target/Browser/SystemInfo/
|
|
58
|
+
* Tracing/Extensions...), so page-scoped domains report "wasn't found"
|
|
59
|
+
* without a session (live-confirmed: browser-level probes said 2/10).
|
|
60
|
+
*/
|
|
61
|
+
async hasMethod(client, method, sessionId) {
|
|
62
|
+
const cached = this.cache.get(method);
|
|
63
|
+
if (cached !== undefined)
|
|
64
|
+
return cached;
|
|
65
|
+
const pending = this.inFlight.get(method);
|
|
66
|
+
if (pending)
|
|
67
|
+
return pending;
|
|
68
|
+
const probe = (async () => {
|
|
69
|
+
try {
|
|
70
|
+
await client.send(method, {}, sessionId);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
if (isMethodMissingError(err))
|
|
75
|
+
return false;
|
|
76
|
+
// Invalid parameters / domain-specific error → the method exists
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
this.inFlight.delete(method);
|
|
81
|
+
}
|
|
82
|
+
})();
|
|
83
|
+
this.inFlight.set(method, probe);
|
|
84
|
+
const present = await probe;
|
|
85
|
+
this.cache.set(method, present);
|
|
86
|
+
return present;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* True when the connected browser supports the given domain. Domain names
|
|
90
|
+
* resolve through their canary; dotted "Domain.method" keys probe directly
|
|
91
|
+
* (useful for version-gated methods like Emulation.setCPUPerformanceOverride).
|
|
92
|
+
*/
|
|
93
|
+
async has(client, key, sessionId) {
|
|
94
|
+
if (key.includes('.'))
|
|
95
|
+
return this.hasMethod(client, key, sessionId);
|
|
96
|
+
const canary = CANARIES[key];
|
|
97
|
+
if (!canary)
|
|
98
|
+
return false; // no canary → unknown, treated as absent
|
|
99
|
+
return this.hasMethod(client, canary, sessionId);
|
|
100
|
+
}
|
|
101
|
+
/** Feature-gate helper: throws an actionable error when absent. */
|
|
102
|
+
async require(client, key, minChrome, sessionId) {
|
|
103
|
+
if (await this.has(client, key, sessionId))
|
|
104
|
+
return;
|
|
105
|
+
const versionNote = minChrome ? ` (requires Chrome ${minChrome}+)` : '';
|
|
106
|
+
const err = new Error(`This browser does not support the CDP "${key}" feature${versionNote}. ` +
|
|
107
|
+
`Update Chrome/Brave or use a feature-gated alternative.`);
|
|
108
|
+
err.name = 'DomainUnsupportedError';
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
/** Invalidate on disconnect/reconnect. */
|
|
112
|
+
clear() {
|
|
113
|
+
this.cache.clear();
|
|
114
|
+
this.inFlight.clear();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Summary for the `status` tool: how many of the notable domains are
|
|
118
|
+
* present, and which are missing. Every entry is individually probed.
|
|
119
|
+
*/
|
|
120
|
+
async summarize(client, sessionId) {
|
|
121
|
+
const results = await Promise.all(NOTABLE_DOMAINS.map(async (d) => [d, await this.has(client, d, sessionId)]));
|
|
122
|
+
const missing = results.filter(([, present]) => !present).map(([d]) => d);
|
|
123
|
+
return { count: results.length - missing.length, missing };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/connection/capabilities.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@ export type { ConnectionState, CDPClientOptions } from './cdp-client.js';
|
|
|
6
6
|
export { discoverBrowserInstances, resolveWsUrl, resolveWsUrlAsync, findBestInstance, parseBrowserCommandLine, scanBrowserProcesses, } from './browser-discovery.js';
|
|
7
7
|
export type { DiscoverOptions, WsUrlResult, CommandLineInfo, ProcessScanResult, } from './browser-discovery.js';
|
|
8
8
|
export { HealthMonitor } from './health-monitor.js';
|
|
9
|
+
export { DomainCapabilities } from './capabilities.js';
|
|
9
10
|
export type { HealthStatus, HealthState, HealthMonitorOptions, ConnectionMode, } from './health-monitor.js';
|
|
10
11
|
export { DomainManager } from './domain-manager.js';
|
|
11
12
|
export { TabSessionService } from './tab-session-service.js';
|
package/dist/connection/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
export { CDPClient } from './cdp-client.js';
|
|
5
5
|
export { discoverBrowserInstances, resolveWsUrl, resolveWsUrlAsync, findBestInstance, parseBrowserCommandLine, scanBrowserProcesses, } from './browser-discovery.js';
|
|
6
6
|
export { HealthMonitor } from './health-monitor.js';
|
|
7
|
+
export { DomainCapabilities } from './capabilities.js';
|
|
7
8
|
export { DomainManager } from './domain-manager.js';
|
|
8
9
|
export { TabSessionService } from './tab-session-service.js';
|
|
9
10
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/connection/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,OAAO,EACL,wBAAwB,EACxB,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAQhC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/connection/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,OAAO,EACL,wBAAwB,EACxB,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAQhC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAQvD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC"}
|
|
@@ -19,6 +19,10 @@ export declare class TabSessionService {
|
|
|
19
19
|
private childToParent;
|
|
20
20
|
/** uid → childSessionId routing for cross-frame element resolution */
|
|
21
21
|
private refSessionRouting;
|
|
22
|
+
/** CDP sessionId → tabId (reverse lookup for auto-attach event routing) */
|
|
23
|
+
private sessionToTab;
|
|
24
|
+
/** CDP clients already wired for auto-attach event routing */
|
|
25
|
+
private wiredClients;
|
|
22
26
|
/**
|
|
23
27
|
* Get (or create) a CDP session for a tab.
|
|
24
28
|
*
|
|
@@ -32,9 +36,15 @@ export declare class TabSessionService {
|
|
|
32
36
|
*/
|
|
33
37
|
ensureDomain(cdpClient: CDPClient, tabId: string, domain: string): Promise<void>;
|
|
34
38
|
/**
|
|
35
|
-
*
|
|
39
|
+
* Register Target.autoAttach event routing (idempotent per CDP client).
|
|
40
|
+
*
|
|
41
|
+
* `Target.attachedToTarget` events emitted by managed page sessions are
|
|
42
|
+
* translated into child-session registrations (OOP iframes);
|
|
43
|
+
* `Target.detachedFromTarget` prunes them. This is what feeds
|
|
44
|
+
* `captureFullTree`'s multi-frame snapshot and the uid → child-session
|
|
45
|
+
* routing used for cross-frame element interaction.
|
|
36
46
|
*/
|
|
37
|
-
|
|
47
|
+
private wireAutoAttachEvents;
|
|
38
48
|
/** Track a child session (OOP iframe) under a parent session. */
|
|
39
49
|
addChildSession(parentSessionId: string, childTargetId: string, childSessionId: string, url: string): void;
|
|
40
50
|
/** Remove a child session when an OOP iframe detaches. */
|
|
@@ -18,6 +18,10 @@ export class TabSessionService {
|
|
|
18
18
|
childToParent = new Map();
|
|
19
19
|
/** uid → childSessionId routing for cross-frame element resolution */
|
|
20
20
|
refSessionRouting = new Map();
|
|
21
|
+
/** CDP sessionId → tabId (reverse lookup for auto-attach event routing) */
|
|
22
|
+
sessionToTab = new Map();
|
|
23
|
+
/** CDP clients already wired for auto-attach event routing */
|
|
24
|
+
wiredClients = new WeakSet();
|
|
21
25
|
/**
|
|
22
26
|
* Get (or create) a CDP session for a tab.
|
|
23
27
|
*
|
|
@@ -25,21 +29,28 @@ export class TabSessionService {
|
|
|
25
29
|
* Otherwise calls Target.attachToTarget with flatten: true.
|
|
26
30
|
*/
|
|
27
31
|
async getSession(cdpClient, tabId) {
|
|
32
|
+
// Idempotent: register auto-attach event routing before any session can
|
|
33
|
+
// emit Target.attachedToTarget (no missed events on first attach)
|
|
34
|
+
this.wireAutoAttachEvents(cdpClient);
|
|
28
35
|
// Check the CDPClient's own session pool first, then our map
|
|
29
36
|
const pooled = cdpClient.getPooledSession(tabId);
|
|
30
37
|
if (pooled) {
|
|
31
38
|
this.sessions.set(tabId, pooled);
|
|
39
|
+
this.sessionToTab.set(pooled, tabId);
|
|
32
40
|
return pooled;
|
|
33
41
|
}
|
|
34
42
|
const existing = this.sessions.get(tabId);
|
|
35
|
-
if (existing)
|
|
43
|
+
if (existing) {
|
|
44
|
+
this.sessionToTab.set(existing, tabId);
|
|
36
45
|
return existing;
|
|
46
|
+
}
|
|
37
47
|
const result = await cdpClient.send('Target.attachToTarget', {
|
|
38
48
|
targetId: tabId,
|
|
39
49
|
flatten: true,
|
|
40
50
|
});
|
|
41
51
|
const sessionId = result.sessionId;
|
|
42
52
|
this.sessions.set(tabId, sessionId);
|
|
53
|
+
this.sessionToTab.set(sessionId, tabId);
|
|
43
54
|
cdpClient.poolSession(tabId, sessionId);
|
|
44
55
|
// Enable auto-attach for OOP (cross-origin) iframe discovery
|
|
45
56
|
try {
|
|
@@ -72,20 +83,41 @@ export class TabSessionService {
|
|
|
72
83
|
// Domain manager already tracks via ensureDomain if needed externally
|
|
73
84
|
}
|
|
74
85
|
/**
|
|
75
|
-
*
|
|
86
|
+
* Register Target.autoAttach event routing (idempotent per CDP client).
|
|
87
|
+
*
|
|
88
|
+
* `Target.attachedToTarget` events emitted by managed page sessions are
|
|
89
|
+
* translated into child-session registrations (OOP iframes);
|
|
90
|
+
* `Target.detachedFromTarget` prunes them. This is what feeds
|
|
91
|
+
* `captureFullTree`'s multi-frame snapshot and the uid → child-session
|
|
92
|
+
* routing used for cross-frame element interaction.
|
|
76
93
|
*/
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
wireAutoAttachEvents(cdpClient) {
|
|
95
|
+
if (this.wiredClients.has(cdpClient))
|
|
96
|
+
return;
|
|
97
|
+
this.wiredClients.add(cdpClient);
|
|
98
|
+
cdpClient.on('event', (event) => {
|
|
99
|
+
if (event.method === 'Target.attachedToTarget' && event.sessionId) {
|
|
100
|
+
const parentSessionId = event.sessionId;
|
|
101
|
+
// Only page sessions we manage — browser-level / foreign events ignored
|
|
102
|
+
if (!this.sessionToTab.has(parentSessionId))
|
|
103
|
+
return;
|
|
104
|
+
const params = event.params;
|
|
105
|
+
if (!params?.sessionId || !params.targetInfo?.targetId)
|
|
106
|
+
return;
|
|
107
|
+
if (params.targetInfo.type !== 'iframe')
|
|
108
|
+
return;
|
|
109
|
+
this.addChildSession(parentSessionId, params.targetInfo.targetId, params.sessionId, params.targetInfo.url ?? '');
|
|
110
|
+
}
|
|
111
|
+
else if (event.method === 'Target.detachedFromTarget') {
|
|
112
|
+
const params = event.params;
|
|
113
|
+
if (!params?.sessionId)
|
|
114
|
+
return;
|
|
115
|
+
const parentSessionId = this.getParentSession(params.sessionId);
|
|
116
|
+
if (parentSessionId) {
|
|
117
|
+
this.removeChildSession(parentSessionId, params.sessionId);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
});
|
|
89
121
|
}
|
|
90
122
|
/** Track a child session (OOP iframe) under a parent session. */
|
|
91
123
|
addChildSession(parentSessionId, childTargetId, childSessionId, url) {
|
|
@@ -148,6 +180,7 @@ export class TabSessionService {
|
|
|
148
180
|
this.childSessions.delete(sessionId);
|
|
149
181
|
}
|
|
150
182
|
this.refSessionRouting.delete(sessionId);
|
|
183
|
+
this.sessionToTab.delete(sessionId);
|
|
151
184
|
cdpClient?.unpoolSession(tabId);
|
|
152
185
|
}
|
|
153
186
|
this.sessions.delete(tabId);
|
|
@@ -167,6 +200,7 @@ export class TabSessionService {
|
|
|
167
200
|
this.childSessions.clear();
|
|
168
201
|
this.childToParent.clear();
|
|
169
202
|
this.refSessionRouting.clear();
|
|
203
|
+
this.sessionToTab.clear();
|
|
170
204
|
}
|
|
171
205
|
/** Iterate over all [tabId, sessionId] pairs. */
|
|
172
206
|
entries() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tab-session-service.js","sourceRoot":"","sources":["../../src/connection/tab-session-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"tab-session-service.js","sourceRoot":"","sources":["../../src/connection/tab-session-service.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ import { SessionManager } from './session/session-manager.js';
|
|
|
30
30
|
import { TabOwnership } from './session/tab-ownership.js';
|
|
31
31
|
import { ModalStateManager } from './session/modal-state.js';
|
|
32
32
|
import { HealthMonitor } from './connection/health-monitor.js';
|
|
33
|
+
import { DomainCapabilities } from './connection/capabilities.js';
|
|
33
34
|
import { SnapshotCache } from './snapshot/cache.js';
|
|
34
35
|
import { ToolRegistry } from './tools/registry.js';
|
|
35
36
|
import { preprocessToolCall } from './tools/dispatch.js';
|
|
@@ -50,7 +51,7 @@ import { registerDebugTools } from './tools/debug.js';
|
|
|
50
51
|
import { registerFormTools } from './tools/form.js';
|
|
51
52
|
import { getSlimTools, mapSlimToFull } from './tools/slim-mode.js';
|
|
52
53
|
// ─── Bootstrap ──────────────────────────────────────────────────────
|
|
53
|
-
const VERSION = '5.0
|
|
54
|
+
const VERSION = '5.1.0';
|
|
54
55
|
const config = loadConfig();
|
|
55
56
|
const cdpClient = new CDPClient({ commandTimeout: config.globalTimeout });
|
|
56
57
|
// Lazy initialization: HealthMonitor is created but doesn't discover browsers
|
|
@@ -64,6 +65,8 @@ const healthMonitor = new HealthMonitor(cdpClient, {
|
|
|
64
65
|
const domainManager = new DomainManager();
|
|
65
66
|
const tabSessionService = new TabSessionService();
|
|
66
67
|
const snapshotCache = new SnapshotCache();
|
|
68
|
+
// CDP domain capability report (5.1.0 B1) — invalidated on disconnect below
|
|
69
|
+
const capabilities = new DomainCapabilities();
|
|
67
70
|
const registry = new ToolRegistry();
|
|
68
71
|
// Wire auto-reconnect: when the WebSocket drops, let HealthMonitor retry
|
|
69
72
|
// and clear domain state since all sessions are invalidated
|
|
@@ -74,6 +77,7 @@ cdpClient.on('disconnected', () => {
|
|
|
74
77
|
eventPipelineWired = false;
|
|
75
78
|
domainManager.clearAll();
|
|
76
79
|
snapshotCache.clear();
|
|
80
|
+
capabilities.clear();
|
|
77
81
|
tabSessionService.clear();
|
|
78
82
|
healthMonitor.onDisconnect().catch(() => {
|
|
79
83
|
// Reconnect failed — next tool call will trigger autoConnect
|
|
@@ -406,6 +410,7 @@ function wireEventPipeline(serverCtx) {
|
|
|
406
410
|
}
|
|
407
411
|
// ─── Server Context (DI container) ──────────────────────────────────
|
|
408
412
|
const ctx = {
|
|
413
|
+
capabilities,
|
|
409
414
|
config,
|
|
410
415
|
cdpClient,
|
|
411
416
|
healthMonitor,
|
|
@@ -422,6 +427,7 @@ const ctx = {
|
|
|
422
427
|
networkReqs: new Map(),
|
|
423
428
|
downloads: new Map(),
|
|
424
429
|
pendingDialogs: new Map(),
|
|
430
|
+
findState: new Map(),
|
|
425
431
|
pendingFileChoosers: new Map(),
|
|
426
432
|
pausedTabs: new Map(),
|
|
427
433
|
pendingFetchRequests: new Map(),
|
|
@@ -442,12 +448,13 @@ async function ensureConnected() {
|
|
|
442
448
|
}
|
|
443
449
|
}
|
|
444
450
|
// ─── Demo Tools ─────────────────────────────────────────────────────
|
|
451
|
+
const AUTO_CONNECT_HINT = '\nBrowser connects automatically when you use any browser tool — just call tabs.list or page.goto.';
|
|
445
452
|
registry.register(defineTool({
|
|
446
453
|
name: 'ping',
|
|
447
454
|
description: 'Health check. Returns server version and connection status.',
|
|
448
455
|
inputSchema: { type: 'object', properties: {} },
|
|
449
456
|
handler: async () => success(`pong — CDP Browser MCP v${VERSION}\nConnected: ${cdpClient.isConnected}` +
|
|
450
|
-
(cdpClient.isConnected ? `\nMode: ${healthMonitor.connectionMode}` :
|
|
457
|
+
(cdpClient.isConnected ? `\nMode: ${healthMonitor.connectionMode}` : AUTO_CONNECT_HINT)),
|
|
451
458
|
}));
|
|
452
459
|
registry.register(defineTool({
|
|
453
460
|
name: 'status',
|
|
@@ -459,13 +466,41 @@ registry.register(defineTool({
|
|
|
459
466
|
`Connected: ${cdpClient.isConnected}`,
|
|
460
467
|
...(cdpClient.isConnected
|
|
461
468
|
? [`Connection mode: ${healthMonitor.connectionMode}`]
|
|
462
|
-
: []),
|
|
469
|
+
: [AUTO_CONNECT_HINT.trim()]),
|
|
463
470
|
`Process scan: ${config.processScan ? 'on' : 'off'}`,
|
|
464
471
|
`Default timeout: ${config.globalTimeout}ms`,
|
|
465
472
|
`Default cleanup: ${config.defaultCleanupStrategy}`,
|
|
466
473
|
`Session TTL: ${config.sessionTTL}ms`,
|
|
467
474
|
`Registered tools: ${registry.size}`,
|
|
468
475
|
];
|
|
476
|
+
if (cdpClient.isConnected) {
|
|
477
|
+
try {
|
|
478
|
+
// Probe through a managed page session - the browser-level endpoint
|
|
479
|
+
// only serves browser-wide domains, so page-scoped domains (Overlay,
|
|
480
|
+
// FindInPage, Ads, ...) report "wasn't found" without one.
|
|
481
|
+
let firstSession = tabSessionService.entries().next().value?.[1];
|
|
482
|
+
if (!firstSession) {
|
|
483
|
+
// No managed tab yet - attach to any open page tab just for probing
|
|
484
|
+
// (canaries are read-only or validation-rejected; attaching is inert)
|
|
485
|
+
try {
|
|
486
|
+
const { targetInfos } = (await cdpClient.send('Target.getTargets', {}));
|
|
487
|
+
const pageTarget = targetInfos?.find((t) => t.type === 'page');
|
|
488
|
+
if (pageTarget) {
|
|
489
|
+
firstSession = (await tabSessionService.getSession(cdpClient, pageTarget.targetId));
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
catch { /* fall back to browser-level probe */ }
|
|
493
|
+
}
|
|
494
|
+
const { count, missing } = await capabilities.summarize(cdpClient, firstSession);
|
|
495
|
+
lines.push(`CDP features (probed${firstSession ? ' on page session' : ' browser-level - no page session'}): ${count}/${count + missing.length}`);
|
|
496
|
+
if (missing.length > 0) {
|
|
497
|
+
lines.push(`Notable domains missing: ${missing.join(', ')}`);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
catch (e) {
|
|
501
|
+
lines.push('CDP features: unavailable (' + (e instanceof Error ? e.message : String(e)) + ')');
|
|
502
|
+
}
|
|
503
|
+
}
|
|
469
504
|
return success(lines.join('\n'));
|
|
470
505
|
},
|
|
471
506
|
}));
|
|
@@ -506,7 +541,12 @@ else {
|
|
|
506
541
|
registerFormTools(registry, ctx);
|
|
507
542
|
}
|
|
508
543
|
// ─── MCP Server─────────────────────────────────────────────────────
|
|
509
|
-
const server = new Server({ name: 'cdp-browser', version: VERSION }, {
|
|
544
|
+
const server = new Server({ name: 'cdp-browser', version: VERSION }, {
|
|
545
|
+
capabilities: { tools: {} },
|
|
546
|
+
instructions: `CDP Browser MCP attaches your REAL running browser (cookies, logins, extensions stay). 14 tools: tabs, page, interact, form, execute, observe, emulate, storage, intercept, debug, browser, cleanup, ping, status. The browser connects automatically on the first browser-tool call - ping/status may say Connected: false before that; just call any browser tool.
|
|
547
|
+
|
|
548
|
+
CALLING CONVENTION (critical): every tool is ONE tool with an action enum parameter - there are NO per-action subtools. Call like tools["cdp-browser"].tabs({ action: "list" }), tools["cdp-browser"].page({ action: "goto", tabId, url }), tools["cdp-browser"].interact({ action: "click", tabId, uid }). WRONG: tabs.list(), tabs(), page.goto(url) - these tool names do not exist and fail schema validation. If unsure of an action or parameter, read the tool's description/enum first; tabs without action defaults to listing. Two connection modes: launch flag (--remote-debugging-port + explicit --user-data-dir) or the browser built-in chrome://inspect/#remote-debugging toggle (a permission dialog appears - click Allow).`,
|
|
549
|
+
});
|
|
510
550
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
511
551
|
tools: config.slimMode
|
|
512
552
|
? registry.list().filter(t => t.name.startsWith('browser_') || t.name === 'ping' || t.name === 'status')
|