firefox-devtools-mcp 0.6.1 → 0.7.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/README.md +13 -1
- package/dist/index.js +60 -35
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -99,9 +99,21 @@ You can pass flags or environment variables (names on the right):
|
|
|
99
99
|
- Input: click/hover/fill/drag/upload/form fill
|
|
100
100
|
- Network: list/get (ID‑first, filters, always‑on capture)
|
|
101
101
|
- Console: list/clear
|
|
102
|
-
- Screenshot: page/by uid
|
|
102
|
+
- Screenshot: page/by uid (with optional `saveTo` for CLI environments)
|
|
103
103
|
- Utilities: accept/dismiss dialog, history back/forward, set viewport
|
|
104
104
|
|
|
105
|
+
### Screenshot optimization for Claude Code
|
|
106
|
+
|
|
107
|
+
When using screenshots in Claude Code CLI, the base64 image data can consume significant context.
|
|
108
|
+
Use the `saveTo` parameter to save screenshots to disk instead:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
screenshot_page({ saveTo: "/tmp/page.png" })
|
|
112
|
+
screenshot_by_uid({ uid: "abc123", saveTo: "/tmp/element.png" })
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The file can then be viewed with Claude Code's `Read` tool without impacting context size.
|
|
116
|
+
|
|
105
117
|
## Local development
|
|
106
118
|
|
|
107
119
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -14072,7 +14072,7 @@ var init_protocol = __esm({
|
|
|
14072
14072
|
return;
|
|
14073
14073
|
}
|
|
14074
14074
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
14075
|
-
await new Promise((
|
|
14075
|
+
await new Promise((resolve4) => setTimeout(resolve4, pollInterval));
|
|
14076
14076
|
options?.signal?.throwIfAborted();
|
|
14077
14077
|
}
|
|
14078
14078
|
} catch (error2) {
|
|
@@ -14089,7 +14089,7 @@ var init_protocol = __esm({
|
|
|
14089
14089
|
*/
|
|
14090
14090
|
request(request, resultSchema, options) {
|
|
14091
14091
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
14092
|
-
return new Promise((
|
|
14092
|
+
return new Promise((resolve4, reject) => {
|
|
14093
14093
|
const earlyReject = (error2) => {
|
|
14094
14094
|
reject(error2);
|
|
14095
14095
|
};
|
|
@@ -14167,7 +14167,7 @@ var init_protocol = __esm({
|
|
|
14167
14167
|
if (!parseResult.success) {
|
|
14168
14168
|
reject(parseResult.error);
|
|
14169
14169
|
} else {
|
|
14170
|
-
|
|
14170
|
+
resolve4(parseResult.data);
|
|
14171
14171
|
}
|
|
14172
14172
|
} catch (error2) {
|
|
14173
14173
|
reject(error2);
|
|
@@ -14428,12 +14428,12 @@ var init_protocol = __esm({
|
|
|
14428
14428
|
}
|
|
14429
14429
|
} catch {
|
|
14430
14430
|
}
|
|
14431
|
-
return new Promise((
|
|
14431
|
+
return new Promise((resolve4, reject) => {
|
|
14432
14432
|
if (signal.aborted) {
|
|
14433
14433
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
14434
14434
|
return;
|
|
14435
14435
|
}
|
|
14436
|
-
const timeoutId = setTimeout(
|
|
14436
|
+
const timeoutId = setTimeout(resolve4, interval);
|
|
14437
14437
|
signal.addEventListener("abort", () => {
|
|
14438
14438
|
clearTimeout(timeoutId);
|
|
14439
14439
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -17460,7 +17460,7 @@ var require_compile = __commonJS({
|
|
|
17460
17460
|
const schOrFunc = root.refs[ref];
|
|
17461
17461
|
if (schOrFunc)
|
|
17462
17462
|
return schOrFunc;
|
|
17463
|
-
let _sch =
|
|
17463
|
+
let _sch = resolve4.call(this, root, ref);
|
|
17464
17464
|
if (_sch === void 0) {
|
|
17465
17465
|
const schema = (_a2 = root.localRefs) === null || _a2 === void 0 ? void 0 : _a2[ref];
|
|
17466
17466
|
const { schemaId } = this.opts;
|
|
@@ -17487,7 +17487,7 @@ var require_compile = __commonJS({
|
|
|
17487
17487
|
function sameSchemaEnv(s1, s2) {
|
|
17488
17488
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
17489
17489
|
}
|
|
17490
|
-
function
|
|
17490
|
+
function resolve4(root, ref) {
|
|
17491
17491
|
let sch;
|
|
17492
17492
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
17493
17493
|
ref = sch;
|
|
@@ -18062,7 +18062,7 @@ var require_fast_uri = __commonJS({
|
|
|
18062
18062
|
}
|
|
18063
18063
|
return uri;
|
|
18064
18064
|
}
|
|
18065
|
-
function
|
|
18065
|
+
function resolve4(baseURI, relativeURI, options) {
|
|
18066
18066
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
18067
18067
|
const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
18068
18068
|
schemelessOptions.skipEscape = true;
|
|
@@ -18289,7 +18289,7 @@ var require_fast_uri = __commonJS({
|
|
|
18289
18289
|
var fastUri = {
|
|
18290
18290
|
SCHEMES,
|
|
18291
18291
|
normalize,
|
|
18292
|
-
resolve:
|
|
18292
|
+
resolve: resolve4,
|
|
18293
18293
|
resolveComponent,
|
|
18294
18294
|
equal,
|
|
18295
18295
|
serialize,
|
|
@@ -21944,12 +21944,12 @@ var init_stdio2 = __esm({
|
|
|
21944
21944
|
this.onclose?.();
|
|
21945
21945
|
}
|
|
21946
21946
|
send(message) {
|
|
21947
|
-
return new Promise((
|
|
21947
|
+
return new Promise((resolve4) => {
|
|
21948
21948
|
const json2 = serializeMessage(message);
|
|
21949
21949
|
if (this._stdout.write(json2)) {
|
|
21950
|
-
|
|
21950
|
+
resolve4();
|
|
21951
21951
|
} else {
|
|
21952
|
-
this._stdout.once("drain",
|
|
21952
|
+
this._stdout.once("drain", resolve4);
|
|
21953
21953
|
}
|
|
21954
21954
|
});
|
|
21955
21955
|
}
|
|
@@ -21963,7 +21963,7 @@ var init_constants = __esm({
|
|
|
21963
21963
|
"src/config/constants.ts"() {
|
|
21964
21964
|
"use strict";
|
|
21965
21965
|
SERVER_NAME = "firefox-devtools";
|
|
21966
|
-
SERVER_VERSION = "0.
|
|
21966
|
+
SERVER_VERSION = "0.7.0";
|
|
21967
21967
|
}
|
|
21968
21968
|
});
|
|
21969
21969
|
|
|
@@ -22791,7 +22791,7 @@ var init_dom = __esm({
|
|
|
22791
22791
|
*/
|
|
22792
22792
|
async waitForEventsAfterAction() {
|
|
22793
22793
|
await this.driver.executeScript("return new Promise(r => requestAnimationFrame(() => r()))");
|
|
22794
|
-
await new Promise((
|
|
22794
|
+
await new Promise((resolve4) => setTimeout(resolve4, 50));
|
|
22795
22795
|
}
|
|
22796
22796
|
// ============================================================================
|
|
22797
22797
|
// Screenshot
|
|
@@ -22820,7 +22820,7 @@ var init_dom = __esm({
|
|
|
22820
22820
|
'arguments[0].scrollIntoView({block: "center", inline: "center"});',
|
|
22821
22821
|
el
|
|
22822
22822
|
);
|
|
22823
|
-
await new Promise((
|
|
22823
|
+
await new Promise((resolve4) => setTimeout(resolve4, 100));
|
|
22824
22824
|
return await el.takeScreenshot();
|
|
22825
22825
|
}
|
|
22826
22826
|
};
|
|
@@ -24933,33 +24933,48 @@ var init_input = __esm({
|
|
|
24933
24933
|
});
|
|
24934
24934
|
|
|
24935
24935
|
// src/tools/screenshot.ts
|
|
24936
|
-
|
|
24937
|
-
|
|
24938
|
-
|
|
24939
|
-
|
|
24940
|
-
|
|
24941
|
-
|
|
24942
|
-
|
|
24943
|
-
|
|
24944
|
-
|
|
24945
|
-
|
|
24946
|
-
}
|
|
24947
|
-
|
|
24936
|
+
import { writeFile, mkdir } from "fs/promises";
|
|
24937
|
+
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
24938
|
+
async function saveScreenshot(base64Png, saveTo) {
|
|
24939
|
+
const buffer = Buffer.from(base64Png, "base64");
|
|
24940
|
+
const resolvedPath = resolve2(saveTo);
|
|
24941
|
+
await mkdir(dirname2(resolvedPath), { recursive: true });
|
|
24942
|
+
await writeFile(resolvedPath, buffer);
|
|
24943
|
+
return successResponse(
|
|
24944
|
+
`Screenshot saved to: ${resolvedPath} (${(buffer.length / 1024).toFixed(1)}KB)`
|
|
24945
|
+
);
|
|
24946
|
+
}
|
|
24947
|
+
function imageResponse(base64Png) {
|
|
24948
|
+
return {
|
|
24949
|
+
content: [
|
|
24950
|
+
{
|
|
24951
|
+
type: "image",
|
|
24952
|
+
data: base64Png,
|
|
24953
|
+
mimeType: "image/png"
|
|
24954
|
+
}
|
|
24955
|
+
]
|
|
24956
|
+
};
|
|
24957
|
+
}
|
|
24958
|
+
async function handleScreenshotPage(args2) {
|
|
24948
24959
|
try {
|
|
24960
|
+
const { saveTo } = args2 ?? {};
|
|
24949
24961
|
const { getFirefox: getFirefox2 } = await init_index().then(() => index_exports);
|
|
24950
24962
|
const firefox3 = await getFirefox2();
|
|
24951
24963
|
const base64Png = await firefox3.takeScreenshotPage();
|
|
24952
24964
|
if (!base64Png || typeof base64Png !== "string") {
|
|
24953
24965
|
throw new Error("Invalid screenshot data");
|
|
24954
24966
|
}
|
|
24955
|
-
|
|
24967
|
+
if (saveTo) {
|
|
24968
|
+
return await saveScreenshot(base64Png, saveTo);
|
|
24969
|
+
}
|
|
24970
|
+
return imageResponse(base64Png);
|
|
24956
24971
|
} catch (error2) {
|
|
24957
24972
|
return errorResponse(error2);
|
|
24958
24973
|
}
|
|
24959
24974
|
}
|
|
24960
24975
|
async function handleScreenshotByUid(args2) {
|
|
24961
24976
|
try {
|
|
24962
|
-
const { uid } = args2;
|
|
24977
|
+
const { uid, saveTo } = args2;
|
|
24963
24978
|
if (!uid || typeof uid !== "string") {
|
|
24964
24979
|
throw new Error("uid required");
|
|
24965
24980
|
}
|
|
@@ -24970,7 +24985,10 @@ async function handleScreenshotByUid(args2) {
|
|
|
24970
24985
|
if (!base64Png || typeof base64Png !== "string") {
|
|
24971
24986
|
throw new Error("Invalid screenshot data");
|
|
24972
24987
|
}
|
|
24973
|
-
|
|
24988
|
+
if (saveTo) {
|
|
24989
|
+
return await saveScreenshot(base64Png, saveTo);
|
|
24990
|
+
}
|
|
24991
|
+
return imageResponse(base64Png);
|
|
24974
24992
|
} catch (error2) {
|
|
24975
24993
|
throw handleUidError(error2, uid);
|
|
24976
24994
|
}
|
|
@@ -24978,18 +24996,24 @@ async function handleScreenshotByUid(args2) {
|
|
|
24978
24996
|
return errorResponse(error2);
|
|
24979
24997
|
}
|
|
24980
24998
|
}
|
|
24981
|
-
var screenshotPageTool, screenshotByUidTool;
|
|
24999
|
+
var SAVE_TO_SCHEMA, screenshotPageTool, screenshotByUidTool;
|
|
24982
25000
|
var init_screenshot = __esm({
|
|
24983
25001
|
"src/tools/screenshot.ts"() {
|
|
24984
25002
|
"use strict";
|
|
24985
25003
|
init_response_helpers();
|
|
24986
25004
|
init_uid_helpers();
|
|
25005
|
+
SAVE_TO_SCHEMA = {
|
|
25006
|
+
type: "string",
|
|
25007
|
+
description: "Optional absolute file path to save the screenshot to instead of returning it as image data in the response. Use this in CLI environments (e.g. Claude Code) to avoid filling up the context window with large base64 image data. Example: '/tmp/screenshot.png'"
|
|
25008
|
+
};
|
|
24987
25009
|
screenshotPageTool = {
|
|
24988
25010
|
name: "screenshot_page",
|
|
24989
25011
|
description: "Capture page screenshot as base64 PNG.",
|
|
24990
25012
|
inputSchema: {
|
|
24991
25013
|
type: "object",
|
|
24992
|
-
properties: {
|
|
25014
|
+
properties: {
|
|
25015
|
+
saveTo: SAVE_TO_SCHEMA
|
|
25016
|
+
}
|
|
24993
25017
|
}
|
|
24994
25018
|
};
|
|
24995
25019
|
screenshotByUidTool = {
|
|
@@ -25001,7 +25025,8 @@ var init_screenshot = __esm({
|
|
|
25001
25025
|
uid: {
|
|
25002
25026
|
type: "string",
|
|
25003
25027
|
description: "Element UID from snapshot"
|
|
25004
|
-
}
|
|
25028
|
+
},
|
|
25029
|
+
saveTo: SAVE_TO_SCHEMA
|
|
25005
25030
|
},
|
|
25006
25031
|
required: ["uid"]
|
|
25007
25032
|
}
|
|
@@ -25595,7 +25620,7 @@ __export(index_exports, {
|
|
|
25595
25620
|
});
|
|
25596
25621
|
import { version as version2 } from "process";
|
|
25597
25622
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
25598
|
-
import { resolve as
|
|
25623
|
+
import { resolve as resolve3 } from "path";
|
|
25599
25624
|
import { realpathSync } from "fs";
|
|
25600
25625
|
function resetFirefox() {
|
|
25601
25626
|
if (firefox2) {
|
|
@@ -25776,7 +25801,7 @@ var init_index = __esm({
|
|
|
25776
25801
|
setViewportSizeTool
|
|
25777
25802
|
];
|
|
25778
25803
|
modulePath = fileURLToPath2(import.meta.url);
|
|
25779
|
-
scriptPath = process.argv[1] ?
|
|
25804
|
+
scriptPath = process.argv[1] ? resolve3(process.argv[1]) : "";
|
|
25780
25805
|
isMainModule = false;
|
|
25781
25806
|
try {
|
|
25782
25807
|
const realModulePath = realpathSync(modulePath);
|