MCP server that exposes OWASP ZAP as tools to Claude and other LLM clients
Project description
mcp-server-zap
Python MCP server for OWASP ZAP — Docker-first, extensible, ~37 tools.
A Model Context Protocol server that exposes OWASP ZAP as tools for Claude Code, Claude Desktop, Cursor, Continue, and any other MCP-compatible LLM client. Spider, active scan, fuzzing, brute force, intercept, schema-driven scanning, the Automation Framework, regex search, and HTML/JSON/Markdown/SARIF reporting — all driven from natural-language conversation.
flowchart LR
Client[Claude / Cursor / Continue]
Server[mcp-server-zap]
ZAP[OWASP ZAP daemon]
Target[Target Application]
Client -- "MCP (stdio or HTTP)" --> Server
Server -- "ZAP REST API" --> ZAP
ZAP -- "HTTP proxy / scans" --> Target
Why this server?
In April 2026 the OWASP ZAP project shipped an official MCP add-on that runs inside the ZAP process with a deliberately limited tool set. If you primarily drive ZAP from its desktop GUI and want one-click MCP, install that add-on.
This project is the alternative for teams that prefer a Python, Docker-first deployment with broader API coverage and explicit auth:
| Official ZAP MCP add-on | mcp-server-zap (this project) | |
|---|---|---|
| Process model | Java add-on inside ZAP | External Python process |
| Install | ZAP Marketplace (one click) | uvx mcp-server-zap or docker compose up |
| Tool count | ~17 (intentionally minimal) | ~37 |
| Transport | HTTP only (port 8282) | Stdio (default) + optional HTTP |
| Auth | Optional shared key | API-key + HS256 JWT |
| Source | Closed/binary (alpha) | MIT, public src/ layout |
| Best for | ZAP Desktop power users | Python/Docker DevOps teams, CI pipelines |
Both projects target the same API. Pick the one that matches your workflow.
Authorized Use Only
This is a security-testing tool. Use it only on systems you own or have written permission to test. Brute-force, fuzzing, and active-scan tools generate traffic indistinguishable from a real attack. Misuse is illegal in most jurisdictions and is solely the operator's responsibility.
Features
- Crawl — Spider and AJAX spider for SPA-heavy targets.
- Scan — Active vulnerability scanning, passive scan status, scan policies and scanner controls.
- Schema import — OpenAPI, GraphQL, SOAP, and Postman collections feed the scanner.
- Attack — Parameter fuzzing and login brute-force.
- Intercept — Toggle break mode, add URL-pattern breakpoints.
- Auth and context — ZAP contexts, sessions, session-token introspection.
- Search — Regex over recorded requests and responses for secret-leak hunting.
- Automation — Run ZAP Automation Framework YAML plans end-to-end.
- Report — HTML, JSON, Markdown, themed templates, and SARIF for GitHub Code Scanning.
Quick Start
Option A — uvx (recommended for local Claude clients)
1. Run a ZAP daemon
docker run -u zap -p 8080:8080 -i ghcr.io/zaproxy/zaproxy:stable \
zap.sh -daemon -host 0.0.0.0 -port 8080 \
-config api.disablekey=true \
-config api.addrs.addr.name=.* -config api.addrs.addr.regex=true
For non-localhost or multi-user setups, drop
api.disablekey=trueand setZAP_API_KEY.
2. Add the MCP server
Claude Desktop — edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"zap": {
"command": "uvx",
"args": ["mcp-server-zap"],
"env": {
"ZAP_URL": "http://localhost:8080",
"ZAP_API_KEY": ""
}
}
}
}
Claude Code:
claude mcp add zap -- uvx mcp-server-zap
Cursor / Continue / other MCP clients use the same JSON shape under their mcpServers block.
Option B — Docker Compose (bundles ZAP + MCP server)
git clone https://github.com/Karacali/mcp-zap.git
cd zap-mcp
cp .env.example .env # set MCP_API_KEY
docker compose up -d
This spins up ZAP and mcp-server-zap on the same network. The MCP server exposes the HTTP transport on 127.0.0.1:8765. Auto-remap rewrites localhost targets to host.docker.internal so you can scan apps running on your dev machine from inside the container.
Connect a remote-MCP-aware client to http://127.0.0.1:8765/ with Authorization: Bearer $MCP_API_KEY.
For local debugging (binds ZAP UI to localhost:8080):
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
3. Try it
Run a spider scan against https://target.example.com
What's the status of the active scan?
List High-risk alerts
Search responses for "api_key|token|secret"
Generate an HTML report
Environment Variables
| Variable | Default | Description |
|---|---|---|
ZAP_URL |
http://localhost:8080 |
ZAP daemon URL |
ZAP_API_KEY |
(empty) | ZAP API key, if configured |
ZAP_MCP_REPORT_DIR |
reports |
Directory where HTML/JSON reports are written |
ZAP_MCP_CONTAINER |
(auto) | Force localhost → host.docker.internal remap (set automatically when /.dockerenv is present) |
MCP_TRANSPORT |
stdio |
stdio or http |
MCP_HTTP_HOST |
127.0.0.1 |
HTTP transport bind host (used when MCP_TRANSPORT=http) |
MCP_HTTP_PORT |
8765 |
HTTP transport port |
MCP_AUTH_MODE |
disabled |
disabled, apikey, or jwt (HTTP transport only) |
MCP_API_KEY |
(empty) | Required when MCP_AUTH_MODE=apikey |
MCP_JWT_SECRET |
(empty) | HMAC secret (HS256) for MCP_AUTH_MODE=jwt |
MCP_LOG_LEVEL |
INFO |
Python logging level |
Tool Reference
| Tool | Purpose |
|---|---|
zap_version |
Connectivity probe; returns ZAP version |
spider_scan, spider_status |
Classic spider crawl |
ajax_spider_scan, ajax_spider_status |
AJAX spider for SPAs |
forced_browse |
Hidden directory/file discovery |
get_sites, get_urls, open_url |
Site and URL listing, proxy open |
active_scan, active_scan_status, passive_scan_status, stop_scan, list_scans |
Vulnerability scanning |
get_alerts |
List findings (filter by URL / risk) |
set_scan_policy, list_scan_policies, list_scanners |
Scan policy controls |
get_messages, get_message_by_id |
Inspect proxied traffic |
send_request |
Send raw HTTP request through ZAP |
search_in_requests, search_in_responses |
Regex search across history |
fuzz_request |
Parameter fuzzing |
brute_force_login |
Login brute-force |
set_break, add_break_point |
Intercept controls |
set_context, list_contexts, new_session, list_sessions, get_session_tokens |
Context and session management |
import_openapi, import_graphql, import_soap, import_postman |
Schema-driven endpoint discovery |
run_automation_plan, automation_plan_status |
ZAP Automation Framework YAML plans |
generate_html_report, generate_json_report, generate_markdown_report |
Legacy core report API (HTML / JSON / Markdown) |
generate_report |
Modern Reports add-on (themed HTML, PDF, SARIF for GitHub Code Scanning, etc.) |
Example Scenario
A typical conversation that runs an end-to-end scan:
You: Open https://juice-shop.example via the proxy and start a spider on it.
Claude: [calls open_url, then spider_scan → returns scan_id 0]
You: How's the spider going?
Claude: [calls spider_status with scan_id=0 → "100%, 184 URLs found"]
You: Now run an active scan on the same target.
Claude: [calls active_scan → scan_id 1]
You: Show me the High-risk alerts when it's done.
Claude: [polls active_scan_status, then get_alerts(risk_level="High")]
You: Generate an HTML report.
Claude: [calls generate_html_report → writes ./reports/zap-report.html]
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
zap_version returns disconnected |
ZAP daemon not reachable from the MCP server | Check ZAP_URL. From inside Docker the value should be http://zap:8080, not http://localhost:8080 |
Spider scan returns 0 URLs after 100% |
Some sites need AJAX spider | Use ajax_spider_scan instead |
Scanning localhost:3000 from compose stack hits the wrong target |
Container's loopback isn't your host | We auto-remap to host.docker.internal. Ensure ZAP_MCP_CONTAINER=1 is set (already set in our Dockerfile) |
| HTTP transport returns 401 | Auth mode mismatch | Set MCP_AUTH_MODE=apikey and MCP_API_KEY=<value>, then send Authorization: Bearer <value> |
import_openapi says "add-on not installed" |
OpenAPI add-on missing in your ZAP build | zap.sh -addoninstall openapi or install from the ZAP Marketplace |
fuzz_request payloads all return error |
ZAP probably can't reach the original message_id host |
Re-record the request (open_url), then use the new ID |
| Reports missing | Output directory unwritable | Set ZAP_MCP_REPORT_DIR to a writable path |
Local Development
git clone https://github.com/Karacali/mcp-zap.git
cd zap-mcp
# uv (recommended)
uv sync --all-extras
uv run mcp-server-zap
# or pip
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
mcp-server-zap
Quality gates:
uv run pytest -q
uv run ruff check src tests
uv run pyright src
Security
For responsible-disclosure procedures and reporting vulnerabilities in this MCP wrapper, see SECURITY.md. ZAP itself is maintained by OWASP — vulnerabilities in ZAP go to the ZAP project.
Contributing
See CONTRIBUTING.md. PRs welcome — run ruff, pyright, and pytest before submitting.
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_server_zap-0.1.0.tar.gz.
File metadata
- Download URL: mcp_server_zap-0.1.0.tar.gz
- Upload date:
- Size: 25.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
451ba5432592842b8f4b3d7f52597398b0098d3957950d1c43a3812b87d9c981
|
|
| MD5 |
513412b1e482038398ccaa822d501820
|
|
| BLAKE2b-256 |
659948b8b3da7df73d3dd0d98fcdfad32fc9d665e2c1edfdf8a7e94d19e0a074
|
Provenance
The following attestation bundles were made for mcp_server_zap-0.1.0.tar.gz:
Publisher:
publish.yml on Karacali/mcp-zap
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_server_zap-0.1.0.tar.gz -
Subject digest:
451ba5432592842b8f4b3d7f52597398b0098d3957950d1c43a3812b87d9c981 - Sigstore transparency entry: 1393281156
- Sigstore integration time:
-
Permalink:
Karacali/mcp-zap@2bc06592d25ad1f4c62c213d1be2f56d0f30de69 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Karacali
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2bc06592d25ad1f4c62c213d1be2f56d0f30de69 -
Trigger Event:
push
-
Statement type:
File details
Details for the file mcp_server_zap-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mcp_server_zap-0.1.0-py3-none-any.whl
- Upload date:
- Size: 25.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7746c35afd8933a9bd6715b6662aa2e5913ae0c082fd8b07de2b33b28da51e12
|
|
| MD5 |
21c4169a13ff09663c3f2fa2c4340f2b
|
|
| BLAKE2b-256 |
16c80459b9926f7d76cb8fb44cb38b16bca97e522d7ff0aedecbd32bf4b8d6bc
|
Provenance
The following attestation bundles were made for mcp_server_zap-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on Karacali/mcp-zap
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_server_zap-0.1.0-py3-none-any.whl -
Subject digest:
7746c35afd8933a9bd6715b6662aa2e5913ae0c082fd8b07de2b33b28da51e12 - Sigstore transparency entry: 1393281213
- Sigstore integration time:
-
Permalink:
Karacali/mcp-zap@2bc06592d25ad1f4c62c213d1be2f56d0f30de69 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Karacali
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2bc06592d25ad1f4c62c213d1be2f56d0f30de69 -
Trigger Event:
push
-
Statement type: