cdp-toolkit 1.0.0 → 1.2.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 +76 -9
- package/CONTRACT.md +7 -5
- package/README.md +99 -28
- package/dist/cli.js +3248 -1033
- package/dist/index.js +1418 -898
- package/dist/mcp.js +3447 -1064
- package/package.json +12 -6
- package/src/backend.ts +86 -0
- package/src/bidi/client.ts +319 -0
- package/src/bidi/driver.ts +851 -0
- package/src/bidi/launch.ts +192 -0
- package/src/bidi/protocol.ts +782 -0
- package/src/bidi/snapshot.ts +419 -0
- package/src/bidi-tools.ts +193 -0
- package/src/capabilities.ts +43 -0
- package/src/cdp/driver.ts +660 -0
- package/src/cli.ts +97 -14
- package/src/client.ts +25 -7
- package/src/driver.ts +424 -0
- package/src/firefox-tools.ts +17 -0
- package/src/index.ts +55 -42
- package/src/leases-tools.ts +101 -0
- package/src/leases.ts +533 -0
- package/src/manifest.ts +211 -13
- package/src/mcp.ts +73 -15
- package/src/shared-tools.ts +466 -0
- package/src/tools/console.ts +3 -3
- package/src/tools/evaluate.ts +2 -2
- package/src/tools/heap.ts +3 -3
- package/src/tools/lighthouse.ts +4 -4
- package/src/tools/navigation.ts +1 -1
- package/src/tools/network.ts +7 -7
- package/src/tools/network_mock.ts +8 -8
- package/src/tools/performance.ts +11 -11
- package/src/tools/recorder.ts +5 -5
- package/src/tools/snapshot.ts +2 -2
- package/src/tools/dialogs.ts +0 -236
- package/src/tools/emulation.ts +0 -212
- package/src/tools/input.ts +0 -399
- package/src/tools/pages.ts +0 -159
- package/src/tools/screenshot.ts +0 -180
package/src/index.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* cdp-toolkit public surface.
|
|
3
3
|
*
|
|
4
4
|
* Two exports:
|
|
5
|
-
* 1. `TOOLS`
|
|
5
|
+
* 1. `TOOLS` : the registry mapping every chrome-devtools-mcp tool name
|
|
6
6
|
* (snake_case string, all 29) to its raw-CDP implementation function. The
|
|
7
7
|
* CLI and any embedder dispatch through this single table.
|
|
8
8
|
* 2. The client primitives, re-exported so consumers can build their own
|
|
@@ -12,21 +12,15 @@
|
|
|
12
12
|
* value (or throws). See CONTRACT.md for the design rules each module follows.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
// ---
|
|
16
|
-
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
import { click, hover, drag, fill, fillForm, typeText, pressKey, uploadFile } from "./tools/input.ts";
|
|
25
|
-
// --- screenshot + emulation ---
|
|
26
|
-
import { takeScreenshot } from "./tools/screenshot.ts";
|
|
27
|
-
import { emulate, resizePage } from "./tools/emulation.ts";
|
|
28
|
-
// --- dialogs ---
|
|
29
|
-
import { handleDialog } from "./tools/dialogs.ts";
|
|
15
|
+
// --- the 20 tools unified with Firefox onto one Driver-based implementation ---
|
|
16
|
+
// (list_pages/new_page/close_page/select_page, navigate_page/wait_for, evaluate_script,
|
|
17
|
+
// take_snapshot, click/hover/drag/fill/fill_form/type_text/press_key/upload_file,
|
|
18
|
+
// take_screenshot/emulate/resize_page, handle_dialog). See shared-tools.ts's file header for
|
|
19
|
+
// the byte-identical-Chrome-behavior contract this bind honors, and for the 7 tools that stay
|
|
20
|
+
// two implementations (console/network/mock, immediately below, unchanged from before).
|
|
21
|
+
import { createCdpDriver } from "./cdp/driver.ts";
|
|
22
|
+
import { LEASE_TOOLS } from "./leases-tools.ts";
|
|
23
|
+
import { SHARED_TOOLS } from "./shared-tools.ts";
|
|
30
24
|
// --- console + network (read the recorder buffer) ---
|
|
31
25
|
import { listConsoleMessages, getConsoleMessage } from "./tools/console.ts";
|
|
32
26
|
import { listNetworkRequests, getNetworkRequest } from "./tools/network.ts";
|
|
@@ -41,49 +35,64 @@ import {
|
|
|
41
35
|
import { takeHeapsnapshot } from "./tools/heap.ts";
|
|
42
36
|
// --- lighthouse (the sole non-CDP tool) ---
|
|
43
37
|
import { lighthouseAudit } from "./tools/lighthouse.ts";
|
|
44
|
-
// --- network mocking (Fetch domain)
|
|
38
|
+
// --- network mocking (Fetch domain) : toolkit addition beyond the 29 parity tools ---
|
|
45
39
|
import { mockRequest, listMocks, clearMocks } from "./tools/network_mock.ts";
|
|
46
40
|
|
|
47
41
|
/** A toolkit tool: a single typed-args function returning JSON-serializable data. */
|
|
48
42
|
export type ToolFn = (args: never) => Promise<unknown>;
|
|
49
43
|
|
|
44
|
+
// One stateless CDP driver, reused across calls (lifetime "per-call": every page() acquisition
|
|
45
|
+
// still opens its own throwaway connection, same as the pre-migration withPage per-call model).
|
|
46
|
+
// Constructing it does not dial a browser (capabilities.ts already relies on this).
|
|
47
|
+
const cdpDriver = createCdpDriver();
|
|
48
|
+
|
|
49
|
+
/** Bind a shared-tools.ts function to the module-level CDP driver, args-typed for the registry. */
|
|
50
|
+
function onCdp<A>(fn: (driver: ReturnType<typeof createCdpDriver>, args: A) => Promise<unknown>): (args: A) => Promise<unknown> {
|
|
51
|
+
return (args: A) => fn(cdpDriver, args);
|
|
52
|
+
}
|
|
53
|
+
|
|
50
54
|
/**
|
|
51
55
|
* The complete chrome-devtools-mcp parity surface: all 29 MCP tools keyed by
|
|
52
56
|
* their canonical MCP (snake_case) name, plus one convenience superset tool
|
|
53
|
-
* (`performance_trace`, a robust single-call trace
|
|
57
|
+
* (`performance_trace`, a robust single-call trace : the start/stop pair cannot
|
|
54
58
|
* span two stateless CLI processes), plus a 3-tool network-mocking group
|
|
55
|
-
* (mock_request/list_mocks/clear_mocks
|
|
56
|
-
*
|
|
59
|
+
* (mock_request/list_mocks/clear_mocks : a persistent per-target fake backend).
|
|
60
|
+
* 36 entries total. Listed explicitly so the mapping is auditable at a glance and
|
|
57
61
|
* the CLI can `--list` it.
|
|
62
|
+
*
|
|
63
|
+
* 20 of the 29 MCP-parity tools (pages/navigation/evaluate/snapshot/interaction/
|
|
64
|
+
* screenshot+emulation/dialogs) now route through shared-tools.ts's single Driver-based
|
|
65
|
+
* implementation via the CDP driver, instead of a Chrome-only copy in src/tools/*.ts.
|
|
66
|
+
* See shared-tools.ts's file header for the shape/behavior contract this preserves.
|
|
58
67
|
*/
|
|
59
68
|
export const TOOLS = {
|
|
60
69
|
// pages (4)
|
|
61
|
-
list_pages:
|
|
62
|
-
new_page:
|
|
63
|
-
close_page:
|
|
64
|
-
select_page:
|
|
70
|
+
list_pages: onCdp(SHARED_TOOLS.list_pages),
|
|
71
|
+
new_page: onCdp(SHARED_TOOLS.new_page),
|
|
72
|
+
close_page: onCdp(SHARED_TOOLS.close_page),
|
|
73
|
+
select_page: onCdp(SHARED_TOOLS.select_page),
|
|
65
74
|
// navigation (2)
|
|
66
|
-
navigate_page:
|
|
67
|
-
wait_for:
|
|
75
|
+
navigate_page: onCdp(SHARED_TOOLS.navigate_page),
|
|
76
|
+
wait_for: onCdp(SHARED_TOOLS.wait_for),
|
|
68
77
|
// evaluate (1)
|
|
69
|
-
evaluate_script:
|
|
78
|
+
evaluate_script: onCdp(SHARED_TOOLS.evaluate_script),
|
|
70
79
|
// snapshot (1)
|
|
71
|
-
take_snapshot:
|
|
80
|
+
take_snapshot: onCdp(SHARED_TOOLS.take_snapshot),
|
|
72
81
|
// interaction (8)
|
|
73
|
-
click: click,
|
|
74
|
-
hover: hover,
|
|
75
|
-
drag: drag,
|
|
76
|
-
fill: fill,
|
|
77
|
-
fill_form:
|
|
78
|
-
type_text:
|
|
79
|
-
press_key:
|
|
80
|
-
upload_file:
|
|
82
|
+
click: onCdp(SHARED_TOOLS.click),
|
|
83
|
+
hover: onCdp(SHARED_TOOLS.hover),
|
|
84
|
+
drag: onCdp(SHARED_TOOLS.drag),
|
|
85
|
+
fill: onCdp(SHARED_TOOLS.fill),
|
|
86
|
+
fill_form: onCdp(SHARED_TOOLS.fill_form),
|
|
87
|
+
type_text: onCdp(SHARED_TOOLS.type_text),
|
|
88
|
+
press_key: onCdp(SHARED_TOOLS.press_key),
|
|
89
|
+
upload_file: onCdp(SHARED_TOOLS.upload_file),
|
|
81
90
|
// screenshot + emulation (3)
|
|
82
|
-
take_screenshot:
|
|
83
|
-
emulate: emulate,
|
|
84
|
-
resize_page:
|
|
91
|
+
take_screenshot: onCdp(SHARED_TOOLS.take_screenshot),
|
|
92
|
+
emulate: onCdp(SHARED_TOOLS.emulate),
|
|
93
|
+
resize_page: onCdp(SHARED_TOOLS.resize_page),
|
|
85
94
|
// dialogs (1)
|
|
86
|
-
handle_dialog:
|
|
95
|
+
handle_dialog: onCdp(SHARED_TOOLS.handle_dialog),
|
|
87
96
|
// console + network (4)
|
|
88
97
|
list_console_messages: listConsoleMessages,
|
|
89
98
|
get_console_message: getConsoleMessage,
|
|
@@ -96,12 +105,16 @@ export const TOOLS = {
|
|
|
96
105
|
performance_trace: performanceTrace,
|
|
97
106
|
// heap (1)
|
|
98
107
|
take_heapsnapshot: takeHeapsnapshot,
|
|
99
|
-
// lighthouse (1)
|
|
108
|
+
// lighthouse (1) : the only non-CDP tool
|
|
100
109
|
lighthouse_audit: lighthouseAudit,
|
|
101
|
-
// network mocking (3)
|
|
110
|
+
// network mocking (3) : persistent per-target fake backend (toolkit addition, Fetch domain)
|
|
102
111
|
mock_request: mockRequest,
|
|
103
112
|
list_mocks: listMocks,
|
|
104
113
|
clear_mocks: clearMocks,
|
|
114
|
+
// tab leases (3) : opt-in ownership so many agents can share one browser
|
|
115
|
+
claim_page: onCdp(LEASE_TOOLS.claim_page),
|
|
116
|
+
release_page: onCdp(LEASE_TOOLS.release_page),
|
|
117
|
+
list_leases: onCdp(LEASE_TOOLS.list_leases),
|
|
105
118
|
} satisfies Record<string, (args: never) => Promise<unknown>>;
|
|
106
119
|
|
|
107
120
|
/** Canonical MCP tool name accepted by the registry. */
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The three lease tools, shaped like src/shared-tools.ts entries
|
|
3
|
+
* ((driver, args) => Promise<result>) so ONE implementation serves Chrome and
|
|
4
|
+
* Firefox, exactly as the other 20 unified tools do.
|
|
5
|
+
*/
|
|
6
|
+
import type { BrowserDriver } from "./driver.ts";
|
|
7
|
+
import {
|
|
8
|
+
claimLease,
|
|
9
|
+
leaseTtlMs,
|
|
10
|
+
listLeases,
|
|
11
|
+
releaseLease,
|
|
12
|
+
type LeaseBackend,
|
|
13
|
+
type LeaseSummary,
|
|
14
|
+
type LeaseToken,
|
|
15
|
+
} from "./leases.ts";
|
|
16
|
+
|
|
17
|
+
class LeaseToolError extends Error {}
|
|
18
|
+
|
|
19
|
+
/** The driver's uid scheme is the one stable per-backend discriminator on the
|
|
20
|
+
* BrowserDriver surface ("cdp" for Chrome, "bidi" for Firefox). */
|
|
21
|
+
function backendOf(driver: BrowserDriver): LeaseBackend {
|
|
22
|
+
return driver.scheme === "bidi" ? "firefox" : "chrome";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ClaimPageResult {
|
|
26
|
+
lease: LeaseToken;
|
|
27
|
+
targetId: string;
|
|
28
|
+
url: string;
|
|
29
|
+
label: string;
|
|
30
|
+
ttlMs: number;
|
|
31
|
+
expiresAt: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Claim a tab. With no targetId, opens a fresh tab first (optionally at `url`)
|
|
36
|
+
* and claims that, so "give me my own tab" is one call. With a targetId, claims
|
|
37
|
+
* an already-open tab.
|
|
38
|
+
*/
|
|
39
|
+
export async function claimPage(
|
|
40
|
+
driver: BrowserDriver,
|
|
41
|
+
args: { targetId?: string; url?: string; label?: string; ttlMs?: number } = {},
|
|
42
|
+
): Promise<ClaimPageResult> {
|
|
43
|
+
const backend = backendOf(driver);
|
|
44
|
+
const label = typeof args.label === "string" && args.label.length ? args.label : `pid-${process.pid}`;
|
|
45
|
+
const pages = await driver.listPages();
|
|
46
|
+
let targetId = args.targetId;
|
|
47
|
+
let url = args.url ?? "about:blank";
|
|
48
|
+
if (targetId === undefined || targetId === "") {
|
|
49
|
+
const page = await driver.newPage(args.url);
|
|
50
|
+
targetId = page.id;
|
|
51
|
+
url = page.url;
|
|
52
|
+
} else {
|
|
53
|
+
const existing = pages.find((p) => p.id === targetId);
|
|
54
|
+
if (!existing) throw new LeaseToolError(`claim_page: no page target with id '${targetId}'`);
|
|
55
|
+
url = existing.url;
|
|
56
|
+
}
|
|
57
|
+
const liveIds = [...pages.map((p) => p.id), targetId];
|
|
58
|
+
const { record, token } = await claimLease(backend, targetId, {
|
|
59
|
+
label,
|
|
60
|
+
ttlMs: typeof args.ttlMs === "number" && args.ttlMs > 0 ? args.ttlMs : leaseTtlMs(),
|
|
61
|
+
liveIds,
|
|
62
|
+
});
|
|
63
|
+
return {
|
|
64
|
+
lease: token,
|
|
65
|
+
targetId,
|
|
66
|
+
url,
|
|
67
|
+
label: record.label,
|
|
68
|
+
ttlMs: record.ttlMs,
|
|
69
|
+
expiresAt: record.lastUsedAt + record.ttlMs,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Release a held lease. Idempotent: an already-released or reclaimed lease
|
|
74
|
+
* reports released:false rather than throwing. */
|
|
75
|
+
export async function releasePage(
|
|
76
|
+
_driver: BrowserDriver,
|
|
77
|
+
args: { lease?: LeaseToken },
|
|
78
|
+
): Promise<{ released: boolean }> {
|
|
79
|
+
if (typeof args.lease !== "string" || !args.lease.length) {
|
|
80
|
+
throw new LeaseToolError("release_page requires the 'lease' token returned by claim_page");
|
|
81
|
+
}
|
|
82
|
+
return releaseLease(args.lease);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Enumerate active leases for diagnosis. Requires no token by design. */
|
|
86
|
+
export async function listLeasesTool(
|
|
87
|
+
driver: BrowserDriver,
|
|
88
|
+
_args: Record<string, never> = {} as Record<string, never>,
|
|
89
|
+
): Promise<{ leases: LeaseSummary[]; count: number }> {
|
|
90
|
+
const liveIds = (await driver.listPages()).map((p) => p.id);
|
|
91
|
+
// liveBackend scopes the target-gone test to the browser these ids came from,
|
|
92
|
+
// so leases held on the OTHER backend are not mislabeled as reclaimable.
|
|
93
|
+
const leases = await listLeases({ liveIds, liveBackend: backendOf(driver) });
|
|
94
|
+
return { leases, count: leases.length };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export const LEASE_TOOLS = {
|
|
98
|
+
claim_page: claimPage,
|
|
99
|
+
release_page: releasePage,
|
|
100
|
+
list_leases: listLeasesTool,
|
|
101
|
+
} satisfies Record<string, (driver: BrowserDriver, args: never) => Promise<unknown>>;
|