npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fulldecent/firefox-devtools-mcp

v0.7.6

Published

Model Context Protocol (MCP) server for Firefox DevTools automation (fork with Firefox management tools)

Readme

@fulldecent/firefox-devtools-mcp

npm version License: MIT

Model Context Protocol server for automating Firefox via WebDriver BiDi (through Selenium WebDriver). Works with Claude Code, Claude Desktop, Cursor, Cline and other MCP clients.

Note: this MCP server requires a local Firefox browser installation and cannot run on cloud hosting services. Use npx @fulldecent/firefox-devtools-mcp@latest to run locally, or use Docker with the provided Dockerfile.

How this differs from upstream

This package is a fork of firefox-devtools-mcp (by freema) via @padenot/firefox-devtools-mcp. The following features are added on top of immediate upstream:

  • Tabs are identified with robust UUIDs in all functions (instead of ephemeral tab index number). This means you can have multiple agents all accessing their own tabs in the same browser profile simultaneously.

The goal is to upstream features that prove useful.

Requirements

  • Node.js ≥ 20.19.0
  • Firefox 100+ installed (auto‑detected, or pass --firefox-path)

Install and use with Claude Code

Recommended: use npx so you always run the latest published version from npm.

Option A — Claude Code CLI

claude mcp add firefox-devtools npx @fulldecent/firefox-devtools-mcp@latest

Pass options either as args or env vars:

# Headless + viewport via args
claude mcp add firefox-devtools npx @fulldecent/firefox-devtools-mcp@latest -- --headless --viewport 1280x720

# Or via environment variables
claude mcp add firefox-devtools npx @fulldecent/firefox-devtools-mcp@latest \
  --env START_URL=https://example.com \
  --env FIREFOX_HEADLESS=true

Option B — edit Claude Code settings JSON

Add to your Claude Code config file:

  • macOS: ~/Library/Application Support/Claude/Code/mcp_settings.json
  • Linux: ~/.config/claude/code/mcp_settings.json
  • Windows: %APPDATA%\Claude\Code\mcp_settings.json
{
  "mcpServers": {
    "firefox-devtools": {
      "command": "npx",
      "args": ["-y", "@fulldecent/firefox-devtools-mcp@latest", "--headless", "--viewport", "1280x720"],
      "env": {
        "START_URL": "about:home"
      }
    }
  }
}

Option C — helper script (local dev build)

npm run setup
# Choose Claude Code; the script saves JSON to the right path

Try it with MCP Inspector

npx @modelcontextprotocol/inspector npx @fulldecent/firefox-devtools-mcp@latest --start-url https://example.com --headless

Then call tools like:

  • list_pages, navigate_page (pass pageId from list_pages)
  • take_snapshot then click_by_uid / fill_by_uid
  • list_network_requests (always‑on capture), get_network_request
  • screenshot_page, list_console_messages

CLI options

You can pass flags or environment variables (names on the right):

| Flag | Environment variable | Description | |---|---|---| | --firefox-path | | Absolute path to Firefox binary | | --headless | FIREFOX_HEADLESS=true | Run without UI | | --viewport 1280x720 | | Initial window size | | --profile-path | | Use a specific Firefox profile | | --firefox-arg | | Extra Firefox arguments (repeatable) | | --start-url | START_URL | Open this URL on start | | --accept-insecure-certs | ACCEPT_INSECURE_CERTS=true | Ignore TLS errors | | --pref name=value | | Set Firefox preference at startup (repeatable, requires MOZ_REMOTE_ALLOW_SYSTEM_ACCESS=1) | | --env KEY=VALUE | | Pass environment variables to Firefox (repeatable) | | --output-file | | Path for Firefox output redirection |

Note on --pref: when Firefox runs in WebDriver BiDi mode, it applies RecommendedPreferences that modify browser behavior for testing. The --pref option allows overriding these defaults when needed (e.g., for Firefox development, debugging, or testing scenarios that require production-like behavior).

Example: --pref "browser.ml.enable=true" enables Firefox's ML/AI features. This is essential when using this MCP server to develop or test AI-powered features like Smart Window, since RecommendedPreferences disables it by default.

Tool reference

All page-aware tools require an explicit pageId parameter — the stable window handle returned by list_pages. This handle is assigned by Firefox at tab-creation time and does not change if other tabs are opened or closed, making it safe to hold across multi-step workflows.

Page management

| Tool | Description | |---|---| | list_pages | List open tabs. Returns stable pageId for each tab. | | new_page | Open new tab at URL. Returns pageId of the new tab. | | navigate_page | Navigate a tab to a URL. | | close_page | Close a tab. |

list_pages — no parameters

new_page

| Parameter | Type | Required | Description | |---|---|---|---| | url | string | yes | Target URL |

navigate_page

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages | | url | string | yes | Target URL |

close_page

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages |

DOM snapshot

UIDs are stable identifiers for DOM elements within a single snapshot. They become invalid after page navigation or DOM changes — call take_snapshot again to get fresh UIDs.

| Tool | Description | |---|---| | take_snapshot | Capture DOM snapshot with stable UIDs for element interaction. | | resolve_uid_to_selector | Resolve a UID to its CSS selector. | | clear_snapshot | Clear snapshot cache. |

take_snapshot

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages | | maxLines | number | no | Maximum lines to display (default: 100) | | includeAttributes | boolean | no | Include ARIA attributes (default: false) | | includeText | boolean | no | Include text content (default: true) | | maxDepth | number | no | Maximum tree depth for traversal | | includeAll | boolean | no | Include all visible elements without relevance filtering, useful for Vue/Livewire/Alpine.js apps (default: false) | | selector | string | no | CSS selector to scope snapshot to a specific subtree (e.g., #app) |

resolve_uid_to_selector

| Parameter | Type | Required | Description | |---|---|---|---| | uid | string | yes | UID from snapshot |

clear_snapshot — no parameters

Input interaction

All input tools require valid UIDs from the current snapshot.

| Tool | Description | |---|---| | click_by_uid | Click an element. | | hover_by_uid | Hover over an element. | | fill_by_uid | Fill a text input or textarea (clears existing value first). | | drag_by_uid_to_uid | Drag one element to another via HTML5 drag events. | | fill_form_by_uid | Fill multiple form fields at once. | | upload_file_by_uid | Upload a file to a file input. |

click_by_uid

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages | | uid | string | yes | Element UID from current snapshot | | dblClick | boolean | no | Double-click instead of single click (default: false) |

hover_by_uid

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages | | uid | string | yes | Element UID from current snapshot |

fill_by_uid

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages | | uid | string | yes | Input element UID from current snapshot | | value | string | yes | Text to fill |

drag_by_uid_to_uid

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages | | fromUid | string | yes | Source element UID | | toUid | string | yes | Target element UID |

fill_form_by_uid

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages | | elements | array | yes | Array of { uid: string, value: string } objects |

upload_file_by_uid

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages | | uid | string | yes | File input element UID from current snapshot | | filePath | string | yes | Local file path (absolute or relative) |

Network monitoring

Network requests are captured automatically. Use list_network_requests to browse and get_network_request to inspect individual requests in detail.

list_network_requests

| Parameter | Type | Required | Description | |---|---|---|---| | limit | number | no | Maximum number of requests (default: 50) | | sinceMs | number | no | Only show requests from last N milliseconds | | urlContains | string | no | Filter by URL substring (case-insensitive) | | method | string | no | HTTP method filter (e.g., GET, POST) | | status | number | no | Exact HTTP status code filter | | statusMin | number | no | Minimum status code | | statusMax | number | no | Maximum status code | | isXHR | boolean | no | Filter to XHR/fetch requests only | | resourceType | string | no | Filter by resource type (case-insensitive) | | sortBy | string | no | Sort field: timestamp (default), duration, or status | | detail | string | no | Detail level: summary (default), min, or full | | format | string | no | Output format: text (default) or json |

get_network_request

| Parameter | Type | Required | Description | |---|---|---|---| | id | string | no | Request ID from list_network_requests (primary lookup) | | url | string | no | URL as fallback lookup (exact match) | | format | string | no | Output format: text (default) or json |

Either id or url must be provided. If multiple requests match a URL, an error is returned listing the matching IDs.

Console

list_console_messages

| Parameter | Type | Required | Description | |---|---|---|---| | level | string | no | Filter by level: debug, info, warn, or error | | limit | number | no | Max messages to return (default: 50) | | sinceMs | number | no | Only show messages from the last N milliseconds | | textContains | string | no | Filter by text content (case-insensitive) | | source | string | no | Filter by source (case-insensitive) | | format | string | no | Output format: text (default) or json |

All filters are combined with AND logic.

clear_console_messages — no parameters. Returns count of cleared messages.

Screenshots

Returns a native MCP image content item (PNG) for GUI clients, or saves to disk when saveTo is provided.

screenshot_page

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages | | saveTo | string | no | File path to save screenshot instead of returning image data |

screenshot_by_uid

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages | | uid | string | yes | Element UID from current snapshot | | saveTo | string | no | File path to save screenshot instead of returning image data |

Screenshot tip for Claude Code: base64 image data consumes significant context. Use the saveTo parameter to save screenshots to disk, then view the file with Claude Code's read tool.

Script evaluation

evaluate_script — execute JavaScript in page context.

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages | | function | string | yes | JS function string (e.g., () => document.title). Max 16 KB. | | args | array | no | Array of objects with uid field to pass as function arguments | | timeout | number | no | Execution timeout in milliseconds (default: 5000) |

evaluate_chrome_script — evaluate JavaScript in the current chrome (privileged) context. Requires MOZ_REMOTE_ALLOW_SYSTEM_ACCESS=1.

| Parameter | Type | Required | Description | |---|---|---|---| | expression | string | yes | JavaScript expression to evaluate in chrome context |

Chrome context (privileged)

These tools require MOZ_REMOTE_ALLOW_SYSTEM_ACCESS=1 environment variable.

list_chrome_contexts — no parameters. Lists privileged browsing contexts with their IDs.

select_chrome_context

| Parameter | Type | Required | Description | |---|---|---|---| | contextId | string | yes | Chrome browsing context ID from list_chrome_contexts |

Firefox management

get_firefox_info — no parameters. Returns Firefox configuration: binary path, headless status, viewport, profile path, start URL, arguments, environment variables, preferences, output file path and size.

get_firefox_output — retrieve Firefox stdout/stderr output (including MOZ_LOG).

| Parameter | Type | Required | Description | |---|---|---|---| | lines | number | no | Number of recent log lines (default: 100, max: 10000) | | grep | string | no | Filter log lines containing this string (case-insensitive) | | since | number | no | Only show logs from last N seconds |

restart_firefox — restart Firefox with different configuration. All current tabs will be closed.

| Parameter | Type | Required | Description | |---|---|---|---| | firefoxPath | string | no | New Firefox binary path | | profilePath | string | no | Firefox profile path | | env | array | no | Environment variables in KEY=VALUE format (e.g., ["MOZ_LOG=HTMLMediaElement:5"]) | | headless | boolean | no | Run in headless mode | | startUrl | string | no | URL to navigate to after restart | | prefs | object | no | Firefox preferences object (values are auto-typed) |

Firefox preferences (runtime)

These tools require MOZ_REMOTE_ALLOW_SYSTEM_ACCESS=1.

set_firefox_prefs

| Parameter | Type | Required | Description | |---|---|---|---| | prefs | object | yes | Map of preference names to values. true/false strings become booleans, integer strings become numbers, everything else stays as strings. |

get_firefox_prefs

| Parameter | Type | Required | Description | |---|---|---|---| | names | array | yes | Array of preference names to read (e.g., ["browser.tabs.drawInTitlebar"]) |

WebExtension management

install_extension

| Parameter | Type | Required | Description | |---|---|---|---| | type | string | yes | Extension data type: archivePath (.xpi/.zip), base64 (encoded data), or path (unpacked directory) | | path | string | conditional | File path to extension archive or directory (required for archivePath/path types) | | value | string | conditional | Base64-encoded extension data (required for base64 type) | | permanent | boolean | no | Install permanently (requires signed extension). Default: false (temporary install). |

uninstall_extension

| Parameter | Type | Required | Description | |---|---|---|---| | id | string | yes | Extension ID (e.g., [email protected]) |

list_extensions — requires MOZ_REMOTE_ALLOW_SYSTEM_ACCESS=1.

| Parameter | Type | Required | Description | |---|---|---|---| | ids | array | no | Filter by exact extension IDs | | name | string | no | Filter by partial name match (case-insensitive) | | isActive | boolean | no | Filter by enabled/disabled status | | isSystem | boolean | no | Filter by system/built-in vs. user-installed |

Utilities

accept_dialog

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages | | promptText | string | no | Text to enter for prompt dialogs |

dismiss_dialog

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages |

navigate_history

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages | | direction | string | yes | back or forward |

set_viewport_size

| Parameter | Type | Required | Description | |---|---|---|---| | pageId | string | yes | Stable tab ID from list_pages | | width | number | yes | Width in pixels | | height | number | yes | Height in pixels |

Local development

npm install
npm run build

# Run with Inspector against local build
npx @modelcontextprotocol/inspector node dist/index.js --headless --viewport 1280x720

# Or run in dev with hot reload
npm run inspector:dev

Troubleshooting

  • Firefox not found: pass --firefox-path "/Applications/Firefox.app/Contents/MacOS/firefox" (macOS) or the correct path on your OS.
  • First run is slow: Selenium sets up the BiDi session; subsequent runs are faster.
  • Stale UIDs after navigation: take a fresh snapshot (take_snapshot) before using UID tools.
  • Windows 10 — MCP error -32000: connection closed:
    • Solution 1: call using cmd (see https://github.com/modelcontextprotocol/servers/issues/1082#issuecomment-2791786310)

      {
        "mcpServers": {
          "firefox-devtools": {
            "command": "cmd",
            "args": ["/c", "npx", "-y", "@fulldecent/firefox-devtools-mcp@latest"]
          }
        }
      }
    • Solution 2: use the absolute path to npx:

      {
        "mcpServers": {
          "firefox-devtools": {
            "command": "C:\\nvm4w\\nodejs\\npx.ps1",
            "args": ["-y", "@fulldecent/firefox-devtools-mcp@latest"]
          }
        }
      }

      Adjust the path to match your installation. The extension might be .cmd, .bat, or .exe rather than .ps1. Use double backslashes (\\) as required by JSON.

Versioning

Use @latest with npx for the newest release.

License

MIT