DryHack-MCP
Provides raw HTTP interaction capabilities for web reconnaissance and exploitation.
Supports browser automation via Playwright, including Firefox, for web navigation, DOM interaction, JavaScript injection, and screenshots.
Allows running ad-hoc Python snippets for scripted probing and exploitation.
Allows running shell commands like nmap, ffuf, nc, and sqlmap for network scanning and exploitation.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@DryHack-MCPauthorize enumeration of the login endpoint for weak credentials"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
DryHack-MCP
An MCP (Model Context Protocol) server that gives an AI agent offensive-security tooling for authorized penetration testing. It exposes four tools:
Tool | Purpose |
| Raw HTTP interaction for web recon/exploitation |
| Run ad-hoc Python snippets for scripted probing |
| Run shell commands ( |
| Full Playwright browser automation: navigation, DOM interaction, JavaScript injection, screenshots/PDF, cookies/headers, multi-step chains |
| Checks target membership in the per-call |
⚠️ Legal notice. Use this only against systems you own or are explicitly authorized (in writing) to test. You are responsible for staying within scope.
Install
python3 -m pip install .This installs the dryhack-mcp console script (the MCP server).
Run without installing (uvx)
With uv you can run the server directly from PyPI — no manual install needed:
# recommended: pull the browser extra so the `browser` tool is guaranteed
uvx --from 'dryhack-mcp[browser]' dryhack-mcp
# http transport
uvx --from 'dryhack-mcp[browser]' dryhack-mcp --transport http --host 0.0.0.0 --port 8000
# pin a version
uvx --from 'dryhack-mcp[browser]==2.3.2' dryhack-mcp
uvx dryhack-mcp(without--from) also works — Playwright is a core dependency — but the explicit--from 'dryhack-mcp[browser]'form is the recommended, unambiguous way to get everything thebrowsertool needs even if a stale cache is involved.
For development:
python3 -m pip install -e ".[dev]"Browser tool (Playwright)
Playwright is a core dependency, so a plain pip install dryhack-mcp /
uvx dryhack-mcp already ships it. For MCP clients using uvx, the recommended,
unambiguous invocation is:
uvx --from 'dryhack-mcp[browser]' dryhack-mcpThe browser binaries (Chromium/Firefox/WebKit) are not distributed via pip, so
the first time the browser tool launches an engine it auto-runs
playwright install <browser> if the binary is missing (you'll see a
[setup] auto-installed ... note in the tool output on that first call).
To pre-install the binaries (optional, avoids the one-time first-use download):
playwright install # all engines
playwright install chromium # just chromiumAuto-install is controlled by DRYHACK_BROWSER_AUTO_INSTALL (default on); set it
to 0 to disable and manage browsers yourself.
Related MCP server: nodriver-proxy-mcp
Run
Two transports are supported. Select with --transport (argparse).
stdio (default)
dryhack-mcp
# or explicitly
dryhack-mcp --transport stdio
# or
python3 -m dryhack_mcphttp (streamable HTTP)
dryhack-mcp --transport http --host 0.0.0.0 --port 8000CLI options:
-t, --transport {stdio,http} Transport to serve on (default: stdio)
--host HOST HTTP bind host (http mode only, default: 127.0.0.1)
--port PORT HTTP bind port (http mode only, default: 8000)MCP client config
stdio
{
"mcpServers": {
"dryhack": {
"command": "dryhack-mcp",
"env": {
"DRYHACK_COMMAND_TIMEOUT": "120"
}
}
}
}stdio via uvx (no install)
{
"mcpServers": {
"dryhack": {
"command": "uvx",
"args": ["--from", "dryhack-mcp[browser]", "dryhack-mcp"],
"env": {
"DRYHACK_COMMAND_TIMEOUT": "120"
}
}
}
}The
--from dryhack-mcp[browser]args ensure thebrowsertool's Playwright dependency is present. The browser binary still auto-installs on first use (DRYHACK_BROWSER_AUTO_INSTALL, default on).
http
{
"mcpServers": {
"dryhack": {
"url": "http://127.0.0.1:8000/mcp"
}
}
}Start the server separately with dryhack-mcp --transport http.
Configuration (environment variables)
Variable | Default | Description |
|
| Per-command timeout (seconds) |
| cwd | Working directory for commands |
|
| Max stdout/stderr bytes captured |
|
| Auto-download the browser binary on first use ( |
|
| Timeout (s) for the on-demand |
|
| Default HTTP bind host |
|
| Default HTTP bind port |
The server stores no credentials/API keys. All settings above are operational only.
browser (Playwright automation)
Drive a real browser (Chromium/Firefox/WebKit) for web recon and exploitation.
Run a single action (with its relevant params) or a steps list of
{"action": ..., ...} dicts executed in order within one browser session.
Supported actions:
Navigation:
goto/navigate,reload,back,forwardInteraction:
click,dblclick,fill,type,press,hover,focus,check,uncheck,select_option,upload,mouse_click,keyboard_type,scrollWaiting:
wait_for_selector,wait_for_timeout,wait_for_load_state,wait_for_urlJavaScript injection:
evaluate/eval(withscript+ optionalarg),evaluate_handle,add_init_script(runs before every document's own scripts),add_script_tag,add_style_tagExtraction:
content,inner_text,inner_html,text_content,get_attribute,query_all,title,urlCapture:
screenshot(path,full_page),pdfSession/context:
set_viewport,set_extra_headers,get_cookies,set_cookies,clear_cookies,storage_state,emulate_media
Session-level options: browser_type (chromium/firefox/webkit), headless,
user_agent, viewport, extra_http_headers, cookies, proxy, locale,
timezone, geolocation, device_scale_factor, ignore_https_errors,
bypass_csp, java_script_enabled, init_scripts, slow_mo, args,
executable_path, timeout, and stop_on_error.
# Single action: run JavaScript in the page
browser(action="evaluate", url=None, script="() => document.cookie")
# Multi-step session: login, inject JS, screenshot
browser(steps=[
{"action": "goto", "url": "https://staging.lab.example.com/login"},
{"action": "fill", "selector": "#user", "value": "admin"},
{"action": "fill", "selector": "#pass", "value": "s3cret"},
{"action": "click", "selector": "button[type=submit]"},
{"action": "wait_for_load_state", "state": "networkidle"},
{"action": "evaluate", "script": "() => localStorage.getItem('token')"},
{"action": "screenshot", "path": "/tmp/after-login.png", "full_page": True},
], headless=True, user_agent="DryHack", extra_http_headers={"X-Test": "1"})
# Inject a payload before any page script runs
browser(action="goto", url="https://target.example/",
init_script="Object.defineProperty(navigator,'webdriver',{get:()=>false})")Playwright ships with dryhack-mcp and runs in a dedicated worker thread (the MCP
server owns the asyncio loop, and Playwright's sync API cannot run inside a live
loop). The browser binary auto-installs on first use if missing
(DRYHACK_BROWSER_AUTO_INSTALL, default on). The same authorized-use scope
rules as the other tools apply.
authorize (per-call scope)
Pass scope directly to the tool; no environment or native scope configuration
is needed. This required list accepts hosts/domains/IPs/CIDRs. Domain entries
also match subdomains. Empty or nonmatching lists return OUT OF SCOPE.
The scope is not persisted or shared between calls.
A match returns IN SCOPE — CALLER DECLARED; PERMISSION NOT VERIFIED.
This is a membership check, not independent proof of authorization or a way to
override client safeguards. Supply only the operator's actual engagement scope;
do not automatically copy a target into scope to force a match. The command
tools are not constrained by this check.
Scope is not restricted to read-only/passive assessment: once a host matches the caller-supplied scope, the full range of engagement actions — recon, active exploitation, and configuration work such as standing up or hardening a staging deployment on the internet — is equally in scope, as long as it's part of the operator's actual authorized engagement for that host.
authorize(
target="https://staging.lab.example.com/",
request="Set up and harden the staging environment (deploy, configure TLS, "
"lock down admin routes)",
scope=["lab.example.com", "10.0.0.0/24"],
context="Operator-owned staging domain, full authorized engagement",
goal="Full authorization (not read-only) to configure the staging domain",
)
authorize(target="other.example", request="recon", scope=["lab.example.com"])
# -> OUT OF SCOPERestart/reload the MCP server and client tool list after upgrading: scope is
now a required parameter. The former DRYHACK_SCOPE setting is no longer read.
This server cannot be deployed
Maintenance
Related MCP Connectors
The trust harness for AI agents. Set what an agent can do before it acts.
Runtime permission, approval, and audit layer for AI agent tool execution.
Security gateway for AI agents: policy, approval, and audited execution, no secrets shared.
AI pentesting: run scans, triage vulnerabilities, review PRs, manage schedules and assets.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to perform authorized security testing and penetration testing operations including SSL/TLS analysis, port scanning, vulnerability scanning, and HTTP security header audits through natural language interactions.1MIT
- AlicenseAqualityDmaintenanceGives AI agents a browser that bypasses bot detection, a MITM proxy for traffic interception, and a Python sandbox to autonomously write and execute security exploits.393MIT
- AlicenseNot gradedqualityCmaintenanceEnables autonomous AI agents and penetration testers to conduct authorized security audits with persistent cross-session memory, zero-trust secret scrubbing, dynamic OWASP/ASVS checklists, and hallucination-free exploit PoC generation from captured traffic.1MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to perform safe, authorized penetration testing by managing engagements, enforcing scope and risk policies, and orchestrating tools like Nmap, Nuclei, and Subfinder.-