cdp-toolkit 1.7.0 → 1.9.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 +403 -0
- package/CONTRACT.md +9 -1
- package/README.md +58 -17
- package/dist/cli.js +1302 -158
- package/dist/index.js +1144 -145
- package/dist/mcp.js +1620 -244
- package/package.json +6 -3
- package/src/activity.ts +533 -0
- package/src/bidi/driver.ts +259 -8
- package/src/capabilities.ts +1 -1
- package/src/cdp/driver.ts +487 -25
- package/src/cdp/workers.ts +177 -0
- package/src/cli.ts +3 -1
- package/src/client.ts +52 -2
- package/src/driver.ts +187 -3
- package/src/index.ts +26 -4
- package/src/leases-tools.ts +127 -6
- package/src/leases.ts +1 -1
- package/src/manifest.ts +279 -46
- package/src/mcp.ts +6 -1
- package/src/origins.ts +41 -1
- package/src/reap.ts +55 -4
- package/src/shared-tools.ts +372 -30
- package/src/tools/browser-session.ts +246 -0
- package/src/tools/dispatch-mouse.ts +108 -0
- package/src/tools/downloads.ts +143 -0
- package/src/tools/permissions.ts +130 -0
- package/src/types.ts +20 -0
- package/src/workers.ts +159 -0
package/src/manifest.ts
CHANGED
|
@@ -25,7 +25,7 @@ export interface ToolSpec {
|
|
|
25
25
|
export const MANIFEST: ToolSpec[] = [
|
|
26
26
|
{
|
|
27
27
|
"name": "list_pages",
|
|
28
|
-
"description": "Enumerate browser page targets via the CDP browser endpoint (GET /json/list). By default returns only page-type tabs; set 'all' to also include workers and background pages. Each entry carries the targetId used as a target selector elsewhere, plus an 'origin' field recording where the tab came from: 'agent' means this toolkit created it (the entry then also carries the creating 'label' and 'createdAt'), and this stays true after the creating agent releases its lease or dies, which is what makes a stray agent tab findable later. 'unknown' means there is no creation record. It never says 'human': the toolkit cannot prove a person opened a tab, so 'unknown' is the honest word for a tab it did not create, one opened before the toolkit ran, or one whose record could not be written. A tab whose record exists but could not be read reports origin 'unknown' plus 'originUnreadable', so a broken record is never mistaken for no record. Under CDP_REQUIRE_LEASE this call also reaps
|
|
28
|
+
"description": "Enumerate browser page targets via the CDP browser endpoint (GET /json/list). By default returns only page-type tabs; set 'all' to also include workers and background pages. Each entry carries the targetId used as a target selector elsewhere, plus an 'origin' field recording where the tab came from: 'agent' means this toolkit created it (the entry then also carries the creating 'label' and 'createdAt'), and this stays true after the creating agent releases its lease or dies, which is what makes a stray agent tab findable later. 'unknown' means there is no creation record. It never says 'human': the toolkit cannot prove a person opened a tab, so 'unknown' is the honest word for a tab it did not create, one opened before the toolkit ran, or one whose record could not be written. A tab whose record exists but could not be read reports origin 'unknown' plus 'originUnreadable', so a broken record is never mistaken for no record. Under CDP_REQUIRE_LEASE this call also reaps abandoned agent tabs, but reap-CLOSE and lease-RECLAIMABLE (list_leases' 'stale') now fire at different times: a lease reads reclaimable the moment its TTL elapses, cheap and reversible since another agent may simply take it, while this call only CLOSES the tab, destructively, after an ADDITIONAL grace period past that TTL (CDP_REAP_GRACE_MS, default 2700000ms/45 minutes, so 60 minutes total after last use) — a tab an agent is mid-build between calls on is not destroyed out from under it. A dead-pid lease is reaped immediately regardless of grace: that process is never coming back. Closed tabs are reported in an additive 'reaped' array ({targetId,label,reason}) present only when something was actually closed; a tab with no lease is never reaped. Every entry under an active, readable lease of this backend also carries 'lease': {label, pid, idleMs, expiresAt, stale} — idleMs and expiresAt are computed fresh on every call (now-lastUsedAt and lastUsedAt+ttlMs), never read off disk, and this is unconditional on 'probe'. Set 'probe' to true to also ping each page-type target's renderer: one bounded (500ms) check per target, never more, so a single wedged tab cannot stall the listing beyond its own budget. This adds 'responsive' (true iff the ping answered in time; false on a timeout, a page-side exception, or an unreachable target — never an error for the whole call) and, where that same round trip found human-attributed input, 'humanActiveMs' (see claim_page and list_leases for what that field means and cannot prove). 'responsive' and 'humanActiveMs' are both ABSENT — never false/null — when 'probe' is not set, and 'responsive' is likewise absent on a backend that cannot answer this ping at all.",
|
|
29
29
|
"inputSchema": {
|
|
30
30
|
"type": "object",
|
|
31
31
|
"properties": {
|
|
@@ -36,6 +36,10 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
36
36
|
"all": {
|
|
37
37
|
"type": "boolean",
|
|
38
38
|
"description": "Include non-page targets (service/shared workers, background pages) when true; otherwise only page-type tabs are listed."
|
|
39
|
+
},
|
|
40
|
+
"probe": {
|
|
41
|
+
"type": "boolean",
|
|
42
|
+
"description": "Ping each page-type target's renderer before returning: one bounded (500ms) Runtime.evaluate per target, never more. Adds 'responsive' to every page-type entry and, where the same round trip finds human-attributed input, 'humanActiveMs'. A wedged or unreachable tab reports responsive:false rather than failing the call. Defaults to false, which is byte-identical to the pre-1.8.0 shape."
|
|
39
43
|
}
|
|
40
44
|
},
|
|
41
45
|
"required": [],
|
|
@@ -85,7 +89,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
85
89
|
},
|
|
86
90
|
"target": {
|
|
87
91
|
"type": "string",
|
|
88
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
92
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
89
93
|
}
|
|
90
94
|
},
|
|
91
95
|
"required": [
|
|
@@ -106,7 +110,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
106
110
|
},
|
|
107
111
|
"target": {
|
|
108
112
|
"type": "string",
|
|
109
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
113
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
110
114
|
}
|
|
111
115
|
},
|
|
112
116
|
"required": [
|
|
@@ -117,7 +121,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
117
121
|
},
|
|
118
122
|
{
|
|
119
123
|
"name": "navigate_page",
|
|
120
|
-
"description": "Navigate a target page to a URL (Page.navigate)
|
|
124
|
+
"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).",
|
|
121
125
|
"inputSchema": {
|
|
122
126
|
"type": "object",
|
|
123
127
|
"properties": {
|
|
@@ -127,7 +131,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
127
131
|
},
|
|
128
132
|
"target": {
|
|
129
133
|
"type": "string",
|
|
130
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
134
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
131
135
|
},
|
|
132
136
|
"url": {
|
|
133
137
|
"type": "string",
|
|
@@ -137,6 +141,14 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
137
141
|
"type": "boolean",
|
|
138
142
|
"description": "Reload the current page (Page.reload) instead of navigating to url. Default false."
|
|
139
143
|
},
|
|
144
|
+
"history": {
|
|
145
|
+
"type": "string",
|
|
146
|
+
"enum": [
|
|
147
|
+
"back",
|
|
148
|
+
"forward"
|
|
149
|
+
],
|
|
150
|
+
"description": "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 rather than resolved by precedence. Works on BOTH backends (Chrome: Page.getNavigationHistory + Page.navigateToHistoryEntry; Firefox: browsingContext.traverseHistory) 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 success that navigated nowhere. The result carries traversed:'back'|'forward' alongside the resulting url."
|
|
151
|
+
},
|
|
140
152
|
"ignoreCache": {
|
|
141
153
|
"type": "boolean",
|
|
142
154
|
"description": "On reload, bypass the HTTP cache (hard reload) so subresources are refetched. Ignored unless reload:true. Default false."
|
|
@@ -169,7 +181,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
169
181
|
},
|
|
170
182
|
"target": {
|
|
171
183
|
"type": "string",
|
|
172
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
184
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
173
185
|
},
|
|
174
186
|
"text": {
|
|
175
187
|
"type": "string",
|
|
@@ -192,7 +204,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
192
204
|
},
|
|
193
205
|
{
|
|
194
206
|
"name": "evaluate_script",
|
|
195
|
-
"description": "Run arbitrary JavaScript in the target page's main-world context over raw CDP and return the evaluated value (returnByValue). With no 'args' the 'expression' is evaluated as a raw expression; when 'args' is provided 'expression' must be a function literal (arrow or classic) invoked on globalThis with the args passed positionally. A thrown exception surfaces as an error; non-serializable returns (DOM nodes, functions) come back as their CDP description string. Pass 'savePath' to write the evaluated value to a JSON file instead: the response then carries only {path,bytes,type,target} and the value itself never appears in it, in any form. That is the way to read a credential (a JWT or session token out of localStorage, for example) without putting the secret into the caller's transcript.",
|
|
207
|
+
"description": "Run arbitrary JavaScript in the target page's main-world context over raw CDP and return the evaluated value (returnByValue). With no 'args' the 'expression' is evaluated as a raw expression; when 'args' is provided 'expression' must be a function literal (arrow or classic) invoked on globalThis with the args passed positionally. A thrown exception surfaces as an error; non-serializable returns (DOM nodes, functions) come back as their CDP description string. Pass 'savePath' to write the evaluated value to a JSON file instead: the response then carries only {path,bytes,type,target} and the value itself never appears in it, in any form. That is the way to read a credential (a JWT or session token out of localStorage, for example) without putting the secret into the caller's transcript. This is also the one tool that can evaluate inside an MV3 extension's background SERVICE WORKER rather than a page: pass target 'worker:<extension-id>' (Chrome only) and read chrome.storage.local, chrome.runtime and the worker's own globals directly, with an idle-evicted worker started for you first (see 'wake').",
|
|
196
208
|
"inputSchema": {
|
|
197
209
|
"type": "object",
|
|
198
210
|
"properties": {
|
|
@@ -202,11 +214,15 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
202
214
|
},
|
|
203
215
|
"target": {
|
|
204
216
|
"type": "string",
|
|
205
|
-
"description": "Page selector: 'active' (or omit) -> first page-type target | '<32-hex targetId>' -> exact target by id | 'index:N' -> Nth page-type target (0-based) | 'url:<substring>' -> first page whose url contains substring | 'title:<substring>' -> first page whose title contains substring."
|
|
217
|
+
"description": "Page selector: 'active' (or omit) -> first page-type target | '<32-hex targetId>' -> exact target by id | 'index:N' -> Nth page-type target (0-based) | 'url:<substring>' -> first page whose url contains substring | 'title:<substring>' -> first page whose title contains substring | 'label:<name>' -> the page-type target with exactly this label (checked against the origin ledger and live leases) | 'worker:<substring>' -> a service/shared worker whose url contains the substring, which is how you reach an MV3 extension's background service worker (worker:<extension-id> or worker:background.js) and read chrome.storage.local from it. The worker: arm is CHROME-ONLY (Capability 'worker.targets') and is accepted by this tool only; an MV3 worker that has been idle-evicted is started automatically first, see 'wake'."
|
|
218
|
+
},
|
|
219
|
+
"wake": {
|
|
220
|
+
"type": "boolean",
|
|
221
|
+
"description": "Only valid with a 'worker:<substring>' target, and rejected on a page target rather than ignored. Default true: an MV3 extension service worker is idle-evicted after seconds of inactivity and then exists in NO target listing, so a wake asks Chrome to start it (ServiceWorker.startWorker over a page session) and then re-reads the target list to confirm it actually came up. Pass false to fail fast instead of starting anything; the error then says the worker may simply be asleep."
|
|
206
222
|
},
|
|
207
223
|
"expression": {
|
|
208
224
|
"type": "string",
|
|
209
|
-
"description": "JavaScript to run. Evaluated as an expression when 'args' is omitted; must be a function literal (arrow or classic) whose parameters receive 'args' when 'args' is provided."
|
|
225
|
+
"description": "JavaScript to run. Evaluated as an expression when 'args' is omitted; must be a function literal (arrow or classic) whose parameters receive 'args' when 'args' is provided. REQUIRED — the code always goes in this key, never in 'function', 'code', 'js', 'script', 'fn' or 'body'; a call using one of those instead is rejected with an error naming the wrong key."
|
|
210
226
|
},
|
|
211
227
|
"awaitPromise": {
|
|
212
228
|
"type": "boolean",
|
|
@@ -239,7 +255,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
239
255
|
},
|
|
240
256
|
"target": {
|
|
241
257
|
"type": "string",
|
|
242
|
-
"description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>'."
|
|
258
|
+
"description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>' | 'label:<name>'."
|
|
243
259
|
},
|
|
244
260
|
"domain": {
|
|
245
261
|
"type": "string",
|
|
@@ -270,7 +286,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
270
286
|
},
|
|
271
287
|
"target": {
|
|
272
288
|
"type": "string",
|
|
273
|
-
"description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>'."
|
|
289
|
+
"description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>' | 'label:<name>'."
|
|
274
290
|
},
|
|
275
291
|
"name": {
|
|
276
292
|
"type": "string",
|
|
@@ -326,7 +342,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
326
342
|
},
|
|
327
343
|
"target": {
|
|
328
344
|
"type": "string",
|
|
329
|
-
"description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>'."
|
|
345
|
+
"description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>' | 'label:<name>'."
|
|
330
346
|
},
|
|
331
347
|
"name": {
|
|
332
348
|
"type": "string",
|
|
@@ -361,7 +377,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
361
377
|
},
|
|
362
378
|
"target": {
|
|
363
379
|
"type": "string",
|
|
364
|
-
"description": "Target page selector: 'active' (default, = first page-type target) | 'index:N' (Nth page-type target, 0-based) | 'url:<substring>' | 'title:<substring>' | '<32-hex targetId>' (exact target by id)."
|
|
380
|
+
"description": "Target page selector: 'active' (default, = first page-type target) | 'index:N' (Nth page-type target, 0-based) | 'url:<substring>' | 'title:<substring>' | 'label:<name>' (exact label match, origin ledger or live lease) | '<32-hex targetId>' (exact target by id)."
|
|
365
381
|
},
|
|
366
382
|
"interactiveOnly": {
|
|
367
383
|
"type": "boolean",
|
|
@@ -374,7 +390,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
374
390
|
},
|
|
375
391
|
{
|
|
376
392
|
"name": "click",
|
|
377
|
-
"description": "Click an element via a synthetic mouse press/release at the element's scrolled-into-view bounding-rect center. Target the element with exactly one of 'uid' (a CDP backendDOMNodeId from take_snapshot) or 'selector' (a CSS selector).",
|
|
393
|
+
"description": "Click an element via a synthetic mouse press/release at the element's scrolled-into-view bounding-rect center. Target the element with exactly one of 'uid' (a CDP backendDOMNodeId from take_snapshot) or 'selector' (a CSS selector). clickCount:3 triple-clicks (selects a paragraph/line in most editors). 'modifiers' holds Alt/Control/Meta/Shift for the press and release, like a real modifier-click; on the Firefox backend a non-empty 'modifiers' throws (not yet supported over BiDi), so a modifier click there needs --browser chrome.",
|
|
378
394
|
"inputSchema": {
|
|
379
395
|
"type": "object",
|
|
380
396
|
"properties": {
|
|
@@ -384,7 +400,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
384
400
|
},
|
|
385
401
|
"target": {
|
|
386
402
|
"type": "string",
|
|
387
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
403
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
388
404
|
},
|
|
389
405
|
"uid": {
|
|
390
406
|
"type": "number",
|
|
@@ -405,7 +421,20 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
405
421
|
},
|
|
406
422
|
"clickCount": {
|
|
407
423
|
"type": "number",
|
|
408
|
-
"description": "Number of clicks: 1 = single (default), 2 = double-click."
|
|
424
|
+
"description": "Number of clicks: 1 = single (default), 2 = double-click, 3 = triple-click."
|
|
425
|
+
},
|
|
426
|
+
"modifiers": {
|
|
427
|
+
"type": "array",
|
|
428
|
+
"items": {
|
|
429
|
+
"type": "string",
|
|
430
|
+
"enum": [
|
|
431
|
+
"Alt",
|
|
432
|
+
"Control",
|
|
433
|
+
"Meta",
|
|
434
|
+
"Shift"
|
|
435
|
+
]
|
|
436
|
+
},
|
|
437
|
+
"description": "Modifier keys held for the click's press and release, e.g. ['Shift'] for a shift-click. Not supported on the Firefox backend: passing a non-empty array there throws."
|
|
409
438
|
}
|
|
410
439
|
},
|
|
411
440
|
"required": [],
|
|
@@ -424,7 +453,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
424
453
|
},
|
|
425
454
|
"target": {
|
|
426
455
|
"type": "string",
|
|
427
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
456
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
428
457
|
},
|
|
429
458
|
"uid": {
|
|
430
459
|
"type": "number",
|
|
@@ -441,7 +470,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
441
470
|
},
|
|
442
471
|
{
|
|
443
472
|
"name": "drag",
|
|
444
|
-
"description": "Drag from a source element to a destination element via synthetic mouse press/move/release
|
|
473
|
+
"description": "Drag from a source element to a destination. 'from' takes exactly one of uid (a CDP backendDOMNodeId from take_snapshot) or selector. The destination is exactly one of 'to' (an element via uid/selector, or an absolute viewport point via x+y) or 'by' ({dx,dy} offset from the source point — sliders, map panning, resize handles). mode:'mouse' (default) dispatches synthetic mouse press/move/release: right for widgets built on raw pointer events, and Chrome does turn it into a real drag, but WHICH drag events reach the page depends on where the interpolated pointer path happens to land — measured on Chrome 151, the default steps:2 delivers ZERO dragover events, so an HTML5 drop zone written the standard way (preventDefault inside dragover) refuses the drop entirely. mode:'html5' performs the drag deterministically instead: Chrome's drag interception hands back the DragData the page's own dragstart built, and the toolkit replays it as dragEnter/dragOver/drop exactly at the destination, so a draggable=\"true\" / dataTransfer drop zone works regardless of the pointer path. mode:'html5' is CHROME-ONLY: it requires capability 'input.html5Drag' and is rejected with a clear error under the Firefox backend, where the tool itself remains available for mouse-mode drags. 'steps' (default 2) sets how many interpolated mouse-move events are dispatched between source and destination; raise it for DnD libraries with a movement threshold or per-frame sampling.",
|
|
445
474
|
"inputSchema": {
|
|
446
475
|
"type": "object",
|
|
447
476
|
"properties": {
|
|
@@ -451,7 +480,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
451
480
|
},
|
|
452
481
|
"target": {
|
|
453
482
|
"type": "string",
|
|
454
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
483
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
455
484
|
},
|
|
456
485
|
"from": {
|
|
457
486
|
"type": "object",
|
|
@@ -470,7 +499,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
470
499
|
},
|
|
471
500
|
"to": {
|
|
472
501
|
"type": "object",
|
|
473
|
-
"description": "
|
|
502
|
+
"description": "Where the drag ends: exactly one of uid, selector, or x+y. Mutually exclusive with 'by'; exactly one of to/by is required.",
|
|
474
503
|
"properties": {
|
|
475
504
|
"uid": {
|
|
476
505
|
"type": "number",
|
|
@@ -479,18 +508,222 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
479
508
|
"selector": {
|
|
480
509
|
"type": "string",
|
|
481
510
|
"description": "CSS selector for the destination element (resolved via document.querySelector)."
|
|
511
|
+
},
|
|
512
|
+
"x": {
|
|
513
|
+
"type": "number",
|
|
514
|
+
"description": "Absolute viewport x-coordinate to drop at. Must be given together with 'y'. Use this when there is no droppable element to name (a canvas, a slider track)."
|
|
515
|
+
},
|
|
516
|
+
"y": {
|
|
517
|
+
"type": "number",
|
|
518
|
+
"description": "Absolute viewport y-coordinate to drop at. Must be given together with 'x'."
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
"additionalProperties": false
|
|
522
|
+
},
|
|
523
|
+
"by": {
|
|
524
|
+
"type": "object",
|
|
525
|
+
"description": "Drag by an offset from the source element's center instead of to a destination: at least one of dx/dy, the other defaults to 0. Mutually exclusive with 'to'; exactly one of to/by is required. Use for sliders (by:{dx:40}), map panning, and resize handles.",
|
|
526
|
+
"properties": {
|
|
527
|
+
"dx": {
|
|
528
|
+
"type": "number",
|
|
529
|
+
"description": "Horizontal offset in CSS pixels; positive drags RIGHT."
|
|
530
|
+
},
|
|
531
|
+
"dy": {
|
|
532
|
+
"type": "number",
|
|
533
|
+
"description": "Vertical offset in CSS pixels; positive drags DOWN."
|
|
482
534
|
}
|
|
483
535
|
},
|
|
484
536
|
"additionalProperties": false
|
|
537
|
+
},
|
|
538
|
+
"mode": {
|
|
539
|
+
"type": "string",
|
|
540
|
+
"enum": [
|
|
541
|
+
"mouse",
|
|
542
|
+
"html5"
|
|
543
|
+
],
|
|
544
|
+
"description": "'mouse' (default): synthetic mouse press/move/release, right for widgets built on raw pointer events. Chrome does turn this into a real HTML5 drag too, but WHICH drag events reach the page depends on the interpolated pointer path: at the default steps:2, an HTML5 drop zone written the standard way (preventDefault inside dragover) sees zero dragover events and refuses the drop. 'html5': real HTML5 drag-and-drop (dragstart/dragEnter/dragOver/drop with the page's own dataTransfer), deterministic regardless of pointer path. 'html5' is CHROME-ONLY and is rejected with a clear error under the Firefox backend."
|
|
545
|
+
},
|
|
546
|
+
"steps": {
|
|
547
|
+
"type": "number",
|
|
548
|
+
"description": "Number of interpolated mouse-move events dispatched between the source and destination points, evenly spaced, the last landing exactly on the destination. Integer 1-500, default 2 (midpoint then destination). Raise it for DnD libraries with a movement threshold or per-frame sampling."
|
|
485
549
|
}
|
|
486
550
|
},
|
|
487
551
|
"required": [
|
|
488
|
-
"from"
|
|
489
|
-
"to"
|
|
552
|
+
"from"
|
|
490
553
|
],
|
|
491
554
|
"additionalProperties": false
|
|
492
555
|
}
|
|
493
556
|
},
|
|
557
|
+
{
|
|
558
|
+
"name": "scroll",
|
|
559
|
+
"description": "Dispatch a wheel/scroll event at an anchor point: provide at most one of 'uid', 'selector', or 'x'+'y'; omit all three to scroll at the viewport center. An element anchor ('uid' or 'selector') is scrolled into view first, the same as click/hover. At least one of 'deltaX'/'deltaY' is required; positive 'deltaY' scrolls DOWN and positive 'deltaX' scrolls RIGHT (wheel-event convention). Chrome dispatches Input.dispatchMouseEvent{type:'mouseWheel'}; Firefox dispatches WebDriver BiDi's 'wheel' input source. Returns the resolved anchor point ({x,y}) plus the delta actually dispatched.",
|
|
560
|
+
"inputSchema": {
|
|
561
|
+
"type": "object",
|
|
562
|
+
"properties": {
|
|
563
|
+
"lease": {
|
|
564
|
+
"type": "string",
|
|
565
|
+
"description": "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
|
|
566
|
+
},
|
|
567
|
+
"target": {
|
|
568
|
+
"type": "string",
|
|
569
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
570
|
+
},
|
|
571
|
+
"uid": {
|
|
572
|
+
"type": "number",
|
|
573
|
+
"description": "CDP backendDOMNodeId of the element to scroll into view and anchor at, obtained from take_snapshot. Provide at most one of uid, selector, or x+y; omit all three to scroll at the viewport center."
|
|
574
|
+
},
|
|
575
|
+
"selector": {
|
|
576
|
+
"type": "string",
|
|
577
|
+
"description": "CSS selector for the element to scroll into view and anchor at (resolved via document.querySelector). Provide at most one of uid, selector, or x+y; omit all three to scroll at the viewport center."
|
|
578
|
+
},
|
|
579
|
+
"x": {
|
|
580
|
+
"type": "number",
|
|
581
|
+
"description": "Absolute viewport x-coordinate to anchor the scroll at. Must be given together with 'y'. Provide at most one of uid, selector, or x+y."
|
|
582
|
+
},
|
|
583
|
+
"y": {
|
|
584
|
+
"type": "number",
|
|
585
|
+
"description": "Absolute viewport y-coordinate to anchor the scroll at. Must be given together with 'x'. Provide at most one of uid, selector, or x+y."
|
|
586
|
+
},
|
|
587
|
+
"deltaX": {
|
|
588
|
+
"type": "number",
|
|
589
|
+
"description": "Horizontal scroll delta; positive scrolls RIGHT. At least one of deltaX/deltaY is required."
|
|
590
|
+
},
|
|
591
|
+
"deltaY": {
|
|
592
|
+
"type": "number",
|
|
593
|
+
"description": "Vertical scroll delta; positive scrolls DOWN. At least one of deltaX/deltaY is required."
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
"required": [],
|
|
597
|
+
"additionalProperties": false
|
|
598
|
+
}
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
"name": "dispatch_mouse",
|
|
602
|
+
"description": "Dispatch exactly one raw mouse event ('move', 'down', or 'up') at absolute viewport coordinates: the toolkit's lowest-level input primitive. Compose move/down/move/up calls yourself to reach anything a physical mouse can do that click/drag's fixed sequences cannot — canvas drag-painting, marquee/rubber-band selection, a custom widget with its own hit-testing. Chrome-only (capability 'input.raw'): absent from tools/list under the Firefox backend, never present-and-throwing.",
|
|
603
|
+
"inputSchema": {
|
|
604
|
+
"type": "object",
|
|
605
|
+
"properties": {
|
|
606
|
+
"lease": {
|
|
607
|
+
"type": "string",
|
|
608
|
+
"description": "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
|
|
609
|
+
},
|
|
610
|
+
"target": {
|
|
611
|
+
"type": "string",
|
|
612
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
613
|
+
},
|
|
614
|
+
"action": {
|
|
615
|
+
"type": "string",
|
|
616
|
+
"enum": [
|
|
617
|
+
"move",
|
|
618
|
+
"down",
|
|
619
|
+
"up"
|
|
620
|
+
],
|
|
621
|
+
"description": "Which raw event to dispatch: 'move' (mouseMoved), 'down' (mousePressed), or 'up' (mouseReleased)."
|
|
622
|
+
},
|
|
623
|
+
"x": {
|
|
624
|
+
"type": "number",
|
|
625
|
+
"description": "Viewport x-coordinate. Required on every call: CDP has no notion of a 'current pointer position' to default from."
|
|
626
|
+
},
|
|
627
|
+
"y": {
|
|
628
|
+
"type": "number",
|
|
629
|
+
"description": "Viewport y-coordinate. Required on every call."
|
|
630
|
+
},
|
|
631
|
+
"button": {
|
|
632
|
+
"type": "string",
|
|
633
|
+
"enum": [
|
|
634
|
+
"left",
|
|
635
|
+
"right",
|
|
636
|
+
"middle"
|
|
637
|
+
],
|
|
638
|
+
"description": "Mouse button: 'left' (default), 'right', or 'middle'."
|
|
639
|
+
},
|
|
640
|
+
"clickCount": {
|
|
641
|
+
"type": "number",
|
|
642
|
+
"description": "Click-run length for a 'down' or 'up' event (2 = the second half of a double-click, 3 = triple-click). Ignored for 'move'; defaults to 1."
|
|
643
|
+
},
|
|
644
|
+
"modifiers": {
|
|
645
|
+
"type": "array",
|
|
646
|
+
"items": {
|
|
647
|
+
"type": "string",
|
|
648
|
+
"enum": [
|
|
649
|
+
"Alt",
|
|
650
|
+
"Control",
|
|
651
|
+
"Meta",
|
|
652
|
+
"Shift"
|
|
653
|
+
]
|
|
654
|
+
},
|
|
655
|
+
"description": "Modifier keys held for this one event, e.g. ['Shift']."
|
|
656
|
+
}
|
|
657
|
+
},
|
|
658
|
+
"required": [
|
|
659
|
+
"action",
|
|
660
|
+
"x",
|
|
661
|
+
"y"
|
|
662
|
+
],
|
|
663
|
+
"additionalProperties": false
|
|
664
|
+
}
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
"name": "wait_for_download",
|
|
668
|
+
"description": "Wait for a file download to finish and return it as a real file on disk: {path,suggestedFilename,bytes,url,target}. The file is written under the artifact dir's downloads/ folder and renamed from Chrome's internal guid to the page's own filename, collision-suffixed (report.csv, report-1.csv, ...). ORDERING RULE, and it is not optional: download capture must be ARMED BEFORE the click that starts the download — call wait_for_download{arm:true} first (it arms and returns immediately, reporting {armed:true,downloadPath,pending}), then click, then call wait_for_download to collect the finished file. This is Chrome's behavior, not a preference: the download-behavior override is per-connection state that Chrome REVERTS the moment the arming client disconnects, and an unarmed headless Chrome denies the download outright, so a download triggered before anything armed is lost with no file anywhere. SIDE EFFECT, browser-global: arming redirects EVERY download in this browser (all tabs, all origins) into the toolkit's downloads directory for as long as this server runs, and downloads no longer land in the user's normal Downloads folder. Because the arm lives on a connection this server process holds open, this is 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 the Firefox backend, never present-and-throwing, because WebDriver BiDi has no command to redirect a download to a chosen directory.",
|
|
669
|
+
"inputSchema": {
|
|
670
|
+
"type": "object",
|
|
671
|
+
"properties": {
|
|
672
|
+
"lease": {
|
|
673
|
+
"type": "string",
|
|
674
|
+
"description": "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
|
|
675
|
+
},
|
|
676
|
+
"target": {
|
|
677
|
+
"type": "string",
|
|
678
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'. A download is browser-scoped, so this names the tab for the lease check and for the echoed target, not which download is returned."
|
|
679
|
+
},
|
|
680
|
+
"arm": {
|
|
681
|
+
"type": "boolean",
|
|
682
|
+
"description": "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."
|
|
683
|
+
},
|
|
684
|
+
"timeoutMs": {
|
|
685
|
+
"type": "number",
|
|
686
|
+
"description": "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 a download still in flight."
|
|
687
|
+
}
|
|
688
|
+
},
|
|
689
|
+
"required": [],
|
|
690
|
+
"additionalProperties": false
|
|
691
|
+
}
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
"name": "grant_permissions",
|
|
695
|
+
"description": "Grant browser permissions for an origin up front, so a page asking for geolocation / notifications / clipboard gets an answer instead of showing a prompt no agent can click. 'permissions' takes CDP PermissionType values ('geolocation', 'notifications', 'clipboardReadWrite', 'camera', 'microphone', 'midi', ...); an unknown name is refused by Chrome with the bad value in the message. 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) — note CDP's reset is not origin-scoped, so it clears them for every origin at once. The grant lives on a connection this server process holds open and Chrome DISCARDS IT when that connection closes, so this is an MCP-server capability: under the one-shot CLI the grant dies with the process. Chrome-only (capability 'browser.permissions'): absent from tools/list under the Firefox backend, never present-and-throwing.",
|
|
696
|
+
"inputSchema": {
|
|
697
|
+
"type": "object",
|
|
698
|
+
"properties": {
|
|
699
|
+
"lease": {
|
|
700
|
+
"type": "string",
|
|
701
|
+
"description": "Opaque lease token from claim_page. Omit it for a tab this process already holds: under CDP_REQUIRE_LEASE the gate acquires a lease automatically and one acquired that way passes for any later call from the same process. Required when the tab is held by ANOTHER process, and required for a tab claimed explicitly via claim_page or new_page{claim:true}, which always demands its own token. Without CDP_REQUIRE_LEASE an unleased tab needs no token at all."
|
|
702
|
+
},
|
|
703
|
+
"target": {
|
|
704
|
+
"type": "string",
|
|
705
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'. Used for the lease check and, when 'origin' is omitted, as the source of the origin to grant for."
|
|
706
|
+
},
|
|
707
|
+
"permissions": {
|
|
708
|
+
"type": "array",
|
|
709
|
+
"items": {
|
|
710
|
+
"type": "string"
|
|
711
|
+
},
|
|
712
|
+
"description": "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."
|
|
713
|
+
},
|
|
714
|
+
"origin": {
|
|
715
|
+
"type": "string",
|
|
716
|
+
"description": "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."
|
|
717
|
+
},
|
|
718
|
+
"reset": {
|
|
719
|
+
"type": "boolean",
|
|
720
|
+
"description": "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."
|
|
721
|
+
}
|
|
722
|
+
},
|
|
723
|
+
"required": [],
|
|
724
|
+
"additionalProperties": false
|
|
725
|
+
}
|
|
726
|
+
},
|
|
494
727
|
{
|
|
495
728
|
"name": "fill",
|
|
496
729
|
"description": "Fill an element by focusing it, clearing existing content, then inserting 'value' via Input.insertText (atomic paste-like commit, not per-character keystrokes). Target with exactly one of 'uid' (a CDP backendDOMNodeId from take_snapshot) or 'selector' (a CSS selector).",
|
|
@@ -503,7 +736,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
503
736
|
},
|
|
504
737
|
"target": {
|
|
505
738
|
"type": "string",
|
|
506
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
739
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
507
740
|
},
|
|
508
741
|
"uid": {
|
|
509
742
|
"type": "number",
|
|
@@ -536,7 +769,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
536
769
|
},
|
|
537
770
|
"target": {
|
|
538
771
|
"type": "string",
|
|
539
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
772
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
540
773
|
},
|
|
541
774
|
"fields": {
|
|
542
775
|
"type": "array",
|
|
@@ -582,7 +815,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
582
815
|
},
|
|
583
816
|
"target": {
|
|
584
817
|
"type": "string",
|
|
585
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
818
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
586
819
|
},
|
|
587
820
|
"uid": {
|
|
588
821
|
"type": "number",
|
|
@@ -615,7 +848,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
615
848
|
},
|
|
616
849
|
"target": {
|
|
617
850
|
"type": "string",
|
|
618
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
851
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
619
852
|
},
|
|
620
853
|
"key": {
|
|
621
854
|
"type": "string",
|
|
@@ -647,7 +880,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
647
880
|
},
|
|
648
881
|
"target": {
|
|
649
882
|
"type": "string",
|
|
650
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
883
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
651
884
|
},
|
|
652
885
|
"uid": {
|
|
653
886
|
"type": "number",
|
|
@@ -686,7 +919,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
686
919
|
},
|
|
687
920
|
"target": {
|
|
688
921
|
"type": "string",
|
|
689
|
-
"description": "Target page selector. undefined or 'active' -> first page target; '<32-hex targetId>' -> exact target by id; 'index:N' -> Nth page target (0-based); 'url:<substring>' -> first page whose url contains substring; 'title:<substring>' -> first page whose title contains substring."
|
|
922
|
+
"description": "Target page selector. undefined or 'active' -> first page target; '<32-hex targetId>' -> exact target by id; 'index:N' -> Nth page target (0-based); 'url:<substring>' -> first page whose url contains substring; 'title:<substring>' -> first page whose title contains substring; 'label:<name>' -> the page with exactly this label (origin ledger or live lease)."
|
|
690
923
|
},
|
|
691
924
|
"format": {
|
|
692
925
|
"type": "string",
|
|
@@ -737,7 +970,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
737
970
|
},
|
|
738
971
|
"target": {
|
|
739
972
|
"type": "string",
|
|
740
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
973
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
741
974
|
},
|
|
742
975
|
"width": {
|
|
743
976
|
"type": "number",
|
|
@@ -837,7 +1070,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
837
1070
|
},
|
|
838
1071
|
"target": {
|
|
839
1072
|
"type": "string",
|
|
840
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
1073
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
841
1074
|
},
|
|
842
1075
|
"width": {
|
|
843
1076
|
"type": "number",
|
|
@@ -875,7 +1108,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
875
1108
|
},
|
|
876
1109
|
"target": {
|
|
877
1110
|
"type": "string",
|
|
878
|
-
"description": "Target page selector: 'active' (or omitted) for the first page-type target | 'index:N' (0-based) | 'url:<substring>' | 'title:<substring>' | a 32-hex <targetId>."
|
|
1111
|
+
"description": "Target page selector: 'active' (or omitted) for the first page-type target | 'index:N' (0-based) | 'url:<substring>' | 'title:<substring>' | 'label:<name>' (exact label match, origin ledger or live lease) | a 32-hex <targetId>."
|
|
879
1112
|
},
|
|
880
1113
|
"accept": {
|
|
881
1114
|
"type": "boolean",
|
|
@@ -912,7 +1145,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
912
1145
|
},
|
|
913
1146
|
"target": {
|
|
914
1147
|
"type": "string",
|
|
915
|
-
"description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>'."
|
|
1148
|
+
"description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>' | 'label:<name>'."
|
|
916
1149
|
},
|
|
917
1150
|
"reload": {
|
|
918
1151
|
"type": "boolean",
|
|
@@ -939,7 +1172,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
939
1172
|
},
|
|
940
1173
|
"target": {
|
|
941
1174
|
"type": "string",
|
|
942
|
-
"description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>'."
|
|
1175
|
+
"description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>' | 'label:<name>'."
|
|
943
1176
|
},
|
|
944
1177
|
"index": {
|
|
945
1178
|
"type": "number",
|
|
@@ -962,7 +1195,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
962
1195
|
},
|
|
963
1196
|
"target": {
|
|
964
1197
|
"type": "string",
|
|
965
|
-
"description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>'."
|
|
1198
|
+
"description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>' | 'label:<name>'."
|
|
966
1199
|
},
|
|
967
1200
|
"reload": {
|
|
968
1201
|
"type": "boolean",
|
|
@@ -993,7 +1226,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
993
1226
|
},
|
|
994
1227
|
"target": {
|
|
995
1228
|
"type": "string",
|
|
996
|
-
"description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>'."
|
|
1229
|
+
"description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>' | 'label:<name>'."
|
|
997
1230
|
},
|
|
998
1231
|
"requestId": {
|
|
999
1232
|
"type": "string",
|
|
@@ -1028,7 +1261,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
1028
1261
|
},
|
|
1029
1262
|
"target": {
|
|
1030
1263
|
"type": "string",
|
|
1031
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
1264
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
1032
1265
|
},
|
|
1033
1266
|
"categories": {
|
|
1034
1267
|
"type": "array",
|
|
@@ -1054,7 +1287,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
1054
1287
|
},
|
|
1055
1288
|
"target": {
|
|
1056
1289
|
"type": "string",
|
|
1057
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
1290
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
1058
1291
|
}
|
|
1059
1292
|
},
|
|
1060
1293
|
"required": [],
|
|
@@ -1092,7 +1325,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
1092
1325
|
},
|
|
1093
1326
|
"target": {
|
|
1094
1327
|
"type": "string",
|
|
1095
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
1328
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
1096
1329
|
},
|
|
1097
1330
|
"durationMs": {
|
|
1098
1331
|
"type": "number",
|
|
@@ -1130,7 +1363,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
1130
1363
|
},
|
|
1131
1364
|
"target": {
|
|
1132
1365
|
"type": "string",
|
|
1133
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
1366
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
1134
1367
|
},
|
|
1135
1368
|
"format": {
|
|
1136
1369
|
"type": "string",
|
|
@@ -1177,7 +1410,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
1177
1410
|
},
|
|
1178
1411
|
"target": {
|
|
1179
1412
|
"type": "string",
|
|
1180
|
-
"description": "Which recording to stop: 'active' (default, valid only when exactly one recording is in flight) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
1413
|
+
"description": "Which recording to stop: 'active' (default, valid only when exactly one recording is in flight) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
1181
1414
|
},
|
|
1182
1415
|
"savePath": {
|
|
1183
1416
|
"type": "string",
|
|
@@ -1200,7 +1433,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
1200
1433
|
},
|
|
1201
1434
|
"target": {
|
|
1202
1435
|
"type": "string",
|
|
1203
|
-
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
1436
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
|
|
1204
1437
|
},
|
|
1205
1438
|
"savePath": {
|
|
1206
1439
|
"type": "string",
|
|
@@ -1267,7 +1500,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
1267
1500
|
},
|
|
1268
1501
|
"target": {
|
|
1269
1502
|
"type": "string",
|
|
1270
|
-
"description": "Target selector: active | index:N | url:<substr> | title:<substr> | <targetId>. Defaults to the active page."
|
|
1503
|
+
"description": "Target selector: active | index:N | url:<substr> | title:<substr> | label:<name> | <targetId>. Defaults to the active page."
|
|
1271
1504
|
},
|
|
1272
1505
|
"urlPattern": {
|
|
1273
1506
|
"type": "string",
|
|
@@ -1369,13 +1602,13 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
1369
1602
|
},
|
|
1370
1603
|
{
|
|
1371
1604
|
"name": "claim_page",
|
|
1372
|
-
"description": "Take exclusive ownership of a browser tab and return an opaque lease token. Two modes. FRESH TAB: with no target and no targetId, opens a new tab (optionally at url) and claims it, so 'give me my own tab' is one call. TAKEOVER: with target, claims a tab that is already open — this is how you work in a tab the human already has open when they ask you to, instead of opening your own — resolving any target selector against the live page list and never creating anything. The answer's 'opened' flag says which happened (true only when this call created the tab), and that same creation record is what release_page consults, so a tab you took over is left open when you release it. Any later tool call against a leased tab must carry the matching token in its 'lease' argument or it is refused, naming the holder. The lease is reclaimable once its owning process dies, its ttlMs elapses without use, or its tab is closed. Refused from the CLI: a CLI invocation is one process per call, so its lease would be reclaimable immediately.",
|
|
1605
|
+
"description": "Take exclusive ownership of a browser tab and return an opaque lease token. Two modes. FRESH TAB: with no target and no targetId, opens a new tab (optionally at url) and claims it, so 'give me my own tab' is one call. TAKEOVER: with target, claims a tab that is already open — this is how you work in a tab the human already has open when they ask you to, instead of opening your own — resolving any target selector against the live page list and never creating anything. The answer's 'opened' flag says which happened (true only when this call created the tab), and that same creation record is what release_page consults, so a tab you took over is left open when you release it. Any later tool call against a leased tab must carry the matching token in its 'lease' argument or it is refused, naming the holder. The lease is reclaimable once its owning process dies, its ttlMs elapses without use, or its tab is closed. Refused from the CLI: a CLI invocation is one process per call, so its lease would be reclaimable immediately. IS SOMEBODY ELSE IN THIS TAB: the answer also carries 'humanActiveMs', milliseconds since input that this server did not dispatch — i.e. since a person last clicked, typed, or scrolled here. null means NO DATA (the tab carries no activity beacon, which is normal the first time anyone claims a person's tab, or every input on it was this server's own); it never means 'no human'. The field is absent entirely on a backend that cannot answer. On a takeover of a tab a human used within the last 30 seconds the answer additionally carries 'contention', a warning string. THE CLAIM IS NEVER REFUSED FOR THIS: taking over a person's tab is what takeover mode is for, so by the time you read the warning you already hold the lease and the tab is yours to drive. It tells you that driving it now means fighting a live person for the keyboard and mouse, so you can open your own tab instead or ask first. Known limits: input inside a cross-origin iframe is invisible to it, and a second MCP server's clicks read as human to this one.",
|
|
1373
1606
|
"inputSchema": {
|
|
1374
1607
|
"type": "object",
|
|
1375
1608
|
"properties": {
|
|
1376
1609
|
"target": {
|
|
1377
1610
|
"type": "string",
|
|
1378
|
-
"description": "Take over an already-open tab, e.g. one the human has open, when asked to: pass any target selector — active | index:N | url:<substr> | title:<substr> | <targetId>. Resolved against the live page list only, so it NEVER opens a tab: a selector that matches nothing is an error, not a new blank tab. The tab is left open on release because the toolkit did not create it. Refused if another live process holds it, including a lease the gate acquired for that process automatically under CDP_REQUIRE_LEASE: this takes over unleased (human) tabs and never steals one from a live agent. Mutually exclusive with targetId."
|
|
1611
|
+
"description": "Take over an already-open tab, e.g. one the human has open, when asked to: pass any target selector — active | index:N | url:<substr> | title:<substr> | label:<name> | <targetId>. Resolved against the live page list only, so it NEVER opens a tab: a selector that matches nothing is an error, not a new blank tab. The tab is left open on release because the toolkit did not create it. Refused if another live process holds it, including a lease the gate acquired for that process automatically under CDP_REQUIRE_LEASE: this takes over unleased (human) tabs and never steals one from a live agent. Mutually exclusive with targetId."
|
|
1379
1612
|
},
|
|
1380
1613
|
"targetId": {
|
|
1381
1614
|
"type": "string",
|
|
@@ -1410,7 +1643,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
1410
1643
|
},
|
|
1411
1644
|
"target": {
|
|
1412
1645
|
"type": "string",
|
|
1413
|
-
"description": "Target selector for a tab this process holds: active | index:N | url:<substr> | title:<substr> | <targetId>. Mutually exclusive with 'lease'. Refused if another process holds the tab."
|
|
1646
|
+
"description": "Target selector for a tab this process holds: active | index:N | url:<substr> | title:<substr> | label:<name> | <targetId>. Mutually exclusive with 'lease'. Refused if another process holds the tab."
|
|
1414
1647
|
},
|
|
1415
1648
|
"close": {
|
|
1416
1649
|
"type": "boolean",
|
|
@@ -1423,7 +1656,7 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
1423
1656
|
},
|
|
1424
1657
|
{
|
|
1425
1658
|
"name": "list_leases",
|
|
1426
|
-
"description": "Enumerate every active lease for diagnosis: backend, target id, agent label, pid, createdAt, lastUsedAt, ttlMs, whether the owning process is still alive, and whether the lease is reclaimable and why. Requires no token. Never returns the lease nonce, so this cannot be used to forge a token. A row for a lease file that could not be read or parsed instead carries `unreadable` (the errno, or \"unparseable\"), with label, pid, and the timestamp fields as zero placeholders and stale always false, since stale is what marks a lease free to take and an unreadable one must never read that way. Under CDP_REQUIRE_LEASE this call reaps abandoned agent tabs exactly as list_pages does, reporting them in an additive 'reaped' array and omitting their rows from the listing.",
|
|
1659
|
+
"description": "Enumerate every active lease for diagnosis: backend, target id, agent label, pid, createdAt, lastUsedAt, ttlMs, whether the owning process is still alive, and whether the lease is reclaimable and why. Requires no token. Never returns the lease nonce, so this cannot be used to forge a token. A row for a lease file that could not be read or parsed instead carries `unreadable` (the errno, or \"unparseable\"), with label, pid, and the timestamp fields as zero placeholders and stale always false, since stale is what marks a lease free to take and an unreadable one must never read that way. Under CDP_REQUIRE_LEASE this call reaps abandoned agent tabs exactly as list_pages does (see that tool's description for the grace period between a lease reading reclaimable and its tab actually being closed), reporting them in an additive 'reaped' array and omitting their rows from the listing. A row also carries 'humanActiveMs' — milliseconds since input this server did not dispatch, i.e. since a person last used that tab — WHERE THE TAB CAN ANSWER. The field is ABSENT rather than null when it cannot: no activity beacon on that tab, every input on it accounted for by this server, a row belonging to the other backend, a tab no longer open, or a page that would not evaluate. Absence therefore means 'no answer', never 'nobody is there'. Note that lastUsedAt measures TOOLKIT calls only, so a tab a person has been typing in for ten minutes looks perfectly idle by that field and is exactly the case humanActiveMs exists to expose. Two further fields are computed fresh on every call, never read off disk: 'idleMs' (now minus lastUsedAt) and 'expiresAt' (lastUsedAt plus ttlMs — the same value claim_page already returns under that name). Both are omitted on an 'unreadable' row, whose lastUsedAt and ttlMs are the zeroed placeholders described above.",
|
|
1427
1660
|
"inputSchema": {
|
|
1428
1661
|
"type": "object",
|
|
1429
1662
|
"properties": {},
|