The problem
You hook up an LLM to Burp's official MCP server and ask it to "replay this request with a tampered cookie." It dutifully crafts a Repeater payload — and silently drops the Cookie header, gets a 401, and confidently tells you the endpoint requires no auth.
Or it forgets Content-Length. Or Host. Or uses LF instead of CRLF. Or pastes a JSON body with no headers at all.
This happens because the upstream Burp MCP takes a free-form content string. Whatever the model emits goes straight to the wire. There's no schema, no validation, no help.
The other thing that breaks long pentest sessions: token cost. Each get_proxy_http_history call ships kilobytes of repeated headers back to the model. Triage a target for an hour and you've burned a fortune re-paginating the same proxy history.
What this fixes
burp-mcp-plus is a Python MCP wrapper that sits between your LLM and Burp's official MCP server. Two big ideas:
1. Structured input, not free-form strings
Every tool that touches HTTP takes typed fields — method, path, set_headers, body — and a baseline (a real entry from Burp's history, or a URL). The wrapper builds the wire format itself. Correct CRLF, auto-Host, auto-Content-Length, default User-Agent, inherited cookies. The LLM literally cannot produce a malformed request because there's no content parameter to put a malformed request in.
2. Local file ingestion for the boring stuff
If you've already triaged a target with the bundled Deduped HTTP History + JS Exporter Burp extension, the wrapper indexes the exports on disk. dedup_search and js_search return file:line + 60-char snippets — meaningfully cheaper than re-hitting Burp every time the model wants to look at past traffic. Full content is only fetched on demand.
Architecture
Plain Python stdio MCP server. Talks SSE to Burp's mcp-proxy-all extension on localhost:9876. Reads dedup/JS exports off disk. Works with any MCP host: Claude Desktop, Claude Code, Cursor, Continue, anything that speaks the protocol.
Features
Live Burp interaction
list_history/search_history— paginate or regex over proxy history. Returns compact summaries (id + method + url + status), not raw bytes.inspect_history_entry— pretty-print one entry's headers, body, target.repeater_from_history— clone a baseline, mutate any subset of (method, path, headers, body), push to Repeater. All other headers preserved verbatim from the baseline. Cookies, auth tokens, Sec-Fetch-, custom Anthropic- / X-* headers — all carry through.repeater_from_template— build from scratch with a URL. Optionally inherit auth from a history baseline.send_request— same shape, but actually sends and returns the response. Skip the Repeater dance when you just want to test.intruder_from_history— push to Intruder with§…§payload markers wrapped automatically around substrings you specify.sitemap— host → method → paths tree, synthesized from history. Burp's MCP doesn't expose Target; we synthesize one.collaborator_generate/collaborator_check— OOB canary payloads + interaction polling.
Local dedup file ingestion
Point at a deduped_requests.txt produced by the bundled extension and the model can search/replay endpoints from past sessions without round-tripping through Burp.
dedup_load/dedup_list— register file(s) under a name.dedup_search— regex overurl/request/response/params/all. Returns 60-char snippets.dedup_get— preview by default, full request/response on demand.dedup_to_repeater— replay a stored entry into a fresh Repeater tab with optional mutations. HTTP/2 lines auto-coerced to HTTP/1.1.
Local JS-export ingestion
Point at a _manifest.csv produced by the bundled extension's JS Exporter and the model can grep across all the JavaScript captured for a target.
js_load/js_list— register an export.js_files— browse the manifest, filter by host regex.js_search— grep across all on-disk JS. Returns file:line + snippet, max N matches per file (default 3). Transparently decodes the legacyarray('b', [...])byte-list format that older versions of the extension produced.js_read— fetch full content for files of interest.
Hardened against the real world
- Tolerates Burp's NDJSON-with-no-separators history format.
- Recovers parse-mid-stream when Burp truncates a long response with
... (truncated). strict=FalseJSON decoding for raw control bytes inside body strings.- Specific error messages for empty inputs, status markers, malformed entries — pointing the model at the next tool to call.
- 20 tests covering wire-format building and edge cases (no Burp required to run them).
Install
1. Burp side
Install MCP Server from Burp's BApp Store. Confirm it's listening on http://127.0.0.1:9876 (Output tab).
If you want the dedup/JS ingestion features, install the bundled extension:
- Set up Jython 2.7 in Burp → Settings → Extensions → Python environment.
- Burp → Extensions → Installed → Add → Python →
burp-extension/deduped_history.pyfrom this repo. - Two new tabs appear: Deduped History and JS Exporter.
Before you start capturing, two things the extension needs:
- Set your target scope. Burp → Target → Scope → add the host(s) you're testing (e.g.
https://app.acme.com/.*). The extension only dedupes/exports in-scope traffic, so this keeps the output clean and avoids ingesting random third-party noise (CDNs, analytics, etc.). - Pick an output directory for the JS Exporter. In the JS Exporter tab, set the output dir + project name before browsing. Files land at
<output_dir>/<project>/<host>/<flattened-path>/<file>.jsalong with a_manifest.csvthat the wrapper indexes.
Then browse the target. The Deduped History tab fills as new endpoints appear; the JS Exporter tab fills as new .js / .mjs responses come through. Hit Export in the Deduped History tab to write deduped_requests.txt.
2. Wrapper side
Requires Python 3.11+ and uv.
git clone https://github.com/titaniumtushar/burp-mcp-plus.git
cd burp-mcp-plus
uv sync
uv run pytest # offline tests; no Burp required
3. Wire it into your MCP host
The configs below use four placeholders. Fill them in for your OS — quick reference at the bottom of this section.
| Placeholder | What it is |
|---|---|
<BURP_JAVA> |
Path to the java binary that ships inside Burp Suite |
<BURP_MCP_JAR> |
Path to mcp-proxy-all.jar (downloaded by the BApp Store extension) |
<REPO_DIR> |
Where you cloned this repo |
<UV> |
"uv" if it's on your PATH; otherwise the absolute path to the uv binary |
Claude Desktop
Edit your Claude Desktop config file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux (unofficial builds only — Claude Desktop isn't officially distributed for Linux):
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"burp": {
"command": "<BURP_JAVA>",
"args": [
"-jar", "<BURP_MCP_JAR>",
"--sse-url", "http://127.0.0.1:9876"
]
},
"burp-plus": {
"command": "<UV>",
"args": [
"run", "--directory", "<REPO_DIR>", "burp-mcp-plus"
]
}
}
}
(Sample at examples/claude_desktop_config.json.)
Restart the host. Tools appear as mcp__burp-plus__*.
Claude Code CLI
Run from the repo directory (uses $PWD as <REPO_DIR>):
# Add the wrapper (user scope = available in every project)
claude mcp add burp-plus --scope user -- \
uv run --directory "$PWD" burp-mcp-plus
# Add the upstream Burp MCP too — substitute your <BURP_JAVA> and <BURP_MCP_JAR>
claude mcp add burp --scope user -- \
<BURP_JAVA> -jar <BURP_MCP_JAR> --sse-url http://127.0.0.1:9876
On Windows PowerShell, replace $PWD with (Get-Location).Path. On cmd.exe, replace it with %CD%.
Verify with claude mcp list. Tools appear in any Claude Code session as mcp__burp-plus__* and mcp__burp__*. Use --scope project if you want it scoped to the current repo only (writes to .mcp.json), or --scope local for just-this-machine config.
Cursor
Edit ~/.cursor/mcp.json (global, available in every workspace) — same path on macOS / Linux / Windows (Cursor maps ~ to your home dir on every OS). Create the file if it doesn't exist:
{
"mcpServers": {
"burp": {
"command": "<BURP_JAVA>",
"args": [
"-jar", "<BURP_MCP_JAR>",
"--sse-url", "http://127.0.0.1:9876"
]
},
"burp-plus": {
"command": "<UV>",
"args": [
"run", "--directory", "<REPO_DIR>", "burp-mcp-plus"
]
}
}
}
Then: Cursor → Settings → MCP → toggle both servers on. The status dot should go green; if it stays red, click View logs in the same panel to see why. Use .cursor/mcp.json in a workspace root instead of ~/.cursor/mcp.json if you want it scoped to one project.
Continue / Cline / other stdio MCP hosts
Same JSON shape, host-specific config path. The wrapper itself doesn't care which host launches it — all it needs is a stdio pipe.
Where the placeholders live on each OS
<BURP_JAVA> — the JRE bundled inside Burp:
| OS | Typical path |
|---|---|
| macOS | /Applications/Burp Suite Professional.app/Contents/Resources/jre.bundle/Contents/Home/bin/java |
| Linux | ~/BurpSuitePro/jre/bin/java (or wherever you extracted Burp's installer) |
| Windows | C:\Users\<you>\AppData\Local\Programs\BurpSuitePro\jre\bin\java.exe |
<BURP_MCP_JAR> — downloaded by Burp's BApp Store when you install the MCP Server extension:
| OS | Typical path |
|---|---|
| macOS / Linux | ~/.BurpSuite/bapps/<extension-id>/burp-mcp-all.jar (or ~/.BurpSuite/mcp-proxy/mcp-proxy-all.jar depending on Burp version) |
| Windows | C:\Users\<you>\AppData\Roaming\BurpSuite\bapps\<extension-id>\burp-mcp-all.jar |
To find the exact path on your machine: find ~/.BurpSuite -name "*.jar" (macOS / Linux) or look in %APPDATA%\BurpSuite\bapps\ (Windows).
<REPO_DIR> — wherever you ran git clone. Get it with pwd (POSIX shells) or cd (Windows cmd).
<UV> — most users can just use "uv" (the literal string) and let the system PATH resolve it. If your MCP host can't find uv that way, use the absolute path:
| Install method | Typical path |
|---|---|
| macOS Homebrew (Apple Silicon) | /opt/homebrew/bin/uv |
| macOS Homebrew (Intel) | /usr/local/bin/uv |
Linux / curl install |
~/.local/bin/uv |
| Windows | %USERPROFILE%\.local\bin\uv.exe |
pipx install uv (any OS) |
check pipx environment |
To find it: which uv (POSIX) or where uv (Windows).
The bundled Burp extension
burp-extension/deduped_history.py is a Jython extension that produces the dedup/JS exports the wrapper indexes.
Tab 1: Deduped History. Watches proxy traffic. Adds a row only when a new (method, host, path, parameters) tuple appears. Re-fires when new query/body parameter names show up on an endpoint. Export the whole thing to deduped_requests.txt.
Tab 2: JS Exporter. Watches for JavaScript responses, saves each unique JS file to <output>/<project>/<host>/<flattened-path>/<name>.js, writes a _manifest.csv. Detects version strings from filenames and content hashes.
Token economics
Rough numbers from a typical pentest session:
| Action | Upstream Burp MCP | burp-mcp-plus | Reduction |
|---|---|---|---|
| List 50 history entries | ~60 KB | ~3 KB | 95% |
| Search history (regex, 30 hits) | ~90 KB | ~4 KB | 95% |
| Replay one auth'd request | ~5 KB request + ~5 KB confirmation | ~1 KB | 80% |
| Find an endpoint in past triage | re-paginate proxy (~60 KB) | dedup_search (~600 B) | 99% |
| Grep all JS for a pattern | not feasible | ~2 KB w/ snippets | — |
The wrapper's job is to keep the model focused on the smallest bytes that answer the question.
Tested with
- Burp Suite Pro 2025.x
- Anthropic MCP Server BApp 1.x
- Claude Desktop on macOS
- Python 3.11, 3.12, 3.13
- macOS arm64, Linux x86_64
Should work on Windows but I haven't tested it. Reports welcome.
Security notes
This is a defensive tool for authorized testing. It's no more dangerous than Burp itself — but:
- The MCP exposes your Burp's full power to whatever model you connect. Don't connect untrusted models.
- File ingestion (
dedup_*,js_*) reads paths you provide. There's no sandbox; treat the wrapper's host as trusted. - The wrapper doesn't authenticate to Burp's MCP — it relies on Burp's
localhost-only binding. Don't expose Burp's MCP port externally. - Pentest scope discipline applies. The wrapper makes it easier to fire requests; it doesn't validate that you should.
Contributing
Issues and PRs welcome. A few ground rules:
- Tests stay green.
uv run pytestbefore opening a PR. The builder insrc/burp_mcp_plus/builder.pyis pure logic and easy to test offline. - No new free-form
contentparameters. That's the whole anti-pattern this tool exists to prevent. Add structured fields instead. - Compact returns. If a new tool would return more than a few KB by default, add a
limit/field/previewknob. - No hidden network calls. Tool side effects should be obvious from the name.
License
MIT.
Thanks
- PortSwigger — Burp Suite and the official MCP server.
- Anthropic — the MCP spec and Python SDK.
- Everyone running long pentest sessions who got tired of debugging "why did my LLM drop the Cookie header again."
No comments yet
Be the first to share your take.