cdp-toolkit 1.11.0 → 2.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/CHANGELOG.md +71 -0
- package/README.md +76 -7
- package/dist/cli.js +331 -299
- package/dist/index.js +11 -11
- package/dist/mcp.js +1002 -336
- package/package.json +3 -2
- package/src/bidi/driver.ts +29 -1
- package/src/bidi/launch.ts +51 -1
- package/src/manifest.ts +297 -297
- package/src/mcp.ts +187 -55
- package/src/toolDocs.ts +468 -0
- package/src/toolGroups.ts +81 -0
- package/src/tools/navigation.ts +4 -2
- package/src/version.ts +9 -0
package/src/toolDocs.ts
ADDED
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
// Generated full tool docs (source: original manifest). Served on demand by describe_tool.
|
|
2
|
+
export type ToolDoc = { readonly description: string; readonly params: Record<string, string> };
|
|
3
|
+
|
|
4
|
+
export const TOOL_DOCS: Record<string, ToolDoc> = {
|
|
5
|
+
"list_pages": {
|
|
6
|
+
"description": "Enumerate browser page targets (GET /json/list); page-type tabs only unless all=true. Each entry carries its targetId plus an origin field: 'agent' means this toolkit created it (also carries the creating label/createdAt, and stays 'agent' after the lease is released or the creator dies, making stray agent tabs findable), 'unknown' means no creation record - it never says 'human', the honest word for any tab it did not create; a record that exists but won't read adds originUnreadable. An entry under an active, readable lease also carries a 'lease' object {label,pid,idleMs,expiresAt,stale}, with idleMs and expiresAt computed fresh every call (never off disk), independent of probe. Under CDP_REQUIRE_LEASE this call also reaps abandoned agent tabs into an additive reaped array - but a lease reads reclaimable the moment its TTL elapses, while the tab is CLOSED only after a further grace (CDP_REAP_GRACE_MS, default 2700000ms/45min, so 60min total after last use); a dead-pid lease is reaped at once, a tab with no lease never. With probe, each page-type entry also gets 'responsive' (and humanActiveMs where human input is seen); both are absent, never false/null, without probe.",
|
|
7
|
+
"params": {
|
|
8
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
9
|
+
"all": "Include non-page targets (service/shared workers, background pages); default false lists page-type tabs only.",
|
|
10
|
+
"probe": "Ping each page-type renderer before returning, one bounded 500ms check per target and never more, so a wedged tab can't stall the listing. Adds 'responsive' (false on timeout/exception/unreachable, never an error for the whole call) and, where the same round trip finds human input, humanActiveMs. Default false. On a backend that cannot answer the ping, responsive is absent too (not false)."
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"new_page": {
|
|
14
|
+
"description": "Open a new browser tab via Target.createTarget and return {targetId,url}. Defaults to about:blank; navigation is not awaited here (use navigate_page to load and wait).",
|
|
15
|
+
"params": {
|
|
16
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
17
|
+
"url": "URL to open in the new tab; defaults to about:blank.",
|
|
18
|
+
"claim": "Claim the new tab atomically and return a lease token alongside {targetId,url}. Under CDP_REQUIRE_LEASE the tab is claimed and a lease returned even without claim:true; claim:true makes it an EXPLICIT lease that demands its token on every later call, even from this process. Default false.",
|
|
19
|
+
"label": "Agent label recorded on the lease when the tab is claimed; surfaced in conflict errors and list_leases. Defaults to pid-<pid>.",
|
|
20
|
+
"ttlMs": "How long a claimed lease survives without use before it is reclaimable. Defaults to CDP_LEASE_TTL_MS, else 900000 (15min); every checked call refreshes it. Ignored when not claiming."
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"close_page": {
|
|
24
|
+
"description": "Close a page target via Target.closeTarget. Requires an explicit, resolvable target; errors rather than guessing when the selector matches nothing.",
|
|
25
|
+
"params": {
|
|
26
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
27
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"select_page": {
|
|
31
|
+
"description": "Activate/focus a page target via Target.activateTarget and persist its bare targetId to the selected-state file (CDP_STATE_DIR/selected). Requires an explicit, resolvable target.",
|
|
32
|
+
"params": {
|
|
33
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
34
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"navigate_page": {
|
|
38
|
+
"description": "Navigate a target page to a URL (Page.navigate), reload it (reload:true), OR go back/forward in its session history (history:'back'|'forward'), then wait for the load milestone with a bounded timeout so a wedged renderer can't hang. Exactly one of url / reload / history per call. Returns {url,frameId,waitedFor} (plus reloaded:true on a reload, traversed:'back'|'forward' on a history move); waitUntil supports 'load'|'domcontentloaded' only (no 'networkidle'), and there is no auto-snapshot of the new page. Pass reload:true with ignoreCache:true for a hard reload that refetches every subresource (e.g. to pick up a freshly-deployed, non-content-hashed bundle the HTTP cache would serve stale).",
|
|
39
|
+
"params": {
|
|
40
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
41
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
42
|
+
"url": "Destination URL to navigate to. Required unless reload:true.",
|
|
43
|
+
"reload": "Reload the current page (Page.reload) instead of navigating to url. Default false.",
|
|
44
|
+
"history": "Traverse this tab's session history instead of loading a url: 'back' and 'forward' are the browser's Back and Forward buttons. Mutually exclusive with 'url' and 'reload' — passing two of the three is refused by name, not resolved by precedence. Works on BOTH backends and waits for the same load milestone as an ordinary navigation. Going back from the first entry, or forward from the last, is an ERROR naming the direction — never a silent no-op. The result carries traversed:'back'|'forward' alongside the resulting url.",
|
|
45
|
+
"ignoreCache": "On reload, bypass the HTTP cache (hard reload) so subresources are refetched. Ignored unless reload:true. Chrome only: Firefox's WebDriver-BiDi rejects the ignoreCache argument outright, so reload+ignoreCache on Firefox throws a clear unsupported error instead (a plain reload works). Default false.",
|
|
46
|
+
"waitUntil": "Which load milestone to wait for. Defaults to 'load'. No 'networkidle' support.",
|
|
47
|
+
"timeoutMs": "Override the navigation timeout in milliseconds."
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"wait_for": {
|
|
51
|
+
"description": "Poll the target until the substring appears in document.body.innerText (Runtime.evaluate on a fixed interval), or throw on timeout. Text-substring only -- no aria/role/selector or event variants; throws rather than returning {found:false}.",
|
|
52
|
+
"params": {
|
|
53
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
54
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
55
|
+
"text": "Substring to wait for in document.body.innerText. Required.",
|
|
56
|
+
"timeoutMs": "Total time budget in ms. Default 15000.",
|
|
57
|
+
"pollMs": "Poll interval in ms. Default 250."
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"evaluate_script": {
|
|
61
|
+
"description": "Run arbitrary JavaScript in the target's main-world context over raw CDP and return the evaluated value (returnByValue). With no 'args', 'expression' is a raw expression; with 'args' it must be a function literal (arrow or classic) invoked on globalThis with args passed positionally. A thrown exception surfaces as an error; non-serializable returns (DOM nodes, functions) come back as their CDP description string. savePath writes the value to a JSON file instead -- the response then carries only {path,bytes,type,target} and the value never appears in it, the way to read a credential (a JWT/session token from localStorage) without putting the secret in the transcript. This is the one tool that EVALUATES inside an MV3 extension's background SERVICE WORKER rather than OBSERVING it (Chrome, Capability 'worker.targets'): a worker: target reads chrome.storage.local, chrome.runtime and the worker's own globals directly, with an idle-evicted worker started first (see 'wake').",
|
|
62
|
+
"params": {
|
|
63
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
64
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', '<targetId>'; plus 'worker:<substring>' to reach a service/shared worker (e.g. an MV3 extension background worker). The worker: arm is CHROME-ONLY (Capability 'worker.targets'). Grammar: see server instructions.",
|
|
65
|
+
"wake": "Worker targets only, when starting a capture. Default true: an idle-evicted MV3 service worker exists in no target listing, so it is started first (ServiceWorker.startWorker) and re-confirmed; false fails fast. Rejected on a page target, a bare target id, or a read-only call. See server instructions.",
|
|
66
|
+
"expression": "JavaScript to run. Evaluated as an expression when 'args' is omitted; must be a function literal (arrow or classic) whose parameters receive 'args' when provided. REQUIRED -- the code always goes in this key, never in 'function', 'code', 'js', 'script', 'fn' or 'body'; a call using one of those is rejected with an error naming the wrong key.",
|
|
67
|
+
"awaitPromise": "Await the result if it is a Promise. Default true.",
|
|
68
|
+
"args": "Positional JSON-serializable arguments passed to the expression (treated as a function). No live element/page handle is bound.",
|
|
69
|
+
"savePath": "Write the evaluated value to this file as JSON and KEEP IT OUT OF THE RESPONSE: the result is {path,bytes,type,target} only, with no copy, preview or truncation of the value -- read credentials without putting them in a transcript. An absolute path (starting with /) is used as-is; a relative path resolves under the artifact dir (/tmp/cdp-toolkit); missing parents are created. Omit to get the value back inline."
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"list_cookies": {
|
|
73
|
+
"description": "Read the target page's cookie store INCLUDING httpOnly cookies, which document.cookie (and therefore evaluate_script) cannot see. Page-scoped, not browser-wide: returns cookies of the resolved tab, so point at a page on the site you want. Each cookie carries name, value, domain, path, expires (Unix seconds, -1 for a session cookie), size, httpOnly, secure, sameSite ('strict'|'lax'|'none'|'default'), session. Filter with 'domain' and/or 'name'. Pass 'savePath' to write the array to a JSON file instead: the response is then {path,bytes,count,target} with no cookie value in any form, the way to capture a session cookie without putting the credential in the transcript.",
|
|
74
|
+
"params": {
|
|
75
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
76
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
77
|
+
"domain": "Keep only cookies for this domain. A leading dot is ignored on both sides and subdomains match too, so 'example.test' matches '.example.test' and 'app.example.test'. No wildcards.",
|
|
78
|
+
"name": "Keep only the cookie with exactly this name. Exact match, not a substring.",
|
|
79
|
+
"savePath": "Write the cookie array here as JSON and KEEP THE VALUES OUT OF THE RESPONSE: the result is {path,bytes,count,target} only, with no preview or truncation of any value. An absolute path (starting with /) is used as-is; a relative path resolves under the artifact dir (/tmp/cdp-toolkit); missing parents are created. Omit to get the cookies back inline."
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"set_cookie": {
|
|
83
|
+
"description": "Write one cookie into the target page's cookie store, INCLUDING httpOnly or secure cookies that document.cookie (and therefore evaluate_script) cannot create. Either 'url' or 'domain' is REQUIRED: the call is refused when neither is given, rather than guessing the page origin. The response is {set:true,target} and never echoes the value back. A 'set:true' is earned, not assumed: Chrome raises an error when it declines the cookie (a domain the url does not belong to, a secure cookie on an insecure origin, an oversized value). On Firefox 'domain' is derived from 'url' when only the url was given (BiDi has no url parameter), and a url with no host such as about:blank or a data URL is an error, not a silent no-op. Read the result back with list_cookies when you need proof.",
|
|
84
|
+
"params": {
|
|
85
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
86
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
87
|
+
"name": "Cookie name. Required and non-empty.",
|
|
88
|
+
"value": "Cookie value. Required. It is not echoed back in the response.",
|
|
89
|
+
"url": "URL the cookie is set for, e.g. 'https://example.com/'. Chrome derives domain, path and secure from it; Firefox derives only the domain from its host. Give this or 'domain'.",
|
|
90
|
+
"domain": "Cookie domain, e.g. 'example.com' or '.example.com' for subdomains. Give this or 'url'. When both are given, this wins on Firefox and Chrome applies its own url plus domain consistency rule.",
|
|
91
|
+
"path": "Cookie path, passed through exactly as given and NOT defaulted to '/': with a 'url' Chrome derives the path from it, so an invented default here would widen a cookie you meant to scope narrowly.",
|
|
92
|
+
"expires": "Expiry as Unix time in SECONDS, matching what list_cookies reports. Omit for a session cookie, which is what both backends do when no expiry is supplied.",
|
|
93
|
+
"httpOnly": "Set the httpOnly flag, making the cookie invisible to document.cookie. Only a protocol write like this one can create such a cookie.",
|
|
94
|
+
"secure": "Set the secure flag. Chrome declines a secure cookie on an insecure origin, and that refusal surfaces as an error.",
|
|
95
|
+
"sameSite": "SameSite attribute, lowercase, matching what list_cookies reports. 'default' means the attribute is not set at all."
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"delete_cookies": {
|
|
99
|
+
"description": "Delete the named cookie from the target page's cookie store, httpOnly cookies included. Both 'name' and one of 'url' or 'domain' are REQUIRED: without a site constraint it would delete by name across the whole partition, so it is refused with an error instead. Narrow further with 'path'. The response is {deleted:true,target} and carries NO count, because neither protocol reports how many cookies it removed and a number here would be invented; call list_cookies before and after for a real count. 'deleted:true' means the backend accepted and performed the deletion, not that a matching cookie existed, since deleting an absent cookie succeeds on both backends.",
|
|
100
|
+
"params": {
|
|
101
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
102
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
103
|
+
"name": "Exact cookie name to delete. Required and non-empty. No wildcards: this removes a named cookie, not a swathe of them.",
|
|
104
|
+
"url": "Delete cookies matching this URL, e.g. 'https://example.com/'. Give this or 'domain'. On Firefox only the host is used, because BiDi's filter has no url field.",
|
|
105
|
+
"domain": "Delete cookies with this exact domain. Give this or 'url'.",
|
|
106
|
+
"path": "Narrow the deletion to cookies with this exact path. Omit to match any path allowed by the other constraints."
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"take_snapshot": {
|
|
110
|
+
"description": "Captures the page's accessibility tree as an indented text tree, each line prefixed [uid] (a CDP backendDOMNodeId). Every interaction tool (click/hover/fill/etc.) resolves that uid via DOM.resolveNode — run this first to discover uids to act on.",
|
|
111
|
+
"params": {
|
|
112
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
113
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
114
|
+
"interactiveOnly": "When true, emit only interactive/meaningful nodes as a flat list; default false returns the full hierarchical tree."
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"click": {
|
|
118
|
+
"description": "Click an element via a synthetic mouse press/release at its scrolled-into-view center. Give exactly one of uid or selector. modifiers (Alt/Control/Meta/Shift) throws on the Firefox backend — use --browser chrome for a modifier-click. clickCount:3 triple-clicks (selects a line/paragraph in most editors).",
|
|
119
|
+
"params": {
|
|
120
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
121
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
122
|
+
"uid": "CDP backendDOMNodeId of the element to click, from take_snapshot. Exactly one of uid or selector.",
|
|
123
|
+
"selector": "CSS selector for the element to click (document.querySelector). Exactly one of uid or selector.",
|
|
124
|
+
"button": "Mouse button: 'left' (default), 'right', or 'middle'.",
|
|
125
|
+
"clickCount": "Number of clicks: 1 (default), 2 = double-click, 3 = triple-click.",
|
|
126
|
+
"modifiers": "Modifier keys held for the click's press and release, e.g. ['Shift']. Non-empty on the Firefox backend throws — not supported over BiDi."
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"hover": {
|
|
130
|
+
"description": "Hovers the mouse over an element by dispatching a mouseMoved event at its scrolled-into-view center, firing framework hover handlers. Give exactly one of uid or selector.",
|
|
131
|
+
"params": {
|
|
132
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
133
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
134
|
+
"uid": "CDP backendDOMNodeId of the element to hover, from take_snapshot. Exactly one of uid or selector.",
|
|
135
|
+
"selector": "CSS selector for the element to hover (document.querySelector). Exactly one of uid or selector."
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"drag": {
|
|
139
|
+
"description": "Drags from a source element to a destination or by an offset. mode:'mouse' (default) dispatches synthetic mouse press/move/release; at the default steps:2 an HTML5 drop zone (dragover preventDefault) gets ZERO dragover events and refuses the drop. mode:'html5' replays real dragstart/dragEnter/dragOver/drop with the page's own dataTransfer instead — deterministic regardless of pointer path, but CHROME-ONLY (rejected with a clear error on the Firefox backend). 'from' takes uid or selector; destination is exactly one of 'to' (uid/selector/x+y) or 'by' ({dx,dy} offset — sliders, map panning, resize handles).",
|
|
140
|
+
"params": {
|
|
141
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
142
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
143
|
+
"from": "Source element to drag from. Exactly one of uid or selector.",
|
|
144
|
+
"to": "Where the drag ends: exactly one of uid, selector, or x+y. Mutually exclusive with 'by'; exactly one of to/by required.",
|
|
145
|
+
"by": "Offset from the source element's center: at least one of dx/dy (other defaults to 0). Mutually exclusive with 'to'; exactly one of to/by required. For sliders (by:{dx:40}), map panning, resize handles.",
|
|
146
|
+
"mode": "'mouse' (default): synthetic mouse press/move/release — at steps:2 an HTML5 drop zone sees zero dragover events and refuses the drop. 'html5': real HTML5 drag-and-drop, deterministic regardless of pointer path, CHROME-ONLY (rejected on Firefox).",
|
|
147
|
+
"steps": "Number of interpolated mouse-move events between source and destination, evenly spaced, last landing on the destination. Integer 1-500, default 2. Raise for DnD libraries with a movement threshold or per-frame sampling."
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
"scroll": {
|
|
151
|
+
"description": "Dispatches a wheel/scroll event at an anchor point — element (uid/selector) or x+y, scrolled into view first if an element; omit all three for viewport center. At least one of deltaX/deltaY required: positive deltaY scrolls DOWN, positive deltaX scrolls RIGHT (wheel-event convention — easy to invert). Returns the resolved anchor {x,y} plus the delta actually dispatched.",
|
|
152
|
+
"params": {
|
|
153
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
154
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
155
|
+
"uid": "CDP backendDOMNodeId of the element to scroll into view and anchor at, from take_snapshot. At most one of uid, selector, or x+y.",
|
|
156
|
+
"selector": "CSS selector for the element to anchor at (document.querySelector). At most one of uid, selector, or x+y.",
|
|
157
|
+
"x": "Absolute viewport x-coordinate to anchor at; must be given with y. At most one of uid, selector, or x+y.",
|
|
158
|
+
"y": "Absolute viewport y-coordinate to anchor at; must be given with x. At most one of uid, selector, or x+y.",
|
|
159
|
+
"deltaX": "Horizontal scroll delta; positive scrolls RIGHT. At least one of deltaX/deltaY required.",
|
|
160
|
+
"deltaY": "Vertical scroll delta; positive scrolls DOWN. At least one of deltaX/deltaY required."
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
"dispatch_mouse": {
|
|
164
|
+
"description": "Dispatches one raw mouse event (move/down/up) at absolute viewport coordinates — the toolkit's lowest-level input primitive. Compose move/down/move/up calls yourself for anything click/drag's fixed sequences can't reach: canvas drag-painting, marquee/rubber-band selection, custom hit-testing widgets. Chrome-only: absent from tools/list under the Firefox backend, never present-and-throwing.",
|
|
165
|
+
"params": {
|
|
166
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
167
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
168
|
+
"action": "Which raw event to dispatch: 'move' (mouseMoved), 'down' (mousePressed), or 'up' (mouseReleased).",
|
|
169
|
+
"x": "Viewport x-coordinate. Required every call — CDP has no 'current pointer position' to default from.",
|
|
170
|
+
"y": "Viewport y-coordinate. Required every call.",
|
|
171
|
+
"button": "Mouse button: 'left' (default), 'right', or 'middle'.",
|
|
172
|
+
"clickCount": "Click-run length for a 'down' or 'up' event (2 = second half of a double-click, 3 = triple-click). Ignored for 'move'; defaults to 1.",
|
|
173
|
+
"modifiers": "Modifier keys held for this one event, e.g. ['Shift']."
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
"wait_for_download": {
|
|
177
|
+
"description": "Wait for a file download to finish and return it as a real file on disk: {path,suggestedFilename,bytes,url,target}, written under the artifact dir's downloads/. ORDERING RULE, not optional: capture must be ARMED BEFORE the click that starts the download — call wait_for_download{arm:true} first (returns {armed:true,downloadPath,pending}), then click, then call again to collect the file. The download-behavior override is per-connection state Chrome REVERTS the moment the arming client disconnects, and an unarmed headless Chrome denies the download outright, so one triggered before arming is lost. SIDE EFFECT, browser-global: arming redirects EVERY download in this browser (all tabs, all origins) into the toolkit's downloads dir until this server exits — they no longer land in the user's normal Downloads folder. The arm lives on a connection this server holds open (an MCP-server capability): under the one-shot CLI the connection dies with the process and nothing is captured. Chrome-only (capability 'browser.downloads'): absent from tools/list under Firefox.",
|
|
178
|
+
"params": {
|
|
179
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
180
|
+
"target": "Names the tab for the lease check and the echoed target — a download is browser-scoped, so this does not pick which download is returned. Grammar: server instructions.",
|
|
181
|
+
"arm": "Arm download capture and return immediately instead of waiting: {armed:true,downloadPath,pending}. Call this BEFORE the click that triggers the download. 'pending' counts downloads that already completed and have not been collected yet, so an arm call doubles as a peek.",
|
|
182
|
+
"timeoutMs": "How long to wait for a download to complete, in milliseconds. Default 30000. Ignored with arm:true. A download that already completed and was not yet collected is returned immediately, so this only bounds the wait for one still in flight."
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
"grant_permissions": {
|
|
186
|
+
"description": "Grant browser permissions for an origin up front, so a page asking for geolocation / notifications / clipboard gets an answer instead of a prompt no agent can click. 'permissions' takes CDP PermissionType values ('geolocation','notifications','clipboardReadWrite','camera',...); an unknown name is refused by Chrome, quoting the bad value. Returns {granted,origin,target}, or {reset:true,target} for a reset-only call. Grants are keyed by ORIGIN, not by tab: every tab on that origin is affected, including ones opened later. reset:true clears this server's previous grants first (or instead, when no permissions are given) — CDP's reset is not origin-scoped, so it clears them for every origin at once. The grant lives on a connection this server holds open and Chrome DISCARDS IT when that connection closes: an MCP-server capability, so under the one-shot CLI the grant dies with the process. Chrome-only (capability 'browser.permissions'): absent from tools/list under Firefox, never present-and-throwing.",
|
|
187
|
+
"params": {
|
|
188
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
189
|
+
"target": "Also the origin source when 'origin' is omitted. Grammar: server instructions.",
|
|
190
|
+
"permissions": "CDP PermissionType values to grant, e.g. ['geolocation'] or ['clipboardReadWrite','clipboardSanitizedWrite']. Required unless reset:true. An empty array is refused rather than treated as a successful no-op.",
|
|
191
|
+
"origin": "Origin the grant applies to, e.g. 'https://example.com'. Defaults to the target tab's own origin. Required explicitly when that tab has no grantable origin (data:, blob:, about:blank all serialize to the opaque origin 'null'), which is refused with a message naming the tab's url.",
|
|
192
|
+
"reset": "Clear this server's previous permission grants (Browser.resetPermissions). With 'permissions' it resets FIRST and then grants, so the result is exactly the listed permissions; on its own it is a reset-only call answering {reset:true}. Not scoped to 'origin': CDP resets every origin at once."
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
"fill": {
|
|
196
|
+
"description": "Fills an element by focusing it, clearing existing content, then inserting value via Input.insertText (atomic paste-like commit, not per-character keystrokes — won't fire per-keypress handlers). Give exactly one of uid or selector.",
|
|
197
|
+
"params": {
|
|
198
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
199
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
200
|
+
"uid": "CDP backendDOMNodeId of the field to fill, from take_snapshot. Exactly one of uid or selector.",
|
|
201
|
+
"selector": "CSS selector for the field to fill (document.querySelector). Exactly one of uid or selector.",
|
|
202
|
+
"value": "Text value to set; the field is cleared first, overwriting existing content."
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
"fill_form": {
|
|
206
|
+
"description": "Fills multiple form fields in one call; each is focused, cleared, then set via Input.insertText (overwrites existing content, same as fill). Each entry in the non-empty 'fields' array takes exactly one of uid or selector plus a string value.",
|
|
207
|
+
"params": {
|
|
208
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
209
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
210
|
+
"fields": "Non-empty array of fields to fill, each with exactly one of uid or selector plus a string value."
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
"type_text": {
|
|
214
|
+
"description": "Focuses an element and appends text via Input.insertText without clearing first — closest primitive to typing, but still atomic (not per-character keystrokes). Give exactly one of uid or selector.",
|
|
215
|
+
"params": {
|
|
216
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
217
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
218
|
+
"uid": "CDP backendDOMNodeId of the element to type into, from take_snapshot. Exactly one of uid or selector.",
|
|
219
|
+
"selector": "CSS selector for the element to type into (document.querySelector). Exactly one of uid or selector.",
|
|
220
|
+
"text": "Text to insert; appended to existing content rather than overwriting it."
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
"press_key": {
|
|
224
|
+
"description": "Dispatches a keyDown/keyUp pair for one key with optional modifiers. 'key' is a named key (Enter, Tab, Escape, ArrowDown, Backspace, etc.) or a single printable character — the named-key table is curated, with no F-keys, numpad, or IME support.",
|
|
225
|
+
"params": {
|
|
226
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
227
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
228
|
+
"key": "Key to press: a named key (Enter, Tab, Escape, ArrowDown, Backspace, ...) or a single printable character.",
|
|
229
|
+
"modifiers": "Modifier names held during the press: 'Control'/'Ctrl', 'Shift', 'Alt', 'Meta'/'Cmd'."
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
"upload_file": {
|
|
233
|
+
"description": "Attaches one or more files to an <input type=file> element via DOM.setFileInputFiles. Give exactly one of uid or selector for the input; 'files' is an array of absolute path(s) — wrap a single path in an array too.",
|
|
234
|
+
"params": {
|
|
235
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
236
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
237
|
+
"uid": "CDP backendDOMNodeId of the file input element, from take_snapshot. Exactly one of uid or selector.",
|
|
238
|
+
"selector": "CSS selector for the file input element (document.querySelector). Exactly one of uid or selector.",
|
|
239
|
+
"files": "Absolute path(s) to attach to the <input type=file>, as an array — wrap a single path too, e.g. [\"/tmp/a.pdf\"]. Array-only because some model APIs (Google Gemini function calling) reject union-typed parameters."
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
"take_screenshot": {
|
|
243
|
+
"description": "Captures the viewport (default), the full scrollable page (fullPage), or one element (uid or selector, mutually exclusive) via CDP Page.captureScreenshot. Past 16384 device px per side Chrome can hang rather than refuse, so size is checked first via Page.getLayoutMetrics; an oversized capture is auto-tiled into vertical bands stitched losslessly into one PNG (see tile) instead of wedging the tab. Writes PNG/JPEG to /tmp/cdp-toolkit (override savePath, dir auto-created); returns {path,bytes,format,target,scale} plus width/height measured from the encoded bytes (omitted if undecodable). renderSize/renderRestored(+renderRestoreError) accompany a renderWidth/renderHeight capture, tiled/bands a banded one. returnBase64 adds raw bytes to the result but is refused on a banded capture. quality applies to jpeg only.",
|
|
244
|
+
"params": {
|
|
245
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
246
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
247
|
+
"format": "Image format, default png. quality applies only to jpeg.",
|
|
248
|
+
"quality": "JPEG quality 0-100, default 80; ignored for png.",
|
|
249
|
+
"fullPage": "Capture the full scrollable height (via Page.getLayoutMetrics), not just the viewport.",
|
|
250
|
+
"scale": "Output-pixel multiplier for this capture only (0<scale<=8, default 1): output px = ceil(css px x scale x devicePixelRatio); the page is never told anything changed. Chrome only (screenshot.scale) — Firefox BiDi has no scale param, use emulate{deviceScaleFactor} then scale:1. A projection over 16384 device px/side is refused up front, naming the largest scale that fits.",
|
|
251
|
+
"renderWidth": "Emulates this viewport width (CSS px, 1-16384) for one capture, then restores it. Required with renderHeight. Unlike scale, this changes what the page believes (media queries re-flow) — e.g. capture a responsive page at 1920x1080 from a differently-sized tab. Restore only works for an override this toolkit itself set; check result.renderRestored (false = still emulated, fix via emulate). Works on both backends (capability screenshot.renderSize).",
|
|
252
|
+
"renderHeight": "Emulates this viewport height (CSS px, 1-16384) for one capture. Required with renderWidth — a viewport is two numbers. A narrow renderWidth often reflows pages TALLER, which is the usual way a render-size capture trips the 16384px encode limit.",
|
|
253
|
+
"tile": "Whether to allow vertical-band stitching: omitted=AUTO (band only if a single shot wouldn't fit), false=never band (refuse instead), true=always band (Chrome-only capability). Banded output is PNG-only, can't returnBase64, and only bands on HEIGHT (oversized WIDTH is refused, not split). Bands are a faithful crop, but lazy/virtualized content the real viewport never scrolled to renders blank.",
|
|
254
|
+
"uid": "Element to clip to: a backendDOMNodeId from take_snapshot. Mutually exclusive with selector.",
|
|
255
|
+
"selector": "CSS selector to clip the capture to. Mutually exclusive with uid.",
|
|
256
|
+
"savePath": "Override the output path (default /tmp/cdp-toolkit/screenshot-<id>-<stamp>.<ext>, stamped at capture START). Directory is created from this path's dirname.",
|
|
257
|
+
"returnBase64": "Also return raw base64 bytes in the result. Refused on a banded capture (see tile) — a stitched image can run to hundreds of MB; read the file at the returned path instead."
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
"emulate": {
|
|
261
|
+
"description": "Applies any subset of Chrome emulation overrides in one call: device metrics (width+height together, +deviceScaleFactor/mobile), userAgent, cpuThrottlingRate(>=1), media type+features, networkConditions. Device-metrics overrides PERSIST on the target until cleared or the renderer navigates/reloads; every other override is session-scoped and resets when this call's connection closes. clearOverrides:true resets everything (ignoring other fields) and, as of 1.9.2, genuinely clears a device-metrics override set by a DIFFERENT process — Chrome's clearDeviceMetricsOverride is normally a no-op unless the clearing connection also set the override, so the driver re-asserts the tab's current size first, then clears, throwing rather than reporting cleared:true if it can't verify.",
|
|
262
|
+
"params": {
|
|
263
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
264
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
265
|
+
"width": "Device-metrics viewport width in CSS px. Must be paired with height.",
|
|
266
|
+
"height": "Device-metrics viewport height in CSS px. Must be paired with width.",
|
|
267
|
+
"deviceScaleFactor": "Device pixel ratio for the device-metrics override; 0 = platform default.",
|
|
268
|
+
"mobile": "Emulate a mobile device (viewport meta, scrollbars, etc.) for the device-metrics override.",
|
|
269
|
+
"userAgent": "User-Agent string override (Emulation.setUserAgentOverride).",
|
|
270
|
+
"cpuThrottlingRate": "CPU throttling multiplier: 1=none, 2=2x slower, etc. Must be >=1.",
|
|
271
|
+
"media": "Emulated CSS media type: 'screen' | 'print' | '' (clear).",
|
|
272
|
+
"mediaFeatures": "Emulated media features, e.g. [{name:'prefers-color-scheme', value:'dark'}].",
|
|
273
|
+
"networkConditions": "Network overrides applied via Network.emulateNetworkConditions.",
|
|
274
|
+
"clearOverrides": "Reset every override (metrics, UA, CPU, media, network) to browser default; ignores all other fields when true."
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
"resize_page": {
|
|
278
|
+
"description": "Sets the page's device-metrics width/height (the narrow case of emulate), optionally deviceScaleFactor/mobile, then verifies by reading back window.innerWidth/innerHeight after applying. Requires positive width and height. The override PERSISTS on the target until cleared (emulate{clearOverrides:true}) or the renderer navigates/reloads.",
|
|
279
|
+
"params": {
|
|
280
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
281
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
282
|
+
"width": "Viewport width in CSS px (required, must be positive).",
|
|
283
|
+
"height": "Viewport height in CSS px (required, must be positive).",
|
|
284
|
+
"deviceScaleFactor": "Device pixel ratio; 0 = platform default.",
|
|
285
|
+
"mobile": "Emulate a mobile device for the device-metrics override."
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
"handle_dialog": {
|
|
289
|
+
"description": "Wait for the next JavaScript dialog (alert/confirm/prompt/beforeunload) on a page and respond via Page.handleJavaScriptDialog, accepting or dismissing it. Default mode resolves with the first handled dialog or throws on timeout; set autoMs to handle every dialog opening during a fixed window and resolve with the list. Trigger the dialog out-of-band (e.g. click a button) — a blocking dialog freezes the renderer, so it cannot be triggered inline.",
|
|
290
|
+
"params": {
|
|
291
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
292
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
293
|
+
"accept": "Whether to accept (OK) or dismiss (Cancel) the dialog.",
|
|
294
|
+
"promptText": "Text to enter for a prompt() dialog when accepting.",
|
|
295
|
+
"timeoutMs": "How long to wait for the next dialog, in milliseconds (default 15000).",
|
|
296
|
+
"autoMs": "Auto-handle mode: keep handling every dialog that opens for this many milliseconds, then resolve with the list of handled dialogs (an empty list is valid; never throws on 'no dialog')."
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
"list_console_messages": {
|
|
300
|
+
"description": "Read console output (logs, warnings, exceptions) captured for the target. Reads the existing shared buffer by default (empty if no capture ran); reload:true reloads and records a fresh capture (console+network together, so a network reload never wipes console history). WORKER capture (Chrome, Capability 'worker.targets'): a worker: target records an MV3 background service worker -- its console.log arrives as Runtime.consoleAPICalled, its outbound requests from CDP's Network domain on the worker's own session -- so the two tricks callers try first fail for plain JS reasons, not worker ones: a value bound at module top level is not visible from evaluate_script's global scope, and assigning self.fetch cannot rebind a fetch the module already captured. A worker has no reload: reload:true means 'listen for durationMs while it runs', so trigger its work (tool call, message, alarm) during the window; a worker woken by the call already ran its top-level code, so a startup message can be missed. SIDE EFFECT: the CDP session KEEPS THE WORKER ALIVE for the capture (an idle MV3 worker is evicted in seconds); Chrome resumes evicting after.",
|
|
301
|
+
"params": {
|
|
302
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
303
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', '<targetId>'; plus 'worker:<substring>' to reach a service/shared worker (e.g. an MV3 extension background worker). The worker: arm is CHROME-ONLY (Capability 'worker.targets'). Grammar: see server instructions.",
|
|
304
|
+
"reload": "Record fresh by reloading the page and capturing a window. Default false (read existing buffer). With a worker: target nothing reloads -- records for durationMs while the worker runs and keeps it alive until the capture stops.",
|
|
305
|
+
"durationMs": "Capture window for reload mode, in ms. Default 2500.",
|
|
306
|
+
"wake": "Worker targets only, when starting a capture. Default true: an idle-evicted MV3 service worker exists in no target listing, so it is started first (ServiceWorker.startWorker) and re-confirmed; false fails fast. Rejected on a page target, a bare target id, or a read-only call. See server instructions."
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
"get_console_message": {
|
|
310
|
+
"description": "Return one console entry by zero-based index from the target's existing console buffer. Throws if the index is out of range; run list_console_messages (optionally reload:true) first to populate the buffer.",
|
|
311
|
+
"params": {
|
|
312
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
313
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
314
|
+
"index": "Zero-based index into the parsed console entries. Default 0."
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
"list_network_requests": {
|
|
318
|
+
"description": "Return correlated network rows (one per requestId; status/headers/state) for the target. Reads the existing buffer by default; reload:true records a fresh both-domains capture window. filterUrl keeps only URLs containing a substring. WORKER capture (Chrome, Capability 'worker.targets'): a worker: target records an MV3 background service worker's outbound requests from CDP's Network domain on the worker's own session -- what the code ACTUALLY SENT -- so the two tricks callers try first fail for plain JS reasons, not worker ones: a value bound at module top level is not visible from evaluate_script's global scope, and assigning self.fetch cannot rebind a fetch the module already captured. A worker has no reload: reload:true means 'listen for durationMs while it runs', so trigger its work (tool call, message, alarm) during the window; a worker woken by the call already ran its top-level code, so a startup request can be missed. SIDE EFFECT: the CDP session KEEPS THE WORKER ALIVE for the capture (an idle MV3 worker is evicted in seconds); Chrome resumes evicting after.",
|
|
319
|
+
"params": {
|
|
320
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
321
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', '<targetId>'; plus 'worker:<substring>' to reach a service/shared worker (e.g. an MV3 extension background worker). The worker: arm is CHROME-ONLY (Capability 'worker.targets'). Grammar: see server instructions.",
|
|
322
|
+
"reload": "Record fresh by reloading the page and capturing a window. Default false (read existing buffer). With a worker: target nothing reloads -- records for durationMs while the worker runs and keeps it alive until the capture stops.",
|
|
323
|
+
"durationMs": "Capture window for reload mode, in ms. Default 2500.",
|
|
324
|
+
"filterUrl": "Return only requests whose URL contains this substring.",
|
|
325
|
+
"wake": "Worker targets only, when starting a capture. Default true: an idle-evicted MV3 service worker exists in no target listing, so it is started first (ServiceWorker.startWorker) and re-confirmed; false fails fast. Rejected on a page target, a bare target id, or a read-only call. See server instructions."
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
"get_network_request": {
|
|
329
|
+
"description": "Return one network request (matched by exact requestId, else url substring) with status/headers. Requires requestId or url (throws otherwise). includeBody:true drives a fresh capture (page reload, or worker listen window) matched by url ONLY -- a fresh capture re-mints requestIds, so a carried-over requestId returns metadata plus bodyUnavailableReason. WORKER capture (Chrome, Capability 'worker.targets'): a worker: target records an MV3 background service worker's outbound requests from CDP's Network domain on the worker's own session -- what the code ACTUALLY SENT -- so the two tricks callers try first fail for plain JS reasons, not worker ones: a value bound at module top level is not visible from evaluate_script's global scope, and assigning self.fetch cannot rebind a fetch the module already captured. A worker has no reload: reload means 'listen for durationMs while it runs', so trigger its work (tool call, message, alarm) during the window; a worker woken by the call already ran its top-level code, so a startup request can be missed. SIDE EFFECT: the CDP session KEEPS THE WORKER ALIVE for the capture (an idle MV3 worker is evicted in seconds); Chrome resumes evicting after.",
|
|
330
|
+
"params": {
|
|
331
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
332
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', '<targetId>'; plus 'worker:<substring>' to reach a service/shared worker (e.g. an MV3 extension background worker). The worker: arm is CHROME-ONLY (Capability 'worker.targets'). Grammar: see server instructions.",
|
|
333
|
+
"requestId": "Match by exact requestId (metadata only; cannot fetch a body, since a reload re-mints requestIds).",
|
|
334
|
+
"url": "Match by URL substring (first match). Required for body fetch (includeBody), since url is stable across reload.",
|
|
335
|
+
"includeBody": "Also fetch the response body; drives a fresh capture and requires the url selector.",
|
|
336
|
+
"durationMs": "Capture window for the body-fetch reload, in ms. Default 2500.",
|
|
337
|
+
"wake": "Worker targets only, when starting a capture. Default true: an idle-evicted MV3 service worker exists in no target listing, so it is started first (ServiceWorker.startWorker) and re-confirmed; false fails fast. Rejected on a page target, a bare target id, or a read-only call. See server instructions."
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
"performance_start_trace": {
|
|
341
|
+
"description": "Starts a CDP trace recording on the target and holds the recording connection in-process; you MUST call performance_stop_trace from the SAME PROCESS to end it, or use performance_trace instead for a robust cross-call trace. Throws if a trace is already in progress for this target.",
|
|
342
|
+
"params": {
|
|
343
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
344
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
345
|
+
"categories": "Trace categories to record. Defaults to timeline + user-timing + loading + disabled-by-default timeline tracks carrying LCP/LayoutShift/RunTask."
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
"performance_stop_trace": {
|
|
349
|
+
"description": "Stops the in-process trace started by performance_start_trace and writes it as JSON under /tmp/cdp-toolkit, returning {path,bytes,events,metrics}. Throws if no live trace exists in THIS process (e.g. start ran in a different process) — use performance_trace instead. The target arg is accepted only for API symmetry; at most one trace is ever live per process.",
|
|
350
|
+
"params": {
|
|
351
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
352
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
"performance_analyze_insight": {
|
|
356
|
+
"description": "Reads a trace JSON file (from performance_trace/performance_stop_trace) at tracePath and returns headline metrics: FCP/LCP/CLS/TBT, long tasks, layout shifts. Requires an EXPLICIT tracePath — there is no implicit 'latest trace'. Numbers approximate DevTools's insight analyzer (no main-thread attribution or frame-scoped LCP).",
|
|
357
|
+
"params": {
|
|
358
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
359
|
+
"tracePath": "Path to a trace JSON file (bare array or {traceEvents:[...]}) written by performance_trace or performance_stop_trace. Required."
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
"performance_trace": {
|
|
363
|
+
"description": "RECOMMENDED entry point: one-shot trace that starts tracing, optionally reloads or navigates the page, waits durationMs (default 3000ms), stops, and writes JSON under /tmp/cdp-toolkit — returns {path,bytes,events,metrics,target}. Holds one connection open for the whole window, so unlike start/stop it is NOT limited to a single process.",
|
|
364
|
+
"params": {
|
|
365
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
366
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
367
|
+
"durationMs": "How long to record after the optional reload/navigate, in ms. Default 3000.",
|
|
368
|
+
"reload": "Reload the page after starting the trace, to capture full navigation timing.",
|
|
369
|
+
"navigateTo": "Navigate to this URL after starting the trace (alternative to reload).",
|
|
370
|
+
"categories": "Trace categories to record. Defaults to timeline + user-timing + loading + disabled-by-default timeline tracks carrying LCP/LayoutShift/RunTask."
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
"start_screen_recording": {
|
|
374
|
+
"description": "Starts recording the target tab to video via CDP Page.startScreencast, holding one persistent connection and spooling every frame to disk — MUST be paired with stop_screen_recording WITHIN THE SAME PROCESS (frames are connection-scoped and cannot be reattached from another process, so this only works under the MCP server, not the one-process-per-call CLI). Chrome only: WebDriver BiDi has no screencast primitive, so both tools are absent under --browser firefox. Frames arrive ON REPAINT not on a clock (variable rate); each is timestamped into a ledger that stop_screen_recording turns into per-frame display durations, so a still page holds one long frame instead of racing. ffmpeg is probed here (not at stop) so a missing encoder fails before frames are captured and thrown away. Throws if the target already has a recording in progress; different targets record concurrently.",
|
|
375
|
+
"params": {
|
|
376
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
377
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
378
|
+
"format": "Frame format, default jpeg (much smaller per repaint); png is lossless. quality applies to jpeg only.",
|
|
379
|
+
"quality": "JPEG frame quality 0-100. Ignored for png; omitted leaves Chrome's own default.",
|
|
380
|
+
"maxWidth": "Caps the streamed frame width in px; also pins frame size if the viewport may change mid-recording.",
|
|
381
|
+
"maxHeight": "Caps the streamed frame height in px.",
|
|
382
|
+
"everyNthFrame": "Capture only every Nth repaint (1=every frame), to shrink spool size on a busy page; per-frame durations keep playback at wallclock speed either way.",
|
|
383
|
+
"bringToFront": "Activate the tab (Page.bringToFront) before recording, default false. A backgrounded/occluded tab may never repaint, yielding a 0-frame recording."
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
"stop_screen_recording": {
|
|
387
|
+
"description": "Stops the recording started by start_screen_recording, assembling spooled frames into an MP4 via ffmpeg with PER-FRAME durations (frame N held until N+1 painted; last frame held until this call) — capped at 25fps by ffmpeg's concat demuxer, so frames under 40ms apart are deliberately coalesced (frameCount=captured, encodedFrames=what reached the video, never silently dropped). Returns {path,bytes,durationMs,frameCount,encodedFrames,codec,encoder,width,height,droppedFrames,target}; durationMs sums encoded durations, the file runs one 40ms step longer (final frame repeated). Encoder ladder (probed at start): hevc_videotoolbox>h264_videotoolbox>libx265>libx264 (+hvc1 tag, faststart, yuv420p, even dims). target: omit with one recording in flight, required with several (avoids guessing which to stop). Throws if nothing is recording in this process, or if 0 frames arrived (no silent empty video). On ffmpeg failure the spooled frames are KEPT — spool path + exact command are in the error.",
|
|
388
|
+
"params": {
|
|
389
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
390
|
+
"target": "Which recording to stop — 'active' valid only when exactly one recording is in flight. Grammar: server instructions.",
|
|
391
|
+
"savePath": "Override the output path (default /tmp/cdp-toolkit/screen-recording-<targetIdShort>-<stamp>.mp4)."
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
"take_heapsnapshot": {
|
|
395
|
+
"description": "Captures a V8 heap snapshot of the target page over CDP and writes it as a .heapsnapshot JSON file (loadable in the DevTools Memory panel) under /tmp/cdp-toolkit unless savePath is given. Returns {path,bytes,chunks,target} only — does NOT parse or summarize the snapshot.",
|
|
396
|
+
"params": {
|
|
397
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
398
|
+
"target": "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions.",
|
|
399
|
+
"savePath": "Override the output path. Absolute paths (starting with /) are used as-is; relative paths resolve under the artifact dir (/tmp/cdp-toolkit). Defaults to an auto-named take_heapsnapshot-<targetId>-<timestamp>.heapsnapshot file."
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
"lighthouse_audit": {
|
|
403
|
+
"description": "Runs a Lighthouse audit against a URL by shelling out to `npx --yes lighthouse` (the toolkit's only non-CDP tool) — it attaches to the already-running Chrome and audits its OWN about:blank tab, NOT any live user tab you've navigated. Writes a JSON report under /tmp/cdp-toolkit; returns {path,bytes} plus per-category scores (0..1 or null).",
|
|
404
|
+
"params": {
|
|
405
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
406
|
+
"url": "The URL to audit. Required — never points at a user tab implicitly.",
|
|
407
|
+
"categories": "Lighthouse categories to run (--only-categories). Defaults to the full set, e.g. [\"performance\"] or [\"performance\",\"accessibility\",\"seo\"].",
|
|
408
|
+
"savePath": "Override the report output path; defaults to a timestamped file under /tmp/cdp-toolkit.",
|
|
409
|
+
"formFactor": "\"desktop\" (default, uses --preset=desktop to avoid heavy mobile throttling) or \"mobile\".",
|
|
410
|
+
"timeoutMs": "Overall budget for the lighthouse process, in ms. Default 120000."
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
"mock_request": {
|
|
414
|
+
"description": "Register a mock rule on a target's persistent fake-backend session (CDP Fetch domain): match requests by urlPattern and fulfill with a canned response, fail (abort), or continue -- optionally with fault injection (delayMs/failRate). The session survives reloads/navigations and lives until clear_mocks; call repeatedly to mock several endpoints on one target. reload:true applies it immediately. Persistent across calls only via the MCP server, not the one-shot CLI.",
|
|
415
|
+
"params": {
|
|
416
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
417
|
+
"target": "Which page's mock session. Defaults to the active page. Grammar: server instructions.",
|
|
418
|
+
"urlPattern": "CDP Fetch urlPattern glob: '*' any run of chars, '?' exactly one, '\\' escapes. Only matching URLs are paused. e.g. \"*/api/users*\".",
|
|
419
|
+
"action": "What to do with a matched request. Default \"fulfill\".",
|
|
420
|
+
"status": "fulfill: HTTP status for the canned response. Default 200.",
|
|
421
|
+
"body": "fulfill: response body string (base64-encoded for CDP internally).",
|
|
422
|
+
"contentType": "fulfill: Content-Type header. Default \"application/json\".",
|
|
423
|
+
"headers": "fulfill: extra response headers (name->value); override Content-Type case-insensitively. Add \"Access-Control-Allow-Origin\" for cross-origin fetches.",
|
|
424
|
+
"errorReason": "fail: CDP Network.ErrorReason, e.g. \"Failed\" (default), \"BlockedByClient\", \"ConnectionRefused\", \"TimedOut\".",
|
|
425
|
+
"method": "Only mock this HTTP method (e.g. \"POST\"); others pass through.",
|
|
426
|
+
"delayMs": "Fault injection: artificial latency in ms before responding.",
|
|
427
|
+
"failRate": "Fault injection: probability 0..1 of failing a matched request regardless of action.",
|
|
428
|
+
"reload": "Reload the target after arming so the mock catches traffic immediately."
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
"list_mocks": {
|
|
432
|
+
"description": "List active fake-backend sessions (one per target) with their rules and hit counts. Prunes sessions whose tab has closed.",
|
|
433
|
+
"params": {
|
|
434
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
435
|
+
"target": "Unused filter placeholder; returns all active sessions."
|
|
436
|
+
}
|
|
437
|
+
},
|
|
438
|
+
"clear_mocks": {
|
|
439
|
+
"description": "Tear down fake-backend sessions (Fetch.disable + close the connection). Clears the resolved target's session by default, or every active session with all:true.",
|
|
440
|
+
"params": {
|
|
441
|
+
"lease": "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions.",
|
|
442
|
+
"target": "Which page's mock session to clear. Defaults to the active page; ignored when all:true. Grammar: server instructions.",
|
|
443
|
+
"all": "Clear every active mock session instead of just the resolved target's."
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
"claim_page": {
|
|
447
|
+
"description": "Take exclusive ownership of a browser tab, returning an opaque lease token (needed once under CDP_REQUIRE_LEASE for any tab you drive). Two modes: FRESH TAB (no target - opens one, optionally at url, and claims it: 'give me my own tab' in one call) and TAKEOVER (target - claims an already-open tab, e.g. the human's, resolving the selector against the live page list, creating nothing). The opened flag is true only when this call created the tab, and release_page consults that record, so a taken-over tab is left open on release. Refused from the CLI (its per-call process would make the lease instantly reclaimable). The answer carries humanActiveMs, ms since input this server did not dispatch; null is NO DATA (no activity beacon, or every input was this server's own) and never means 'no human'; absent on a backend that cannot answer. On takeover of a tab a human used within 30s it adds contention, a warning - but THE CLAIM IS NEVER REFUSED FOR THIS: takeover is its purpose, you already hold the lease; it only warns you're fighting a live person, so open your own tab or ask first. Limits: input inside a cross-origin iframe is invisible, and a second MCP server's clicks read as human.",
|
|
448
|
+
"params": {
|
|
449
|
+
"target": "Take over an already-open tab (e.g. one the human has open). Resolved against the LIVE page list only, so it never opens a tab — a selector matching nothing is an error. Left open on release. Refused if another live process holds it (including a lease auto-acquired under CDP_REQUIRE_LEASE): takes over unleased human tabs, never steals from a live agent. Mutually exclusive with targetId. Selector grammar: server instructions.",
|
|
450
|
+
"targetId": "Exact target id (not a selector) of an already-open page to claim instead of opening one. Back-compat only; prefer target, which also accepts an exact id. Mutually exclusive with target.",
|
|
451
|
+
"url": "When opening a fresh tab, navigate it here. Ignored when target or targetId is given.",
|
|
452
|
+
"label": "Agent label recorded on the lease; surfaced in conflict errors and list_leases. Defaults to pid-<pid>.",
|
|
453
|
+
"ttlMs": "How long the lease survives without use before it is reclaimable. Defaults to CDP_LEASE_TTL_MS, else 900000 (15min); every checked call refreshes it."
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
"release_page": {
|
|
457
|
+
"description": "Give a lease back, closing the tab only if this toolkit opened it. Take exactly one of lease (the token) or target (a selector for a tab this process holds - use this to release a lease the gate acquired for you automatically, since that path never handed you a token). A tab with a creation record from this toolkit is closed; a tab that was already open and merely claimed is released and left alone - override either way with close. Idempotent: an already-released, reclaimed, or expired lease reports released:false and closes nothing (by then the tab may belong to another agent). Answers {released, closed, targetId}.",
|
|
458
|
+
"params": {
|
|
459
|
+
"lease": "Token from claim_page / new_page{claim:true}. Mutually exclusive with 'target'. Under CDP_REQUIRE_LEASE an auto-acquired lease never produced a token — give 'target' instead.",
|
|
460
|
+
"target": "A tab THIS process holds (grammar: server instructions). Mutually exclusive with 'lease'. Refused if another process holds the tab.",
|
|
461
|
+
"close": "Force the close decision instead of letting the creation record decide: true closes even a tab this toolkit did not open; false keeps an agent-created tab open. Omit to close only tabs this toolkit created."
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
"list_leases": {
|
|
465
|
+
"description": "Enumerate every active lease for diagnosis - backend, target id, label, pid, createdAt, lastUsedAt, ttlMs, whether the owning process is alive, and whether the lease is reclaimable and why. No token required; it never returns the lease nonce, so it cannot be used to forge one. An unreadable or unparseable lease row instead carries unreadable, with label, pid and timestamps zeroed and stale forced false (an unreadable lease must never read as free to take). Under CDP_REQUIRE_LEASE it reaps abandoned agent tabs exactly as list_pages does, into an additive reaped array, omitting their rows. Where the tab can answer, a row also carries humanActiveMs, ms since input this server did not dispatch - note lastUsedAt tracks TOOLKIT calls only, so a tab a person has typed in for ten minutes looks idle, which is what this exposes; the field is absent, never null, when the tab cannot answer, and that absence means 'no answer', never 'nobody is there'. idleMs (now - lastUsedAt) and expiresAt (lastUsedAt + ttlMs) are computed fresh each call and omitted on an unreadable row.",
|
|
466
|
+
"params": {}
|
|
467
|
+
}
|
|
468
|
+
};
|