A Model Context Protocol (MCP) server for
the Mayhem CLI
(mayhem).
Note
The code in this repository is provided as-is and is intended only for demonstration purposes. This project is not officially supported or actively maintained.
Note
Not all MCP clients surface prompts as slash commands. VS Code Copilot shows slash commands in the prompt picker. Claude Desktop, Claude Code, and most other clients require asking the model to run the prompt by name (e.g., "Run the onboard-mapi-scan prompt") or using the individual tools directly.
Discover APIs running on a single host, multiple hosts, CIDR blocks, or domains.
Run a scan to check an API for defects.
The /onboard-mapi-scan prompt runs an end-to-end fuzzing workflow. It verifies
your environment, runs an initial scan, evaluates endpoint coverage, suggests
configuration improvements, and emits a bash script you can commit to CI. The
loop iterates until coverage meets a target threshold or the iteration limit is
reached.
Tools used:
evaluate_scan_quality- parses the HAR output and spec to compute endpoint coverage (covered_pct), surface auth hints, and identify unreachable endpointssuggest_tune_changes- applies heuristic rules (auth headers, request count, duration, endpoint exclusions, validation errors) to propose the next tuning stepemit_scan_script- writes aset -euo pipefailbash script with all finalized flags and env-var guards for the leave-behind artifact
Invoking the prompt:
In your MCP client, invoke /onboard-mapi-scan with the following arguments:
| Argument | Required | Default | Description |
|---|---|---|---|
workspace |
yes | — | Mayhem workspace name (e.g. myorg) |
project |
yes | — | Mayhem project name (e.g. my-api) |
target_name |
no | "" |
Specific target within the project; omit to use the project default |
specification |
yes | - | Path to an OpenAPI/Swagger/Postman spec file |
url |
yes | - | Base URL of the API under test |
duration |
no | 30s |
Initial scan duration |
max_iterations |
no | 3 |
Maximum tune-loop iterations |
min_covered_pct |
no | 25 |
Coverage threshold that stops the loop early |
The --har flag is handled automatically. mapi writes HAR output to /tmp;
evaluate_scan_quality reads it from there.
Note
Any suggestion to add --ignore-endpoint (which narrows the fuzzer's attack
surface) will be surfaced with a [FUZZING NARROWING WARNING] and requires
explicit confirmation before it is applied.
After the first quality evaluation, the /onboard-mapi-scan prompt optionally
analyzes the API spec and source code to propose targeted configuration improvements:
resource hints for low-coverage PATH parameters, rule prioritization based on
observed code patterns, and endpoint or tag filters where appropriate.
Tools used:
mapi_describe_specification- fetches the full parameter table from a spec (used internally by the prompt to identify which parameters need seeding)suggest_source_aware_changes- applies heuristic rules to spec parameters and source-extracted values to propose--resource-hint,--include-rule, and--experimental-ruleschangesemit_mapi_config- generates a.mapiYAML configuration file with correlated resource hint groups and issue suppressions for team sharing or SCM storage
How it works:
Capability 2 runs as an optional Step 4.5 inside the /onboard-mapi-scan
flow, after the first scan quality evaluation. The prompt identifies PATH parameters
with zero coverage, asks you to point to relevant source files (fixture data, enum
definitions, seed files), reads them, and generates a small number of targeted
hints. It also detects code patterns (SQL queries, subprocess calls, file operations,
PII fields) and suggests enabling the corresponding mapi rules.
You don't need a separate invocation. It runs inside the standard
/onboard-mapi-scan flow.
Fuzziness guardrail:
--resource-hintand--include-rulesuggestions are applied without extra confirmation - they expand mapi's reach, not narrow it- Any suggestion involving
--ignore-endpoint,--ignore-endpoints-by-tag, or--ignore-rulecarries a[FUZZING NARROWING WARNING]and requires explicit confirmation before it is applied - Resource hints are capped at 3-5 per session to preserve fuzzer input entropy (mapi applies hints on the majority of generated requests)
.mapi config file:
At the end of the flow, the prompt optionally offers to generate a .mapi YAML
config file via emit_mapi_config. This is most useful when you need correlated
parameter groups (multiple parameters seeded together consistently) or want to
commit suppressions to source control for team sharing. For one-off scans, the
emitted bash script is sufficient.
Warning
The server never sends exploit requests. All output is text for the user to review and decide whether to run. Obtain appropriate authorization before executing any suggested request.
For each defect found by a mapi run, the /generate-exploit prompt confirms
the defect still reproduces, crafts a targeted HTTP request demonstrating its
impact, and emits a leave-behind markdown report.
How to invoke:
In your MCP client, invoke /generate-exploit with:
| Argument | Required | Default | Description |
|---|---|---|---|
run_id |
yes | - | Mayhem run ID containing the defects (e.g. myorg/api/42) |
url |
yes | - | Base URL of the API under test |
specification |
no | "" |
Spec path for endpoint context |
source_dir |
no | "" |
Source root for higher-fidelity exploit crafting |
output_path |
no | exploit-report.md |
Path for the leave-behind report |
Note
The server resolves output_path on its own filesystem. When the server runs
in a Docker container (the default for all client configurations shown below),
that path lives inside the ephemeral container and disappears when it exits.
Two options:
- The inline chat output from the prompt is the reliable artifact and works regardless of how you launch the server.
- To write a file to the host, add a volume mount to the Docker args
(
-v /path/to/workspace:/work) and setoutput_pathto a path under/work.
For a local uv run launch (see Local Development),
output_path writes to the host directly.
Leave-behind tool:
emit_exploit_report generates a markdown file with one section per defect:
the reproducing request, the suggested exploit, and source code references if
available.
Safety boundary:
- The server never issues HTTP requests to the API. The exploit suggestion is text only; the user manually copies and runs it.
- Any suggestion that would mutate or delete server state (account changes, data
deletion, DoS) is tagged
[DESTRUCTIVE]and requires explicit user confirmation before it is included in the report. - The prompt replaces any credentials or tokens observed in defect data with
typed placeholders (
<BEARER_TOKEN>,<PASSWORD>, etc.). Real values never reach the report. - Safety warnings appear at four points: prompt start, before each exploit is crafted, at the destructive-action gate, and after the report is generated.
This is a parallel capability to the API-testing tools above: fuzz testing of
binaries and Docker images via the mayhem
CLI. Unlike the mapi capabilities, this is a straightforward sequential
lifecycle - there's no iterative coverage-tuning loop or exploit-generation
step, since neither has a meaningful mayhem equivalent.
The typical path through a mayhem run:
mayhem_login → mayhem_validate → mayhem_run → mayhem_wait / mayhem_show
mayhem_login- authenticates with a Mayhem server. Persists credentials to the~/.config/mayhemXDG dir and logs into the Mayhem Docker registry.mayhem_validate- checks that a packaged target's Mayhemfile is correct before running it. Operates on a packaged directory, not a bare Docker image tag.mayhem_run- starts a run (regression/static/dynamic/coverage analysis) against a packaged target directory, or against a Docker image tag/hash passed directly aspackage. This tool has the largest flag surface in the project - full parity withmayhem run --help, no trimming.mayhem_wait- blocks until a run finishes and returns its results. Takes apoll_timeout_sfield (default 1800s / 30 minutes) that controls how long the tool call itself is allowed to block, independent of the run's own--duration- raise it for long-running targets. Whenfail_on_defectsis set, a run that completes with defects present is returned as a normal result rather than raised as an error.mayhem_show- a non-blocking snapshot of one or all runs, as an alternative tomayhem_waitwhen you don't want to block.
Mayhem fuzzes Docker image contents directly, so a Docker-based target needs no local packaging step - it's the preferred path when a suitable image already exists. For targets that aren't already a Docker image:
mayhem_package- packages a local target binary and its dependencies for Mayhem. This is the fallback path.mayhem_init- scaffolds a Mayhemfile (from a Docker image, a language template, or explicit flags) - themayhem_packagepath's counterpart, and the tool the/onboard-mayhem-runprompt points you to if you haven't built or packaged a target yet.
Note
Neither this server nor its prompts will author a fuzz harness, Dockerfile,
or Mayhemfile on your behalf. If a target isn't packaged or built yet,
mayhem_init/mayhem_package expect you to supply one - they package and
validate existing targets, they don't create them.
The remaining subcommands round out full mayhem CLI coverage:
mayhem_logout, mayhem_list (projects/targets you've run), mayhem_download
(a target and its test cases), mayhem_sync (refresh a package with the
latest test cases), mayhem_stop (stop one or all runs for a target/project),
mayhem_check (check whether local files are Mayhem-eligible), and
mayhem_docker_registry (get the URI for Mayhem's Docker registry).
emit_cicd_config generates pipeline configuration that reruns a target in CI.
The platform argument takes exactly four values: github-actions,
gitlab-ci, jenkins, and azure-devops.
It fans out one CI job per Mayhemfile, so targets run in parallel and a failing target does not stop its siblings.
- The tool returns text and writes nothing. The client agent writes the file
where the platform expects it. This is deliberate, and differs from the older
emit_scan_script,emit_mapi_config, andemit_exploit_reporttools, which do write to disk. - The Mayhem token always comes from the platform's secret store -
${{ secrets.MAYHEM_TOKEN }}on GitHub Actions, a masked CI/CD variable on GitLab, a credentials binding on Jenkins, a secret pipeline variable on Azure DevOps. A token value never appears in the generated configuration. - GitHub Actions uses the official
ForAllSecure/mcode-action. The other three invoke themayhemCLI directly. include_build_jobadds an upstream build-and-push job, for repositories that build their image in the same pipeline. Registry login is zero-configuration on GitHub Actions and GitLab, which each supply a token for their own registry. Jenkins and Azure DevOps have no equivalent, so those templates reference a placeholder credential you need to create before the build job will run. Prefer an image that already exists over building one here.
Verification status. All four templates render without residual
placeholders, and the mayhem command line each one builds has been executed
against stub binaries with its arguments recorded. The GitHub Actions and GitLab
output validates against those platforms' published schemas, and the Azure
DevOps output against a corrected copy of Microsoft's. No Groovy parser was run
against the Jenkins template; it has had structural review only. No pipeline
has been executed on any platform.
Step 2 of the onboarding prompt reviews how the repository is arranged, reasoning about three properties:
- Are Mayhemfiles discoverable in a predictable location?
- Is each target's configuration separable from every other target's?
- Is harness source distinct from Mayhem configuration?
It reports what it observes and what it would recommend, then stops. It never creates directories, moves files, or writes configuration without your explicit agreement.
It advises rather than enforces because there is nothing to enforce against:
Mayhem's documentation specifies no convention for where Mayhemfiles live and
does not address repositories holding several of them, and real repositories
differ. Where a language already has a convention, the step follows it instead of
overriding it - Go fuzz targets live in _test.go files via testing.F with no
separate harness directory, and Rust's cargo-fuzz standardizes
fuzz/fuzz_targets/. It is a thin pass over the three properties above, not a
linter or a scoring system.
The /onboard-mayhem-run prompt walks through the lifecycle above end-to-end in
ten steps: it verifies login, reviews repository layout and offers a
recommendation, asks whether you have a Docker image ready, an unpackaged
local binary, or nothing built yet (stopping if the latter, since building a
target is outside what these tools do), packages and validates if needed, starts
the run, monitors it to completion, and then offers to generate CI/CD
configuration so the run is repeatable.
Invoking the prompt:
In your MCP client, invoke /onboard-mayhem-run with the following arguments:
| Argument | Required | Default | Description |
|---|---|---|---|
url |
yes | — | Base URL of the Mayhem server |
project |
no | "" |
Mayhem project name, if already known |
target |
no | "" |
Mayhem target name, if already known |
owner |
no | "" |
Owner (user or organization) to scope calls to |
MCP servers connect to AI applications like Claude, Cursor, or VS Code Copilot. The sections below cover setup for each supported client.
If necessary, follow
the steps
to authenticate to the GitHub Container registry with a personal access token
(classic). You only need the read:packages scope.
Note
To check login status, run docker login ghcr.io.
Visual Studio Code has
native MCP support.
This repository includes a reference .vscode/mcp.json.
To add the server to a project, copy .vscode/mcp.json to the same location in
your target project. If your project already has a .vscode/mcp.json, merge the
mapi entry into it. To apply it across all projects in a
VS Code profile, place
the file in the profile directory instead.
Once configured, open the Copilot Chat window, start the server, and use the tool
picker to enable the mapi server. See the
official documentation
for details.
VS Code supports prompted input via ${input:promptString}. The included
.vscode/mcp.json prompts for MAYHEM_TOKEN and MAYHEM_URL on first use
and stores them in VS Code's secret storage.
Add the following to .cursor/mcp.json in your project (or ~/.cursor/mcp.json
for global access):
{
"mcpServers": {
"mayhem": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"--network", "host",
"-e", "MAYHEM_URL",
"-e", "MAYHEM_TOKEN",
"ghcr.io/forallsecure/mcp-server-mayhem:latest",
"uv", "run", "mcp-server-mayhem", "mcp"
]
}
}
}Both come from the host environment via the -e flags in the Docker args.
Cursor does not support prompted input. Export both before launching:
export MAYHEM_TOKEN=your-token-here
export MAYHEM_URL=https://app.mayhem.securityAdd these lines to your shell startup file (~/.zshrc, ~/.bashrc, etc.) to
avoid setting them manually each session.
This repository also includes a reference .cursor/mcp.json.
Add the following to .windsurf/mcp.json in your project (or
~/.codeium/windsurf/mcp_config.json for global access):
{
"mcpServers": {
"mayhem": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"--network", "host",
"-e", "MAYHEM_URL",
"-e", "MAYHEM_TOKEN",
"ghcr.io/forallsecure/mcp-server-mayhem:latest",
"uv", "run", "mcp-server-mayhem", "mcp"
]
}
}
}Like Cursor, Windsurf picks up MAYHEM_TOKEN and MAYHEM_URL from the host
environment. Export both before launching:
export MAYHEM_TOKEN=your-token-here
export MAYHEM_URL=https://app.mayhem.securityThis repository also includes a reference .windsurf/mcp.json.
Add the following to .mcp.json at your project root (project-scoped), or
configure globally with claude mcp add:
{
"mcpServers": {
"mayhem": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"--network", "host",
"-e", "MAYHEM_URL",
"-e", "MAYHEM_TOKEN",
"ghcr.io/forallsecure/mcp-server-mayhem:latest",
"uv", "run", "mcp-server-mayhem", "mcp"
]
}
}
}Like Cursor and Windsurf, both come from the host shell. Export them before launching:
export MAYHEM_TOKEN=your-token-here
export MAYHEM_URL=https://app.mayhem.securityNote
Claude Code does not surface MCP prompts as slash commands. To run
/onboard-mapi-scan or /generate-exploit, ask the model to invoke the prompt
by name, or use the individual tools directly.
A reference .mcp.json is not included in this repository.
Add the following to your Claude Desktop config file.
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"mayhem": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"--network", "host",
"-e", "MAYHEM_URL",
"-e", "MAYHEM_TOKEN",
"ghcr.io/forallsecure/mcp-server-mayhem:latest",
"uv", "run", "mcp-server-mayhem", "mcp"
]
}
}
}Both come from the shell you launched Claude Desktop from. On macOS, start it from a terminal with both exported:
export MAYHEM_TOKEN=your-token-here
export MAYHEM_URL=https://app.mayhem.security
open -a "Claude"This repository includes a reference
claude_desktop_config.json.
Note
Claude Desktop does not surface MCP prompts as slash commands. To run
/onboard-mapi-scan or /generate-exploit, ask the model to invoke the prompt
by name, or use the individual tools directly.
This section describes how to acquire and run the code locally for development purposes.
Clone this repository:
git clone git@github.com:ForAllSecure/mcp-server-mayhem.gitUse uv to run the MCP server for mapi:
MAYHEM_TOKEN=your-token-here uv run mcp-server-mayhem mcp