@mozilla/firefox-devtools-mcp-moz 0.9.9 → 0.9.12
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.moz/index.js +32 -16
- package/package.json +2 -1
- package/plugins/firefox-devtools-mcp/.claude-plugin/plugin.json +24 -0
- package/plugins/firefox-devtools-mcp/agents/e2e-tester.md +42 -0
- package/plugins/firefox-devtools-mcp/agents/web-extractor.md +36 -0
- package/plugins/firefox-devtools-mcp/skills/browser-automation/SKILL.md +77 -0
- package/plugins/firefox-devtools-mcp/skills/debug/SKILL.md +32 -0
- package/plugins/firefox-devtools-mcp/skills/navigate/SKILL.md +32 -0
- package/plugins/firefox-devtools-mcp/skills/screenshot/SKILL.md +30 -0
- package/plugins/firefox-devtools-troubleshoot/.claude-plugin/plugin.json +11 -0
- package/plugins/firefox-devtools-troubleshoot/skills/diagnose/SKILL.md +41 -0
- package/scripts/build-mcpb.mjs +52 -0
package/dist.moz/index.js
CHANGED
|
@@ -39,8 +39,19 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
39
39
|
));
|
|
40
40
|
|
|
41
41
|
// src/cli.ts
|
|
42
|
+
import { createHash } from "crypto";
|
|
43
|
+
import { homedir } from "os";
|
|
44
|
+
import { join } from "path";
|
|
42
45
|
import yargs from "yargs";
|
|
43
46
|
import { hideBin } from "yargs/helpers";
|
|
47
|
+
function defaultProfileDir(firefoxPath) {
|
|
48
|
+
const base = join(homedir(), ".firefox-devtools-mcp");
|
|
49
|
+
if (!firefoxPath) {
|
|
50
|
+
return join(base, "profile");
|
|
51
|
+
}
|
|
52
|
+
const hash2 = createHash("sha1").update(firefoxPath).digest("hex").slice(0, 8);
|
|
53
|
+
return join(base, `profile-${hash2}`);
|
|
54
|
+
}
|
|
44
55
|
function parsePrefs(prefs) {
|
|
45
56
|
const result = {};
|
|
46
57
|
if (!prefs || prefs.length === 0) {
|
|
@@ -122,6 +133,11 @@ var init_cli = __esm({
|
|
|
122
133
|
type: "string",
|
|
123
134
|
description: "Path to Firefox profile directory (optional, for persistent profile)"
|
|
124
135
|
},
|
|
136
|
+
autoProfile: {
|
|
137
|
+
type: "boolean",
|
|
138
|
+
description: "Automatically use a persistent profile stored in ~/.firefox-devtools-mcp/. When --firefox-path is set, the profile is scoped to that binary so different Firefox builds stay isolated.",
|
|
139
|
+
default: (process.env.AUTO_PROFILE ?? "false") === "true"
|
|
140
|
+
},
|
|
125
141
|
firefoxArg: {
|
|
126
142
|
type: "array",
|
|
127
143
|
description: "Additional arguments for Firefox. Only applies when Firefox is launched by firefox-devtools-mcp."
|
|
@@ -28076,8 +28092,8 @@ var SERVER_NAME, SERVER_VERSION;
|
|
|
28076
28092
|
var init_constants = __esm({
|
|
28077
28093
|
"src/config/constants.ts"() {
|
|
28078
28094
|
"use strict";
|
|
28079
|
-
SERVER_NAME = "firefox-devtools";
|
|
28080
|
-
SERVER_VERSION = "0.
|
|
28095
|
+
SERVER_NAME = true ? "@mozilla/firefox-devtools-mcp" : "firefox-devtools";
|
|
28096
|
+
SERVER_VERSION = true ? "0.9.12" : "dev";
|
|
28081
28097
|
}
|
|
28082
28098
|
});
|
|
28083
28099
|
|
|
@@ -28157,12 +28173,12 @@ var init_logger = __esm({
|
|
|
28157
28173
|
|
|
28158
28174
|
// src/firefox/profile.ts
|
|
28159
28175
|
import { existsSync, mkdirSync, copyFileSync } from "fs";
|
|
28160
|
-
import { join } from "path";
|
|
28176
|
+
import { join as join2 } from "path";
|
|
28161
28177
|
function isFirefoxProfile(dir) {
|
|
28162
|
-
return FIREFOX_PROFILE_INDICATORS.some((file2) => existsSync(
|
|
28178
|
+
return FIREFOX_PROFILE_INDICATORS.some((file2) => existsSync(join2(dir, file2)));
|
|
28163
28179
|
}
|
|
28164
28180
|
function resolveProfilePath(parentPath) {
|
|
28165
|
-
const mcpProfilePath =
|
|
28181
|
+
const mcpProfilePath = join2(parentPath, MCP_PROFILE_DIR_NAME);
|
|
28166
28182
|
let warning = null;
|
|
28167
28183
|
if (isFirefoxProfile(parentPath)) {
|
|
28168
28184
|
warning = `Warning: The path "${parentPath}" looks like an existing Firefox profile.
|
|
@@ -28177,9 +28193,9 @@ function resolveProfilePath(parentPath) {
|
|
|
28177
28193
|
if (isNew) {
|
|
28178
28194
|
mkdirSync(mcpProfilePath, { recursive: true });
|
|
28179
28195
|
log(`Created MCP profile directory: ${mcpProfilePath}`);
|
|
28180
|
-
const parentPrefs =
|
|
28196
|
+
const parentPrefs = join2(parentPath, "prefs.js");
|
|
28181
28197
|
if (existsSync(parentPrefs)) {
|
|
28182
|
-
copyFileSync(parentPrefs,
|
|
28198
|
+
copyFileSync(parentPrefs, join2(mcpProfilePath, "prefs.js"));
|
|
28183
28199
|
log(` Copied prefs.js from parent profile for initial preferences.`);
|
|
28184
28200
|
}
|
|
28185
28201
|
}
|
|
@@ -28199,14 +28215,14 @@ var init_profile = __esm({
|
|
|
28199
28215
|
import { Builder, Browser, Capabilities } from "selenium-webdriver";
|
|
28200
28216
|
import firefox from "selenium-webdriver/firefox.js";
|
|
28201
28217
|
import { mkdirSync as mkdirSync2, openSync, closeSync, existsSync as existsSync2, readdirSync, statSync } from "fs";
|
|
28202
|
-
import { homedir } from "os";
|
|
28203
|
-
import { join as
|
|
28218
|
+
import { homedir as homedir2 } from "os";
|
|
28219
|
+
import { join as join3, delimiter } from "path";
|
|
28204
28220
|
function findGeckodriverInPath(binaryName) {
|
|
28205
28221
|
for (const dir of (process.env.PATH ?? "").split(delimiter)) {
|
|
28206
28222
|
if (!dir) {
|
|
28207
28223
|
continue;
|
|
28208
28224
|
}
|
|
28209
|
-
const candidate =
|
|
28225
|
+
const candidate = join3(dir, binaryName);
|
|
28210
28226
|
if (existsSync2(candidate)) {
|
|
28211
28227
|
return candidate;
|
|
28212
28228
|
}
|
|
@@ -28214,18 +28230,18 @@ function findGeckodriverInPath(binaryName) {
|
|
|
28214
28230
|
return null;
|
|
28215
28231
|
}
|
|
28216
28232
|
function findGeckodriverInSeleniumCache(binaryName) {
|
|
28217
|
-
const cacheBase =
|
|
28233
|
+
const cacheBase = join3(homedir2(), ".cache/selenium/geckodriver");
|
|
28218
28234
|
try {
|
|
28219
28235
|
if (!existsSync2(cacheBase)) {
|
|
28220
28236
|
return null;
|
|
28221
28237
|
}
|
|
28222
28238
|
for (const platformDir of readdirSync(cacheBase)) {
|
|
28223
|
-
const platformPath =
|
|
28239
|
+
const platformPath = join3(cacheBase, platformDir);
|
|
28224
28240
|
if (!statSync(platformPath).isDirectory()) {
|
|
28225
28241
|
continue;
|
|
28226
28242
|
}
|
|
28227
28243
|
for (const versionDir of readdirSync(platformPath).sort().reverse()) {
|
|
28228
|
-
const candidate =
|
|
28244
|
+
const candidate = join3(platformPath, versionDir, binaryName);
|
|
28229
28245
|
if (existsSync2(candidate)) {
|
|
28230
28246
|
return candidate;
|
|
28231
28247
|
}
|
|
@@ -28315,10 +28331,10 @@ var init_core3 = __esm({
|
|
|
28315
28331
|
if (this.options.logFile) {
|
|
28316
28332
|
this.logFilePath = this.options.logFile;
|
|
28317
28333
|
} else if (this.options.env && Object.keys(this.options.env).length > 0) {
|
|
28318
|
-
const outputDir =
|
|
28334
|
+
const outputDir = join3(homedir2(), ".firefox-devtools-mcp", "output");
|
|
28319
28335
|
mkdirSync2(outputDir, { recursive: true });
|
|
28320
28336
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
28321
|
-
this.logFilePath =
|
|
28337
|
+
this.logFilePath = join3(outputDir, `firefox-${timestamp}.log`);
|
|
28322
28338
|
}
|
|
28323
28339
|
if (this.options.env) {
|
|
28324
28340
|
for (const [key, value] of Object.entries(this.options.env)) {
|
|
@@ -33419,7 +33435,7 @@ async function getFirefox() {
|
|
|
33419
33435
|
options = {
|
|
33420
33436
|
firefoxPath: args.firefoxPath ?? void 0,
|
|
33421
33437
|
headless: args.headless,
|
|
33422
|
-
profilePath: args.profilePath ?? void 0,
|
|
33438
|
+
profilePath: args.profilePath ?? (args.autoProfile ? defaultProfileDir(args.firefoxPath) : void 0),
|
|
33423
33439
|
viewport: args.viewport ?? void 0,
|
|
33424
33440
|
args: args.firefoxArg ?? void 0,
|
|
33425
33441
|
startUrl: args.startUrl ?? void 0,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mozilla/firefox-devtools-mcp-moz",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.12",
|
|
4
4
|
"description": "Model Context Protocol (MCP) server for Firefox DevTools automation (moz build with privileged context support)",
|
|
5
5
|
"author": "Mozilla",
|
|
6
6
|
"license": "MIT OR Apache-2.0",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"yargs": "17.7.2"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
+
"@anthropic-ai/mcpb": "2.1.2",
|
|
41
42
|
"@types/jsdom": "28.0.0",
|
|
42
43
|
"@types/node": "24.1.0",
|
|
43
44
|
"@types/selenium-webdriver": "4.35.1",
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "firefox-devtools-mcp",
|
|
3
|
+
"description": "Control Firefox for browsing, web testing, and debugging. Fill forms, capture network and console activity, take screenshots, run scripts, and profile performance. Supports Android devices.",
|
|
4
|
+
"author": {
|
|
5
|
+
"name": "Mozilla",
|
|
6
|
+
"url": "https://github.com/mozilla/firefox-devtools-mcp"
|
|
7
|
+
},
|
|
8
|
+
"repository": "https://github.com/mozilla/firefox-devtools-mcp",
|
|
9
|
+
"homepage": "https://github.com/mozilla/firefox-devtools-mcp",
|
|
10
|
+
"license": "MIT OR Apache-2.0",
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"firefox-devtools": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": [
|
|
15
|
+
"-y",
|
|
16
|
+
"@mozilla/firefox-devtools-mcp@latest",
|
|
17
|
+
"--auto-profile",
|
|
18
|
+
"--enable-script",
|
|
19
|
+
"--pref",
|
|
20
|
+
"remote.prefs.recommended=false"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: e2e-tester
|
|
3
|
+
description: Agent for running E2E tests on web applications. Navigates pages, fills forms, clicks buttons, and verifies results.
|
|
4
|
+
model: sonnet
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You are an E2E testing agent specializing in automated browser testing using Firefox DevTools MCP.
|
|
8
|
+
|
|
9
|
+
## Your Task
|
|
10
|
+
|
|
11
|
+
When given a test scenario, execute it step-by-step using Firefox automation tools, verify the results, and report pass/fail status.
|
|
12
|
+
|
|
13
|
+
## Process
|
|
14
|
+
|
|
15
|
+
1. **Navigate to the target**: Use `navigate_page` to open the URL
|
|
16
|
+
2. **Take snapshot**: Always call `take_snapshot` before interacting
|
|
17
|
+
3. **Execute test steps**: Use `fill_by_uid`, `click_by_uid`, etc.
|
|
18
|
+
4. **Re-snapshot after changes**: DOM updates require fresh snapshots
|
|
19
|
+
5. **Verify results**: Check for expected elements, text, or states
|
|
20
|
+
6. **Report outcome**: Clear pass/fail with evidence (screenshots if needed)
|
|
21
|
+
|
|
22
|
+
## Available Tools
|
|
23
|
+
|
|
24
|
+
- `navigate_page` - Go to URL
|
|
25
|
+
- `navigate_history` - Go back or forward
|
|
26
|
+
- `take_snapshot` - Get DOM with UIDs
|
|
27
|
+
- `fill_by_uid` / `fill_form_by_uid` - Enter text into fields
|
|
28
|
+
- `click_by_uid` - Click elements
|
|
29
|
+
- `hover_by_uid` - Hover over elements
|
|
30
|
+
- `drag_by_uid_to_uid` - Drag and drop
|
|
31
|
+
- `accept_dialog` / `dismiss_dialog` - Handle browser dialogs
|
|
32
|
+
- `screenshot_page` - Capture evidence
|
|
33
|
+
- `list_console_messages` - Check for JS errors
|
|
34
|
+
- `list_network_requests` - Verify API calls
|
|
35
|
+
|
|
36
|
+
## Guidelines
|
|
37
|
+
|
|
38
|
+
- Always snapshot before AND after interactions
|
|
39
|
+
- Take screenshots at key checkpoints using `screenshot_page` — display the returned image inline as evidence
|
|
40
|
+
- Report console errors as test failures
|
|
41
|
+
- Be specific about what passed or failed
|
|
42
|
+
- Handle dialogs explicitly — unexpected dialogs block interactions
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: web-extractor
|
|
3
|
+
description: Agent for browsing and extracting structured content from web pages. Navigates pages, handles pagination, and returns structured data.
|
|
4
|
+
model: sonnet
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You are a web extraction agent specializing in retrieving structured content from web pages using Firefox DevTools MCP.
|
|
8
|
+
|
|
9
|
+
## Your Task
|
|
10
|
+
|
|
11
|
+
When given an extraction task, navigate to pages, locate the target content, handle pagination if needed, and return structured results.
|
|
12
|
+
|
|
13
|
+
## Process
|
|
14
|
+
|
|
15
|
+
1. **Navigate to source**: Use `navigate_page` to open the URL
|
|
16
|
+
2. **Take snapshot**: Call `take_snapshot` to see page structure
|
|
17
|
+
3. **Identify target elements**: Find UIDs for elements containing target data
|
|
18
|
+
4. **Extract content**: The snapshot contains text content of elements
|
|
19
|
+
5. **Handle pagination**: Click "next" buttons, re-snapshot, repeat
|
|
20
|
+
6. **Structure output**: Return data in requested format (JSON, table, etc.)
|
|
21
|
+
|
|
22
|
+
## Available Tools
|
|
23
|
+
|
|
24
|
+
- `navigate_page` - Go to URL
|
|
25
|
+
- `navigate_history` - Go back or forward
|
|
26
|
+
- `take_snapshot` - Get DOM with content and UIDs
|
|
27
|
+
- `click_by_uid` - Navigate pagination or interact with elements
|
|
28
|
+
- `list_network_requests` - Monitor API calls (often cleaner than DOM extraction)
|
|
29
|
+
- `screenshot_page` - Capture page state (returns base64 image, display it inline)
|
|
30
|
+
|
|
31
|
+
## Guidelines
|
|
32
|
+
|
|
33
|
+
- Snapshots contain element text — no need for separate "get text" calls
|
|
34
|
+
- Check network requests for API endpoints (often cleaner than parsing the DOM)
|
|
35
|
+
- Handle "load more" buttons and infinite scroll patterns
|
|
36
|
+
- Return structured data, not raw HTML
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: browser-automation
|
|
3
|
+
description: This skill should be used when the user asks about browser automation, testing web pages, extracting content, filling forms, taking screenshots, or monitoring console/network activity. Activates for E2E testing, form automation, browsing tasks, or debugging web applications.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
When the user asks about browser automation, use Firefox DevTools MCP to control a real Firefox browser.
|
|
7
|
+
|
|
8
|
+
## Before Starting
|
|
9
|
+
|
|
10
|
+
Always call `list_pages` first. This checks whether Firefox is already running and which pages are open. Do not assume Firefox needs to be restarted or that you need to navigate from scratch — reuse the existing session whenever possible.
|
|
11
|
+
|
|
12
|
+
## When to Use This Skill
|
|
13
|
+
|
|
14
|
+
Activate this skill when the user:
|
|
15
|
+
|
|
16
|
+
- Wants to automate browser interactions ("Fill out this form", "Click the login button")
|
|
17
|
+
- Needs E2E testing ("Test the checkout flow", "Verify the login works")
|
|
18
|
+
- Wants to browse or extract content ("Get all links on this page", "Extract prices")
|
|
19
|
+
- Needs screenshots ("Screenshot this page", "Capture the error state")
|
|
20
|
+
- Wants to debug ("Check for JS errors", "Show failed network requests")
|
|
21
|
+
- Needs to profile performance ("Profile this page load")
|
|
22
|
+
|
|
23
|
+
## Core Workflow
|
|
24
|
+
|
|
25
|
+
### Step 1: Navigate and Snapshot
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
navigate_page url="https://example.com"
|
|
29
|
+
take_snapshot
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The snapshot returns a DOM representation with UIDs (e.g., `e42`) for each interactive element.
|
|
33
|
+
|
|
34
|
+
### Step 2: Interact with Elements
|
|
35
|
+
|
|
36
|
+
Use UIDs from the snapshot:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
fill_by_uid uid="e5" text="user@example.com"
|
|
40
|
+
click_by_uid uid="e8"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Step 3: Re-snapshot After Changes
|
|
44
|
+
|
|
45
|
+
DOM changes invalidate UIDs. Always re-snapshot after:
|
|
46
|
+
- Page navigation
|
|
47
|
+
- Form submissions
|
|
48
|
+
- Dynamic content loads
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
take_snapshot # Get fresh UIDs
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Quick Reference
|
|
55
|
+
|
|
56
|
+
| Task | Tools |
|
|
57
|
+
|------|-------|
|
|
58
|
+
| Navigate | `navigate_page`, `navigate_history` |
|
|
59
|
+
| See DOM | `take_snapshot` |
|
|
60
|
+
| Click | `click_by_uid` |
|
|
61
|
+
| Hover | `hover_by_uid` |
|
|
62
|
+
| Type | `fill_by_uid`, `fill_form_by_uid` |
|
|
63
|
+
| Drag | `drag_by_uid_to_uid` |
|
|
64
|
+
| Dialogs | `accept_dialog`, `dismiss_dialog` |
|
|
65
|
+
| Screenshot | `screenshot_page`, `screenshot_by_uid` |
|
|
66
|
+
| Debug | `list_console_messages`, `list_network_requests` |
|
|
67
|
+
| Profile | `profiler_start`, `profiler_stop` |
|
|
68
|
+
|
|
69
|
+
## Guidelines
|
|
70
|
+
|
|
71
|
+
- **Check existing session first**: Call `list_pages` before navigating — reuse the running Firefox session rather than starting fresh
|
|
72
|
+
- **Always snapshot first**: UIDs only exist after `take_snapshot`
|
|
73
|
+
- **Re-snapshot after DOM changes**: UIDs become stale after interactions
|
|
74
|
+
- **Screenshots**: in Cowork (system prompt has an outputs folder host path), call `screenshot_page saveTo="<host-outputs-path>/screenshot.png"` then call `present_files` with that path. Otherwise call `screenshot_page` without `saveTo` and include the returned image directly in your reply — the user cannot see tool call outputs.
|
|
75
|
+
- **Check for errors**: Use `list_console_messages level="error"` to catch JS issues
|
|
76
|
+
- **Firefox only**: This MCP controls Firefox, not Chrome or Safari
|
|
77
|
+
- **Reconfiguring Firefox**: to use a specific binary, profile, or headless mode, call `restart_firefox` with the relevant options (`firefoxPath`, `profilePath`, `headless`)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show console errors and failed network requests
|
|
3
|
+
argument-hint: [console|network|all]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /firefox-devtools-mcp:debug
|
|
7
|
+
|
|
8
|
+
Displays debugging information from the current page.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
/firefox-devtools-mcp:debug # Show all (console errors + failed requests)
|
|
14
|
+
/firefox-devtools-mcp:debug console # Console messages only
|
|
15
|
+
/firefox-devtools-mcp:debug network # Network requests only
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Examples
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
/firefox-devtools-mcp:debug
|
|
22
|
+
/firefox-devtools-mcp:debug console
|
|
23
|
+
/firefox-devtools-mcp:debug network
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## What Happens
|
|
27
|
+
|
|
28
|
+
- `console`: Calls `list_console_messages` with `level="error"`
|
|
29
|
+
- `network`: Calls `list_network_requests` with `statusMin=400`
|
|
30
|
+
- `all` (default): Shows both console errors and failed network requests
|
|
31
|
+
|
|
32
|
+
Requires Firefox to already be running and on the page you want to debug. If Firefox is not running or is on about:blank, call `navigate_page` first.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: navigate
|
|
3
|
+
description: Navigate Firefox to a URL and take a DOM snapshot for interaction
|
|
4
|
+
argument-hint: <url>
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /firefox-devtools-mcp:navigate
|
|
8
|
+
|
|
9
|
+
Opens a URL in Firefox and takes a DOM snapshot for interaction.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
/firefox-devtools-mcp:navigate <url>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Examples
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
/firefox-devtools-mcp:navigate https://example.com
|
|
21
|
+
/firefox-devtools-mcp:navigate https://github.com/login
|
|
22
|
+
/firefox-devtools-mcp:navigate file:///path/to/local.html
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## What Happens
|
|
26
|
+
|
|
27
|
+
1. Calls `navigate_page` with the URL
|
|
28
|
+
2. Waits for page load
|
|
29
|
+
3. Calls `take_snapshot` to create UID mappings
|
|
30
|
+
4. Returns the DOM snapshot with interactive elements marked
|
|
31
|
+
|
|
32
|
+
After navigating, you can interact with elements using their UIDs (e.g., `e42`).
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: screenshot
|
|
3
|
+
description: Take a screenshot of a URL or the current page. Use when the user asks to capture, screenshot, or photograph a web page or URL.
|
|
4
|
+
argument-hint: [url or uid]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /firefox-devtools-mcp:screenshot
|
|
8
|
+
|
|
9
|
+
Captures a screenshot of a URL or the current page and shows it to the user.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
/firefox-devtools-mcp:screenshot https://example.com # Navigate then screenshot
|
|
15
|
+
/firefox-devtools-mcp:screenshot # Screenshot current page
|
|
16
|
+
/firefox-devtools-mcp:screenshot <uid> # Screenshot specific element
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Steps
|
|
20
|
+
|
|
21
|
+
1. Navigate if a URL was given: call `navigate_page`.
|
|
22
|
+
2. Take the screenshot using the method that matches your environment:
|
|
23
|
+
|
|
24
|
+
**In Cowork** (system prompt contains an outputs folder host path under "Shell access"):
|
|
25
|
+
- Call `screenshot_page saveTo="<host-outputs-path>/screenshot.png"` using the host path from the system prompt, not the container path.
|
|
26
|
+
- Load and call `present_files` with that same path so the user receives a clickable file card.
|
|
27
|
+
|
|
28
|
+
**In Claude.ai chat or Claude Desktop** (no outputs folder in system prompt):
|
|
29
|
+
- Call `screenshot_page` without `saveTo`.
|
|
30
|
+
- Your final response must include the actual image returned — not a description of it. The user cannot see tool call outputs, only what you include in your reply.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "firefox-devtools-troubleshoot",
|
|
3
|
+
"description": "Diagnose and fix Firefox DevTools MCP setup issues. Use this if the firefox-devtools-mcp plugin is not working.",
|
|
4
|
+
"author": {
|
|
5
|
+
"name": "Mozilla",
|
|
6
|
+
"url": "https://github.com/mozilla/firefox-devtools-mcp"
|
|
7
|
+
},
|
|
8
|
+
"repository": "https://github.com/mozilla/firefox-devtools-mcp",
|
|
9
|
+
"homepage": "https://github.com/mozilla/firefox-devtools-mcp",
|
|
10
|
+
"license": "MIT OR Apache-2.0"
|
|
11
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: firefox-devtools-diagnose
|
|
3
|
+
description: Diagnose Firefox DevTools MCP setup issues. Activate when the firefox-devtools-mcp plugin fails to connect, its tools are not available, or the user reports Firefox DevTools not working in Cowork.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
When Firefox DevTools MCP tools are unavailable or the user reports issues with the firefox-devtools-mcp plugin, run this diagnostic sequence automatically. Do not ask the user to do these checks manually.
|
|
7
|
+
|
|
8
|
+
## Diagnostic Steps
|
|
9
|
+
|
|
10
|
+
### 1. Check Node.js
|
|
11
|
+
|
|
12
|
+
Run `node --version` using the Bash tool.
|
|
13
|
+
|
|
14
|
+
- If the command fails with "command not found": tell the user Node.js is not installed and direct them to download Node.js 20.19.0 or higher from https://nodejs.org.
|
|
15
|
+
- If the version is below 20.19.0: tell the user their Node.js version is too old and they need to upgrade to 20.19.0 or higher from https://nodejs.org.
|
|
16
|
+
- If the version is 20.19.0 or higher: Node.js is not the issue, continue to the next check.
|
|
17
|
+
|
|
18
|
+
### 2. Check Your Own Tool List
|
|
19
|
+
|
|
20
|
+
Check whether any `firefox-devtools-mcp:*` tools are present in your current tool list.
|
|
21
|
+
|
|
22
|
+
- If present: the plugin is installed and connected in this conversation. The reported issue is not a setup problem — investigate the specific tool failure directly (bad arguments, target page state, etc.) rather than continuing this checklist.
|
|
23
|
+
- If absent: this is ambiguous by itself. An empty tool list looks identical whether the plugin isn't installed, the user is in the Chat tab instead of Cowork, or the plugin is installed in Cowork but failing for some other reason. Do not guess which; continue to the next step.
|
|
24
|
+
|
|
25
|
+
### 3. Check Installation and Tab Together
|
|
26
|
+
|
|
27
|
+
Since an absent tool list can't be attributed to a single cause from your side, ask the user to confirm both of the following in one pass:
|
|
28
|
+
|
|
29
|
+
- Open **Customize > Plugins** in Claude Cowork and confirm `firefox-devtools-mcp` appears in the list.
|
|
30
|
+
- Confirm they are currently in the **Cowork** tab, not the **Chat** tab — plugins only work in Cowork.
|
|
31
|
+
|
|
32
|
+
- If the plugin is missing: direct them to the installation steps at https://github.com/mozilla/firefox-devtools-mcp.
|
|
33
|
+
- If the plugin is present but they were in Chat: ask them to switch to Cowork and retry.
|
|
34
|
+
- If the plugin is present and they are already in Cowork: continue to the next step.
|
|
35
|
+
|
|
36
|
+
### 4. Escalate
|
|
37
|
+
|
|
38
|
+
If all checks pass and the plugin still does not work, tell the user to report the issue:
|
|
39
|
+
|
|
40
|
+
- File a bug on [Bugzilla](https://bugzilla.mozilla.org/enter_bug.cgi?format=__default__&blocked=2026717&product=Developer%20Infrastructure&component=Firefox%20MCP)
|
|
41
|
+
- Or ask in the [#firefox-devtools-mcp Matrix room](https://chat.mozilla.org/#/room/#firefox-devtools-mcp:mozilla.org)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Builds the firefox-devtools-mcp .mcpb bundle (Claude Desktop extension).
|
|
4
|
+
* Assembles a staging directory with dist/, production node_modules and
|
|
5
|
+
* manifest.json, then runs `mcpb pack` on it.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { readFileSync, writeFileSync, existsSync, cpSync, mkdtempSync, rmSync } from 'node:fs';
|
|
9
|
+
import { execSync } from 'node:child_process';
|
|
10
|
+
import { resolve, dirname } from 'node:path';
|
|
11
|
+
import { fileURLToPath } from 'node:url';
|
|
12
|
+
import { tmpdir } from 'node:os';
|
|
13
|
+
|
|
14
|
+
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
15
|
+
const pkg = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'));
|
|
16
|
+
const manifest = JSON.parse(readFileSync(resolve(root, 'manifest.json'), 'utf8'));
|
|
17
|
+
|
|
18
|
+
console.log('Building server...');
|
|
19
|
+
execSync('npm run build', { cwd: root, stdio: 'inherit' });
|
|
20
|
+
|
|
21
|
+
const stagingDir = mkdtempSync(resolve(tmpdir(), 'firefox-devtools-mcpb-'));
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
cpSync(resolve(root, 'dist'), resolve(stagingDir, 'dist'), { recursive: true });
|
|
25
|
+
for (const file of ['README.md', 'LICENSE-MIT', 'LICENSE-APACHE', 'package.json', 'package-lock.json']) {
|
|
26
|
+
cpSync(resolve(root, file), resolve(stagingDir, file));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
console.log('Installing production dependencies...');
|
|
30
|
+
execSync('npm ci --omit=dev', { cwd: stagingDir, stdio: 'inherit' });
|
|
31
|
+
|
|
32
|
+
writeFileSync(
|
|
33
|
+
resolve(stagingDir, 'manifest.json'),
|
|
34
|
+
JSON.stringify({ ...manifest, version: pkg.version }, null, 2) + '\n'
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const outDir = resolve(root, 'dist-mcpb');
|
|
38
|
+
if (!existsSync(outDir)) {
|
|
39
|
+
execSync(`mkdir -p ${outDir}`);
|
|
40
|
+
}
|
|
41
|
+
const outFile = resolve(outDir, `firefox-devtools-mcp-${pkg.version}.mcpb`);
|
|
42
|
+
|
|
43
|
+
console.log('Packing .mcpb bundle...');
|
|
44
|
+
execSync(`npx mcpb pack "${stagingDir}" "${outFile}"`, {
|
|
45
|
+
cwd: root,
|
|
46
|
+
stdio: 'inherit',
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
console.log(`Written ${outFile}`);
|
|
50
|
+
} finally {
|
|
51
|
+
rmSync(stagingDir, { recursive: true, force: true });
|
|
52
|
+
}
|