cdp-toolkit 1.4.0 → 1.6.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 +96 -0
- package/CONTRACT.md +3 -1
- package/README.md +21 -17
- package/dist/cli.js +399 -30
- package/dist/index.js +384 -15
- package/dist/mcp.js +470 -31
- package/package.json +3 -2
- package/src/bidi/driver.ts +4 -0
- package/src/capabilities.ts +1 -1
- package/src/cdp/driver.ts +3 -0
- package/src/driver.ts +4 -1
- package/src/index.ts +15 -4
- package/src/leases-tools.ts +1 -1
- package/src/leases.ts +1 -1
- package/src/manifest.ts +70 -0
- package/src/mcp.ts +1 -1
- package/src/shared-tools.ts +2 -1
- package/src/tools/screencast.ts +741 -0
package/src/cdp/driver.ts
CHANGED
|
@@ -259,12 +259,15 @@ async function elementClip(conn: CdpConnection, loc: ElementLocator): Promise<{
|
|
|
259
259
|
* not "not armed in advance", so an honest capability set omits it rather than reading true by
|
|
260
260
|
* construction. locate.text/locate.xpath both ride DOM.performSearch (see searchLocate above),
|
|
261
261
|
* which is a real Chrome capability, not a line-budget artifact, so both ARE declared.
|
|
262
|
+
* capture.screencast rides Page.startScreencast / Page.screencastFrame / Page.screencastFrameAck,
|
|
263
|
+
* the streamed-repaint primitive behind start_screen_recording and stop_screen_recording.
|
|
262
264
|
*/
|
|
263
265
|
const CDP_CAPABILITIES: ReadonlySet<Capability> = new Set<Capability>([
|
|
264
266
|
"trace.performance", "heap.snapshot", "audit.lighthouse", "emulate.cpuThrottling",
|
|
265
267
|
"emulate.mediaFeatures", "emulate.deviceMetrics", "emulate.networkConditions",
|
|
266
268
|
"screenshot.fullPage", "screenshot.element", "network.intercept",
|
|
267
269
|
"snapshot.accessibilityTree", "input.insertTextAtomic", "locate.text", "locate.xpath",
|
|
270
|
+
"capture.screencast",
|
|
268
271
|
]);
|
|
269
272
|
/* ---------------------------------- PageDriver ---------------------------------- */
|
|
270
273
|
class CdpPageDriver implements PageDriver {
|
package/src/driver.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ADR-001: one browser-neutral Driver interface behind the
|
|
2
|
+
* ADR-001: one browser-neutral Driver interface behind the 41 tools.
|
|
3
3
|
*
|
|
4
4
|
* Context. Every tool in src/tools/ is a stateless one-shot on withPage():
|
|
5
5
|
* open a socket, act, always close. That is only correct because a CDP `Uid`
|
|
@@ -126,6 +126,7 @@ export type Capability =
|
|
|
126
126
|
| "trace.performance" // Chrome tracing, behind every performance_* tool
|
|
127
127
|
| "heap.snapshot" // V8 heap snapshots
|
|
128
128
|
| "audit.lighthouse" // shelling out to lighthouse against a debug port
|
|
129
|
+
| "capture.screencast" // streamed repaint frames (CDP Page.startScreencast); BiDi has no equivalent
|
|
129
130
|
| "emulate.cpuThrottling" // CPU multiplier; absent from BiDi's emulation module
|
|
130
131
|
| "emulate.mediaFeatures" // media type + features, e.g. prefers-color-scheme
|
|
131
132
|
| "emulate.deviceMetrics" // past width/height: scale factor, mobile flag
|
|
@@ -151,6 +152,8 @@ export const REQUIRED_CAPABILITIES: Partial<Record<ToolName, readonly Capability
|
|
|
151
152
|
performance_trace: ["trace.performance"],
|
|
152
153
|
take_heapsnapshot: ["heap.snapshot"],
|
|
153
154
|
lighthouse_audit: ["audit.lighthouse"],
|
|
155
|
+
start_screen_recording: ["capture.screencast"],
|
|
156
|
+
stop_screen_recording: ["capture.screencast"],
|
|
154
157
|
mock_request: ["network.intercept"],
|
|
155
158
|
list_mocks: ["network.intercept"],
|
|
156
159
|
clear_mocks: ["network.intercept"],
|
package/src/index.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Two exports:
|
|
5
5
|
* 1. `TOOLS` : the registry mapping every chrome-devtools-mcp tool name
|
|
6
|
-
* (snake_case string, all 29)
|
|
6
|
+
* (snake_case string, all 29 of them) plus the toolkit's own superset
|
|
7
|
+
* tools, 41 entries in all, to its raw-CDP implementation function. The
|
|
7
8
|
* CLI and any embedder dispatch through this single table.
|
|
8
9
|
* 2. The client primitives, re-exported so consumers can build their own
|
|
9
10
|
* flows on the same connection/timeout machinery the tools use.
|
|
@@ -12,8 +13,9 @@
|
|
|
12
13
|
* value (or throws). See CONTRACT.md for the design rules each module follows.
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
|
-
// --- the
|
|
16
|
+
// --- the 23 tools unified with Firefox onto one Driver-based implementation ---
|
|
16
17
|
// (list_pages/new_page/close_page/select_page, navigate_page/wait_for, evaluate_script,
|
|
18
|
+
// list_cookies/set_cookie/delete_cookies,
|
|
17
19
|
// take_snapshot, click/hover/drag/fill/fill_form/type_text/press_key/upload_file,
|
|
18
20
|
// take_screenshot/emulate/resize_page, handle_dialog). See shared-tools.ts's file header for
|
|
19
21
|
// the byte-identical-Chrome-behavior contract this bind honors, and for the 7 tools that stay
|
|
@@ -31,6 +33,8 @@ import {
|
|
|
31
33
|
performanceAnalyzeInsight,
|
|
32
34
|
performanceTrace,
|
|
33
35
|
} from "./tools/performance.ts";
|
|
36
|
+
// --- screen recording (Page.startScreencast + ffmpeg) ---
|
|
37
|
+
import { startScreenRecording, stopScreenRecording } from "./tools/screencast.ts";
|
|
34
38
|
// --- heap ---
|
|
35
39
|
import { takeHeapsnapshot } from "./tools/heap.ts";
|
|
36
40
|
// --- lighthouse (the sole non-CDP tool) ---
|
|
@@ -59,8 +63,12 @@ function onCdp<A>(fn: (driver: ReturnType<typeof createCdpDriver>, args: A) => P
|
|
|
59
63
|
* (mock_request/list_mocks/clear_mocks : a persistent per-target fake backend),
|
|
60
64
|
* plus a 3-tool cookie group (list_cookies/set_cookie/delete_cookies : the
|
|
61
65
|
* cookie store including httpOnly cookies, which no page script can read or
|
|
62
|
-
* write)
|
|
63
|
-
*
|
|
66
|
+
* write), plus a 3-tool lease group (claim_page/release_page/list_leases :
|
|
67
|
+
* opt-in tab ownership so many agents can share one browser), plus a 2-tool
|
|
68
|
+
* screen-recording pair (start_screen_recording/stop_screen_recording : a tab
|
|
69
|
+
* captured to an H.265 MP4 with per-frame durations, so a variable-rate
|
|
70
|
+
* repaint stream plays back at wallclock speed).
|
|
71
|
+
* 29 + 1 + 3 + 3 + 3 + 2 = 41 entries total. Listed explicitly so the mapping is auditable at a glance and
|
|
64
72
|
* the CLI can `--list` it.
|
|
65
73
|
*
|
|
66
74
|
* 20 of the 29 MCP-parity tools (pages/navigation/evaluate/snapshot/interaction/
|
|
@@ -110,6 +118,9 @@ export const TOOLS = {
|
|
|
110
118
|
performance_stop_trace: performanceStopTrace,
|
|
111
119
|
performance_analyze_insight: performanceAnalyzeInsight,
|
|
112
120
|
performance_trace: performanceTrace,
|
|
121
|
+
// screen recording (2) : toolkit addition, a tab-to-H.265-MP4 pair over Page.startScreencast
|
|
122
|
+
start_screen_recording: startScreenRecording,
|
|
123
|
+
stop_screen_recording: stopScreenRecording,
|
|
113
124
|
// heap (1)
|
|
114
125
|
take_heapsnapshot: takeHeapsnapshot,
|
|
115
126
|
// lighthouse (1) : the only non-CDP tool
|
package/src/leases-tools.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The three lease tools, shaped like src/shared-tools.ts entries
|
|
3
3
|
* ((driver, args) => Promise<result>) so ONE implementation serves Chrome and
|
|
4
|
-
* Firefox, exactly as the
|
|
4
|
+
* Firefox, exactly as the 23 unified tools in that file do.
|
|
5
5
|
*/
|
|
6
6
|
import type { BrowserDriver } from "./driver.ts";
|
|
7
7
|
import { newTrackedPage } from "./origins.ts";
|
package/src/leases.ts
CHANGED
|
@@ -265,7 +265,7 @@ export async function releaseLeaseFor(backend: LeaseBackend, targetId: string):
|
|
|
265
265
|
* This exists so enforcement can stay at ONE point per resolution path while
|
|
266
266
|
* the token still reaches it. The token arrives as a key on a tool's args
|
|
267
267
|
* object, many frames above resolveTarget, and threading a parameter through
|
|
268
|
-
* all
|
|
268
|
+
* all 41 tools would put the burden on every future contributor to remember
|
|
269
269
|
* the check exists: one missed tool would silently defeat the feature for that
|
|
270
270
|
* tool. mcp.ts and cli.ts open this scope once per dispatch instead, so a tool
|
|
271
271
|
* added tomorrow is covered with no action from whoever writes it.
|
package/src/manifest.ts
CHANGED
|
@@ -1118,6 +1118,76 @@ export const MANIFEST: ToolSpec[] = [
|
|
|
1118
1118
|
"additionalProperties": false
|
|
1119
1119
|
}
|
|
1120
1120
|
},
|
|
1121
|
+
{
|
|
1122
|
+
"name": "start_screen_recording",
|
|
1123
|
+
"description": "Start recording the target tab to video over raw CDP (Page.startScreencast), holding one persistent connection open and spooling every Page.screencastFrame to disk. Chrome emits a frame ON REPAINT, not on a clock, so the stream is variable-rate: each frame is timestamped into a ledger and stop_screen_recording turns those timestamps into per-frame display durations, which is what makes a still page hold one long frame instead of the video racing or freezing. Every frame is acked immediately (an unacked frame stalls the stream). ffmpeg is probed here, not at stop, so a missing encoder fails before a recording is captured and thrown away. Must be paired with stop_screen_recording WITHIN THE SAME PROCESS (the frames are events on this connection and cannot be re-attached from another process, so the pair works under the MCP server, not the one-process-per-call CLI). Throws if a recording is already in progress for the target; recordings on DIFFERENT targets run concurrently. Chrome only: WebDriver BiDi has no screencast primitive, so both tools are absent under --browser firefox.",
|
|
1124
|
+
"inputSchema": {
|
|
1125
|
+
"type": "object",
|
|
1126
|
+
"properties": {
|
|
1127
|
+
"lease": {
|
|
1128
|
+
"type": "string",
|
|
1129
|
+
"description": "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
|
|
1130
|
+
},
|
|
1131
|
+
"target": {
|
|
1132
|
+
"type": "string",
|
|
1133
|
+
"description": "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | '<targetId>'."
|
|
1134
|
+
},
|
|
1135
|
+
"format": {
|
|
1136
|
+
"type": "string",
|
|
1137
|
+
"enum": [
|
|
1138
|
+
"jpeg",
|
|
1139
|
+
"png"
|
|
1140
|
+
],
|
|
1141
|
+
"description": "Frame image format. Defaults to jpeg (far smaller per repaint); png is lossless. quality applies to jpeg only."
|
|
1142
|
+
},
|
|
1143
|
+
"quality": {
|
|
1144
|
+
"type": "number",
|
|
1145
|
+
"description": "JPEG frame quality 0-100. Ignored for png. Omitted by default, which leaves Chrome's own default in place."
|
|
1146
|
+
},
|
|
1147
|
+
"maxWidth": {
|
|
1148
|
+
"type": "number",
|
|
1149
|
+
"description": "Cap the streamed frame width in pixels. Also the way to pin frame size if the viewport might change mid-recording."
|
|
1150
|
+
},
|
|
1151
|
+
"maxHeight": {
|
|
1152
|
+
"type": "number",
|
|
1153
|
+
"description": "Cap the streamed frame height in pixels."
|
|
1154
|
+
},
|
|
1155
|
+
"everyNthFrame": {
|
|
1156
|
+
"type": "number",
|
|
1157
|
+
"description": "Capture only every Nth repaint (1 = every frame). Reduces spool size on a busy page; per-frame durations keep playback at wallclock speed either way."
|
|
1158
|
+
},
|
|
1159
|
+
"bringToFront": {
|
|
1160
|
+
"type": "boolean",
|
|
1161
|
+
"description": "Activate the tab (Page.bringToFront) before recording. Default false. A fully backgrounded or occluded tab may never repaint, and a recording of one captures 0 frames."
|
|
1162
|
+
}
|
|
1163
|
+
},
|
|
1164
|
+
"required": [],
|
|
1165
|
+
"additionalProperties": false
|
|
1166
|
+
}
|
|
1167
|
+
},
|
|
1168
|
+
{
|
|
1169
|
+
"name": "stop_screen_recording",
|
|
1170
|
+
"description": "Stop the recording started by start_screen_recording, assemble the spooled frames into an MP4 with ffmpeg using PER-FRAME durations from the ledger (frame N is held until frame N+1 painted; the last frame is held until this call), and return {path,bytes,durationMs,frameCount,encodedFrames,codec,encoder,width,height,droppedFrames,target}. Encoder ladder, probed once at start: hevc_videotoolbox then h264_videotoolbox then libx265 then libx264, with -tag:v hvc1 on HEVC so QuickTime plays it, +faststart, yuv420p, and even dimensions forced. With one recording in flight 'target' may be omitted; with several it is required, because guessing which to stop can lose another agent's recording. Throws if nothing is recording in this process, and throws rather than writing a silent empty video when 0 frames arrived. On an ffmpeg failure the spooled frames are KEPT and the spool path plus the exact command are named in the error. Encoded video tops out at 25 fps: ffmpeg's concat demuxer represents image timestamps on a 1/25s grid, so frames captured less than 40ms apart are coalesced deliberately (frameCount reports what was captured, encodedFrames what reached the video) instead of being dropped silently by ffmpeg. durationMs is the sum of the encoded durations; the file itself runs one 40ms step longer, because the concat demuxer needs the final frame repeated for its hold to count.",
|
|
1171
|
+
"inputSchema": {
|
|
1172
|
+
"type": "object",
|
|
1173
|
+
"properties": {
|
|
1174
|
+
"lease": {
|
|
1175
|
+
"type": "string",
|
|
1176
|
+
"description": "Opaque lease token from claim_page. Required only when the tab this call resolves to is leased by someone; omit it for unleased tabs, which behave exactly as before."
|
|
1177
|
+
},
|
|
1178
|
+
"target": {
|
|
1179
|
+
"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>'."
|
|
1181
|
+
},
|
|
1182
|
+
"savePath": {
|
|
1183
|
+
"type": "string",
|
|
1184
|
+
"description": "Override the output file path. Default: /tmp/cdp-toolkit/screen-recording-<targetIdShort>-<stamp>.mp4."
|
|
1185
|
+
}
|
|
1186
|
+
},
|
|
1187
|
+
"required": [],
|
|
1188
|
+
"additionalProperties": false
|
|
1189
|
+
}
|
|
1190
|
+
},
|
|
1121
1191
|
{
|
|
1122
1192
|
"name": "take_heapsnapshot",
|
|
1123
1193
|
"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.",
|
package/src/mcp.ts
CHANGED
|
@@ -23,7 +23,7 @@ import { toolAvailability } from "./capabilities.ts";
|
|
|
23
23
|
import { FIREFOX_TOOLS } from "./firefox-tools.ts";
|
|
24
24
|
import { leaseFromArgs, withLeaseScope } from "./leases.ts";
|
|
25
25
|
|
|
26
|
-
const VERSION = "1.
|
|
26
|
+
const VERSION = "1.6.0";
|
|
27
27
|
|
|
28
28
|
// --browser is read once at startup (MCP has no per-call notion of backend): explicit flag,
|
|
29
29
|
// else CDP_BROWSER env var, else "chrome" (zero behavior change for existing users/configs).
|
package/src/shared-tools.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* (ADR-001), used by BOTH Chrome (via cdp/driver.ts's createCdpDriver()) and Firefox (via
|
|
4
4
|
* bidi/driver.ts's createFirefoxDriver()). This file replaces the split that used to exist
|
|
5
5
|
* between src/tools/*.ts (raw CDP, Chrome only) and src/neutral.ts (Driver-based, Firefox only)
|
|
6
|
-
* for the
|
|
6
|
+
* for 20 of the 23 tools below. The other three, the list_cookies/set_cookie/delete_cookies
|
|
7
|
+
* cookie group, landed here directly and never had a Chrome-only copy.
|
|
7
8
|
*
|
|
8
9
|
* THE HARD REQUIREMENT this file exists to satisfy: Chrome's return shape, timing, and quirks
|
|
9
10
|
* stay byte-identical to what src/tools/*.ts produced before this migration: that already
|