cdp-toolkit 1.0.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.
@@ -0,0 +1,1030 @@
1
+ /**
2
+ * MCP tool manifest — the JSON Schemas the cdp-toolkit MCP server advertises via
3
+ * `tools/list`. Each entry's `name` matches a key in the TOOLS registry
4
+ * (src/index.ts) and its `inputSchema` mirrors that tool's TypeScript Args.
5
+ *
6
+ * Generated from the real Args interfaces (extracted + adversarially verified by
7
+ * workflow cdp-toolkit-mcp-schemas). Regenerate if a tool's Args change.
8
+ */
9
+
10
+ /** A JSON-Schema object describing one tool's arguments. */
11
+ export interface ToolInputSchema {
12
+ type: "object";
13
+ properties?: Record<string, unknown>;
14
+ required?: string[];
15
+ additionalProperties?: boolean;
16
+ }
17
+
18
+ /** One MCP tool advertisement. */
19
+ export interface ToolSpec {
20
+ name: string;
21
+ description: string;
22
+ inputSchema: ToolInputSchema;
23
+ }
24
+
25
+ export const MANIFEST: ToolSpec[] = [
26
+ {
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.",
29
+ "inputSchema": {
30
+ "type": "object",
31
+ "properties": {
32
+ "all": {
33
+ "type": "boolean",
34
+ "description": "Include non-page targets (service/shared workers, background pages) when true; otherwise only page-type tabs are listed."
35
+ }
36
+ },
37
+ "required": [],
38
+ "additionalProperties": false
39
+ }
40
+ },
41
+ {
42
+ "name": "new_page",
43
+ "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).",
44
+ "inputSchema": {
45
+ "type": "object",
46
+ "properties": {
47
+ "url": {
48
+ "type": "string",
49
+ "description": "URL to open in the new tab; defaults to about:blank."
50
+ }
51
+ },
52
+ "required": [],
53
+ "additionalProperties": false
54
+ }
55
+ },
56
+ {
57
+ "name": "close_page",
58
+ "description": "Close a page target via Target.closeTarget. Requires an explicit, resolvable target; refuses to guess and errors if the selector matches no target.",
59
+ "inputSchema": {
60
+ "type": "object",
61
+ "properties": {
62
+ "target": {
63
+ "type": "string",
64
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
65
+ }
66
+ },
67
+ "required": [
68
+ "target"
69
+ ],
70
+ "additionalProperties": false
71
+ }
72
+ },
73
+ {
74
+ "name": "select_page",
75
+ "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.",
76
+ "inputSchema": {
77
+ "type": "object",
78
+ "properties": {
79
+ "target": {
80
+ "type": "string",
81
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
82
+ }
83
+ },
84
+ "required": [
85
+ "target"
86
+ ],
87
+ "additionalProperties": false
88
+ }
89
+ },
90
+ {
91
+ "name": "navigate_page",
92
+ "description": "Navigate a target page to a URL (Page.navigate) OR reload it (reload:true) over raw CDP, then wait for the load milestone with a bounded timeout so a wedged renderer can't hang. Returns {url,frameId,waitedFor} (plus reloaded:true on a reload); 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).",
93
+ "inputSchema": {
94
+ "type": "object",
95
+ "properties": {
96
+ "target": {
97
+ "type": "string",
98
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
99
+ },
100
+ "url": {
101
+ "type": "string",
102
+ "description": "Destination URL to navigate to. Required unless reload:true."
103
+ },
104
+ "reload": {
105
+ "type": "boolean",
106
+ "description": "Reload the current page (Page.reload) instead of navigating to url. Default false."
107
+ },
108
+ "ignoreCache": {
109
+ "type": "boolean",
110
+ "description": "On reload, bypass the HTTP cache (hard reload) so subresources are refetched. Ignored unless reload:true. Default false."
111
+ },
112
+ "waitUntil": {
113
+ "type": "string",
114
+ "enum": [
115
+ "load",
116
+ "domcontentloaded"
117
+ ],
118
+ "description": "Which load milestone to wait for. Defaults to 'load'. No 'networkidle' support."
119
+ },
120
+ "timeoutMs": {
121
+ "type": "number",
122
+ "description": "Override the navigation timeout in milliseconds."
123
+ }
124
+ },
125
+ "additionalProperties": false
126
+ }
127
+ },
128
+ {
129
+ "name": "wait_for",
130
+ "description": "Poll a target page until the given substring appears in document.body.innerText (Runtime.evaluate on a fixed interval), or throw on timeout. Text-substring waiting only — no aria/role/selector or event variants; throws rather than returning {found:false}.",
131
+ "inputSchema": {
132
+ "type": "object",
133
+ "properties": {
134
+ "target": {
135
+ "type": "string",
136
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
137
+ },
138
+ "text": {
139
+ "type": "string",
140
+ "description": "Substring to wait for in document.body.innerText. Required."
141
+ },
142
+ "timeoutMs": {
143
+ "type": "number",
144
+ "description": "Total time budget in milliseconds. Defaults to 15000."
145
+ },
146
+ "pollMs": {
147
+ "type": "number",
148
+ "description": "Poll interval in milliseconds. Defaults to 250."
149
+ }
150
+ },
151
+ "required": [
152
+ "text"
153
+ ],
154
+ "additionalProperties": false
155
+ }
156
+ },
157
+ {
158
+ "name": "evaluate_script",
159
+ "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.",
160
+ "inputSchema": {
161
+ "type": "object",
162
+ "properties": {
163
+ "target": {
164
+ "type": "string",
165
+ "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."
166
+ },
167
+ "expression": {
168
+ "type": "string",
169
+ "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."
170
+ },
171
+ "awaitPromise": {
172
+ "type": "boolean",
173
+ "description": "Await the result if it is a Promise (default true)."
174
+ },
175
+ "args": {
176
+ "type": "array",
177
+ "description": "Positional JSON-serializable arguments to pass to the expression, treating it as a function. No live element/page handle is bound."
178
+ }
179
+ },
180
+ "required": [
181
+ "expression"
182
+ ],
183
+ "additionalProperties": false
184
+ }
185
+ },
186
+ {
187
+ "name": "take_snapshot",
188
+ "description": "Capture the page's accessibility tree (Accessibility.getFullAXTree) as a compact indented text tree where each line is prefixed with [uid] — the node's CDP backendDOMNodeId. These uids are the stateless element references that every interaction tool (click/hover/fill/etc.) feeds back to resolve a live DOM node (via DOM.resolveNode({ backendNodeId: uid })), so run this first to discover uids.",
189
+ "inputSchema": {
190
+ "type": "object",
191
+ "properties": {
192
+ "target": {
193
+ "type": "string",
194
+ "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)."
195
+ },
196
+ "interactiveOnly": {
197
+ "type": "boolean",
198
+ "description": "When true, emit only interactive/meaningful nodes flattened into a readable list; default false returns the full hierarchical a11y tree."
199
+ }
200
+ },
201
+ "required": [],
202
+ "additionalProperties": false
203
+ }
204
+ },
205
+ {
206
+ "name": "click",
207
+ "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).",
208
+ "inputSchema": {
209
+ "type": "object",
210
+ "properties": {
211
+ "target": {
212
+ "type": "string",
213
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
214
+ },
215
+ "uid": {
216
+ "type": "number",
217
+ "description": "CDP backendDOMNodeId of the element to click, obtained from take_snapshot. Provide exactly one of uid or selector."
218
+ },
219
+ "selector": {
220
+ "type": "string",
221
+ "description": "CSS selector for the element to click (resolved via document.querySelector). Provide exactly one of uid or selector."
222
+ },
223
+ "button": {
224
+ "type": "string",
225
+ "enum": [
226
+ "left",
227
+ "right",
228
+ "middle"
229
+ ],
230
+ "description": "Mouse button: 'left' (default), 'right', or 'middle'."
231
+ },
232
+ "clickCount": {
233
+ "type": "number",
234
+ "description": "Number of clicks: 1 = single (default), 2 = double-click."
235
+ }
236
+ },
237
+ "required": [],
238
+ "additionalProperties": false
239
+ }
240
+ },
241
+ {
242
+ "name": "hover",
243
+ "description": "Hover the mouse over an element by dispatching a mouseMoved event at its scrolled-into-view center, firing framework hover handlers. Target with exactly one of 'uid' (a CDP backendDOMNodeId from take_snapshot) or 'selector' (a CSS selector).",
244
+ "inputSchema": {
245
+ "type": "object",
246
+ "properties": {
247
+ "target": {
248
+ "type": "string",
249
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
250
+ },
251
+ "uid": {
252
+ "type": "number",
253
+ "description": "CDP backendDOMNodeId of the element to hover, obtained from take_snapshot. Provide exactly one of uid or selector."
254
+ },
255
+ "selector": {
256
+ "type": "string",
257
+ "description": "CSS selector for the element to hover (resolved via document.querySelector). Provide exactly one of uid or selector."
258
+ }
259
+ },
260
+ "required": [],
261
+ "additionalProperties": false
262
+ }
263
+ },
264
+ {
265
+ "name": "drag",
266
+ "description": "Drag from a source element to a destination element via synthetic mouse press/move/release (approximates HTML5 drag-and-drop; not guaranteed for every custom DnD library). 'from' and 'to' each take exactly one of uid (a CDP backendDOMNodeId from take_snapshot) or selector.",
267
+ "inputSchema": {
268
+ "type": "object",
269
+ "properties": {
270
+ "target": {
271
+ "type": "string",
272
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
273
+ },
274
+ "from": {
275
+ "type": "object",
276
+ "description": "Source element to drag from. Provide exactly one of uid or selector.",
277
+ "properties": {
278
+ "uid": {
279
+ "type": "number",
280
+ "description": "CDP backendDOMNodeId of the source element, obtained from take_snapshot."
281
+ },
282
+ "selector": {
283
+ "type": "string",
284
+ "description": "CSS selector for the source element (resolved via document.querySelector)."
285
+ }
286
+ },
287
+ "additionalProperties": false
288
+ },
289
+ "to": {
290
+ "type": "object",
291
+ "description": "Destination element to drag to. Provide exactly one of uid or selector.",
292
+ "properties": {
293
+ "uid": {
294
+ "type": "number",
295
+ "description": "CDP backendDOMNodeId of the destination element, obtained from take_snapshot."
296
+ },
297
+ "selector": {
298
+ "type": "string",
299
+ "description": "CSS selector for the destination element (resolved via document.querySelector)."
300
+ }
301
+ },
302
+ "additionalProperties": false
303
+ }
304
+ },
305
+ "required": [
306
+ "from",
307
+ "to"
308
+ ],
309
+ "additionalProperties": false
310
+ }
311
+ },
312
+ {
313
+ "name": "fill",
314
+ "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).",
315
+ "inputSchema": {
316
+ "type": "object",
317
+ "properties": {
318
+ "target": {
319
+ "type": "string",
320
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
321
+ },
322
+ "uid": {
323
+ "type": "number",
324
+ "description": "CDP backendDOMNodeId of the field to fill, obtained from take_snapshot. Provide exactly one of uid or selector."
325
+ },
326
+ "selector": {
327
+ "type": "string",
328
+ "description": "CSS selector for the field to fill (resolved via document.querySelector). Provide exactly one of uid or selector."
329
+ },
330
+ "value": {
331
+ "type": "string",
332
+ "description": "The text value to set; the field is cleared first so this overwrites existing content."
333
+ }
334
+ },
335
+ "required": [
336
+ "value"
337
+ ],
338
+ "additionalProperties": false
339
+ }
340
+ },
341
+ {
342
+ "name": "fill_form",
343
+ "description": "Fill multiple form fields in one call; each field is focused, cleared, then set via Input.insertText. Each field in the non-empty 'fields' array takes exactly one of uid (a CDP backendDOMNodeId from take_snapshot) or selector, plus its string value.",
344
+ "inputSchema": {
345
+ "type": "object",
346
+ "properties": {
347
+ "target": {
348
+ "type": "string",
349
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
350
+ },
351
+ "fields": {
352
+ "type": "array",
353
+ "description": "Non-empty array of fields to fill, each with exactly one of uid or selector plus a string value.",
354
+ "items": {
355
+ "type": "object",
356
+ "properties": {
357
+ "uid": {
358
+ "type": "number",
359
+ "description": "CDP backendDOMNodeId of the field, obtained from take_snapshot. Provide exactly one of uid or selector."
360
+ },
361
+ "selector": {
362
+ "type": "string",
363
+ "description": "CSS selector for the field (resolved via document.querySelector). Provide exactly one of uid or selector."
364
+ },
365
+ "value": {
366
+ "type": "string",
367
+ "description": "The text value to set; the field is cleared first so this overwrites existing content."
368
+ }
369
+ },
370
+ "required": [
371
+ "value"
372
+ ],
373
+ "additionalProperties": false
374
+ }
375
+ }
376
+ },
377
+ "required": [
378
+ "fields"
379
+ ],
380
+ "additionalProperties": false
381
+ }
382
+ },
383
+ {
384
+ "name": "type_text",
385
+ "description": "Focus an element and append 'text' via Input.insertText without clearing first (closest to typing). Target with exactly one of 'uid' (a CDP backendDOMNodeId from take_snapshot) or 'selector' (a CSS selector).",
386
+ "inputSchema": {
387
+ "type": "object",
388
+ "properties": {
389
+ "target": {
390
+ "type": "string",
391
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
392
+ },
393
+ "uid": {
394
+ "type": "number",
395
+ "description": "CDP backendDOMNodeId of the element to type into, obtained from take_snapshot. Provide exactly one of uid or selector."
396
+ },
397
+ "selector": {
398
+ "type": "string",
399
+ "description": "CSS selector for the element to type into (resolved via document.querySelector). Provide exactly one of uid or selector."
400
+ },
401
+ "text": {
402
+ "type": "string",
403
+ "description": "The text to insert; appended to existing content rather than overwriting it."
404
+ }
405
+ },
406
+ "required": [
407
+ "text"
408
+ ],
409
+ "additionalProperties": false
410
+ }
411
+ },
412
+ {
413
+ "name": "press_key",
414
+ "description": "Dispatch a keyDown/keyUp pair for a single 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 (no F-keys/numpad/IME).",
415
+ "inputSchema": {
416
+ "type": "object",
417
+ "properties": {
418
+ "target": {
419
+ "type": "string",
420
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
421
+ },
422
+ "key": {
423
+ "type": "string",
424
+ "description": "Key to press: a named key like 'Enter', 'Tab', 'Escape', 'ArrowDown', 'Backspace', or a single printable character. Required."
425
+ },
426
+ "modifiers": {
427
+ "type": "array",
428
+ "description": "Optional modifier names held during the press: 'Control'/'Ctrl', 'Shift', 'Alt', 'Meta'/'Cmd'.",
429
+ "items": {
430
+ "type": "string"
431
+ }
432
+ }
433
+ },
434
+ "required": [
435
+ "key"
436
+ ],
437
+ "additionalProperties": false
438
+ }
439
+ },
440
+ {
441
+ "name": "upload_file",
442
+ "description": "Attach one or more files to an <input type=file> element via DOM.setFileInputFiles. Target the input with exactly one of 'uid' (a CDP backendDOMNodeId from take_snapshot) or 'selector'; 'files' is an absolute path or array of absolute paths.",
443
+ "inputSchema": {
444
+ "type": "object",
445
+ "properties": {
446
+ "target": {
447
+ "type": "string",
448
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
449
+ },
450
+ "uid": {
451
+ "type": "number",
452
+ "description": "CDP backendDOMNodeId of the file input element, obtained from take_snapshot. Provide exactly one of uid or selector."
453
+ },
454
+ "selector": {
455
+ "type": "string",
456
+ "description": "CSS selector for the file input element (resolved via document.querySelector). Provide exactly one of uid or selector."
457
+ },
458
+ "files": {
459
+ "type": [
460
+ "string",
461
+ "array"
462
+ ],
463
+ "items": {
464
+ "type": "string"
465
+ },
466
+ "description": "Absolute path, or array of absolute paths, to the file(s) to attach to the <input type=file>. Accepts a single string or an array of strings."
467
+ }
468
+ },
469
+ "required": [
470
+ "files"
471
+ ],
472
+ "additionalProperties": false
473
+ }
474
+ },
475
+ {
476
+ "name": "take_screenshot",
477
+ "description": "Capture the viewport (default), the full scrollable page (fullPage), or a single element (uid or selector — exactly one, mutually exclusive) via raw CDP Page.captureScreenshot. Writes a PNG/JPEG under /tmp/cdp-toolkit (override with savePath) and returns {path,bytes,format,target}; raw base64 is only included when returnBase64 is set. quality applies to jpeg only.",
478
+ "inputSchema": {
479
+ "type": "object",
480
+ "properties": {
481
+ "target": {
482
+ "type": "string",
483
+ "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."
484
+ },
485
+ "format": {
486
+ "type": "string",
487
+ "enum": [
488
+ "png",
489
+ "jpeg"
490
+ ],
491
+ "description": "Image format. Defaults to png. quality applies only to jpeg."
492
+ },
493
+ "quality": {
494
+ "type": "number",
495
+ "description": "JPEG quality 0-100 (default 80). Ignored for png."
496
+ },
497
+ "fullPage": {
498
+ "type": "boolean",
499
+ "description": "Capture the full scrollable content height computed from Page.getLayoutMetrics, not just the viewport."
500
+ },
501
+ "uid": {
502
+ "type": "number",
503
+ "description": "Element to clip to — a CDP backendDOMNodeId obtained from take_snapshot. Mutually exclusive with selector."
504
+ },
505
+ "selector": {
506
+ "type": "string",
507
+ "description": "CSS selector to clip the capture to. Mutually exclusive with uid."
508
+ },
509
+ "savePath": {
510
+ "type": "string",
511
+ "description": "Override the output file path. Default: /tmp/cdp-toolkit/screenshot-<id>-<stamp>.<ext>."
512
+ },
513
+ "returnBase64": {
514
+ "type": "boolean",
515
+ "description": "Also return the raw base64 image bytes in the result, in addition to writing the file."
516
+ }
517
+ },
518
+ "required": [],
519
+ "additionalProperties": false
520
+ }
521
+ },
522
+ {
523
+ "name": "emulate",
524
+ "description": "Apply any subset of Chrome emulation overrides in one call: device metrics (width/height together, plus deviceScaleFactor/mobile), userAgent, cpuThrottlingRate (>=1), emulated media type + mediaFeatures, and networkConditions. Pass clearOverrides:true to reset every override to the browser default (ignores all other fields). Non-metrics overrides are session-scoped and reset when the per-call connection closes; device-metrics overrides persist on the target until cleared or the renderer navigates/reloads.",
525
+ "inputSchema": {
526
+ "type": "object",
527
+ "properties": {
528
+ "target": {
529
+ "type": "string",
530
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
531
+ },
532
+ "width": {
533
+ "type": "number",
534
+ "description": "Device-metrics viewport width in CSS pixels. Must be supplied together with height."
535
+ },
536
+ "height": {
537
+ "type": "number",
538
+ "description": "Device-metrics viewport height in CSS pixels. Must be supplied together with width."
539
+ },
540
+ "deviceScaleFactor": {
541
+ "type": "number",
542
+ "description": "Device pixel ratio (DPR) for the device-metrics override; 0 uses the platform default."
543
+ },
544
+ "mobile": {
545
+ "type": "boolean",
546
+ "description": "Whether to emulate a mobile device (affects viewport meta handling, scrollbars, etc.) for the device-metrics override."
547
+ },
548
+ "userAgent": {
549
+ "type": "string",
550
+ "description": "User-Agent string to override via Emulation.setUserAgentOverride."
551
+ },
552
+ "cpuThrottlingRate": {
553
+ "type": "number",
554
+ "description": "CPU throttling multiplier: 1 = no throttle, 2 = 2x slower, etc. Must be >= 1."
555
+ },
556
+ "media": {
557
+ "type": "string",
558
+ "description": "Emulated CSS media type: 'screen' | 'print' | '' (clear)."
559
+ },
560
+ "mediaFeatures": {
561
+ "type": "array",
562
+ "description": "Emulated media features, e.g. [{ name: 'prefers-color-scheme', value: 'dark' }].",
563
+ "items": {
564
+ "type": "object",
565
+ "properties": {
566
+ "name": {
567
+ "type": "string",
568
+ "description": "Media feature name, e.g. 'prefers-color-scheme'."
569
+ },
570
+ "value": {
571
+ "type": "string",
572
+ "description": "Media feature value, e.g. 'dark'."
573
+ }
574
+ },
575
+ "required": [
576
+ "name",
577
+ "value"
578
+ ],
579
+ "additionalProperties": false
580
+ }
581
+ },
582
+ "networkConditions": {
583
+ "type": "object",
584
+ "description": "Network condition overrides applied via Network.emulateNetworkConditions.",
585
+ "properties": {
586
+ "offline": {
587
+ "type": "boolean",
588
+ "description": "True to simulate offline."
589
+ },
590
+ "latency": {
591
+ "type": "number",
592
+ "description": "Additional round-trip latency in milliseconds."
593
+ },
594
+ "downloadThroughput": {
595
+ "type": "number",
596
+ "description": "Max download throughput in bytes/sec (-1 = no limit)."
597
+ },
598
+ "uploadThroughput": {
599
+ "type": "number",
600
+ "description": "Max upload throughput in bytes/sec (-1 = no limit)."
601
+ },
602
+ "connectionType": {
603
+ "type": "string",
604
+ "description": "Connection type: 'none' | 'cellular2g' | 'cellular3g' | 'cellular4g' | 'bluetooth' | 'ethernet' | 'wifi' | 'wimax' | 'other'."
605
+ }
606
+ },
607
+ "additionalProperties": false
608
+ },
609
+ "clearOverrides": {
610
+ "type": "boolean",
611
+ "description": "Reset every override (device metrics, UA, CPU, media, network) to the browser default; ignores all other fields when true."
612
+ }
613
+ },
614
+ "required": [],
615
+ "additionalProperties": false
616
+ }
617
+ },
618
+ {
619
+ "name": "resize_page",
620
+ "description": "Set the page's device-metrics width/height (the narrow case of emulate), optionally with deviceScaleFactor and mobile, then verify by reading back window.innerWidth/innerHeight after the override is applied. Requires positive numeric width and height. The device-metrics override persists on the target until cleared or the renderer navigates/reloads.",
621
+ "inputSchema": {
622
+ "type": "object",
623
+ "properties": {
624
+ "target": {
625
+ "type": "string",
626
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
627
+ },
628
+ "width": {
629
+ "type": "number",
630
+ "description": "Viewport width in CSS pixels (must be positive)."
631
+ },
632
+ "height": {
633
+ "type": "number",
634
+ "description": "Viewport height in CSS pixels (must be positive)."
635
+ },
636
+ "deviceScaleFactor": {
637
+ "type": "number",
638
+ "description": "Device pixel ratio (DPR); 0 uses the platform default."
639
+ },
640
+ "mobile": {
641
+ "type": "boolean",
642
+ "description": "Whether to emulate a mobile device for the device-metrics override."
643
+ }
644
+ },
645
+ "required": [
646
+ "width",
647
+ "height"
648
+ ],
649
+ "additionalProperties": false
650
+ }
651
+ },
652
+ {
653
+ "name": "handle_dialog",
654
+ "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. The dialog must be triggered out-of-band (e.g. by clicking a button), since a blocking dialog freezes the renderer.",
655
+ "inputSchema": {
656
+ "type": "object",
657
+ "properties": {
658
+ "target": {
659
+ "type": "string",
660
+ "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>."
661
+ },
662
+ "accept": {
663
+ "type": "boolean",
664
+ "description": "Whether to accept (OK) or dismiss (Cancel) the dialog."
665
+ },
666
+ "promptText": {
667
+ "type": "string",
668
+ "description": "Text to enter for a prompt() dialog when accepting."
669
+ },
670
+ "timeoutMs": {
671
+ "type": "number",
672
+ "description": "How long to wait for the next dialog in milliseconds (default 15000)."
673
+ },
674
+ "autoMs": {
675
+ "type": "number",
676
+ "description": "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')."
677
+ }
678
+ },
679
+ "required": [
680
+ "accept"
681
+ ],
682
+ "additionalProperties": false
683
+ }
684
+ },
685
+ {
686
+ "name": "list_console_messages",
687
+ "description": "Read console output (logs, warnings, exceptions) captured for the target page. By default reads the target's existing shared buffer and returns parsed console entries (empty if no capture has run); with reload:true it reloads the page and records a fresh capture window (both console+network) so a network reload never wipes console history.",
688
+ "inputSchema": {
689
+ "type": "object",
690
+ "properties": {
691
+ "target": {
692
+ "type": "string",
693
+ "description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>'."
694
+ },
695
+ "reload": {
696
+ "type": "boolean",
697
+ "description": "Record fresh by reloading the page and capturing for a window. Default false (read the existing buffer)."
698
+ },
699
+ "durationMs": {
700
+ "type": "number",
701
+ "description": "Capture window for reload mode, in milliseconds. Default 2500."
702
+ }
703
+ },
704
+ "required": [],
705
+ "additionalProperties": false
706
+ }
707
+ },
708
+ {
709
+ "name": "get_console_message",
710
+ "description": "Return a single 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 with reload:true) first to populate the buffer.",
711
+ "inputSchema": {
712
+ "type": "object",
713
+ "properties": {
714
+ "target": {
715
+ "type": "string",
716
+ "description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>'."
717
+ },
718
+ "index": {
719
+ "type": "number",
720
+ "description": "Zero-based index into the parsed console entries. Default 0."
721
+ }
722
+ },
723
+ "required": [],
724
+ "additionalProperties": false
725
+ }
726
+ },
727
+ {
728
+ "name": "list_network_requests",
729
+ "description": "Return correlated network request rows (one per requestId, with status/headers/state) for the target page. By default reads the target's existing buffer; with reload:true it reloads and records a fresh both-domains capture window. Use filterUrl to keep only requests whose URL contains a substring.",
730
+ "inputSchema": {
731
+ "type": "object",
732
+ "properties": {
733
+ "target": {
734
+ "type": "string",
735
+ "description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>'."
736
+ },
737
+ "reload": {
738
+ "type": "boolean",
739
+ "description": "Record fresh by reloading the page and capturing for a window. Default false (read the existing buffer)."
740
+ },
741
+ "durationMs": {
742
+ "type": "number",
743
+ "description": "Capture window for reload mode, in milliseconds. Default 2500."
744
+ },
745
+ "filterUrl": {
746
+ "type": "string",
747
+ "description": "Only return requests whose URL contains this substring."
748
+ }
749
+ },
750
+ "required": [],
751
+ "additionalProperties": false
752
+ }
753
+ },
754
+ {
755
+ "name": "get_network_request",
756
+ "description": "Return one network request (matched by exact requestId, else by url substring) including status/headers. Requires at least one of requestId or url (throws otherwise). With includeBody:true the body fetch drives a fresh reload capture and is matched by url ONLY (reload re-mints requestIds, so a carried-over requestId cannot fetch a body — it returns metadata plus bodyUnavailableReason).",
757
+ "inputSchema": {
758
+ "type": "object",
759
+ "properties": {
760
+ "target": {
761
+ "type": "string",
762
+ "description": "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>'."
763
+ },
764
+ "requestId": {
765
+ "type": "string",
766
+ "description": "Match by exact requestId (metadata only — cannot fetch a body, since reload re-mints requestIds)."
767
+ },
768
+ "url": {
769
+ "type": "string",
770
+ "description": "Match by URL substring (first match). Required for body fetch (includeBody), since url is stable across reload."
771
+ },
772
+ "includeBody": {
773
+ "type": "boolean",
774
+ "description": "Also fetch the response body; drives a fresh reload capture and must be used with the `url` selector."
775
+ },
776
+ "durationMs": {
777
+ "type": "number",
778
+ "description": "Capture window for the reload-driven body fetch, in milliseconds. Default 2500."
779
+ }
780
+ },
781
+ "required": [],
782
+ "additionalProperties": false
783
+ }
784
+ },
785
+ {
786
+ "name": "performance_start_trace",
787
+ "description": "Start a performance trace on the target page over raw CDP (Tracing.start) and park the recording connection in-process. Must be paired with performance_stop_trace WITHIN THE SAME PROCESS; for a robust cross-call trace use performance_trace instead. Throws if a trace is already in progress for the target.",
788
+ "inputSchema": {
789
+ "type": "object",
790
+ "properties": {
791
+ "target": {
792
+ "type": "string",
793
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
794
+ },
795
+ "categories": {
796
+ "type": "array",
797
+ "items": {
798
+ "type": "string"
799
+ },
800
+ "description": "Trace categories to include. Defaults to the timeline + user-timing + loading + disabled-by-default timeline tracks that carry LCP/LayoutShift/RunTask."
801
+ }
802
+ },
803
+ "required": [],
804
+ "additionalProperties": false
805
+ }
806
+ },
807
+ {
808
+ "name": "performance_stop_trace",
809
+ "description": "Stop the in-process trace started by performance_start_trace, drain buffered Tracing.dataCollected events, write the trace JSON under /tmp/cdp-toolkit, and return {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.",
810
+ "inputSchema": {
811
+ "type": "object",
812
+ "properties": {
813
+ "target": {
814
+ "type": "string",
815
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
816
+ }
817
+ },
818
+ "required": [],
819
+ "additionalProperties": false
820
+ }
821
+ },
822
+ {
823
+ "name": "performance_analyze_insight",
824
+ "description": "CDP-native approximation of the DevTools insight analyzer: read a trace JSON file (bare array or {traceEvents:[...]}) at the given tracePath and return headline metrics (FCP/LCP/CLS/TBT, long tasks, layout shifts). Requires an explicit tracePath returned by performance_trace/performance_stop_trace — there is no implicit 'latest trace'. Numbers approximate DevTools (no main-thread attribution or frame-scoped LCP).",
825
+ "inputSchema": {
826
+ "type": "object",
827
+ "properties": {
828
+ "tracePath": {
829
+ "type": "string",
830
+ "description": "Filesystem path to a trace JSON file written by performance_trace or performance_stop_trace (bare array OR {traceEvents:[...]}). Required."
831
+ }
832
+ },
833
+ "required": [],
834
+ "additionalProperties": false
835
+ }
836
+ },
837
+ {
838
+ "name": "performance_trace",
839
+ "description": "PRIMARY one-shot trace: start tracing, optionally reload or navigate the page, wait durationMs (default 3000), end the trace, write the trace JSON under /tmp/cdp-toolkit, and return {path,bytes,events,metrics,target}. Holds one connection open for the whole window, so it is immune to the cross-process limitation of start/stop — the recommended entry point.",
840
+ "inputSchema": {
841
+ "type": "object",
842
+ "properties": {
843
+ "target": {
844
+ "type": "string",
845
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
846
+ },
847
+ "durationMs": {
848
+ "type": "number",
849
+ "description": "How long to record after the optional reload/navigate, in milliseconds. Default 3000."
850
+ },
851
+ "reload": {
852
+ "type": "boolean",
853
+ "description": "Reload the page after starting the trace to capture full navigation timing."
854
+ },
855
+ "navigateTo": {
856
+ "type": "string",
857
+ "description": "Navigate to this URL after starting the trace (alternative to reload)."
858
+ },
859
+ "categories": {
860
+ "type": "array",
861
+ "items": {
862
+ "type": "string"
863
+ },
864
+ "description": "Trace categories to include. Defaults to the timeline + user-timing + loading + disabled-by-default timeline tracks that carry LCP/LayoutShift/RunTask."
865
+ }
866
+ },
867
+ "required": [],
868
+ "additionalProperties": false
869
+ }
870
+ },
871
+ {
872
+ "name": "take_heapsnapshot",
873
+ "description": "Capture a V8 heap snapshot of the selected page target over raw CDP (HeapProfiler.takeHeapSnapshot, accumulating addHeapSnapshotChunk events) and write it as a .heapsnapshot JSON file loadable by the DevTools Memory panel; returns {path,bytes,chunks,target} only and does not parse/summarize the snapshot. Writes under /tmp/cdp-toolkit (CDP_ARTIFACT_DIR) unless savePath is given.",
874
+ "inputSchema": {
875
+ "type": "object",
876
+ "properties": {
877
+ "target": {
878
+ "type": "string",
879
+ "description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
880
+ },
881
+ "savePath": {
882
+ "type": "string",
883
+ "description": "Override the output path. An absolute path (starting with /) is used as-is; a relative path is resolved under the artifact dir (/tmp/cdp-toolkit). Defaults to an auto-named take_heapsnapshot-<targetId>-<timestamp>.heapsnapshot file."
884
+ }
885
+ },
886
+ "required": [],
887
+ "additionalProperties": false
888
+ }
889
+ },
890
+ {
891
+ "name": "lighthouse_audit",
892
+ "description": "Run a Lighthouse audit against a URL by shelling out to `npx --yes lighthouse` (the toolkit's sole non-CDP tool); Lighthouse attaches to the already-running Chrome on the remote-debugging port and audits its own about:blank tab rather than any live user tab. Writes a JSON report under /tmp/cdp-toolkit and returns {path, bytes} plus per-category scores (0..1 or null).",
893
+ "inputSchema": {
894
+ "type": "object",
895
+ "properties": {
896
+ "url": {
897
+ "type": "string",
898
+ "description": "The URL to audit. Required — never points at a user tab implicitly."
899
+ },
900
+ "categories": {
901
+ "type": "array",
902
+ "items": {
903
+ "type": "string"
904
+ },
905
+ "description": "Lighthouse categories to run (passed as --only-categories). Defaults to the full set, e.g. [\"performance\"] or [\"performance\",\"accessibility\",\"seo\"]."
906
+ },
907
+ "savePath": {
908
+ "type": "string",
909
+ "description": "Override the report output path; defaults to a timestamped file under /tmp/cdp-toolkit."
910
+ },
911
+ "formFactor": {
912
+ "type": "string",
913
+ "enum": [
914
+ "desktop",
915
+ "mobile"
916
+ ],
917
+ "description": "Form factor: \"desktop\" (default, uses --preset=desktop to avoid heavy mobile throttling) or \"mobile\"."
918
+ },
919
+ "timeoutMs": {
920
+ "type": "number",
921
+ "description": "Overall budget for the lighthouse process in milliseconds. Default 120000."
922
+ }
923
+ },
924
+ "required": [
925
+ "url"
926
+ ],
927
+ "additionalProperties": false
928
+ }
929
+ },
930
+ {
931
+ "name": "mock_request",
932
+ "description": "Register a mock rule on a target's persistent fake-backend session (CDP Fetch domain): intercept requests whose URL matches urlPattern and fulfill them with a canned response, fail (abort) them, or continue them — optionally with fault injection (delayMs/failRate). The session survives reloads and navigations and lives until clear_mocks. Call repeatedly to mock several endpoints on the same target. Pass reload:true to apply immediately. Persistent across calls only via the MCP server (not the one-shot CLI).",
933
+ "inputSchema": {
934
+ "type": "object",
935
+ "properties": {
936
+ "target": {
937
+ "type": "string",
938
+ "description": "Target selector: active | index:N | url:<substr> | title:<substr> | <targetId>. Defaults to the active page."
939
+ },
940
+ "urlPattern": {
941
+ "type": "string",
942
+ "description": "CDP Fetch urlPattern glob: '*' matches any run of characters, '?' exactly one, '\\' escapes. Only matching request URLs are paused. e.g. \"*/api/users*\"."
943
+ },
944
+ "action": {
945
+ "type": "string",
946
+ "enum": [
947
+ "fulfill",
948
+ "fail",
949
+ "continue"
950
+ ],
951
+ "description": "What to do with a matched request. Default \"fulfill\"."
952
+ },
953
+ "status": {
954
+ "type": "number",
955
+ "description": "fulfill: HTTP status code for the canned response. Default 200."
956
+ },
957
+ "body": {
958
+ "type": "string",
959
+ "description": "fulfill: response body string (base64-encoded for CDP internally)."
960
+ },
961
+ "contentType": {
962
+ "type": "string",
963
+ "description": "fulfill: Content-Type header. Default \"application/json\"."
964
+ },
965
+ "headers": {
966
+ "type": "object",
967
+ "description": "fulfill: extra response headers (name->value); override Content-Type case-insensitively. Add \"Access-Control-Allow-Origin\" for cross-origin fetches."
968
+ },
969
+ "errorReason": {
970
+ "type": "string",
971
+ "description": "fail: CDP Network.ErrorReason, e.g. \"Failed\" (default), \"BlockedByClient\", \"ConnectionRefused\", \"TimedOut\"."
972
+ },
973
+ "method": {
974
+ "type": "string",
975
+ "description": "Only mock requests with this HTTP method (e.g. \"POST\"); other methods pass through."
976
+ },
977
+ "delayMs": {
978
+ "type": "number",
979
+ "description": "Fault injection: artificial latency in ms before responding."
980
+ },
981
+ "failRate": {
982
+ "type": "number",
983
+ "description": "Fault injection: probability 0..1 of failing a matched request regardless of action (resilience testing)."
984
+ },
985
+ "reload": {
986
+ "type": "boolean",
987
+ "description": "Reload the target after arming so the mock immediately catches traffic."
988
+ }
989
+ },
990
+ "required": [
991
+ "urlPattern"
992
+ ],
993
+ "additionalProperties": false
994
+ }
995
+ },
996
+ {
997
+ "name": "list_mocks",
998
+ "description": "List active fake-backend sessions (one per target) with their rules and hit counts. Prunes sessions whose tab has closed. Use to see what is currently being mocked.",
999
+ "inputSchema": {
1000
+ "type": "object",
1001
+ "properties": {
1002
+ "target": {
1003
+ "type": "string",
1004
+ "description": "Unused filter placeholder; list_mocks returns all active sessions."
1005
+ }
1006
+ },
1007
+ "required": [],
1008
+ "additionalProperties": false
1009
+ }
1010
+ },
1011
+ {
1012
+ "name": "clear_mocks",
1013
+ "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.",
1014
+ "inputSchema": {
1015
+ "type": "object",
1016
+ "properties": {
1017
+ "target": {
1018
+ "type": "string",
1019
+ "description": "Target selector whose mock session to clear. Defaults to the active page. Ignored when all:true."
1020
+ },
1021
+ "all": {
1022
+ "type": "boolean",
1023
+ "description": "Clear every active mock session instead of just the resolved target's."
1024
+ }
1025
+ },
1026
+ "required": [],
1027
+ "additionalProperties": false
1028
+ }
1029
+ }
1030
+ ];