Skip to main content

fx-audit-mcp

MCP tools for Firefox security auditing. Provides async Python tools and a FastMCP server for running testcases in Firefox and SpiderMonkey, building Firefox and NSS with ASAN, and querying Bugzilla — all with structured Pydantic return types suitable for use with LLM agent frameworks.

Tools

Tool Description
browser_evaluator Run a multi-file testcase in ASAN Firefox via grizzly replay, detect crashes
package_testcase Bundle a testcase directory with prefs and env into a grizzly TestCase
js_shell_evaluator Run a JS testcase in the SpiderMonkey shell, detect crashes and sanitizer output
nss_gtest_evaluator Run an NSS GTest and report any ASan crash
build_firefox Build Firefox via mach build with a specified MOZCONFIG
build_nss Build NSS with ASAN via security/nss/build.sh
search_bugs Search Bugzilla using raw REST query parameters
get_bugs Fetch bugs by ID in bulk
get_bug_comments Fetch all comments for a single bug
get_bug_attachments Fetch attachments for a bug

Installation

pip install fx-audit-mcp

Requires Python 3.12+.

Usage

As Python functions

The execution tools (browser, JS shell, NSS gtest, Firefox/NSS build) are async functions with structured Pydantic return types. The Bugzilla tools are only available via the MCP server (see below).

import asyncio
from pathlib import Path
from fx_audit_mcp import browser_evaluator, js_shell_evaluator

async def main():
    result = await browser_evaluator(
        # Maps the name each file takes in the testcase to its path on disk,
        # so testcases may span several files and include binary assets.
        # Use forward slashes for subdirectories ("sub/frame.html").
        file_paths={
            "test.html": Path("/repro/test.html"),
            "boom.js": Path("/repro/boom.js"),
            "font.woff2": Path("/repro/font.woff2"),
        },
        entry_point="test.html",
        firefox_binary=Path("/path/to/obj-firefox-asan/dist/bin/firefox"),
        timeout=30,
    )
    print(result.crashed, result.timed_out)
    # Complete, untruncated logs are on disk; result.logs holds their paths,
    # grouped into stderr/stdout/crashdata.
    # The ASAN report is in crashdata (log_ffp_asan_<pid>.txt), not stderr.
    for log in result.logs.crashdata:
        print(Path(log).read_text()[:500])
    # Logs live in a fresh temp directory that is never deleted; cleaning it
    # up is up to you: shutil.rmtree(Path(result.logs.stderr[0]).parent)

asyncio.run(main())

As an MCP server

fx-audit-mcp exposes all execution tools (browser, JS shell, NSS gtest, Firefox/NSS build) as an MCP server over stdio:

fx-audit-mcp

fx-audit-bugzilla-mcp exposes the Bugzilla query tools separately:

BUGZILLA_API_KEY=your_key fx-audit-bugzilla-mcp

Set BUGZILLA_URL to override the default Mozilla Bugzilla instance.

Claude Desktop / Claude Code .mcp.json example:

{
  "mcpServers": {
    "fx-audit": {
      "command": "fx-audit-mcp",
      "env": {
        "FIREFOX_SOURCE_ROOT": "/path/to/firefox",
        "FIREFOX_BINARY": "/path/to/firefox/obj-firefox-asan/dist/bin/firefox"
      }
    },
    "fx-audit-bugzilla": {
      "command": "fx-audit-bugzilla-mcp",
      "env": {
        "BUGZILLA_API_KEY": "your_key_here"
      }
    }
  }
}

With pydantic-ai

Tools integrate directly with pydantic-ai agents:

from pydantic_ai import Agent
from fx_audit_mcp import browser_evaluator, js_shell_evaluator

agent = Agent(
    "anthropic:claude-opus-4-7",
    tools=[browser_evaluator, js_shell_evaluator],
)

Environment Variables

Variable Used by Description
BUGZILLA_API_KEY fx-audit-bugzilla-mcp Required; your Bugzilla API key
BUGZILLA_URL fx-audit-bugzilla-mcp Bugzilla REST base URL (default: Mozilla's)
FIREFOX_SOURCE_ROOT fx-audit-build-firefox Default --firefox-dir for the CLI entry point

Crash Detection

Every tool writes complete logs to a fresh temp directory each run and returns their paths in logs instead of the contents, so they can be grepped rather than truncated to fit. The build tools return stderr/stdout; the evaluators add crashdata. The directory is never deleted and logs are unbounded, so callers should clean up — take the parent of any returned path. The returned paths are only meaningful to a client sharing a filesystem with the server.

  • browser_evaluator: Crash signatures in ignored_signatures/ (FuzzManager format) are filtered out before returning, so common shutdown hangs don't pollute results. The ASAN report is in crashdata (log_ffp_asan_<pid>.txt), not stderr.
  • js_shell_evaluator: Detects crashes via negative exit code (signal) or AddressSanitizer/UndefinedBehaviorSanitizer in stderr. JS errors (positive exit codes) are not treated as crashes. Crash diagnostics arrive on stderr, so on a crash crashdata names that same stderr file.
  • nss_gtest_evaluator: Detects AddressSanitizer in stdout or stderr, and crashdata names whichever of those files carried the report.

A run that hits its time limit does not raise: the evaluators return timed_out: true with the logs, which show how far the run got before the hang. For the browser this means a process was still busy executing when the window expired (it is aborted to capture stacks); an idle browser at the time limit is a normal clean run, since testcases are not expected to close the browser. A timed-out browser is never reported as a crash, since the report that abort produces is a hang.

The JS shell and NSS gtest evaluators do report a crash on a timed-out run, when the log holds a sanitizer report the process finished writing — UBSAN does not halt on error, so a testcase can trip it and then hang. Since a kill can cut a report off mid-stack, a timeout is judged on the report's closing SUMMARY: line rather than any mention of the sanitizer, and the exit code is ignored because it is the kill signal rather than a fault.

Development

# Install with dev dependencies
uv sync --group dev

# Run tests
uv run pytest

# Lint and format
uv run ruff check --fix .
uv run ruff format .

# Type check
uv run mypy src/

# Install pre-commit hooks
uv run pre-commit install

License

Mozilla Public License 2.0

Metadata

Release files for fx-audit-mcp 4.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fx-audit-mcp 4.1.1
File Size Uploaded
fx_audit_mcp-4.1.1.tar.gz 170.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fx-audit-mcp 4.1.1
File Interpreter ABI Platform
fx_audit_mcp-4.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 204.7 kB

Release files / fx_audit_mcp-4.1.1.tar.gz

Download URL fx_audit_mcp-4.1.1.tar.gz
Size 170.0 kB
Tags Source
SHA-256 checksum
How to use checksums
a00b4efff0d5cab77f531ed91a5809b4af9a8b2e843fd018d9d4fd6ff6c8aef2
BLAKE2b-256 checksum
How to use checksums
a55d93938e241b5594b7f0623210e8b01ab9a2c0698dfa0d63138b2ff86588ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / fx_audit_mcp-4.1.1-py3-none-any.whl

Download URL fx_audit_mcp-4.1.1-py3-none-any.whl
Size 34.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4a215dabf6ce9df184ee45de8c7a0f9463638ac52e3c312ad03ce0d45b6899f8
BLAKE2b-256 checksum
How to use checksums
984317f63d4cc500e3d1dedff732d8fd2c6e038fe12fc21868a067734d0ac7c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release history Release notifications | RSS feed

4.1.2

2 release files

This release

4.1.1 This release

2 release files

4.1.0

2 release files

4.0.0

2 release files

3.0.0

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.4.2

2 release files

1.4.1

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.4

2 release files

1.2.3

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page