cdp-toolkit 1.9.5 → 1.10.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/dist/cli.js CHANGED
@@ -3702,12 +3702,14 @@ import { readFile as readFile4 } from "node:fs/promises";
3702
3702
 
3703
3703
  // src/tools/recorder.ts
3704
3704
  import { mkdir as mkdir6, appendFile, writeFile as writeFile5, copyFile } from "node:fs/promises";
3705
- var ARTIFACT_DIR2 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
3705
+ function artifactDir() {
3706
+ return process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
3707
+ }
3706
3708
  function recFile(targetId) {
3707
- return `${ARTIFACT_DIR2}/rec-${targetId}.jsonl`;
3709
+ return `${artifactDir()}/rec-${targetId}.jsonl`;
3708
3710
  }
3709
3711
  function captureFile(targetId, captureId) {
3710
- return `${ARTIFACT_DIR2}/rec-${targetId}-${captureId}.jsonl`;
3712
+ return `${artifactDir()}/rec-${targetId}-${captureId}.jsonl`;
3711
3713
  }
3712
3714
  function delay2(ms) {
3713
3715
  return new Promise((r) => setTimeout(r, ms));
@@ -3747,7 +3749,7 @@ var CONSOLE_EVENTS = ["Runtime.consoleAPICalled", "Runtime.exceptionThrown", "Lo
3747
3749
  async function startRecorder(target, opts = {}) {
3748
3750
  const network = opts.network ?? true;
3749
3751
  const consoleCap = opts.console ?? true;
3750
- await mkdir6(ARTIFACT_DIR2, { recursive: true });
3752
+ await mkdir6(artifactDir(), { recursive: true });
3751
3753
  const { conn, target: resolved } = await openPage(target, { timeoutMs: opts.timeoutMs });
3752
3754
  const file = opts.file ?? recFile(resolved.id);
3753
3755
  if (opts.truncate) {
@@ -4107,7 +4109,7 @@ async function getNetworkRequest(args = {}) {
4107
4109
  // src/tools/performance.ts
4108
4110
  import { mkdir as mkdir7, readFile as readFile6, writeFile as writeFile6, stat, unlink as unlink4 } from "node:fs/promises";
4109
4111
  import { join as join5 } from "node:path";
4110
- var ARTIFACT_DIR3 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
4112
+ var ARTIFACT_DIR2 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
4111
4113
  var STATE_DIR2 = process.env.CDP_STATE_DIR ?? "/tmp/cdp-toolkit";
4112
4114
  var DEFAULT_CATEGORIES = [
4113
4115
  "devtools.timeline",
@@ -4146,8 +4148,8 @@ async function endTrace(conn, sink, timeoutMs = 30000) {
4146
4148
  return sink;
4147
4149
  }
4148
4150
  async function writeTrace(events, targetId) {
4149
- await mkdir7(ARTIFACT_DIR3, { recursive: true });
4150
- const path = join5(ARTIFACT_DIR3, `trace-${shortId(targetId)}-${stamp2()}.json`);
4151
+ await mkdir7(ARTIFACT_DIR2, { recursive: true });
4152
+ const path = join5(ARTIFACT_DIR2, `trace-${shortId(targetId)}-${stamp2()}.json`);
4151
4153
  const body = JSON.stringify({ traceEvents: events, metadata: { source: "cdp-toolkit" } });
4152
4154
  await writeFile6(path, body, "utf8");
4153
4155
  const { size } = await stat(path);
@@ -4340,7 +4342,7 @@ async function performanceAnalyzeInsight(args = {}) {
4340
4342
  import { spawn } from "node:child_process";
4341
4343
  import { mkdir as mkdir8, rm as rm2, stat as stat2, writeFile as writeFile7 } from "node:fs/promises";
4342
4344
  import { join as join6 } from "node:path";
4343
- var ARTIFACT_DIR4 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
4345
+ var ARTIFACT_DIR3 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
4344
4346
  var FFMPEG_BIN = process.env.CDP_FFMPEG ?? "ffmpeg";
4345
4347
  function frameDurationsMs(ledger, stopWallclockMs) {
4346
4348
  return ledger.map((entry, i) => {
@@ -4560,7 +4562,7 @@ async function startScreenRecording(args = {}) {
4560
4562
  conn.close();
4561
4563
  throw err;
4562
4564
  }
4563
- const spoolDir = join6(ARTIFACT_DIR4, `screencast-${shortId2(target.id)}-${stamp3()}`);
4565
+ const spoolDir = join6(ARTIFACT_DIR3, `screencast-${shortId2(target.id)}-${stamp3()}`);
4564
4566
  try {
4565
4567
  await mkdir8(spoolDir, { recursive: true });
4566
4568
  } catch (err) {
@@ -4666,8 +4668,8 @@ async function stopScreenRecording(args = {}) {
4666
4668
  await rm2(rec.spoolDir, { recursive: true, force: true }).catch(() => {});
4667
4669
  throw new CdpError(`screen recording captured 0 frames for target ${shortId2(rec.target.id)}. Chrome emits a screencast frame only on repaint: a fully backgrounded or occluded tab may never paint. Retry with bringToFront:true, or drive the page while recording.`);
4668
4670
  }
4669
- await mkdir8(ARTIFACT_DIR4, { recursive: true });
4670
- const outPath = args.savePath ?? join6(ARTIFACT_DIR4, `screen-recording-${shortId2(rec.target.id)}-${stamp3()}.mp4`);
4671
+ await mkdir8(ARTIFACT_DIR3, { recursive: true });
4672
+ const outPath = args.savePath ?? join6(ARTIFACT_DIR3, `screen-recording-${shortId2(rec.target.id)}-${stamp3()}.mp4`);
4671
4673
  const frames = coalesceToConcatGrid(ledger, stoppedAt);
4672
4674
  const manifestPath = join6(rec.spoolDir, "frames.ffconcat");
4673
4675
  await writeFile7(manifestPath, buildConcatManifest(frames), "utf8");
@@ -4703,7 +4705,7 @@ ffmpeg said: ${res.stderr.trim().slice(0, 800)}`);
4703
4705
  // src/tools/heap.ts
4704
4706
  import { mkdir as mkdir9, writeFile as writeFile8 } from "node:fs/promises";
4705
4707
  import { join as join7 } from "node:path";
4706
- var ARTIFACT_DIR5 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
4708
+ var ARTIFACT_DIR4 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
4707
4709
  function stamp4(targetId) {
4708
4710
  const short = targetId.slice(0, 8);
4709
4711
  const iso = new Date().toISOString().replace(/[:.]/g, "-");
@@ -4727,8 +4729,8 @@ async function takeHeapsnapshot(args = {}) {
4727
4729
  if (snapshot.length === 0) {
4728
4730
  throw new Error("HeapProfiler.takeHeapSnapshot produced no chunks");
4729
4731
  }
4730
- await mkdir9(ARTIFACT_DIR5, { recursive: true });
4731
- const path = args.savePath ? args.savePath.startsWith("/") ? args.savePath : join7(ARTIFACT_DIR5, args.savePath) : join7(ARTIFACT_DIR5, `take_heapsnapshot-${stamp4(target.id)}.heapsnapshot`);
4732
+ await mkdir9(ARTIFACT_DIR4, { recursive: true });
4733
+ const path = args.savePath ? args.savePath.startsWith("/") ? args.savePath : join7(ARTIFACT_DIR4, args.savePath) : join7(ARTIFACT_DIR4, `take_heapsnapshot-${stamp4(target.id)}.heapsnapshot`);
4732
4734
  await writeFile8(path, snapshot, "utf8");
4733
4735
  const bytes = Buffer.byteLength(snapshot, "utf8");
4734
4736
  return {
@@ -4743,7 +4745,7 @@ async function takeHeapsnapshot(args = {}) {
4743
4745
  // src/tools/lighthouse.ts
4744
4746
  import { spawn as spawn2 } from "node:child_process";
4745
4747
  import { mkdir as mkdir10, readFile as readFile7, stat as stat3 } from "node:fs/promises";
4746
- var ARTIFACT_DIR6 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
4748
+ var ARTIFACT_DIR5 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
4747
4749
  function cdpPort() {
4748
4750
  const base = process.env.CDP_BASE ?? "http://127.0.0.1:9222";
4749
4751
  const m = base.match(/:(\d+)/);
@@ -4803,8 +4805,8 @@ async function lighthouseAudit(args) {
4803
4805
  const url = args.url.trim();
4804
4806
  const timeoutMs = args.timeoutMs ?? 120000;
4805
4807
  const port = cdpPort();
4806
- await mkdir10(ARTIFACT_DIR6, { recursive: true });
4807
- const outPath = args.savePath ?? `${ARTIFACT_DIR6}/lighthouse-${shortHost(url)}-${stamp5()}.json`;
4808
+ await mkdir10(ARTIFACT_DIR5, { recursive: true });
4809
+ const outPath = args.savePath ?? `${ARTIFACT_DIR5}/lighthouse-${shortHost(url)}-${stamp5()}.json`;
4808
4810
  const formFactor = args.formFactor ?? "desktop";
4809
4811
  const lhArgs = [
4810
4812
  "--yes",
@@ -4925,8 +4927,8 @@ import { basename, extname, join as join9 } from "node:path";
4925
4927
  // src/tools/browser-session.ts
4926
4928
  import { mkdir as mkdir11 } from "node:fs/promises";
4927
4929
  import { join as join8 } from "node:path";
4928
- var ARTIFACT_DIR7 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
4929
- var DOWNLOADS_DIR = join8(ARTIFACT_DIR7, "downloads");
4930
+ var ARTIFACT_DIR6 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
4931
+ var DOWNLOADS_DIR = join8(ARTIFACT_DIR6, "downloads");
4930
4932
  var DOWNLOAD_BUFFER_LIMIT = 50;
4931
4933
  var session;
4932
4934
  function isDisconnect(e) {
@@ -5235,6 +5237,9 @@ class BidiConnection {
5235
5237
  get holders() {
5236
5238
  return this.refCount;
5237
5239
  }
5240
+ get isOpen() {
5241
+ return !this.closed && this.ws !== undefined;
5242
+ }
5238
5243
  connect() {
5239
5244
  return new Promise((resolve, reject) => {
5240
5245
  const ws = new WebSocket(this.wsUrl);
@@ -5969,10 +5974,12 @@ var BIDI_CAPABILITIES = new Set([
5969
5974
  var connections = new Map;
5970
5975
  async function getConnection(endpoint, timeoutMs) {
5971
5976
  const existing = connections.get(endpoint);
5972
- if (existing) {
5977
+ if (existing && existing.isOpen) {
5973
5978
  existing.retain();
5974
5979
  return existing;
5975
5980
  }
5981
+ if (existing)
5982
+ connections.delete(endpoint);
5976
5983
  const conn = await connectBidiSessionUrl(endpoint, {
5977
5984
  ...timeoutMs !== undefined ? { timeoutMs } : {},
5978
5985
  capabilities: { alwaysMatch: { unhandledPromptBehavior: { default: "ignore" } } }
@@ -6768,7 +6775,7 @@ function createFirefoxDriverForEndpoint(wsUrl, opts) {
6768
6775
 
6769
6776
  // src/bidi/launch.ts
6770
6777
  import { spawn as spawn3 } from "node:child_process";
6771
- import { mkdtempSync, rmSync } from "node:fs";
6778
+ import { existsSync, mkdtempSync, rmSync } from "node:fs";
6772
6779
  import { createConnection, createServer } from "node:net";
6773
6780
  import { tmpdir } from "node:os";
6774
6781
  import { join as join10 } from "node:path";
@@ -6779,8 +6786,12 @@ function resolveBinary() {
6779
6786
  "firefox"
6780
6787
  ];
6781
6788
  for (const c of candidates) {
6782
- if (c)
6783
- return c;
6789
+ if (!c)
6790
+ continue;
6791
+ const isAbsolute = c.startsWith("/");
6792
+ if (isAbsolute && !existsSync(c))
6793
+ continue;
6794
+ return c;
6784
6795
  }
6785
6796
  throw new Error("Firefox binary not found. Tried FIREFOX_BIN env var, " + "/Applications/Firefox.app/Contents/MacOS/firefox, and 'firefox' on PATH.");
6786
6797
  }
@@ -7199,21 +7210,21 @@ var FIREFOX_TOOLS = {
7199
7210
  var MANIFEST = [
7200
7211
  {
7201
7212
  name: "list_pages",
7202
- 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.",
7213
+ description: "Enumerate browser page targets (GET /json/list); page-type tabs only unless all=true. Each entry carries its targetId plus an origin field: 'agent' means this toolkit created it (also carries the creating label/createdAt, and stays 'agent' after the lease is released or the creator dies, making stray agent tabs findable), 'unknown' means no creation record - it never says 'human', the honest word for any tab it did not create; a record that exists but won't read adds originUnreadable. An entry under an active, readable lease also carries a 'lease' object {label,pid,idleMs,expiresAt,stale}, with idleMs and expiresAt computed fresh every call (never off disk), independent of probe. Under CDP_REQUIRE_LEASE this call also reaps abandoned agent tabs into an additive reaped array - but a lease reads reclaimable the moment its TTL elapses, while the tab is CLOSED only after a further grace (CDP_REAP_GRACE_MS, default 2700000ms/45min, so 60min total after last use); a dead-pid lease is reaped at once, a tab with no lease never. With probe, each page-type entry also gets 'responsive' (and humanActiveMs where human input is seen); both are absent, never false/null, without probe.",
7203
7214
  inputSchema: {
7204
7215
  type: "object",
7205
7216
  properties: {
7206
7217
  lease: {
7207
7218
  type: "string",
7208
- 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."
7219
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7209
7220
  },
7210
7221
  all: {
7211
7222
  type: "boolean",
7212
- description: "Include non-page targets (service/shared workers, background pages) when true; otherwise only page-type tabs are listed."
7223
+ description: "Include non-page targets (service/shared workers, background pages); default false lists page-type tabs only."
7213
7224
  },
7214
7225
  probe: {
7215
7226
  type: "boolean",
7216
- 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."
7227
+ description: "Ping each page-type renderer before returning, one bounded 500ms check per target and never more, so a wedged tab can't stall the listing. Adds 'responsive' (false on timeout/exception/unreachable, never an error for the whole call) and, where the same round trip finds human input, humanActiveMs. Default false. On a backend that cannot answer the ping, responsive is absent too (not false)."
7217
7228
  }
7218
7229
  },
7219
7230
  required: [],
@@ -7228,7 +7239,7 @@ var MANIFEST = [
7228
7239
  properties: {
7229
7240
  lease: {
7230
7241
  type: "string",
7231
- 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."
7242
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7232
7243
  },
7233
7244
  url: {
7234
7245
  type: "string",
@@ -7236,15 +7247,15 @@ var MANIFEST = [
7236
7247
  },
7237
7248
  claim: {
7238
7249
  type: "boolean",
7239
- description: "Claim the new tab atomically as part of creating it and return a lease token alongside {targetId,url}. Default false, which is byte-identical to the pre-1.2 behavior. Under CDP_REQUIRE_LEASE the new tab is claimed and a lease returned even without claim:true, because a tab nobody holds is a tab nobody may drive; passing claim:true additionally makes the lease an explicit one, which requires its token on every later call even from this same process."
7250
+ description: "Claim the new tab atomically and return a lease token alongside {targetId,url}. Under CDP_REQUIRE_LEASE the tab is claimed and a lease returned even without claim:true; claim:true makes it an EXPLICIT lease that demands its token on every later call, even from this process. Default false."
7240
7251
  },
7241
7252
  label: {
7242
7253
  type: "string",
7243
- description: "Agent label recorded on the lease when claim:true, surfaced in conflict errors and list_leases. Defaults to pid-<pid>."
7254
+ description: "Agent label recorded on the lease when the tab is claimed; surfaced in conflict errors and list_leases. Defaults to pid-<pid>."
7244
7255
  },
7245
7256
  ttlMs: {
7246
7257
  type: "number",
7247
- description: "How long the lease taken by claim:true survives without use before it is reclaimable. Defaults to CDP_LEASE_TTL_MS, else 900000 (15 minutes). Every checked call refreshes it, so an active agent never expires. Ignored without claim:true."
7258
+ description: "How long a claimed lease survives without use before it is reclaimable. Defaults to CDP_LEASE_TTL_MS, else 900000 (15min); every checked call refreshes it. Ignored when not claiming."
7248
7259
  }
7249
7260
  },
7250
7261
  required: [],
@@ -7253,17 +7264,17 @@ var MANIFEST = [
7253
7264
  },
7254
7265
  {
7255
7266
  name: "close_page",
7256
- description: "Close a page target via Target.closeTarget. Requires an explicit, resolvable target; refuses to guess and errors if the selector matches no target.",
7267
+ description: "Close a page target via Target.closeTarget. Requires an explicit, resolvable target; errors rather than guessing when the selector matches nothing.",
7257
7268
  inputSchema: {
7258
7269
  type: "object",
7259
7270
  properties: {
7260
7271
  lease: {
7261
7272
  type: "string",
7262
- 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."
7273
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7263
7274
  },
7264
7275
  target: {
7265
7276
  type: "string",
7266
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
7277
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7267
7278
  }
7268
7279
  },
7269
7280
  required: [
@@ -7280,11 +7291,11 @@ var MANIFEST = [
7280
7291
  properties: {
7281
7292
  lease: {
7282
7293
  type: "string",
7283
- 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."
7294
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7284
7295
  },
7285
7296
  target: {
7286
7297
  type: "string",
7287
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
7298
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7288
7299
  }
7289
7300
  },
7290
7301
  required: [
@@ -7301,11 +7312,11 @@ var MANIFEST = [
7301
7312
  properties: {
7302
7313
  lease: {
7303
7314
  type: "string",
7304
- 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."
7315
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7305
7316
  },
7306
7317
  target: {
7307
7318
  type: "string",
7308
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
7319
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7309
7320
  },
7310
7321
  url: {
7311
7322
  type: "string",
@@ -7321,7 +7332,7 @@ var MANIFEST = [
7321
7332
  "back",
7322
7333
  "forward"
7323
7334
  ],
7324
- 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."
7335
+ 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, not resolved by precedence. Works on BOTH backends and waits for the same load milestone as an ordinary navigation. Going back from the first entry, or forward from the last, is an ERROR naming the direction — never a silent no-op. The result carries traversed:'back'|'forward' alongside the resulting url."
7325
7336
  },
7326
7337
  ignoreCache: {
7327
7338
  type: "boolean",
@@ -7345,17 +7356,17 @@ var MANIFEST = [
7345
7356
  },
7346
7357
  {
7347
7358
  name: "wait_for",
7348
- 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}.",
7359
+ description: "Poll the target until the substring appears in document.body.innerText (Runtime.evaluate on a fixed interval), or throw on timeout. Text-substring only -- no aria/role/selector or event variants; throws rather than returning {found:false}.",
7349
7360
  inputSchema: {
7350
7361
  type: "object",
7351
7362
  properties: {
7352
7363
  lease: {
7353
7364
  type: "string",
7354
- 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."
7365
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7355
7366
  },
7356
7367
  target: {
7357
7368
  type: "string",
7358
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
7369
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7359
7370
  },
7360
7371
  text: {
7361
7372
  type: "string",
@@ -7363,11 +7374,11 @@ var MANIFEST = [
7363
7374
  },
7364
7375
  timeoutMs: {
7365
7376
  type: "number",
7366
- description: "Total time budget in milliseconds. Defaults to 15000."
7377
+ description: "Total time budget in ms. Default 15000."
7367
7378
  },
7368
7379
  pollMs: {
7369
7380
  type: "number",
7370
- description: "Poll interval in milliseconds. Defaults to 250."
7381
+ description: "Poll interval in ms. Default 250."
7371
7382
  }
7372
7383
  },
7373
7384
  required: [
@@ -7378,37 +7389,37 @@ var MANIFEST = [
7378
7389
  },
7379
7390
  {
7380
7391
  name: "evaluate_script",
7381
- 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 the one tool that can EVALUATE inside an MV3 extension's background SERVICE WORKER rather than a page (list_network_requests/get_network_request/list_console_messages OBSERVE one): 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').",
7392
+ description: "Run arbitrary JavaScript in the target's main-world context over raw CDP and return the evaluated value (returnByValue). With no 'args', 'expression' is a raw expression; with 'args' it must be a function literal (arrow or classic) invoked on globalThis with args passed positionally. A thrown exception surfaces as an error; non-serializable returns (DOM nodes, functions) come back as their CDP description string. savePath writes the value to a JSON file instead -- the response then carries only {path,bytes,type,target} and the value never appears in it, the way to read a credential (a JWT/session token from localStorage) without putting the secret in the transcript. This is the one tool that EVALUATES inside an MV3 extension's background SERVICE WORKER rather than OBSERVING it (Chrome, Capability 'worker.targets'): a worker: target reads chrome.storage.local, chrome.runtime and the worker's own globals directly, with an idle-evicted worker started first (see 'wake').",
7382
7393
  inputSchema: {
7383
7394
  type: "object",
7384
7395
  properties: {
7385
7396
  lease: {
7386
7397
  type: "string",
7387
- 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."
7398
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7388
7399
  },
7389
7400
  target: {
7390
7401
  type: "string",
7391
- 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 four tools only — evaluate_script, list_network_requests, get_network_request and list_console_messages — never as universal grammar; an MV3 worker that has been idle-evicted is started automatically first, see 'wake'."
7402
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', '<targetId>'; plus 'worker:<substring>' to reach a service/shared worker (e.g. an MV3 extension background worker). The worker: arm is CHROME-ONLY (Capability 'worker.targets'). Grammar: see server instructions."
7392
7403
  },
7393
7404
  wake: {
7394
7405
  type: "boolean",
7395
- 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."
7406
+ description: "Worker targets only, when starting a capture. Default true: an idle-evicted MV3 service worker exists in no target listing, so it is started first (ServiceWorker.startWorker) and re-confirmed; false fails fast. Rejected on a page target, a bare target id, or a read-only call. See server instructions."
7396
7407
  },
7397
7408
  expression: {
7398
7409
  type: "string",
7399
- 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."
7410
+ 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 provided. REQUIRED -- the code always goes in this key, never in 'function', 'code', 'js', 'script', 'fn' or 'body'; a call using one of those is rejected with an error naming the wrong key."
7400
7411
  },
7401
7412
  awaitPromise: {
7402
7413
  type: "boolean",
7403
- description: "Await the result if it is a Promise (default true)."
7414
+ description: "Await the result if it is a Promise. Default true."
7404
7415
  },
7405
7416
  args: {
7406
7417
  type: "array",
7407
- description: "Positional JSON-serializable arguments to pass to the expression, treating it as a function. No live element/page handle is bound."
7418
+ description: "Positional JSON-serializable arguments passed to the expression (treated as a function). No live element/page handle is bound."
7408
7419
  },
7409
7420
  savePath: {
7410
7421
  type: "string",
7411
- description: "Write the evaluated value to this file as JSON and KEEP IT OUT OF THE RESPONSE: with savePath set the result is {path,bytes,type,target} only, with no copy, preview or truncation of the value. Use it to read credentials without putting them in a transcript. An absolute path (starting with /) is used as-is; a relative path is resolved under the artifact dir (/tmp/cdp-toolkit). Missing parent directories are created. Omit it to get the value back inline, exactly as before."
7422
+ description: "Write the evaluated value to this file as JSON and KEEP IT OUT OF THE RESPONSE: the result is {path,bytes,type,target} only, with no copy, preview or truncation of the value -- read credentials without putting them in a transcript. An absolute path (starting with /) is used as-is; a relative path resolves under the artifact dir (/tmp/cdp-toolkit); missing parents are created. Omit to get the value back inline."
7412
7423
  }
7413
7424
  },
7414
7425
  required: [
@@ -7419,21 +7430,21 @@ var MANIFEST = [
7419
7430
  },
7420
7431
  {
7421
7432
  name: "list_cookies",
7422
- description: "Read the cookie store for the target page, INCLUDING httpOnly cookies, which document.cookie cannot see and an evaluate_script call therefore cannot reach. Each cookie carries name, value, domain, path, expires (Unix seconds, -1 for a session cookie), size, httpOnly, secure, sameSite ('strict'|'lax'|'none'|'default') and session. The read is page-scoped, not browser-wide: it returns the cookies of the resolved tab (Chrome: Network.getCookies; Firefox: storage.getCookies partitioned by that browsing context), so point at a page on the site whose cookies you want. Filter with 'domain' and/or 'name'. Pass 'savePath' to write the cookie array to a JSON file instead: the response is then {path,bytes,count,target} only, with no cookie value in it in any form, which is how to capture a session cookie without putting the credential in the caller's transcript.",
7433
+ description: "Read the target page's cookie store INCLUDING httpOnly cookies, which document.cookie (and therefore evaluate_script) cannot see. Page-scoped, not browser-wide: returns cookies of the resolved tab, so point at a page on the site you want. Each cookie carries name, value, domain, path, expires (Unix seconds, -1 for a session cookie), size, httpOnly, secure, sameSite ('strict'|'lax'|'none'|'default'), session. Filter with 'domain' and/or 'name'. Pass 'savePath' to write the array to a JSON file instead: the response is then {path,bytes,count,target} with no cookie value in any form, the way to capture a session cookie without putting the credential in the transcript.",
7423
7434
  inputSchema: {
7424
7435
  type: "object",
7425
7436
  properties: {
7426
7437
  lease: {
7427
7438
  type: "string",
7428
- 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."
7439
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7429
7440
  },
7430
7441
  target: {
7431
7442
  type: "string",
7432
- description: "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>' | 'label:<name>'."
7443
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7433
7444
  },
7434
7445
  domain: {
7435
7446
  type: "string",
7436
- description: "Keep only cookies for this domain. A leading dot is ignored on both sides and subdomains of the given domain match too, so 'example.test' matches '.example.test' and 'app.example.test'. No wildcards."
7447
+ description: "Keep only cookies for this domain. A leading dot is ignored on both sides and subdomains match too, so 'example.test' matches '.example.test' and 'app.example.test'. No wildcards."
7437
7448
  },
7438
7449
  name: {
7439
7450
  type: "string",
@@ -7441,7 +7452,7 @@ var MANIFEST = [
7441
7452
  },
7442
7453
  savePath: {
7443
7454
  type: "string",
7444
- description: "Write the cookie array to this file as JSON and KEEP THE VALUES OUT OF THE RESPONSE: with savePath set the result is {path,bytes,count,target} only, with no copy, preview or truncation of any cookie value. An absolute path (starting with /) is used as-is; a relative path is resolved under the artifact dir (/tmp/cdp-toolkit). Missing parent directories are created. Omit it to get the cookies back inline."
7455
+ description: "Write the cookie array here as JSON and KEEP THE VALUES OUT OF THE RESPONSE: the result is {path,bytes,count,target} only, with no preview or truncation of any value. An absolute path (starting with /) is used as-is; a relative path resolves under the artifact dir (/tmp/cdp-toolkit); missing parents are created. Omit to get the cookies back inline."
7445
7456
  }
7446
7457
  },
7447
7458
  required: [],
@@ -7450,17 +7461,17 @@ var MANIFEST = [
7450
7461
  },
7451
7462
  {
7452
7463
  name: "set_cookie",
7453
- description: "Write one cookie into the target page's cookie store, INCLUDING an httpOnly or secure cookie, which document.cookie cannot create and an evaluate_script call therefore cannot either. Chrome uses Network.setCookie, Firefox uses storage.setCookie partitioned by the resolved browsing context. Either 'url' or 'domain' is REQUIRED: a cookie has to be attributed to a site and the call is refused with an error when neither is given, rather than guessing the current page's origin. The response is {set:true,target} and never echoes the value back, so a credential you just supplied does not land in the transcript twice. A 'set:true' is earned, not assumed: Chrome answers Network.setCookie with success:false when it declines a cookie (a domain the url does not belong to, a secure cookie on an insecure origin, an oversized value) and that refusal is raised as an error. On Firefox, 'domain' is derived from 'url' when only the url was given, because BiDi has no url parameter; a url with no host, such as about:blank or a data URL, is an error rather than a silent no-op. Read the result back with list_cookies when you need proof.",
7464
+ description: "Write one cookie into the target page's cookie store, INCLUDING httpOnly or secure cookies that document.cookie (and therefore evaluate_script) cannot create. Either 'url' or 'domain' is REQUIRED: the call is refused when neither is given, rather than guessing the page origin. The response is {set:true,target} and never echoes the value back. A 'set:true' is earned, not assumed: Chrome raises an error when it declines the cookie (a domain the url does not belong to, a secure cookie on an insecure origin, an oversized value). On Firefox 'domain' is derived from 'url' when only the url was given (BiDi has no url parameter), and a url with no host such as about:blank or a data URL is an error, not a silent no-op. Read the result back with list_cookies when you need proof.",
7454
7465
  inputSchema: {
7455
7466
  type: "object",
7456
7467
  properties: {
7457
7468
  lease: {
7458
7469
  type: "string",
7459
- 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."
7470
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7460
7471
  },
7461
7472
  target: {
7462
7473
  type: "string",
7463
- description: "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>' | 'label:<name>'."
7474
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7464
7475
  },
7465
7476
  name: {
7466
7477
  type: "string",
@@ -7472,19 +7483,19 @@ var MANIFEST = [
7472
7483
  },
7473
7484
  url: {
7474
7485
  type: "string",
7475
- description: "The URL the cookie is set for, for example 'https://example.com/'. Chrome derives domain, path and secure from it. Firefox derives only the domain from its host. Give this or 'domain'."
7486
+ description: "URL the cookie is set for, e.g. 'https://example.com/'. Chrome derives domain, path and secure from it; Firefox derives only the domain from its host. Give this or 'domain'."
7476
7487
  },
7477
7488
  domain: {
7478
7489
  type: "string",
7479
- description: "Cookie domain, for example 'example.com' or '.example.com' for subdomains. Give this or 'url'. When both are given, this wins on Firefox and Chrome applies its own url plus domain consistency rule."
7490
+ description: "Cookie domain, e.g. 'example.com' or '.example.com' for subdomains. Give this or 'url'. When both are given, this wins on Firefox and Chrome applies its own url plus domain consistency rule."
7480
7491
  },
7481
7492
  path: {
7482
7493
  type: "string",
7483
- description: "Cookie path. Passed through exactly as given and NOT defaulted to '/': with a 'url' Chrome derives the path from it, so an invented default here would widen a cookie you meant to scope narrowly."
7494
+ description: "Cookie path, passed through exactly as given and NOT defaulted to '/': with a 'url' Chrome derives the path from it, so an invented default here would widen a cookie you meant to scope narrowly."
7484
7495
  },
7485
7496
  expires: {
7486
7497
  type: "number",
7487
- description: "Expiry as Unix time in SECONDS, matching what list_cookies reports. Omit it for a session cookie, which is what both backends do when no expiry is supplied."
7498
+ description: "Expiry as Unix time in SECONDS, matching what list_cookies reports. Omit for a session cookie, which is what both backends do when no expiry is supplied."
7488
7499
  },
7489
7500
  httpOnly: {
7490
7501
  type: "boolean",
@@ -7496,27 +7507,35 @@ var MANIFEST = [
7496
7507
  },
7497
7508
  sameSite: {
7498
7509
  type: "string",
7499
- enum: ["strict", "lax", "none", "default"],
7510
+ enum: [
7511
+ "strict",
7512
+ "lax",
7513
+ "none",
7514
+ "default"
7515
+ ],
7500
7516
  description: "SameSite attribute, lowercase, matching what list_cookies reports. 'default' means the attribute is not set at all."
7501
7517
  }
7502
7518
  },
7503
- required: ["name", "value"],
7519
+ required: [
7520
+ "name",
7521
+ "value"
7522
+ ],
7504
7523
  additionalProperties: false
7505
7524
  }
7506
7525
  },
7507
7526
  {
7508
7527
  name: "delete_cookies",
7509
- description: "Delete the named cookie from the target page's cookie store, httpOnly cookies included. Chrome uses Network.deleteCookies, Firefox uses storage.deleteCookies with a filter, partitioned by the resolved browsing context. Both 'name' and one of 'url' or 'domain' are REQUIRED: without a site constraint the call would delete by name across the whole partition, so it is refused with an error instead. Narrow further with 'path'. The response is {deleted:true,target} and carries NO count, because neither protocol reports how many cookies it removed and a number here would be invented; call list_cookies before and after when you need a real count. 'deleted:true' means the backend accepted and performed the deletion, not that a matching cookie existed, since deleting an absent cookie is a success on both backends.",
7528
+ description: "Delete the named cookie from the target page's cookie store, httpOnly cookies included. Both 'name' and one of 'url' or 'domain' are REQUIRED: without a site constraint it would delete by name across the whole partition, so it is refused with an error instead. Narrow further with 'path'. The response is {deleted:true,target} and carries NO count, because neither protocol reports how many cookies it removed and a number here would be invented; call list_cookies before and after for a real count. 'deleted:true' means the backend accepted and performed the deletion, not that a matching cookie existed, since deleting an absent cookie succeeds on both backends.",
7510
7529
  inputSchema: {
7511
7530
  type: "object",
7512
7531
  properties: {
7513
7532
  lease: {
7514
7533
  type: "string",
7515
- 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."
7534
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7516
7535
  },
7517
7536
  target: {
7518
7537
  type: "string",
7519
- description: "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>' | 'label:<name>'."
7538
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7520
7539
  },
7521
7540
  name: {
7522
7541
  type: "string",
@@ -7524,7 +7543,7 @@ var MANIFEST = [
7524
7543
  },
7525
7544
  url: {
7526
7545
  type: "string",
7527
- description: "Delete cookies matching this URL, for example 'https://example.com/'. Give this or 'domain'. On Firefox only the host is used, because BiDi's filter has no url field."
7546
+ description: "Delete cookies matching this URL, e.g. 'https://example.com/'. Give this or 'domain'. On Firefox only the host is used, because BiDi's filter has no url field."
7528
7547
  },
7529
7548
  domain: {
7530
7549
  type: "string",
@@ -7535,27 +7554,29 @@ var MANIFEST = [
7535
7554
  description: "Narrow the deletion to cookies with this exact path. Omit to match any path allowed by the other constraints."
7536
7555
  }
7537
7556
  },
7538
- required: ["name"],
7557
+ required: [
7558
+ "name"
7559
+ ],
7539
7560
  additionalProperties: false
7540
7561
  }
7541
7562
  },
7542
7563
  {
7543
7564
  name: "take_snapshot",
7544
- 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.",
7565
+ description: "Captures the page's accessibility tree as an indented text tree, each line prefixed [uid] (a CDP backendDOMNodeId). Every interaction tool (click/hover/fill/etc.) resolves that uid via DOM.resolveNode — run this first to discover uids to act on.",
7545
7566
  inputSchema: {
7546
7567
  type: "object",
7547
7568
  properties: {
7548
7569
  lease: {
7549
7570
  type: "string",
7550
- 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."
7571
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7551
7572
  },
7552
7573
  target: {
7553
7574
  type: "string",
7554
- 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)."
7575
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7555
7576
  },
7556
7577
  interactiveOnly: {
7557
7578
  type: "boolean",
7558
- description: "When true, emit only interactive/meaningful nodes flattened into a readable list; default false returns the full hierarchical a11y tree."
7579
+ description: "When true, emit only interactive/meaningful nodes as a flat list; default false returns the full hierarchical tree."
7559
7580
  }
7560
7581
  },
7561
7582
  required: [],
@@ -7564,25 +7585,25 @@ var MANIFEST = [
7564
7585
  },
7565
7586
  {
7566
7587
  name: "click",
7567
- 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.",
7588
+ description: "Click an element via a synthetic mouse press/release at its scrolled-into-view center. Give exactly one of uid or selector. modifiers (Alt/Control/Meta/Shift) throws on the Firefox backend — use --browser chrome for a modifier-click. clickCount:3 triple-clicks (selects a line/paragraph in most editors).",
7568
7589
  inputSchema: {
7569
7590
  type: "object",
7570
7591
  properties: {
7571
7592
  lease: {
7572
7593
  type: "string",
7573
- 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."
7594
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7574
7595
  },
7575
7596
  target: {
7576
7597
  type: "string",
7577
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
7598
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7578
7599
  },
7579
7600
  uid: {
7580
7601
  type: "number",
7581
- description: "CDP backendDOMNodeId of the element to click, obtained from take_snapshot. Provide exactly one of uid or selector."
7602
+ description: "CDP backendDOMNodeId of the element to click, from take_snapshot. Exactly one of uid or selector."
7582
7603
  },
7583
7604
  selector: {
7584
7605
  type: "string",
7585
- description: "CSS selector for the element to click (resolved via document.querySelector). Provide exactly one of uid or selector."
7606
+ description: "CSS selector for the element to click (document.querySelector). Exactly one of uid or selector."
7586
7607
  },
7587
7608
  button: {
7588
7609
  type: "string",
@@ -7595,7 +7616,7 @@ var MANIFEST = [
7595
7616
  },
7596
7617
  clickCount: {
7597
7618
  type: "number",
7598
- description: "Number of clicks: 1 = single (default), 2 = double-click, 3 = triple-click."
7619
+ description: "Number of clicks: 1 (default), 2 = double-click, 3 = triple-click."
7599
7620
  },
7600
7621
  modifiers: {
7601
7622
  type: "array",
@@ -7608,7 +7629,7 @@ var MANIFEST = [
7608
7629
  "Shift"
7609
7630
  ]
7610
7631
  },
7611
- 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."
7632
+ description: "Modifier keys held for the click's press and release, e.g. ['Shift']. Non-empty on the Firefox backend throws — not supported over BiDi."
7612
7633
  }
7613
7634
  },
7614
7635
  required: [],
@@ -7617,25 +7638,25 @@ var MANIFEST = [
7617
7638
  },
7618
7639
  {
7619
7640
  name: "hover",
7620
- 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).",
7641
+ description: "Hovers the mouse over an element by dispatching a mouseMoved event at its scrolled-into-view center, firing framework hover handlers. Give exactly one of uid or selector.",
7621
7642
  inputSchema: {
7622
7643
  type: "object",
7623
7644
  properties: {
7624
7645
  lease: {
7625
7646
  type: "string",
7626
- 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."
7647
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7627
7648
  },
7628
7649
  target: {
7629
7650
  type: "string",
7630
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
7651
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7631
7652
  },
7632
7653
  uid: {
7633
7654
  type: "number",
7634
- description: "CDP backendDOMNodeId of the element to hover, obtained from take_snapshot. Provide exactly one of uid or selector."
7655
+ description: "CDP backendDOMNodeId of the element to hover, from take_snapshot. Exactly one of uid or selector."
7635
7656
  },
7636
7657
  selector: {
7637
7658
  type: "string",
7638
- description: "CSS selector for the element to hover (resolved via document.querySelector). Provide exactly one of uid or selector."
7659
+ description: "CSS selector for the element to hover (document.querySelector). Exactly one of uid or selector."
7639
7660
  }
7640
7661
  },
7641
7662
  required: [],
@@ -7644,21 +7665,21 @@ var MANIFEST = [
7644
7665
  },
7645
7666
  {
7646
7667
  name: "drag",
7647
- 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.`,
7668
+ description: "Drags from a source element to a destination or by an offset. mode:'mouse' (default) dispatches synthetic mouse press/move/release; at the default steps:2 an HTML5 drop zone (dragover preventDefault) gets ZERO dragover events and refuses the drop. mode:'html5' replays real dragstart/dragEnter/dragOver/drop with the page's own dataTransfer instead — deterministic regardless of pointer path, but CHROME-ONLY (rejected with a clear error on the Firefox backend). 'from' takes uid or selector; destination is exactly one of 'to' (uid/selector/x+y) or 'by' ({dx,dy} offset — sliders, map panning, resize handles).",
7648
7669
  inputSchema: {
7649
7670
  type: "object",
7650
7671
  properties: {
7651
7672
  lease: {
7652
7673
  type: "string",
7653
- 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."
7674
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7654
7675
  },
7655
7676
  target: {
7656
7677
  type: "string",
7657
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
7678
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7658
7679
  },
7659
7680
  from: {
7660
7681
  type: "object",
7661
- description: "Source element to drag from. Provide exactly one of uid or selector.",
7682
+ description: "Source element to drag from. Exactly one of uid or selector.",
7662
7683
  properties: {
7663
7684
  uid: {
7664
7685
  type: "number",
@@ -7673,7 +7694,7 @@ var MANIFEST = [
7673
7694
  },
7674
7695
  to: {
7675
7696
  type: "object",
7676
- description: "Where the drag ends: exactly one of uid, selector, or x+y. Mutually exclusive with 'by'; exactly one of to/by is required.",
7697
+ description: "Where the drag ends: exactly one of uid, selector, or x+y. Mutually exclusive with 'by'; exactly one of to/by required.",
7677
7698
  properties: {
7678
7699
  uid: {
7679
7700
  type: "number",
@@ -7696,7 +7717,7 @@ var MANIFEST = [
7696
7717
  },
7697
7718
  by: {
7698
7719
  type: "object",
7699
- 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.",
7720
+ description: "Offset from the source element's center: at least one of dx/dy (other defaults to 0). Mutually exclusive with 'to'; exactly one of to/by required. For sliders (by:{dx:40}), map panning, resize handles.",
7700
7721
  properties: {
7701
7722
  dx: {
7702
7723
  type: "number",
@@ -7715,11 +7736,11 @@ var MANIFEST = [
7715
7736
  "mouse",
7716
7737
  "html5"
7717
7738
  ],
7718
- 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."
7739
+ description: "'mouse' (default): synthetic mouse press/move/release — at steps:2 an HTML5 drop zone sees zero dragover events and refuses the drop. 'html5': real HTML5 drag-and-drop, deterministic regardless of pointer path, CHROME-ONLY (rejected on Firefox)."
7719
7740
  },
7720
7741
  steps: {
7721
7742
  type: "number",
7722
- 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."
7743
+ description: "Number of interpolated mouse-move events between source and destination, evenly spaced, last landing on the destination. Integer 1-500, default 2. Raise for DnD libraries with a movement threshold or per-frame sampling."
7723
7744
  }
7724
7745
  },
7725
7746
  required: [
@@ -7730,41 +7751,41 @@ var MANIFEST = [
7730
7751
  },
7731
7752
  {
7732
7753
  name: "scroll",
7733
- 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.",
7754
+ description: "Dispatches a wheel/scroll event at an anchor point — element (uid/selector) or x+y, scrolled into view first if an element; omit all three for viewport center. At least one of deltaX/deltaY required: positive deltaY scrolls DOWN, positive deltaX scrolls RIGHT (wheel-event convention — easy to invert). Returns the resolved anchor {x,y} plus the delta actually dispatched.",
7734
7755
  inputSchema: {
7735
7756
  type: "object",
7736
7757
  properties: {
7737
7758
  lease: {
7738
7759
  type: "string",
7739
- 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."
7760
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7740
7761
  },
7741
7762
  target: {
7742
7763
  type: "string",
7743
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
7764
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7744
7765
  },
7745
7766
  uid: {
7746
7767
  type: "number",
7747
- 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."
7768
+ description: "CDP backendDOMNodeId of the element to scroll into view and anchor at, from take_snapshot. At most one of uid, selector, or x+y."
7748
7769
  },
7749
7770
  selector: {
7750
7771
  type: "string",
7751
- 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."
7772
+ description: "CSS selector for the element to anchor at (document.querySelector). At most one of uid, selector, or x+y."
7752
7773
  },
7753
7774
  x: {
7754
7775
  type: "number",
7755
- 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."
7776
+ description: "Absolute viewport x-coordinate to anchor at; must be given with y. At most one of uid, selector, or x+y."
7756
7777
  },
7757
7778
  y: {
7758
7779
  type: "number",
7759
- 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."
7780
+ description: "Absolute viewport y-coordinate to anchor at; must be given with x. At most one of uid, selector, or x+y."
7760
7781
  },
7761
7782
  deltaX: {
7762
7783
  type: "number",
7763
- description: "Horizontal scroll delta; positive scrolls RIGHT. At least one of deltaX/deltaY is required."
7784
+ description: "Horizontal scroll delta; positive scrolls RIGHT. At least one of deltaX/deltaY required."
7764
7785
  },
7765
7786
  deltaY: {
7766
7787
  type: "number",
7767
- description: "Vertical scroll delta; positive scrolls DOWN. At least one of deltaX/deltaY is required."
7788
+ description: "Vertical scroll delta; positive scrolls DOWN. At least one of deltaX/deltaY required."
7768
7789
  }
7769
7790
  },
7770
7791
  required: [],
@@ -7773,17 +7794,17 @@ var MANIFEST = [
7773
7794
  },
7774
7795
  {
7775
7796
  name: "dispatch_mouse",
7776
- 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.",
7797
+ description: "Dispatches one raw mouse event (move/down/up) at absolute viewport coordinates — the toolkit's lowest-level input primitive. Compose move/down/move/up calls yourself for anything click/drag's fixed sequences can't reach: canvas drag-painting, marquee/rubber-band selection, custom hit-testing widgets. Chrome-only: absent from tools/list under the Firefox backend, never present-and-throwing.",
7777
7798
  inputSchema: {
7778
7799
  type: "object",
7779
7800
  properties: {
7780
7801
  lease: {
7781
7802
  type: "string",
7782
- 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."
7803
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7783
7804
  },
7784
7805
  target: {
7785
7806
  type: "string",
7786
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
7807
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7787
7808
  },
7788
7809
  action: {
7789
7810
  type: "string",
@@ -7796,11 +7817,11 @@ var MANIFEST = [
7796
7817
  },
7797
7818
  x: {
7798
7819
  type: "number",
7799
- description: "Viewport x-coordinate. Required on every call: CDP has no notion of a 'current pointer position' to default from."
7820
+ description: "Viewport x-coordinate. Required every call — CDP has no 'current pointer position' to default from."
7800
7821
  },
7801
7822
  y: {
7802
7823
  type: "number",
7803
- description: "Viewport y-coordinate. Required on every call."
7824
+ description: "Viewport y-coordinate. Required every call."
7804
7825
  },
7805
7826
  button: {
7806
7827
  type: "string",
@@ -7813,7 +7834,7 @@ var MANIFEST = [
7813
7834
  },
7814
7835
  clickCount: {
7815
7836
  type: "number",
7816
- 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."
7837
+ description: "Click-run length for a 'down' or 'up' event (2 = second half of a double-click, 3 = triple-click). Ignored for 'move'; defaults to 1."
7817
7838
  },
7818
7839
  modifiers: {
7819
7840
  type: "array",
@@ -7839,17 +7860,17 @@ var MANIFEST = [
7839
7860
  },
7840
7861
  {
7841
7862
  name: "wait_for_download",
7842
- 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.",
7863
+ description: "Wait for a file download to finish and return it as a real file on disk: {path,suggestedFilename,bytes,url,target}, written under the artifact dir's downloads/. ORDERING RULE, not optional: capture must be ARMED BEFORE the click that starts the download — call wait_for_download{arm:true} first (returns {armed:true,downloadPath,pending}), then click, then call again to collect the file. The download-behavior override is per-connection state Chrome REVERTS the moment the arming client disconnects, and an unarmed headless Chrome denies the download outright, so one triggered before arming is lost. SIDE EFFECT, browser-global: arming redirects EVERY download in this browser (all tabs, all origins) into the toolkit's downloads dir until this server exits — they no longer land in the user's normal Downloads folder. The arm lives on a connection this server holds open (an MCP-server capability): under the one-shot CLI the connection dies with the process and nothing is captured. Chrome-only (capability 'browser.downloads'): absent from tools/list under Firefox.",
7843
7864
  inputSchema: {
7844
7865
  type: "object",
7845
7866
  properties: {
7846
7867
  lease: {
7847
7868
  type: "string",
7848
- 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."
7869
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7849
7870
  },
7850
7871
  target: {
7851
7872
  type: "string",
7852
- 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."
7873
+ description: "Names the tab for the lease check and the echoed target — a download is browser-scoped, so this does not pick which download is returned. Grammar: server instructions."
7853
7874
  },
7854
7875
  arm: {
7855
7876
  type: "boolean",
@@ -7857,7 +7878,7 @@ var MANIFEST = [
7857
7878
  },
7858
7879
  timeoutMs: {
7859
7880
  type: "number",
7860
- 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."
7881
+ 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 one still in flight."
7861
7882
  }
7862
7883
  },
7863
7884
  required: [],
@@ -7866,17 +7887,17 @@ var MANIFEST = [
7866
7887
  },
7867
7888
  {
7868
7889
  name: "grant_permissions",
7869
- 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.",
7890
+ description: "Grant browser permissions for an origin up front, so a page asking for geolocation / notifications / clipboard gets an answer instead of a prompt no agent can click. 'permissions' takes CDP PermissionType values ('geolocation','notifications','clipboardReadWrite','camera',...); an unknown name is refused by Chrome, quoting the bad value. Returns {granted,origin,target}, or {reset:true,target} for a reset-only call. Grants are keyed by ORIGIN, not by tab: every tab on that origin is affected, including ones opened later. reset:true clears this server's previous grants first (or instead, when no permissions are given) — CDP's reset is not origin-scoped, so it clears them for every origin at once. The grant lives on a connection this server holds open and Chrome DISCARDS IT when that connection closes: an MCP-server capability, so under the one-shot CLI the grant dies with the process. Chrome-only (capability 'browser.permissions'): absent from tools/list under Firefox, never present-and-throwing.",
7870
7891
  inputSchema: {
7871
7892
  type: "object",
7872
7893
  properties: {
7873
7894
  lease: {
7874
7895
  type: "string",
7875
- 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."
7896
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7876
7897
  },
7877
7898
  target: {
7878
7899
  type: "string",
7879
- 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."
7900
+ description: "Also the origin source when 'origin' is omitted. Grammar: server instructions."
7880
7901
  },
7881
7902
  permissions: {
7882
7903
  type: "array",
@@ -7900,29 +7921,29 @@ var MANIFEST = [
7900
7921
  },
7901
7922
  {
7902
7923
  name: "fill",
7903
- 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).",
7924
+ description: "Fills an element by focusing it, clearing existing content, then inserting value via Input.insertText (atomic paste-like commit, not per-character keystrokes — won't fire per-keypress handlers). Give exactly one of uid or selector.",
7904
7925
  inputSchema: {
7905
7926
  type: "object",
7906
7927
  properties: {
7907
7928
  lease: {
7908
7929
  type: "string",
7909
- 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."
7930
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7910
7931
  },
7911
7932
  target: {
7912
7933
  type: "string",
7913
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
7934
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7914
7935
  },
7915
7936
  uid: {
7916
7937
  type: "number",
7917
- description: "CDP backendDOMNodeId of the field to fill, obtained from take_snapshot. Provide exactly one of uid or selector."
7938
+ description: "CDP backendDOMNodeId of the field to fill, from take_snapshot. Exactly one of uid or selector."
7918
7939
  },
7919
7940
  selector: {
7920
7941
  type: "string",
7921
- description: "CSS selector for the field to fill (resolved via document.querySelector). Provide exactly one of uid or selector."
7942
+ description: "CSS selector for the field to fill (document.querySelector). Exactly one of uid or selector."
7922
7943
  },
7923
7944
  value: {
7924
7945
  type: "string",
7925
- description: "The text value to set; the field is cleared first so this overwrites existing content."
7946
+ description: "Text value to set; the field is cleared first, overwriting existing content."
7926
7947
  }
7927
7948
  },
7928
7949
  required: [
@@ -7933,17 +7954,17 @@ var MANIFEST = [
7933
7954
  },
7934
7955
  {
7935
7956
  name: "fill_form",
7936
- 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.",
7957
+ description: "Fills multiple form fields in one call; each is focused, cleared, then set via Input.insertText (overwrites existing content, same as fill). Each entry in the non-empty 'fields' array takes exactly one of uid or selector plus a string value.",
7937
7958
  inputSchema: {
7938
7959
  type: "object",
7939
7960
  properties: {
7940
7961
  lease: {
7941
7962
  type: "string",
7942
- 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."
7963
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7943
7964
  },
7944
7965
  target: {
7945
7966
  type: "string",
7946
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
7967
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7947
7968
  },
7948
7969
  fields: {
7949
7970
  type: "array",
@@ -7979,29 +8000,29 @@ var MANIFEST = [
7979
8000
  },
7980
8001
  {
7981
8002
  name: "type_text",
7982
- 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).",
8003
+ description: "Focuses an element and appends text via Input.insertText without clearing first — closest primitive to typing, but still atomic (not per-character keystrokes). Give exactly one of uid or selector.",
7983
8004
  inputSchema: {
7984
8005
  type: "object",
7985
8006
  properties: {
7986
8007
  lease: {
7987
8008
  type: "string",
7988
- 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."
8009
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
7989
8010
  },
7990
8011
  target: {
7991
8012
  type: "string",
7992
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
8013
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
7993
8014
  },
7994
8015
  uid: {
7995
8016
  type: "number",
7996
- description: "CDP backendDOMNodeId of the element to type into, obtained from take_snapshot. Provide exactly one of uid or selector."
8017
+ description: "CDP backendDOMNodeId of the element to type into, from take_snapshot. Exactly one of uid or selector."
7997
8018
  },
7998
8019
  selector: {
7999
8020
  type: "string",
8000
- description: "CSS selector for the element to type into (resolved via document.querySelector). Provide exactly one of uid or selector."
8021
+ description: "CSS selector for the element to type into (document.querySelector). Exactly one of uid or selector."
8001
8022
  },
8002
8023
  text: {
8003
8024
  type: "string",
8004
- description: "The text to insert; appended to existing content rather than overwriting it."
8025
+ description: "Text to insert; appended to existing content rather than overwriting it."
8005
8026
  }
8006
8027
  },
8007
8028
  required: [
@@ -8012,25 +8033,25 @@ var MANIFEST = [
8012
8033
  },
8013
8034
  {
8014
8035
  name: "press_key",
8015
- 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).",
8036
+ description: "Dispatches a keyDown/keyUp pair for one key with optional modifiers. 'key' is a named key (Enter, Tab, Escape, ArrowDown, Backspace, etc.) or a single printable character — the named-key table is curated, with no F-keys, numpad, or IME support.",
8016
8037
  inputSchema: {
8017
8038
  type: "object",
8018
8039
  properties: {
8019
8040
  lease: {
8020
8041
  type: "string",
8021
- 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."
8042
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8022
8043
  },
8023
8044
  target: {
8024
8045
  type: "string",
8025
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
8046
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
8026
8047
  },
8027
8048
  key: {
8028
8049
  type: "string",
8029
- description: "Key to press: a named key like 'Enter', 'Tab', 'Escape', 'ArrowDown', 'Backspace', or a single printable character. Required."
8050
+ description: "Key to press: a named key (Enter, Tab, Escape, ArrowDown, Backspace, ...) or a single printable character."
8030
8051
  },
8031
8052
  modifiers: {
8032
8053
  type: "array",
8033
- description: "Optional modifier names held during the press: 'Control'/'Ctrl', 'Shift', 'Alt', 'Meta'/'Cmd'.",
8054
+ description: "Modifier names held during the press: 'Control'/'Ctrl', 'Shift', 'Alt', 'Meta'/'Cmd'.",
8034
8055
  items: {
8035
8056
  type: "string"
8036
8057
  }
@@ -8044,35 +8065,32 @@ var MANIFEST = [
8044
8065
  },
8045
8066
  {
8046
8067
  name: "upload_file",
8047
- 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.",
8068
+ description: "Attaches one or more files to an <input type=file> element via DOM.setFileInputFiles. Give exactly one of uid or selector for the input; 'files' is an array of absolute path(s) — wrap a single path in an array too.",
8048
8069
  inputSchema: {
8049
8070
  type: "object",
8050
8071
  properties: {
8051
8072
  lease: {
8052
8073
  type: "string",
8053
- 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."
8074
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8054
8075
  },
8055
8076
  target: {
8056
8077
  type: "string",
8057
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
8078
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
8058
8079
  },
8059
8080
  uid: {
8060
8081
  type: "number",
8061
- description: "CDP backendDOMNodeId of the file input element, obtained from take_snapshot. Provide exactly one of uid or selector."
8082
+ description: "CDP backendDOMNodeId of the file input element, from take_snapshot. Exactly one of uid or selector."
8062
8083
  },
8063
8084
  selector: {
8064
8085
  type: "string",
8065
- description: "CSS selector for the file input element (resolved via document.querySelector). Provide exactly one of uid or selector."
8086
+ description: "CSS selector for the file input element (document.querySelector). Exactly one of uid or selector."
8066
8087
  },
8067
8088
  files: {
8068
- type: [
8069
- "string",
8070
- "array"
8071
- ],
8089
+ type: "array",
8072
8090
  items: {
8073
8091
  type: "string"
8074
8092
  },
8075
- 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."
8093
+ description: 'Absolute path(s) to attach to the <input type=file>, as an array — wrap a single path too, e.g. ["/tmp/a.pdf"]. Array-only because some model APIs (Google Gemini function calling) reject union-typed parameters.'
8076
8094
  }
8077
8095
  },
8078
8096
  required: [
@@ -8083,17 +8101,17 @@ var MANIFEST = [
8083
8101
  },
8084
8102
  {
8085
8103
  name: "take_screenshot",
8086
- description: "Capture the viewport (default), the full scrollable page (fullPage), or a single element (uid or selector, exactly one and mutually exclusive) via raw CDP Page.captureScreenshot — as one image when it fits, or as vertical bands stitched losslessly into one PNG when it does not (see tile). Writes a PNG/JPEG under /tmp/cdp-toolkit (override with savePath; its directory is created for you) and returns {path,bytes,format,target,scale} plus width/height MEASURED from the encoded bytes, which are omitted rather than guessed when the bytes cannot be decoded; renderSize/renderRestored (+renderRestoreError) accompany a renderWidth/renderHeight capture, tiled/bands a banded one. Raw base64 is only included when returnBase64 is set, and is refused on a banded capture. quality applies to jpeg only. Every capture costs one Page.getLayoutMetrics round trip, because Chrome does not refuse an oversized capture politely: past 16384 device px per side Page.captureScreenshot can simply never answer, and captureBeyondViewport leaves the tab resized to the clip, so the size is checked before the capture rather than after.",
8104
+ description: "Captures the viewport (default), the full scrollable page (fullPage), or one element (uid or selector, mutually exclusive) via CDP Page.captureScreenshot. Past 16384 device px per side Chrome can hang rather than refuse, so size is checked first via Page.getLayoutMetrics; an oversized capture is auto-tiled into vertical bands stitched losslessly into one PNG (see tile) instead of wedging the tab. Writes PNG/JPEG to /tmp/cdp-toolkit (override savePath, dir auto-created); returns {path,bytes,format,target,scale} plus width/height measured from the encoded bytes (omitted if undecodable). renderSize/renderRestored(+renderRestoreError) accompany a renderWidth/renderHeight capture, tiled/bands a banded one. returnBase64 adds raw bytes to the result but is refused on a banded capture. quality applies to jpeg only.",
8087
8105
  inputSchema: {
8088
8106
  type: "object",
8089
8107
  properties: {
8090
8108
  lease: {
8091
8109
  type: "string",
8092
- 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."
8110
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8093
8111
  },
8094
8112
  target: {
8095
8113
  type: "string",
8096
- 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)."
8114
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
8097
8115
  },
8098
8116
  format: {
8099
8117
  type: "string",
@@ -8101,35 +8119,35 @@ var MANIFEST = [
8101
8119
  "png",
8102
8120
  "jpeg"
8103
8121
  ],
8104
- description: "Image format. Defaults to png. quality applies only to jpeg."
8122
+ description: "Image format, default png. quality applies only to jpeg."
8105
8123
  },
8106
8124
  quality: {
8107
8125
  type: "number",
8108
- description: "JPEG quality 0-100 (default 80). Ignored for png."
8126
+ description: "JPEG quality 0-100, default 80; ignored for png."
8109
8127
  },
8110
8128
  fullPage: {
8111
8129
  type: "boolean",
8112
- description: "Capture the full scrollable content height computed from Page.getLayoutMetrics, not just the viewport."
8130
+ description: "Capture the full scrollable height (via Page.getLayoutMetrics), not just the viewport."
8113
8131
  },
8114
8132
  scale: {
8115
8133
  type: "number",
8116
- description: "Output-pixel multiplier for this one capture: greater than 0, at most 8, default 1. Output px = ceil(css px x scale x devicePixelRatio), so on a ratio-2 display scale 3 is 6x the CSS size; the page is never told anything changed (devicePixelRatio and innerWidth/innerHeight read identically before and after). Chrome only (capability screenshot.scale) — WebDriver BiDi's browsingContext.captureScreenshot has no scale parameter, so under Firefox call emulate with deviceScaleFactor first and capture at scale 1. A projection past Chrome's 16384 device px per side is refused before the browser is dialled, naming the largest scale that fits."
8134
+ description: "Output-pixel multiplier for this capture only (0<scale<=8, default 1): output px = ceil(css px x scale x devicePixelRatio); the page is never told anything changed. Chrome only (screenshot.scale) — Firefox BiDi has no scale param, use emulate{deviceScaleFactor} then scale:1. A projection over 16384 device px/side is refused up front, naming the largest scale that fits."
8117
8135
  },
8118
8136
  renderWidth: {
8119
8137
  type: "number",
8120
- description: "Emulate this viewport width, in CSS px (integer, 1-16384), for the length of ONE capture, then put the previous viewport back. REQUIRED together with renderHeight. Not the same knob as scale: scale re-renders the same layout at more pixels, this changes what the page BELIEVES, so media queries flip and the document re-lays-out — which is how you capture a responsive page at 1920x1080 from a tab that is not that size. Declared by BOTH backends (capability screenshot.renderSize). The restore can only put back an override this toolkit itself applied: one set by the DevTools UI, another client, or a pre-1.9.2 build is invisible and gets reset to the real device. The result reports renderSize and renderRestored; renderRestored:false means the tab is STILL emulated and you have to fix it with emulate."
8138
+ description: "Emulates this viewport width (CSS px, 1-16384) for one capture, then restores it. Required with renderHeight. Unlike scale, this changes what the page believes (media queries re-flow) — e.g. capture a responsive page at 1920x1080 from a differently-sized tab. Restore only works for an override this toolkit itself set; check result.renderRestored (false = still emulated, fix via emulate). Works on both backends (capability screenshot.renderSize)."
8121
8139
  },
8122
8140
  renderHeight: {
8123
8141
  type: "number",
8124
- description: "Emulate this viewport height, in CSS px (integer, 1-16384), for the length of one capture. Required together with renderWidth — a viewport is two numbers, and honouring one while inventing the other would render at a size you never named and never see in the result. Note a narrow renderWidth reflows most documents TALLER, which is the usual way a render-size capture trips the 16384-device-px encode limit."
8142
+ description: "Emulates this viewport height (CSS px, 1-16384) for one capture. Required with renderWidth — a viewport is two numbers. A narrow renderWidth often reflows pages TALLER, which is the usual way a render-size capture trips the 16384px encode limit."
8125
8143
  },
8126
8144
  tile: {
8127
8145
  type: "boolean",
8128
- description: "Whether this capture may be taken as vertical bands and stitched into one lossless PNG. Three-valued: omitted = AUTO (one shot when the projected output fits under Chrome's 16384 device px per side, bands when it does not — this is why a whole-page capture of a very long page now returns a file instead of hanging and wedging the tab); false = never band, refuse instead (the pre-1.9.2 behaviour); true = always band, even when one shot would have fitted. Only true costs a capability (screenshot.tile, Chrome only; Firefox was never driven for the band arithmetic). A banded capture is PNG-only and cannot also returnBase64, and only HEIGHT is tiled — a projected WIDTH past the limit is refused, not split, because bands are stitched by concatenating scanlines. Bands are a faithful crop of one document render: fixed and sticky elements do not repeat per band and seams are pixel-exact, but content the page only loads on real scroll (lazy images, virtualized lists) renders blank in bands the real viewport never reached, which is a property of the page and not of the stitch."
8146
+ description: "Whether to allow vertical-band stitching: omitted=AUTO (band only if a single shot wouldn't fit), false=never band (refuse instead), true=always band (Chrome-only capability). Banded output is PNG-only, can't returnBase64, and only bands on HEIGHT (oversized WIDTH is refused, not split). Bands are a faithful crop, but lazy/virtualized content the real viewport never scrolled to renders blank."
8129
8147
  },
8130
8148
  uid: {
8131
8149
  type: "number",
8132
- description: "Element to clip to: a CDP backendDOMNodeId obtained from take_snapshot. Mutually exclusive with selector."
8150
+ description: "Element to clip to: a backendDOMNodeId from take_snapshot. Mutually exclusive with selector."
8133
8151
  },
8134
8152
  selector: {
8135
8153
  type: "string",
@@ -8137,11 +8155,11 @@ var MANIFEST = [
8137
8155
  },
8138
8156
  savePath: {
8139
8157
  type: "string",
8140
- description: "Override the output file path. Default: /tmp/cdp-toolkit/screenshot-<id>-<stamp>.<ext>, where the stamp is the capture's START (a banded capture writes as it goes and has no finished image to name a file after). The destination directory is created from this path's own dirname, so a savePath outside /tmp/cdp-toolkit works."
8158
+ description: "Override the output path (default /tmp/cdp-toolkit/screenshot-<id>-<stamp>.<ext>, stamped at capture START). Directory is created from this path's dirname."
8141
8159
  },
8142
8160
  returnBase64: {
8143
8161
  type: "boolean",
8144
- description: "Also return the raw base64 image bytes in the result, in addition to writing the file. Refused on a banded capture (see tile): a stitched image runs to hundreds of megabytes and base64 inflates it by a third, into the caller's response — read the file at the returned path instead."
8162
+ description: "Also return raw base64 bytes in the result. Refused on a banded capture (see tile) — a stitched image can run to hundreds of MB; read the file at the returned path instead."
8145
8163
  }
8146
8164
  },
8147
8165
  required: [],
@@ -8150,41 +8168,41 @@ var MANIFEST = [
8150
8168
  },
8151
8169
  {
8152
8170
  name: "emulate",
8153
- 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); as of 1.9.2 that genuinely clears a device-metrics override set by a DIFFERENT process (Emulation.clearDeviceMetricsOverride is a no-op unless the clearing connection also set the override, so the driver re-asserts the tab's current size on its own connection first, then clears — and throws rather than answering cleared:true if it cannot verify that). 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.",
8171
+ description: "Applies any subset of Chrome emulation overrides in one call: device metrics (width+height together, +deviceScaleFactor/mobile), userAgent, cpuThrottlingRate(>=1), media type+features, networkConditions. Device-metrics overrides PERSIST on the target until cleared or the renderer navigates/reloads; every other override is session-scoped and resets when this call's connection closes. clearOverrides:true resets everything (ignoring other fields) and, as of 1.9.2, genuinely clears a device-metrics override set by a DIFFERENT process — Chrome's clearDeviceMetricsOverride is normally a no-op unless the clearing connection also set the override, so the driver re-asserts the tab's current size first, then clears, throwing rather than reporting cleared:true if it can't verify.",
8154
8172
  inputSchema: {
8155
8173
  type: "object",
8156
8174
  properties: {
8157
8175
  lease: {
8158
8176
  type: "string",
8159
- 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."
8177
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8160
8178
  },
8161
8179
  target: {
8162
8180
  type: "string",
8163
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
8181
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
8164
8182
  },
8165
8183
  width: {
8166
8184
  type: "number",
8167
- description: "Device-metrics viewport width in CSS pixels. Must be supplied together with height."
8185
+ description: "Device-metrics viewport width in CSS px. Must be paired with height."
8168
8186
  },
8169
8187
  height: {
8170
8188
  type: "number",
8171
- description: "Device-metrics viewport height in CSS pixels. Must be supplied together with width."
8189
+ description: "Device-metrics viewport height in CSS px. Must be paired with width."
8172
8190
  },
8173
8191
  deviceScaleFactor: {
8174
8192
  type: "number",
8175
- description: "Device pixel ratio (DPR) for the device-metrics override; 0 uses the platform default."
8193
+ description: "Device pixel ratio for the device-metrics override; 0 = platform default."
8176
8194
  },
8177
8195
  mobile: {
8178
8196
  type: "boolean",
8179
- description: "Whether to emulate a mobile device (affects viewport meta handling, scrollbars, etc.) for the device-metrics override."
8197
+ description: "Emulate a mobile device (viewport meta, scrollbars, etc.) for the device-metrics override."
8180
8198
  },
8181
8199
  userAgent: {
8182
8200
  type: "string",
8183
- description: "User-Agent string to override via Emulation.setUserAgentOverride."
8201
+ description: "User-Agent string override (Emulation.setUserAgentOverride)."
8184
8202
  },
8185
8203
  cpuThrottlingRate: {
8186
8204
  type: "number",
8187
- description: "CPU throttling multiplier: 1 = no throttle, 2 = 2x slower, etc. Must be >= 1."
8205
+ description: "CPU throttling multiplier: 1=none, 2=2x slower, etc. Must be >=1."
8188
8206
  },
8189
8207
  media: {
8190
8208
  type: "string",
@@ -8192,7 +8210,7 @@ var MANIFEST = [
8192
8210
  },
8193
8211
  mediaFeatures: {
8194
8212
  type: "array",
8195
- description: "Emulated media features, e.g. [{ name: 'prefers-color-scheme', value: 'dark' }].",
8213
+ description: "Emulated media features, e.g. [{name:'prefers-color-scheme', value:'dark'}].",
8196
8214
  items: {
8197
8215
  type: "object",
8198
8216
  properties: {
@@ -8214,7 +8232,7 @@ var MANIFEST = [
8214
8232
  },
8215
8233
  networkConditions: {
8216
8234
  type: "object",
8217
- description: "Network condition overrides applied via Network.emulateNetworkConditions.",
8235
+ description: "Network overrides applied via Network.emulateNetworkConditions.",
8218
8236
  properties: {
8219
8237
  offline: {
8220
8238
  type: "boolean",
@@ -8241,7 +8259,7 @@ var MANIFEST = [
8241
8259
  },
8242
8260
  clearOverrides: {
8243
8261
  type: "boolean",
8244
- description: "Reset every override (device metrics, UA, CPU, media, network) to the browser default; ignores all other fields when true."
8262
+ description: "Reset every override (metrics, UA, CPU, media, network) to browser default; ignores all other fields when true."
8245
8263
  }
8246
8264
  },
8247
8265
  required: [],
@@ -8250,33 +8268,33 @@ var MANIFEST = [
8250
8268
  },
8251
8269
  {
8252
8270
  name: "resize_page",
8253
- 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.",
8271
+ description: "Sets the page's device-metrics width/height (the narrow case of emulate), optionally deviceScaleFactor/mobile, then verifies by reading back window.innerWidth/innerHeight after applying. Requires positive width and height. The override PERSISTS on the target until cleared (emulate{clearOverrides:true}) or the renderer navigates/reloads.",
8254
8272
  inputSchema: {
8255
8273
  type: "object",
8256
8274
  properties: {
8257
8275
  lease: {
8258
8276
  type: "string",
8259
- 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."
8277
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8260
8278
  },
8261
8279
  target: {
8262
8280
  type: "string",
8263
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
8281
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
8264
8282
  },
8265
8283
  width: {
8266
8284
  type: "number",
8267
- description: "Viewport width in CSS pixels (must be positive)."
8285
+ description: "Viewport width in CSS px (required, must be positive)."
8268
8286
  },
8269
8287
  height: {
8270
8288
  type: "number",
8271
- description: "Viewport height in CSS pixels (must be positive)."
8289
+ description: "Viewport height in CSS px (required, must be positive)."
8272
8290
  },
8273
8291
  deviceScaleFactor: {
8274
8292
  type: "number",
8275
- description: "Device pixel ratio (DPR); 0 uses the platform default."
8293
+ description: "Device pixel ratio; 0 = platform default."
8276
8294
  },
8277
8295
  mobile: {
8278
8296
  type: "boolean",
8279
- description: "Whether to emulate a mobile device for the device-metrics override."
8297
+ description: "Emulate a mobile device for the device-metrics override."
8280
8298
  }
8281
8299
  },
8282
8300
  required: [
@@ -8288,17 +8306,17 @@ var MANIFEST = [
8288
8306
  },
8289
8307
  {
8290
8308
  name: "handle_dialog",
8291
- 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.",
8309
+ description: "Wait for the next JavaScript dialog (alert/confirm/prompt/beforeunload) on a page and respond via Page.handleJavaScriptDialog, accepting or dismissing it. Default mode resolves with the first handled dialog or throws on timeout; set autoMs to handle every dialog opening during a fixed window and resolve with the list. Trigger the dialog out-of-band (e.g. click a button) — a blocking dialog freezes the renderer, so it cannot be triggered inline.",
8292
8310
  inputSchema: {
8293
8311
  type: "object",
8294
8312
  properties: {
8295
8313
  lease: {
8296
8314
  type: "string",
8297
- 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."
8315
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8298
8316
  },
8299
8317
  target: {
8300
8318
  type: "string",
8301
- 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>."
8319
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
8302
8320
  },
8303
8321
  accept: {
8304
8322
  type: "boolean",
@@ -8310,7 +8328,7 @@ var MANIFEST = [
8310
8328
  },
8311
8329
  timeoutMs: {
8312
8330
  type: "number",
8313
- description: "How long to wait for the next dialog in milliseconds (default 15000)."
8331
+ description: "How long to wait for the next dialog, in milliseconds (default 15000)."
8314
8332
  },
8315
8333
  autoMs: {
8316
8334
  type: "number",
@@ -8325,29 +8343,29 @@ var MANIFEST = [
8325
8343
  },
8326
8344
  {
8327
8345
  name: "list_console_messages",
8328
- 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. SERVICE WORKERS (Chrome only, Capability 'worker.targets'): pass target 'worker:<extension-id>' to watch an MV3 extension's BACKGROUND SERVICE WORKER. The outbound request that worker makes to your backend is recorded from CDP's Network domain on the worker's own session, which observes what the code ACTUALLY SENT and so needs neither of the two tricks a caller reaches for first. Both of those fail for ordinary JavaScript reasons rather than service-worker ones: a value bound at module top level is not visible from evaluate_script's global scope (plain lexical scoping, exactly the same in a page), and assigning self.fetch cannot rebind a fetch reference the module already captured. A worker's console.log arrives as Runtime.consoleAPICalled on its own session. A worker capture has no reload to drive it: reload:true means 'listen for durationMs while the worker runs', so trigger the worker's work (another tool call, an extension message, an alarm) during the window; a worker woken by the call has already run its top-level code by the time the recorder attaches, so a request it makes at startup can be missed. SIDE EFFECT, deliberate and documented: the recording holds a CDP session on the worker, and that KEEPS THE WORKER ALIVE for as long as the capture runs — an MV3 worker is otherwise idle-evicted within seconds — and Chrome resumes evicting it once the capture stops.",
8346
+ description: "Read console output (logs, warnings, exceptions) captured for the target. Reads the existing shared buffer by default (empty if no capture ran); reload:true reloads and records a fresh capture (console+network together, so a network reload never wipes console history). WORKER capture (Chrome, Capability 'worker.targets'): a worker: target records an MV3 background service worker -- its console.log arrives as Runtime.consoleAPICalled, its outbound requests from CDP's Network domain on the worker's own session -- so the two tricks callers try first fail for plain JS reasons, not worker ones: a value bound at module top level is not visible from evaluate_script's global scope, and assigning self.fetch cannot rebind a fetch the module already captured. A worker has no reload: reload:true means 'listen for durationMs while it runs', so trigger its work (tool call, message, alarm) during the window; a worker woken by the call already ran its top-level code, so a startup message can be missed. SIDE EFFECT: the CDP session KEEPS THE WORKER ALIVE for the capture (an idle MV3 worker is evicted in seconds); Chrome resumes evicting after.",
8329
8347
  inputSchema: {
8330
8348
  type: "object",
8331
8349
  properties: {
8332
8350
  lease: {
8333
8351
  type: "string",
8334
- 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."
8352
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8335
8353
  },
8336
8354
  target: {
8337
8355
  type: "string",
8338
- description: "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>' | 'label:<name>' | '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). The worker: arm is CHROME-ONLY (Capability 'worker.targets'), is refused on Firefox, and a bare worker target id works too."
8356
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', '<targetId>'; plus 'worker:<substring>' to reach a service/shared worker (e.g. an MV3 extension background worker). The worker: arm is CHROME-ONLY (Capability 'worker.targets'). Grammar: see server instructions."
8339
8357
  },
8340
8358
  reload: {
8341
8359
  type: "boolean",
8342
- description: "Record fresh by reloading the page and capturing for a window. Default false (read the existing buffer). With a worker: target there is nothing to reload: the window records for durationMs while the worker runs, and the session it holds keeps that worker from being idle-evicted until the capture stops."
8360
+ description: "Record fresh by reloading the page and capturing a window. Default false (read existing buffer). With a worker: target nothing reloads -- records for durationMs while the worker runs and keeps it alive until the capture stops."
8343
8361
  },
8344
8362
  durationMs: {
8345
8363
  type: "number",
8346
- description: "Capture window for reload mode, in milliseconds. Default 2500."
8364
+ description: "Capture window for reload mode, in ms. Default 2500."
8347
8365
  },
8348
8366
  wake: {
8349
8367
  type: "boolean",
8350
- description: "Worker targets only, and only when a capture is being started (reload:true). Default true: an MV3 extension service worker is idle-evicted after seconds of inactivity and then exists in NO target listing, so the capture 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. Rejected rather than ignored on a page target, on a bare target id (Chrome re-mints a worker's target id when it restarts, so only the url-substring form can name a worker that is not running), and on a read-only call (the buffer is keyed by target id, so a woken worker's buffer would be empty)."
8368
+ description: "Worker targets only, when starting a capture. Default true: an idle-evicted MV3 service worker exists in no target listing, so it is started first (ServiceWorker.startWorker) and re-confirmed; false fails fast. Rejected on a page target, a bare target id, or a read-only call. See server instructions."
8351
8369
  }
8352
8370
  },
8353
8371
  required: [],
@@ -8356,17 +8374,17 @@ var MANIFEST = [
8356
8374
  },
8357
8375
  {
8358
8376
  name: "get_console_message",
8359
- 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.",
8377
+ description: "Return one console entry by zero-based index from the target's existing console buffer. Throws if the index is out of range; run list_console_messages (optionally reload:true) first to populate the buffer.",
8360
8378
  inputSchema: {
8361
8379
  type: "object",
8362
8380
  properties: {
8363
8381
  lease: {
8364
8382
  type: "string",
8365
- 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."
8383
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8366
8384
  },
8367
8385
  target: {
8368
8386
  type: "string",
8369
- description: "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>' | 'label:<name>'."
8387
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
8370
8388
  },
8371
8389
  index: {
8372
8390
  type: "number",
@@ -8379,33 +8397,33 @@ var MANIFEST = [
8379
8397
  },
8380
8398
  {
8381
8399
  name: "list_network_requests",
8382
- 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. SERVICE WORKERS (Chrome only, Capability 'worker.targets'): pass target 'worker:<extension-id>' to watch an MV3 extension's BACKGROUND SERVICE WORKER. The outbound request that worker makes to your backend is recorded from CDP's Network domain on the worker's own session, which observes what the code ACTUALLY SENT and so needs neither of the two tricks a caller reaches for first. Both of those fail for ordinary JavaScript reasons rather than service-worker ones: a value bound at module top level is not visible from evaluate_script's global scope (plain lexical scoping, exactly the same in a page), and assigning self.fetch cannot rebind a fetch reference the module already captured. A worker capture has no reload to drive it: reload:true means 'listen for durationMs while the worker runs', so trigger the worker's work (another tool call, an extension message, an alarm) during the window; a worker woken by the call has already run its top-level code by the time the recorder attaches, so a request it makes at startup can be missed. SIDE EFFECT, deliberate and documented: the recording holds a CDP session on the worker, and that KEEPS THE WORKER ALIVE for as long as the capture runs — an MV3 worker is otherwise idle-evicted within seconds — and Chrome resumes evicting it once the capture stops.",
8400
+ description: "Return correlated network rows (one per requestId; status/headers/state) for the target. Reads the existing buffer by default; reload:true records a fresh both-domains capture window. filterUrl keeps only URLs containing a substring. WORKER capture (Chrome, Capability 'worker.targets'): a worker: target records an MV3 background service worker's outbound requests from CDP's Network domain on the worker's own session -- what the code ACTUALLY SENT -- so the two tricks callers try first fail for plain JS reasons, not worker ones: a value bound at module top level is not visible from evaluate_script's global scope, and assigning self.fetch cannot rebind a fetch the module already captured. A worker has no reload: reload:true means 'listen for durationMs while it runs', so trigger its work (tool call, message, alarm) during the window; a worker woken by the call already ran its top-level code, so a startup request can be missed. SIDE EFFECT: the CDP session KEEPS THE WORKER ALIVE for the capture (an idle MV3 worker is evicted in seconds); Chrome resumes evicting after.",
8383
8401
  inputSchema: {
8384
8402
  type: "object",
8385
8403
  properties: {
8386
8404
  lease: {
8387
8405
  type: "string",
8388
- 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."
8406
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8389
8407
  },
8390
8408
  target: {
8391
8409
  type: "string",
8392
- description: "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>' | 'label:<name>' | '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). The worker: arm is CHROME-ONLY (Capability 'worker.targets'), is refused on Firefox, and a bare worker target id works too."
8410
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', '<targetId>'; plus 'worker:<substring>' to reach a service/shared worker (e.g. an MV3 extension background worker). The worker: arm is CHROME-ONLY (Capability 'worker.targets'). Grammar: see server instructions."
8393
8411
  },
8394
8412
  reload: {
8395
8413
  type: "boolean",
8396
- description: "Record fresh by reloading the page and capturing for a window. Default false (read the existing buffer). With a worker: target there is nothing to reload: the window records for durationMs while the worker runs, and the session it holds keeps that worker from being idle-evicted until the capture stops."
8414
+ description: "Record fresh by reloading the page and capturing a window. Default false (read existing buffer). With a worker: target nothing reloads -- records for durationMs while the worker runs and keeps it alive until the capture stops."
8397
8415
  },
8398
8416
  durationMs: {
8399
8417
  type: "number",
8400
- description: "Capture window for reload mode, in milliseconds. Default 2500."
8418
+ description: "Capture window for reload mode, in ms. Default 2500."
8401
8419
  },
8402
8420
  filterUrl: {
8403
8421
  type: "string",
8404
- description: "Only return requests whose URL contains this substring."
8422
+ description: "Return only requests whose URL contains this substring."
8405
8423
  },
8406
8424
  wake: {
8407
8425
  type: "boolean",
8408
- description: "Worker targets only, and only when a capture is being started (reload:true). Default true: an MV3 extension service worker is idle-evicted after seconds of inactivity and then exists in NO target listing, so the capture 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. Rejected rather than ignored on a page target, on a bare target id (Chrome re-mints a worker's target id when it restarts, so only the url-substring form can name a worker that is not running), and on a read-only call (the buffer is keyed by target id, so a woken worker's buffer would be empty)."
8426
+ description: "Worker targets only, when starting a capture. Default true: an idle-evicted MV3 service worker exists in no target listing, so it is started first (ServiceWorker.startWorker) and re-confirmed; false fails fast. Rejected on a page target, a bare target id, or a read-only call. See server instructions."
8409
8427
  }
8410
8428
  },
8411
8429
  required: [],
@@ -8414,21 +8432,21 @@ var MANIFEST = [
8414
8432
  },
8415
8433
  {
8416
8434
  name: "get_network_request",
8417
- 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 capture (a reload for a page, a listen window for a worker) and is matched by url ONLY (a fresh capture re-mints requestIds, so a carried-over requestId cannot fetch a body, so it returns metadata plus bodyUnavailableReason). SERVICE WORKERS (Chrome only, Capability 'worker.targets'): pass target 'worker:<extension-id>' to watch an MV3 extension's BACKGROUND SERVICE WORKER. The outbound request that worker makes to your backend is recorded from CDP's Network domain on the worker's own session, which observes what the code ACTUALLY SENT and so needs neither of the two tricks a caller reaches for first. Both of those fail for ordinary JavaScript reasons rather than service-worker ones: a value bound at module top level is not visible from evaluate_script's global scope (plain lexical scoping, exactly the same in a page), and assigning self.fetch cannot rebind a fetch reference the module already captured. A worker capture has no reload to drive it: reload:true means 'listen for durationMs while the worker runs', so trigger the worker's work (another tool call, an extension message, an alarm) during the window; a worker woken by the call has already run its top-level code by the time the recorder attaches, so a request it makes at startup can be missed. SIDE EFFECT, deliberate and documented: the recording holds a CDP session on the worker, and that KEEPS THE WORKER ALIVE for as long as the capture runs — an MV3 worker is otherwise idle-evicted within seconds — and Chrome resumes evicting it once the capture stops.",
8435
+ description: "Return one network request (matched by exact requestId, else url substring) with status/headers. Requires requestId or url (throws otherwise). includeBody:true drives a fresh capture (page reload, or worker listen window) matched by url ONLY -- a fresh capture re-mints requestIds, so a carried-over requestId returns metadata plus bodyUnavailableReason. WORKER capture (Chrome, Capability 'worker.targets'): a worker: target records an MV3 background service worker's outbound requests from CDP's Network domain on the worker's own session -- what the code ACTUALLY SENT -- so the two tricks callers try first fail for plain JS reasons, not worker ones: a value bound at module top level is not visible from evaluate_script's global scope, and assigning self.fetch cannot rebind a fetch the module already captured. A worker has no reload: reload means 'listen for durationMs while it runs', so trigger its work (tool call, message, alarm) during the window; a worker woken by the call already ran its top-level code, so a startup request can be missed. SIDE EFFECT: the CDP session KEEPS THE WORKER ALIVE for the capture (an idle MV3 worker is evicted in seconds); Chrome resumes evicting after.",
8418
8436
  inputSchema: {
8419
8437
  type: "object",
8420
8438
  properties: {
8421
8439
  lease: {
8422
8440
  type: "string",
8423
- 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."
8441
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8424
8442
  },
8425
8443
  target: {
8426
8444
  type: "string",
8427
- description: "Target page selector: 'active' (default) | '<targetId>' | 'index:N' | 'url:<substring>' | 'title:<substring>' | 'label:<name>' | '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). The worker: arm is CHROME-ONLY (Capability 'worker.targets'), is refused on Firefox, and a bare worker target id works too."
8445
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', '<targetId>'; plus 'worker:<substring>' to reach a service/shared worker (e.g. an MV3 extension background worker). The worker: arm is CHROME-ONLY (Capability 'worker.targets'). Grammar: see server instructions."
8428
8446
  },
8429
8447
  requestId: {
8430
8448
  type: "string",
8431
- description: "Match by exact requestId (metadata only, cannot fetch a body, since reload re-mints requestIds)."
8449
+ description: "Match by exact requestId (metadata only; cannot fetch a body, since a reload re-mints requestIds)."
8432
8450
  },
8433
8451
  url: {
8434
8452
  type: "string",
@@ -8436,15 +8454,15 @@ var MANIFEST = [
8436
8454
  },
8437
8455
  includeBody: {
8438
8456
  type: "boolean",
8439
- description: "Also fetch the response body; drives a fresh reload capture and must be used with the `url` selector."
8457
+ description: "Also fetch the response body; drives a fresh capture and requires the url selector."
8440
8458
  },
8441
8459
  durationMs: {
8442
8460
  type: "number",
8443
- description: "Capture window for the reload-driven body fetch, in milliseconds. Default 2500."
8461
+ description: "Capture window for the body-fetch reload, in ms. Default 2500."
8444
8462
  },
8445
8463
  wake: {
8446
8464
  type: "boolean",
8447
- description: "Worker targets only, and only when a capture is being started (includeBody together with url). Default true: an MV3 extension service worker is idle-evicted after seconds of inactivity and then exists in NO target listing, so the capture 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. Rejected rather than ignored on a page target, on a bare target id (Chrome re-mints a worker's target id when it restarts, so only the url-substring form can name a worker that is not running), and on a read-only call (the buffer is keyed by target id, so a woken worker's buffer would be empty)."
8465
+ description: "Worker targets only, when starting a capture. Default true: an idle-evicted MV3 service worker exists in no target listing, so it is started first (ServiceWorker.startWorker) and re-confirmed; false fails fast. Rejected on a page target, a bare target id, or a read-only call. See server instructions."
8448
8466
  }
8449
8467
  },
8450
8468
  required: [],
@@ -8453,24 +8471,24 @@ var MANIFEST = [
8453
8471
  },
8454
8472
  {
8455
8473
  name: "performance_start_trace",
8456
- 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.",
8474
+ description: "Starts a CDP trace recording on the target and holds the recording connection in-process; you MUST call performance_stop_trace from the SAME PROCESS to end it, or use performance_trace instead for a robust cross-call trace. Throws if a trace is already in progress for this target.",
8457
8475
  inputSchema: {
8458
8476
  type: "object",
8459
8477
  properties: {
8460
8478
  lease: {
8461
8479
  type: "string",
8462
- 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."
8480
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8463
8481
  },
8464
8482
  target: {
8465
8483
  type: "string",
8466
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
8484
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
8467
8485
  },
8468
8486
  categories: {
8469
8487
  type: "array",
8470
8488
  items: {
8471
8489
  type: "string"
8472
8490
  },
8473
- description: "Trace categories to include. Defaults to the timeline + user-timing + loading + disabled-by-default timeline tracks that carry LCP/LayoutShift/RunTask."
8491
+ description: "Trace categories to record. Defaults to timeline + user-timing + loading + disabled-by-default timeline tracks carrying LCP/LayoutShift/RunTask."
8474
8492
  }
8475
8493
  },
8476
8494
  required: [],
@@ -8479,17 +8497,17 @@ var MANIFEST = [
8479
8497
  },
8480
8498
  {
8481
8499
  name: "performance_stop_trace",
8482
- 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.",
8500
+ description: "Stops the in-process trace started by performance_start_trace and writes it as JSON under /tmp/cdp-toolkit, returning {path,bytes,events,metrics}. Throws if no live trace exists in THIS process (e.g. start ran in a different process) — use performance_trace instead. The target arg is accepted only for API symmetry; at most one trace is ever live per process.",
8483
8501
  inputSchema: {
8484
8502
  type: "object",
8485
8503
  properties: {
8486
8504
  lease: {
8487
8505
  type: "string",
8488
- 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."
8506
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8489
8507
  },
8490
8508
  target: {
8491
8509
  type: "string",
8492
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
8510
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
8493
8511
  }
8494
8512
  },
8495
8513
  required: [],
@@ -8498,17 +8516,17 @@ var MANIFEST = [
8498
8516
  },
8499
8517
  {
8500
8518
  name: "performance_analyze_insight",
8501
- 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).",
8519
+ description: "Reads a trace JSON file (from performance_trace/performance_stop_trace) at tracePath and returns headline metrics: FCP/LCP/CLS/TBT, long tasks, layout shifts. Requires an EXPLICIT tracePath — there is no implicit 'latest trace'. Numbers approximate DevTools's insight analyzer (no main-thread attribution or frame-scoped LCP).",
8502
8520
  inputSchema: {
8503
8521
  type: "object",
8504
8522
  properties: {
8505
8523
  lease: {
8506
8524
  type: "string",
8507
- 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."
8525
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8508
8526
  },
8509
8527
  tracePath: {
8510
8528
  type: "string",
8511
- description: "Filesystem path to a trace JSON file written by performance_trace or performance_stop_trace (bare array OR {traceEvents:[...]}). Required."
8529
+ description: "Path to a trace JSON file (bare array or {traceEvents:[...]}) written by performance_trace or performance_stop_trace. Required."
8512
8530
  }
8513
8531
  },
8514
8532
  required: [],
@@ -8517,25 +8535,25 @@ var MANIFEST = [
8517
8535
  },
8518
8536
  {
8519
8537
  name: "performance_trace",
8520
- 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, and it is the recommended entry point.",
8538
+ description: "RECOMMENDED entry point: one-shot trace that starts tracing, optionally reloads or navigates the page, waits durationMs (default 3000ms), stops, and writes JSON under /tmp/cdp-toolkit — returns {path,bytes,events,metrics,target}. Holds one connection open for the whole window, so unlike start/stop it is NOT limited to a single process.",
8521
8539
  inputSchema: {
8522
8540
  type: "object",
8523
8541
  properties: {
8524
8542
  lease: {
8525
8543
  type: "string",
8526
- 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."
8544
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8527
8545
  },
8528
8546
  target: {
8529
8547
  type: "string",
8530
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
8548
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
8531
8549
  },
8532
8550
  durationMs: {
8533
8551
  type: "number",
8534
- description: "How long to record after the optional reload/navigate, in milliseconds. Default 3000."
8552
+ description: "How long to record after the optional reload/navigate, in ms. Default 3000."
8535
8553
  },
8536
8554
  reload: {
8537
8555
  type: "boolean",
8538
- description: "Reload the page after starting the trace to capture full navigation timing."
8556
+ description: "Reload the page after starting the trace, to capture full navigation timing."
8539
8557
  },
8540
8558
  navigateTo: {
8541
8559
  type: "string",
@@ -8546,7 +8564,7 @@ var MANIFEST = [
8546
8564
  items: {
8547
8565
  type: "string"
8548
8566
  },
8549
- description: "Trace categories to include. Defaults to the timeline + user-timing + loading + disabled-by-default timeline tracks that carry LCP/LayoutShift/RunTask."
8567
+ description: "Trace categories to record. Defaults to timeline + user-timing + loading + disabled-by-default timeline tracks carrying LCP/LayoutShift/RunTask."
8550
8568
  }
8551
8569
  },
8552
8570
  required: [],
@@ -8555,17 +8573,17 @@ var MANIFEST = [
8555
8573
  },
8556
8574
  {
8557
8575
  name: "start_screen_recording",
8558
- 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.",
8576
+ description: "Starts recording the target tab to video via CDP Page.startScreencast, holding one persistent connection and spooling every frame to disk — MUST be paired with stop_screen_recording WITHIN THE SAME PROCESS (frames are connection-scoped and cannot be reattached from another process, so this only works under the MCP server, not the one-process-per-call CLI). Chrome only: WebDriver BiDi has no screencast primitive, so both tools are absent under --browser firefox. Frames arrive ON REPAINT not on a clock (variable rate); each is timestamped into a ledger that stop_screen_recording turns into per-frame display durations, so a still page holds one long frame instead of racing. ffmpeg is probed here (not at stop) so a missing encoder fails before frames are captured and thrown away. Throws if the target already has a recording in progress; different targets record concurrently.",
8559
8577
  inputSchema: {
8560
8578
  type: "object",
8561
8579
  properties: {
8562
8580
  lease: {
8563
8581
  type: "string",
8564
- 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."
8582
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8565
8583
  },
8566
8584
  target: {
8567
8585
  type: "string",
8568
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
8586
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
8569
8587
  },
8570
8588
  format: {
8571
8589
  type: "string",
@@ -8573,27 +8591,27 @@ var MANIFEST = [
8573
8591
  "jpeg",
8574
8592
  "png"
8575
8593
  ],
8576
- description: "Frame image format. Defaults to jpeg (far smaller per repaint); png is lossless. quality applies to jpeg only."
8594
+ description: "Frame format, default jpeg (much smaller per repaint); png is lossless. quality applies to jpeg only."
8577
8595
  },
8578
8596
  quality: {
8579
8597
  type: "number",
8580
- description: "JPEG frame quality 0-100. Ignored for png. Omitted by default, which leaves Chrome's own default in place."
8598
+ description: "JPEG frame quality 0-100. Ignored for png; omitted leaves Chrome's own default."
8581
8599
  },
8582
8600
  maxWidth: {
8583
8601
  type: "number",
8584
- description: "Cap the streamed frame width in pixels. Also the way to pin frame size if the viewport might change mid-recording."
8602
+ description: "Caps the streamed frame width in px; also pins frame size if the viewport may change mid-recording."
8585
8603
  },
8586
8604
  maxHeight: {
8587
8605
  type: "number",
8588
- description: "Cap the streamed frame height in pixels."
8606
+ description: "Caps the streamed frame height in px."
8589
8607
  },
8590
8608
  everyNthFrame: {
8591
8609
  type: "number",
8592
- 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."
8610
+ description: "Capture only every Nth repaint (1=every frame), to shrink spool size on a busy page; per-frame durations keep playback at wallclock speed either way."
8593
8611
  },
8594
8612
  bringToFront: {
8595
8613
  type: "boolean",
8596
- 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."
8614
+ description: "Activate the tab (Page.bringToFront) before recording, default false. A backgrounded/occluded tab may never repaint, yielding a 0-frame recording."
8597
8615
  }
8598
8616
  },
8599
8617
  required: [],
@@ -8602,21 +8620,21 @@ var MANIFEST = [
8602
8620
  },
8603
8621
  {
8604
8622
  name: "stop_screen_recording",
8605
- 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.",
8623
+ description: "Stops the recording started by start_screen_recording, assembling spooled frames into an MP4 via ffmpeg with PER-FRAME durations (frame N held until N+1 painted; last frame held until this call) — capped at 25fps by ffmpeg's concat demuxer, so frames under 40ms apart are deliberately coalesced (frameCount=captured, encodedFrames=what reached the video, never silently dropped). Returns {path,bytes,durationMs,frameCount,encodedFrames,codec,encoder,width,height,droppedFrames,target}; durationMs sums encoded durations, the file runs one 40ms step longer (final frame repeated). Encoder ladder (probed at start): hevc_videotoolbox>h264_videotoolbox>libx265>libx264 (+hvc1 tag, faststart, yuv420p, even dims). target: omit with one recording in flight, required with several (avoids guessing which to stop). Throws if nothing is recording in this process, or if 0 frames arrived (no silent empty video). On ffmpeg failure the spooled frames are KEPT — spool path + exact command are in the error.",
8606
8624
  inputSchema: {
8607
8625
  type: "object",
8608
8626
  properties: {
8609
8627
  lease: {
8610
8628
  type: "string",
8611
- 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."
8629
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8612
8630
  },
8613
8631
  target: {
8614
8632
  type: "string",
8615
- 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>'."
8633
+ description: "Which recording to stop — 'active' valid only when exactly one recording is in flight. Grammar: server instructions."
8616
8634
  },
8617
8635
  savePath: {
8618
8636
  type: "string",
8619
- description: "Override the output file path. Default: /tmp/cdp-toolkit/screen-recording-<targetIdShort>-<stamp>.mp4."
8637
+ description: "Override the output path (default /tmp/cdp-toolkit/screen-recording-<targetIdShort>-<stamp>.mp4)."
8620
8638
  }
8621
8639
  },
8622
8640
  required: [],
@@ -8625,21 +8643,21 @@ var MANIFEST = [
8625
8643
  },
8626
8644
  {
8627
8645
  name: "take_heapsnapshot",
8628
- 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.",
8646
+ description: "Captures a V8 heap snapshot of the target page over CDP and writes it as a .heapsnapshot JSON file (loadable in the DevTools Memory panel) under /tmp/cdp-toolkit unless savePath is given. Returns {path,bytes,chunks,target} only — does NOT parse or summarize the snapshot.",
8629
8647
  inputSchema: {
8630
8648
  type: "object",
8631
8649
  properties: {
8632
8650
  lease: {
8633
8651
  type: "string",
8634
- 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."
8652
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8635
8653
  },
8636
8654
  target: {
8637
8655
  type: "string",
8638
- description: "Target page selector: 'active' (default) | 'index:N' | 'url:<substr>' | 'title:<substr>' | 'label:<name>' | '<targetId>'."
8656
+ description: "Page selector: 'active' (default), 'index:N', 'url:<substr>', 'title:<substr>', 'label:<name>', or a 32-hex '<targetId>'. Grammar: see server instructions."
8639
8657
  },
8640
8658
  savePath: {
8641
8659
  type: "string",
8642
- 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."
8660
+ description: "Override the output path. Absolute paths (starting with /) are used as-is; relative paths resolve under the artifact dir (/tmp/cdp-toolkit). Defaults to an auto-named take_heapsnapshot-<targetId>-<timestamp>.heapsnapshot file."
8643
8661
  }
8644
8662
  },
8645
8663
  required: [],
@@ -8648,24 +8666,24 @@ var MANIFEST = [
8648
8666
  },
8649
8667
  {
8650
8668
  name: "lighthouse_audit",
8651
- 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).",
8669
+ description: "Runs a Lighthouse audit against a URL by shelling out to `npx --yes lighthouse` (the toolkit's only non-CDP tool) — it attaches to the already-running Chrome and audits its OWN about:blank tab, NOT any live user tab you've navigated. Writes a JSON report under /tmp/cdp-toolkit; returns {path,bytes} plus per-category scores (0..1 or null).",
8652
8670
  inputSchema: {
8653
8671
  type: "object",
8654
8672
  properties: {
8655
8673
  lease: {
8656
8674
  type: "string",
8657
- 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."
8675
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8658
8676
  },
8659
8677
  url: {
8660
8678
  type: "string",
8661
- description: "The URL to audit. Required, and never points at a user tab implicitly."
8679
+ description: "The URL to audit. Required — never points at a user tab implicitly."
8662
8680
  },
8663
8681
  categories: {
8664
8682
  type: "array",
8665
8683
  items: {
8666
8684
  type: "string"
8667
8685
  },
8668
- description: 'Lighthouse categories to run (passed as --only-categories). Defaults to the full set, e.g. ["performance"] or ["performance","accessibility","seo"].'
8686
+ description: 'Lighthouse categories to run (--only-categories). Defaults to the full set, e.g. ["performance"] or ["performance","accessibility","seo"].'
8669
8687
  },
8670
8688
  savePath: {
8671
8689
  type: "string",
@@ -8677,11 +8695,11 @@ var MANIFEST = [
8677
8695
  "desktop",
8678
8696
  "mobile"
8679
8697
  ],
8680
- description: 'Form factor: "desktop" (default, uses --preset=desktop to avoid heavy mobile throttling) or "mobile".'
8698
+ description: '"desktop" (default, uses --preset=desktop to avoid heavy mobile throttling) or "mobile".'
8681
8699
  },
8682
8700
  timeoutMs: {
8683
8701
  type: "number",
8684
- description: "Overall budget for the lighthouse process in milliseconds. Default 120000."
8702
+ description: "Overall budget for the lighthouse process, in ms. Default 120000."
8685
8703
  }
8686
8704
  },
8687
8705
  required: [
@@ -8692,21 +8710,21 @@ var MANIFEST = [
8692
8710
  },
8693
8711
  {
8694
8712
  name: "mock_request",
8695
- 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).",
8713
+ description: "Register a mock rule on a target's persistent fake-backend session (CDP Fetch domain): match requests by urlPattern and fulfill with a canned response, fail (abort), or continue -- optionally with fault injection (delayMs/failRate). The session survives reloads/navigations and lives until clear_mocks; call repeatedly to mock several endpoints on one target. reload:true applies it immediately. Persistent across calls only via the MCP server, not the one-shot CLI.",
8696
8714
  inputSchema: {
8697
8715
  type: "object",
8698
8716
  properties: {
8699
8717
  lease: {
8700
8718
  type: "string",
8701
- 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."
8719
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8702
8720
  },
8703
8721
  target: {
8704
8722
  type: "string",
8705
- description: "Target selector: active | index:N | url:<substr> | title:<substr> | label:<name> | <targetId>. Defaults to the active page."
8723
+ description: "Which page's mock session. Defaults to the active page. Grammar: server instructions."
8706
8724
  },
8707
8725
  urlPattern: {
8708
8726
  type: "string",
8709
- description: `CDP Fetch urlPattern glob: '*' matches any run of characters, '?' exactly one, '\\' escapes. Only matching request URLs are paused. e.g. "*/api/users*".`
8727
+ description: `CDP Fetch urlPattern glob: '*' any run of chars, '?' exactly one, '\\' escapes. Only matching URLs are paused. e.g. "*/api/users*".`
8710
8728
  },
8711
8729
  action: {
8712
8730
  type: "string",
@@ -8719,7 +8737,7 @@ var MANIFEST = [
8719
8737
  },
8720
8738
  status: {
8721
8739
  type: "number",
8722
- description: "fulfill: HTTP status code for the canned response. Default 200."
8740
+ description: "fulfill: HTTP status for the canned response. Default 200."
8723
8741
  },
8724
8742
  body: {
8725
8743
  type: "string",
@@ -8739,7 +8757,7 @@ var MANIFEST = [
8739
8757
  },
8740
8758
  method: {
8741
8759
  type: "string",
8742
- description: 'Only mock requests with this HTTP method (e.g. "POST"); other methods pass through.'
8760
+ description: 'Only mock this HTTP method (e.g. "POST"); others pass through.'
8743
8761
  },
8744
8762
  delayMs: {
8745
8763
  type: "number",
@@ -8747,11 +8765,11 @@ var MANIFEST = [
8747
8765
  },
8748
8766
  failRate: {
8749
8767
  type: "number",
8750
- description: "Fault injection: probability 0..1 of failing a matched request regardless of action (resilience testing)."
8768
+ description: "Fault injection: probability 0..1 of failing a matched request regardless of action."
8751
8769
  },
8752
8770
  reload: {
8753
8771
  type: "boolean",
8754
- description: "Reload the target after arming so the mock immediately catches traffic."
8772
+ description: "Reload the target after arming so the mock catches traffic immediately."
8755
8773
  }
8756
8774
  },
8757
8775
  required: [
@@ -8762,17 +8780,17 @@ var MANIFEST = [
8762
8780
  },
8763
8781
  {
8764
8782
  name: "list_mocks",
8765
- 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.",
8783
+ description: "List active fake-backend sessions (one per target) with their rules and hit counts. Prunes sessions whose tab has closed.",
8766
8784
  inputSchema: {
8767
8785
  type: "object",
8768
8786
  properties: {
8769
8787
  lease: {
8770
8788
  type: "string",
8771
- 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."
8789
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8772
8790
  },
8773
8791
  target: {
8774
8792
  type: "string",
8775
- description: "Unused filter placeholder; list_mocks returns all active sessions."
8793
+ description: "Unused filter placeholder; returns all active sessions."
8776
8794
  }
8777
8795
  },
8778
8796
  required: [],
@@ -8787,11 +8805,11 @@ var MANIFEST = [
8787
8805
  properties: {
8788
8806
  lease: {
8789
8807
  type: "string",
8790
- 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."
8808
+ description: "Lease token from claim_page. Omit for a tab this process holds; required for a tab held by another process or one claimed explicitly. Auto-acquired under CDP_REQUIRE_LEASE (then pass target, not lease). See server instructions."
8791
8809
  },
8792
8810
  target: {
8793
8811
  type: "string",
8794
- description: "Target selector whose mock session to clear. Defaults to the active page. Ignored when all:true."
8812
+ description: "Which page's mock session to clear. Defaults to the active page; ignored when all:true. Grammar: server instructions."
8795
8813
  },
8796
8814
  all: {
8797
8815
  type: "boolean",
@@ -8804,29 +8822,29 @@ var MANIFEST = [
8804
8822
  },
8805
8823
  {
8806
8824
  name: "claim_page",
8807
- 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.",
8825
+ description: "Take exclusive ownership of a browser tab, returning an opaque lease token (needed once under CDP_REQUIRE_LEASE for any tab you drive). Two modes: FRESH TAB (no target - opens one, optionally at url, and claims it: 'give me my own tab' in one call) and TAKEOVER (target - claims an already-open tab, e.g. the human's, resolving the selector against the live page list, creating nothing). The opened flag is true only when this call created the tab, and release_page consults that record, so a taken-over tab is left open on release. Refused from the CLI (its per-call process would make the lease instantly reclaimable). The answer carries humanActiveMs, ms since input this server did not dispatch; null is NO DATA (no activity beacon, or every input was this server's own) and never means 'no human'; absent on a backend that cannot answer. On takeover of a tab a human used within 30s it adds contention, a warning - but THE CLAIM IS NEVER REFUSED FOR THIS: takeover is its purpose, you already hold the lease; it only warns you're fighting a live person, so open your own tab or ask first. Limits: input inside a cross-origin iframe is invisible, and a second MCP server's clicks read as human.",
8808
8826
  inputSchema: {
8809
8827
  type: "object",
8810
8828
  properties: {
8811
8829
  target: {
8812
8830
  type: "string",
8813
- 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."
8831
+ description: "Take over an already-open tab (e.g. one the human has open). Resolved against the LIVE page list only, so it never opens a tab — a selector matching nothing is an error. Left open on release. Refused if another live process holds it (including a lease auto-acquired under CDP_REQUIRE_LEASE): takes over unleased human tabs, never steals from a live agent. Mutually exclusive with targetId. Selector grammar: server instructions."
8814
8832
  },
8815
8833
  targetId: {
8816
8834
  type: "string",
8817
- description: "Claim this already-open page target instead of opening a new tab. Must be an exact target id, not a selector. Kept for back-compat: prefer 'target', which accepts an exact id too plus every other selector form. Mutually exclusive with target."
8835
+ description: "Exact target id (not a selector) of an already-open page to claim instead of opening one. Back-compat only; prefer target, which also accepts an exact id. Mutually exclusive with target."
8818
8836
  },
8819
8837
  url: {
8820
8838
  type: "string",
8821
- description: "When opening a fresh tab, navigate it here. Ignored when target or targetId is given, since both of those claim a tab that is already open."
8839
+ description: "When opening a fresh tab, navigate it here. Ignored when target or targetId is given."
8822
8840
  },
8823
8841
  label: {
8824
8842
  type: "string",
8825
- description: "Agent label recorded on the lease and surfaced in conflict errors and list_leases. Defaults to pid-<pid>."
8843
+ description: "Agent label recorded on the lease; surfaced in conflict errors and list_leases. Defaults to pid-<pid>."
8826
8844
  },
8827
8845
  ttlMs: {
8828
8846
  type: "number",
8829
- description: "How long the lease survives without use before it is reclaimable. Defaults to CDP_LEASE_TTL_MS, else 900000 (15 minutes). Every checked call refreshes it, so an active agent never expires."
8847
+ description: "How long the lease survives without use before it is reclaimable. Defaults to CDP_LEASE_TTL_MS, else 900000 (15min); every checked call refreshes it."
8830
8848
  }
8831
8849
  },
8832
8850
  required: [],
@@ -8835,21 +8853,21 @@ var MANIFEST = [
8835
8853
  },
8836
8854
  {
8837
8855
  name: "release_page",
8838
- description: "Give a lease back, and close the tab if this toolkit opened it. Takes exactly one of 'lease' (the token claim_page returned) or 'target' (a selector for a tab this process holds, which is how you release a lease the gate acquired for you automatically, since that path never hands you a token). A tab with a creation record from this toolkit is closed; a tab that was already open and merely claimed is released and left alone. Override either way with 'close'. Idempotent: an already-released, reclaimed, or expired lease reports released:false, and a release that did not happen never closes anything, because by then the tab may belong to another agent. Answers {released, closed, targetId}.",
8856
+ description: "Give a lease back, closing the tab only if this toolkit opened it. Take exactly one of lease (the token) or target (a selector for a tab this process holds - use this to release a lease the gate acquired for you automatically, since that path never handed you a token). A tab with a creation record from this toolkit is closed; a tab that was already open and merely claimed is released and left alone - override either way with close. Idempotent: an already-released, reclaimed, or expired lease reports released:false and closes nothing (by then the tab may belong to another agent). Answers {released, closed, targetId}.",
8839
8857
  inputSchema: {
8840
8858
  type: "object",
8841
8859
  properties: {
8842
8860
  lease: {
8843
8861
  type: "string",
8844
- description: "The opaque token claim_page (or new_page with claim:true) returned. Mutually exclusive with 'target'. Under CDP_REQUIRE_LEASE a lease the gate acquired for you automatically never produced a token in the first place, so give 'target' instead."
8862
+ description: "Token from claim_page / new_page{claim:true}. Mutually exclusive with 'target'. Under CDP_REQUIRE_LEASE an auto-acquired lease never produced a token — give 'target' instead."
8845
8863
  },
8846
8864
  target: {
8847
8865
  type: "string",
8848
- 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."
8866
+ description: "A tab THIS process holds (grammar: server instructions). Mutually exclusive with 'lease'. Refused if another process holds the tab."
8849
8867
  },
8850
8868
  close: {
8851
8869
  type: "boolean",
8852
- description: "Force the close decision instead of letting the creation ledger decide. true closes even a tab this toolkit did not open; false keeps an agent-created tab open. Omit for the default, which closes only tabs this toolkit created."
8870
+ description: "Force the close decision instead of letting the creation record decide: true closes even a tab this toolkit did not open; false keeps an agent-created tab open. Omit to close only tabs this toolkit created."
8853
8871
  }
8854
8872
  },
8855
8873
  required: [],
@@ -8858,7 +8876,7 @@ var MANIFEST = [
8858
8876
  },
8859
8877
  {
8860
8878
  name: "list_leases",
8861
- 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.",
8879
+ description: "Enumerate every active lease for diagnosis - backend, target id, label, pid, createdAt, lastUsedAt, ttlMs, whether the owning process is alive, and whether the lease is reclaimable and why. No token required; it never returns the lease nonce, so it cannot be used to forge one. An unreadable or unparseable lease row instead carries unreadable, with label, pid and timestamps zeroed and stale forced false (an unreadable lease must never read as free to take). Under CDP_REQUIRE_LEASE it reaps abandoned agent tabs exactly as list_pages does, into an additive reaped array, omitting their rows. Where the tab can answer, a row also carries humanActiveMs, ms since input this server did not dispatch - note lastUsedAt tracks TOOLKIT calls only, so a tab a person has typed in for ten minutes looks idle, which is what this exposes; the field is absent, never null, when the tab cannot answer, and that absence means 'no answer', never 'nobody is there'. idleMs (now - lastUsedAt) and expiresAt (lastUsedAt + ttlMs) are computed fresh each call and omitted on an unreadable row.",
8862
8880
  inputSchema: {
8863
8881
  type: "object",
8864
8882
  properties: {},