@mozilla/firefox-devtools-mcp 0.9.4 → 0.9.5
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 +14 -14
- package/dist/index.js +133 -46
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Firefox DevTools MCP
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/mozilla/firefox-devtools-mcp)
|
|
4
4
|
[](https://github.com/mozilla/firefox-devtools-mcp/actions/workflows/ci.yml)
|
|
5
5
|
[](https://codecov.io/gh/mozilla/firefox-devtools-mcp)
|
|
6
6
|
[](LICENSE-MIT) [](LICENSE-APACHE)
|
|
@@ -11,7 +11,7 @@ Model Context Protocol server for automating Firefox via WebDriver BiDi (through
|
|
|
11
11
|
|
|
12
12
|
Repository: https://github.com/mozilla/firefox-devtools-mcp
|
|
13
13
|
|
|
14
|
-
> **Note**: This MCP server requires a local Firefox browser installation and cannot run on cloud hosting services like glama.ai. Use `npx firefox-devtools-mcp@latest` to run locally, or use Docker with the provided Dockerfile.
|
|
14
|
+
> **Note**: This MCP server requires a local Firefox browser installation and cannot run on cloud hosting services like glama.ai. Use `npx @mozilla/firefox-devtools-mcp@latest` to run locally, or use Docker with the provided Dockerfile.
|
|
15
15
|
|
|
16
16
|
## Security
|
|
17
17
|
|
|
@@ -35,17 +35,17 @@ Recommended: use npx so you always run the latest published version from npm.
|
|
|
35
35
|
Option A — Claude Code CLI
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
claude mcp add firefox-devtools npx firefox-devtools-mcp@latest
|
|
38
|
+
claude mcp add firefox-devtools npx @mozilla/firefox-devtools-mcp@latest
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
Pass options either as args or env vars. Examples:
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
44
|
# Headless + viewport via args
|
|
45
|
-
claude mcp add firefox-devtools npx firefox-devtools-mcp@latest -- --headless --viewport 1280x720
|
|
45
|
+
claude mcp add firefox-devtools npx @mozilla/firefox-devtools-mcp@latest -- --headless --viewport 1280x720
|
|
46
46
|
|
|
47
47
|
# Or via environment variables
|
|
48
|
-
claude mcp add firefox-devtools npx firefox-devtools-mcp@latest \
|
|
48
|
+
claude mcp add firefox-devtools npx @mozilla/firefox-devtools-mcp@latest \
|
|
49
49
|
--env START_URL=https://example.com \
|
|
50
50
|
--env FIREFOX_HEADLESS=true
|
|
51
51
|
```
|
|
@@ -63,9 +63,9 @@ Add to your Claude Code config file:
|
|
|
63
63
|
"mcpServers": {
|
|
64
64
|
"firefox-devtools": {
|
|
65
65
|
"command": "npx",
|
|
66
|
-
"args": ["-y", "firefox-devtools-mcp@latest", "--headless", "--viewport", "1280x720"],
|
|
66
|
+
"args": ["-y", "@mozilla/firefox-devtools-mcp@latest", "--headless", "--viewport", "1280x720"],
|
|
67
67
|
"env": {
|
|
68
|
-
"START_URL": "about:
|
|
68
|
+
"START_URL": "about:blank"
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
}
|
|
@@ -82,7 +82,7 @@ npm run setup
|
|
|
82
82
|
## Try it with MCP Inspector
|
|
83
83
|
|
|
84
84
|
```bash
|
|
85
|
-
npx @modelcontextprotocol/inspector npx firefox-devtools-mcp@latest --start-url https://example.com --headless
|
|
85
|
+
npx @modelcontextprotocol/inspector npx @mozilla/firefox-devtools-mcp@latest --start-url https://example.com --headless
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
Then call tools like:
|
|
@@ -122,13 +122,13 @@ Use `--android-device` to automate Firefox running on an Android device. Require
|
|
|
122
122
|
adb devices
|
|
123
123
|
|
|
124
124
|
# Launch Firefox for Android on the single connected device
|
|
125
|
-
npx firefox-devtools-mcp --android-device auto
|
|
125
|
+
npx @mozilla/firefox-devtools-mcp --android-device auto
|
|
126
126
|
|
|
127
127
|
# Target a specific device
|
|
128
|
-
npx firefox-devtools-mcp --android-device <serial>
|
|
128
|
+
npx @mozilla/firefox-devtools-mcp --android-device <serial>
|
|
129
129
|
|
|
130
130
|
# Use Firefox Nightly instead
|
|
131
|
-
npx firefox-devtools-mcp --android-device <serial> --android-package org.mozilla.fenix
|
|
131
|
+
npx @mozilla/firefox-devtools-mcp --android-device <serial> --android-package org.mozilla.fenix
|
|
132
132
|
```
|
|
133
133
|
|
|
134
134
|
Port forwarding between the host and device is handled automatically by geckodriver.
|
|
@@ -142,7 +142,7 @@ Use `--connect-existing` to automate your real browsing session — with cookies
|
|
|
142
142
|
firefox --marionette
|
|
143
143
|
|
|
144
144
|
# Run the MCP server
|
|
145
|
-
npx firefox-devtools-mcp --connect-existing --marionette-port 2828
|
|
145
|
+
npx @mozilla/firefox-devtools-mcp --connect-existing --marionette-port 2828
|
|
146
146
|
```
|
|
147
147
|
|
|
148
148
|
Or set `marionette.enabled` to `true` in `about:config` (or `user.js`) to enable Marionette on every launch.
|
|
@@ -208,7 +208,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for more details on local development, te
|
|
|
208
208
|
"mcpServers": {
|
|
209
209
|
"firefox-devtools": {
|
|
210
210
|
"command": "cmd",
|
|
211
|
-
"args": ["/c", "npx", "-y", "firefox-devtools-mcp@latest"]
|
|
211
|
+
"args": ["/c", "npx", "-y", "@mozilla/firefox-devtools-mcp@latest"]
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
```
|
|
@@ -219,7 +219,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for more details on local development, te
|
|
|
219
219
|
"mcpServers": {
|
|
220
220
|
"firefox-devtools": {
|
|
221
221
|
"command": "C:\\nvm4w\\nodejs\\npx.ps1",
|
|
222
|
-
"args": ["-y", "firefox-devtools-mcp@latest"]
|
|
222
|
+
"args": ["-y", "@mozilla/firefox-devtools-mcp@latest"]
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
```
|
package/dist/index.js
CHANGED
|
@@ -128,8 +128,8 @@ var init_cli = __esm({
|
|
|
128
128
|
},
|
|
129
129
|
startUrl: {
|
|
130
130
|
type: "string",
|
|
131
|
-
description: "URL to open when Firefox starts (default: about:
|
|
132
|
-
default: process.env.START_URL ?? "about:
|
|
131
|
+
description: "URL to open when Firefox starts (default: about:blank)",
|
|
132
|
+
default: process.env.START_URL ?? "about:blank"
|
|
133
133
|
},
|
|
134
134
|
connectExisting: {
|
|
135
135
|
type: "boolean",
|
|
@@ -17762,6 +17762,9 @@ var require_utils = __commonJS({
|
|
|
17762
17762
|
"use strict";
|
|
17763
17763
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
17764
17764
|
var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
17765
|
+
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
17766
|
+
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
17767
|
+
var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu);
|
|
17765
17768
|
function stringArrayToHexStripped(input) {
|
|
17766
17769
|
let acc = "";
|
|
17767
17770
|
let code = 0;
|
|
@@ -17954,27 +17957,77 @@ var require_utils = __commonJS({
|
|
|
17954
17957
|
}
|
|
17955
17958
|
return output.join("");
|
|
17956
17959
|
}
|
|
17957
|
-
|
|
17958
|
-
|
|
17959
|
-
|
|
17960
|
-
|
|
17961
|
-
|
|
17962
|
-
|
|
17963
|
-
|
|
17964
|
-
|
|
17965
|
-
|
|
17966
|
-
|
|
17960
|
+
var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
|
|
17961
|
+
var HOST_DELIM_RE = /[@/?#:]/g;
|
|
17962
|
+
var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
|
|
17963
|
+
function reescapeHostDelimiters(host, isIP) {
|
|
17964
|
+
const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
|
|
17965
|
+
re.lastIndex = 0;
|
|
17966
|
+
return host.replace(re, (ch) => HOST_DELIMS[ch]);
|
|
17967
|
+
}
|
|
17968
|
+
function normalizePercentEncoding(input, decodeUnreserved = false) {
|
|
17969
|
+
if (input.indexOf("%") === -1) {
|
|
17970
|
+
return input;
|
|
17967
17971
|
}
|
|
17968
|
-
|
|
17969
|
-
|
|
17972
|
+
let output = "";
|
|
17973
|
+
for (let i = 0; i < input.length; i++) {
|
|
17974
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
17975
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
17976
|
+
if (isHexPair(hex3)) {
|
|
17977
|
+
const normalizedHex = hex3.toUpperCase();
|
|
17978
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
17979
|
+
if (decodeUnreserved && isUnreserved(decoded)) {
|
|
17980
|
+
output += decoded;
|
|
17981
|
+
} else {
|
|
17982
|
+
output += "%" + normalizedHex;
|
|
17983
|
+
}
|
|
17984
|
+
i += 2;
|
|
17985
|
+
continue;
|
|
17986
|
+
}
|
|
17987
|
+
}
|
|
17988
|
+
output += input[i];
|
|
17970
17989
|
}
|
|
17971
|
-
|
|
17972
|
-
|
|
17990
|
+
return output;
|
|
17991
|
+
}
|
|
17992
|
+
function normalizePathEncoding(input) {
|
|
17993
|
+
let output = "";
|
|
17994
|
+
for (let i = 0; i < input.length; i++) {
|
|
17995
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
17996
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
17997
|
+
if (isHexPair(hex3)) {
|
|
17998
|
+
const normalizedHex = hex3.toUpperCase();
|
|
17999
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
18000
|
+
if (decoded !== "." && isUnreserved(decoded)) {
|
|
18001
|
+
output += decoded;
|
|
18002
|
+
} else {
|
|
18003
|
+
output += "%" + normalizedHex;
|
|
18004
|
+
}
|
|
18005
|
+
i += 2;
|
|
18006
|
+
continue;
|
|
18007
|
+
}
|
|
18008
|
+
}
|
|
18009
|
+
if (isPathCharacter(input[i])) {
|
|
18010
|
+
output += input[i];
|
|
18011
|
+
} else {
|
|
18012
|
+
output += escape(input[i]);
|
|
18013
|
+
}
|
|
17973
18014
|
}
|
|
17974
|
-
|
|
17975
|
-
|
|
18015
|
+
return output;
|
|
18016
|
+
}
|
|
18017
|
+
function escapePreservingEscapes(input) {
|
|
18018
|
+
let output = "";
|
|
18019
|
+
for (let i = 0; i < input.length; i++) {
|
|
18020
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
18021
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
18022
|
+
if (isHexPair(hex3)) {
|
|
18023
|
+
output += "%" + hex3.toUpperCase();
|
|
18024
|
+
i += 2;
|
|
18025
|
+
continue;
|
|
18026
|
+
}
|
|
18027
|
+
}
|
|
18028
|
+
output += escape(input[i]);
|
|
17976
18029
|
}
|
|
17977
|
-
return
|
|
18030
|
+
return output;
|
|
17978
18031
|
}
|
|
17979
18032
|
function recomposeAuthority(component) {
|
|
17980
18033
|
const uriTokens = [];
|
|
@@ -17989,7 +18042,7 @@ var require_utils = __commonJS({
|
|
|
17989
18042
|
if (ipV6res.isIPV6 === true) {
|
|
17990
18043
|
host = `[${ipV6res.escapedHost}]`;
|
|
17991
18044
|
} else {
|
|
17992
|
-
host =
|
|
18045
|
+
host = reescapeHostDelimiters(host, false);
|
|
17993
18046
|
}
|
|
17994
18047
|
}
|
|
17995
18048
|
uriTokens.push(host);
|
|
@@ -18003,7 +18056,10 @@ var require_utils = __commonJS({
|
|
|
18003
18056
|
module.exports = {
|
|
18004
18057
|
nonSimpleDomain,
|
|
18005
18058
|
recomposeAuthority,
|
|
18006
|
-
|
|
18059
|
+
reescapeHostDelimiters,
|
|
18060
|
+
normalizePercentEncoding,
|
|
18061
|
+
normalizePathEncoding,
|
|
18062
|
+
escapePreservingEscapes,
|
|
18007
18063
|
removeDotSegments,
|
|
18008
18064
|
isIPv4,
|
|
18009
18065
|
isUUID,
|
|
@@ -18227,12 +18283,12 @@ var require_schemes = __commonJS({
|
|
|
18227
18283
|
var require_fast_uri = __commonJS({
|
|
18228
18284
|
"node_modules/fast-uri/index.js"(exports, module) {
|
|
18229
18285
|
"use strict";
|
|
18230
|
-
var { normalizeIPv6, removeDotSegments, recomposeAuthority,
|
|
18286
|
+
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
18231
18287
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
18232
18288
|
function normalize(uri, options) {
|
|
18233
18289
|
if (typeof uri === "string") {
|
|
18234
18290
|
uri = /** @type {T} */
|
|
18235
|
-
|
|
18291
|
+
normalizeString(uri, options);
|
|
18236
18292
|
} else if (typeof uri === "object") {
|
|
18237
18293
|
uri = /** @type {T} */
|
|
18238
18294
|
parse3(serialize(uri, options), options);
|
|
@@ -18299,19 +18355,9 @@ var require_fast_uri = __commonJS({
|
|
|
18299
18355
|
return target;
|
|
18300
18356
|
}
|
|
18301
18357
|
function equal(uriA, uriB, options) {
|
|
18302
|
-
|
|
18303
|
-
|
|
18304
|
-
|
|
18305
|
-
} else if (typeof uriA === "object") {
|
|
18306
|
-
uriA = serialize(normalizeComponentEncoding(uriA, true), { ...options, skipEscape: true });
|
|
18307
|
-
}
|
|
18308
|
-
if (typeof uriB === "string") {
|
|
18309
|
-
uriB = unescape(uriB);
|
|
18310
|
-
uriB = serialize(normalizeComponentEncoding(parse3(uriB, options), true), { ...options, skipEscape: true });
|
|
18311
|
-
} else if (typeof uriB === "object") {
|
|
18312
|
-
uriB = serialize(normalizeComponentEncoding(uriB, true), { ...options, skipEscape: true });
|
|
18313
|
-
}
|
|
18314
|
-
return uriA.toLowerCase() === uriB.toLowerCase();
|
|
18358
|
+
const normalizedA = normalizeComparableURI(uriA, options);
|
|
18359
|
+
const normalizedB = normalizeComparableURI(uriB, options);
|
|
18360
|
+
return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA.toLowerCase() === normalizedB.toLowerCase();
|
|
18315
18361
|
}
|
|
18316
18362
|
function serialize(cmpts, opts) {
|
|
18317
18363
|
const component = {
|
|
@@ -18336,12 +18382,12 @@ var require_fast_uri = __commonJS({
|
|
|
18336
18382
|
if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
|
|
18337
18383
|
if (component.path !== void 0) {
|
|
18338
18384
|
if (!options.skipEscape) {
|
|
18339
|
-
component.path =
|
|
18385
|
+
component.path = escapePreservingEscapes(component.path);
|
|
18340
18386
|
if (component.scheme !== void 0) {
|
|
18341
18387
|
component.path = component.path.split("%3A").join(":");
|
|
18342
18388
|
}
|
|
18343
18389
|
} else {
|
|
18344
|
-
component.path =
|
|
18390
|
+
component.path = normalizePercentEncoding(component.path);
|
|
18345
18391
|
}
|
|
18346
18392
|
}
|
|
18347
18393
|
if (options.reference !== "suffix" && component.scheme) {
|
|
@@ -18376,7 +18422,16 @@ var require_fast_uri = __commonJS({
|
|
|
18376
18422
|
return uriTokens.join("");
|
|
18377
18423
|
}
|
|
18378
18424
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
18379
|
-
function
|
|
18425
|
+
function getParseError(parsed, matches) {
|
|
18426
|
+
if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
|
|
18427
|
+
return 'URI path must start with "/" when authority is present.';
|
|
18428
|
+
}
|
|
18429
|
+
if (typeof parsed.port === "number" && (parsed.port < 0 || parsed.port > 65535)) {
|
|
18430
|
+
return "URI port is malformed.";
|
|
18431
|
+
}
|
|
18432
|
+
return void 0;
|
|
18433
|
+
}
|
|
18434
|
+
function parseWithStatus(uri, opts) {
|
|
18380
18435
|
const options = Object.assign({}, opts);
|
|
18381
18436
|
const parsed = {
|
|
18382
18437
|
scheme: void 0,
|
|
@@ -18387,6 +18442,7 @@ var require_fast_uri = __commonJS({
|
|
|
18387
18442
|
query: void 0,
|
|
18388
18443
|
fragment: void 0
|
|
18389
18444
|
};
|
|
18445
|
+
let malformedAuthorityOrPort = false;
|
|
18390
18446
|
let isIP = false;
|
|
18391
18447
|
if (options.reference === "suffix") {
|
|
18392
18448
|
if (options.scheme) {
|
|
@@ -18407,6 +18463,11 @@ var require_fast_uri = __commonJS({
|
|
|
18407
18463
|
if (isNaN(parsed.port)) {
|
|
18408
18464
|
parsed.port = matches[5];
|
|
18409
18465
|
}
|
|
18466
|
+
const parseError = getParseError(parsed, matches);
|
|
18467
|
+
if (parseError !== void 0) {
|
|
18468
|
+
parsed.error = parsed.error || parseError;
|
|
18469
|
+
malformedAuthorityOrPort = true;
|
|
18470
|
+
}
|
|
18410
18471
|
if (parsed.host) {
|
|
18411
18472
|
const ipv4result = isIPv4(parsed.host);
|
|
18412
18473
|
if (ipv4result === false) {
|
|
@@ -18445,14 +18506,18 @@ var require_fast_uri = __commonJS({
|
|
|
18445
18506
|
parsed.scheme = unescape(parsed.scheme);
|
|
18446
18507
|
}
|
|
18447
18508
|
if (parsed.host !== void 0) {
|
|
18448
|
-
parsed.host = unescape(parsed.host);
|
|
18509
|
+
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
|
|
18449
18510
|
}
|
|
18450
18511
|
}
|
|
18451
18512
|
if (parsed.path) {
|
|
18452
|
-
parsed.path =
|
|
18513
|
+
parsed.path = normalizePathEncoding(parsed.path);
|
|
18453
18514
|
}
|
|
18454
18515
|
if (parsed.fragment) {
|
|
18455
|
-
|
|
18516
|
+
try {
|
|
18517
|
+
parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
|
|
18518
|
+
} catch {
|
|
18519
|
+
parsed.error = parsed.error || "URI malformed";
|
|
18520
|
+
}
|
|
18456
18521
|
}
|
|
18457
18522
|
}
|
|
18458
18523
|
if (schemeHandler && schemeHandler.parse) {
|
|
@@ -18461,7 +18526,29 @@ var require_fast_uri = __commonJS({
|
|
|
18461
18526
|
} else {
|
|
18462
18527
|
parsed.error = parsed.error || "URI can not be parsed.";
|
|
18463
18528
|
}
|
|
18464
|
-
return parsed;
|
|
18529
|
+
return { parsed, malformedAuthorityOrPort };
|
|
18530
|
+
}
|
|
18531
|
+
function parse3(uri, opts) {
|
|
18532
|
+
return parseWithStatus(uri, opts).parsed;
|
|
18533
|
+
}
|
|
18534
|
+
function normalizeString(uri, opts) {
|
|
18535
|
+
return normalizeStringWithStatus(uri, opts).normalized;
|
|
18536
|
+
}
|
|
18537
|
+
function normalizeStringWithStatus(uri, opts) {
|
|
18538
|
+
const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
|
|
18539
|
+
return {
|
|
18540
|
+
normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
|
|
18541
|
+
malformedAuthorityOrPort
|
|
18542
|
+
};
|
|
18543
|
+
}
|
|
18544
|
+
function normalizeComparableURI(uri, opts) {
|
|
18545
|
+
if (typeof uri === "string") {
|
|
18546
|
+
const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts);
|
|
18547
|
+
return malformedAuthorityOrPort ? void 0 : normalized;
|
|
18548
|
+
}
|
|
18549
|
+
if (typeof uri === "object") {
|
|
18550
|
+
return serialize(uri, opts);
|
|
18551
|
+
}
|
|
18465
18552
|
}
|
|
18466
18553
|
var fastUri = {
|
|
18467
18554
|
SCHEMES,
|
|
@@ -31782,7 +31869,7 @@ async function handleRestartFirefox(input) {
|
|
|
31782
31869
|
profilePath: profilePath ?? currentOptions.profilePath,
|
|
31783
31870
|
env: newEnv !== void 0 ? newEnv : currentOptions.env,
|
|
31784
31871
|
headless: headless !== void 0 ? headless : currentOptions.headless,
|
|
31785
|
-
startUrl: startUrl ?? currentOptions.startUrl ?? "about:
|
|
31872
|
+
startUrl: startUrl ?? currentOptions.startUrl ?? "about:blank",
|
|
31786
31873
|
prefs: mergedPrefs
|
|
31787
31874
|
};
|
|
31788
31875
|
setNextLaunchOptions(newOptions);
|
|
@@ -31836,7 +31923,7 @@ ${changes.join("\n")}`
|
|
|
31836
31923
|
profilePath: profilePath ?? args.profilePath ?? void 0,
|
|
31837
31924
|
env: newEnv,
|
|
31838
31925
|
headless: headless ?? false,
|
|
31839
|
-
startUrl: startUrl ?? "about:
|
|
31926
|
+
startUrl: startUrl ?? "about:blank"
|
|
31840
31927
|
};
|
|
31841
31928
|
setNextLaunchOptions(newOptions);
|
|
31842
31929
|
const config2 = [`Binary: ${resolvedFirefoxPath}`];
|
|
@@ -31927,7 +32014,7 @@ var init_firefox_management = __esm({
|
|
|
31927
32014
|
},
|
|
31928
32015
|
startUrl: {
|
|
31929
32016
|
type: "string",
|
|
31930
|
-
description: "URL to navigate to after restart (optional, uses about:
|
|
32017
|
+
description: "URL to navigate to after restart (optional, uses about:blank if not specified)"
|
|
31931
32018
|
},
|
|
31932
32019
|
prefs: {
|
|
31933
32020
|
type: "object",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mozilla/firefox-devtools-mcp",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.5",
|
|
4
4
|
"description": "Model Context Protocol (MCP) server for Firefox DevTools automation",
|
|
5
5
|
"author": "Mozilla",
|
|
6
6
|
"license": "MIT OR Apache-2.0",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"build": "tsup",
|
|
16
16
|
"build:moz": "node scripts/generate-moz-package.mjs && tsup --config tsup.config.moz.ts",
|
|
17
17
|
"build:all": "npm run build && npm run build:moz",
|
|
18
|
+
"publish:moz": "node scripts/publish-moz-package.mjs",
|
|
18
19
|
"start": "node dist/index.js",
|
|
19
20
|
"setup": "node scripts/setup-mcp-config.js",
|
|
20
21
|
"clean": "rm -rf dist",
|