loading…
Search for a command to run...
loading…
An HTTP/HTTPS MITM proxy server that enables capture, modification, and mocking of network traffic across Chrome, CLI tools, Docker containers, and Android devi
An HTTP/HTTPS MITM proxy server that enables capture, modification, and mocking of network traffic across Chrome, CLI tools, Docker containers, and Android devices. It supports advanced capabilities like JA3/JA4 TLS fingerprinting, JA3 spoofing, and upstream proxy chaining.
proxy-mcp is an MCP server that runs an explicit HTTP/HTTPS MITM proxy (L7). It captures requests/responses, lets you modify traffic in-flight (headers/bodies/mock/forward/drop), supports upstream proxy chaining, and records TLS fingerprints for connections to the proxy (JA3/JA4) plus optional upstream server JA3S. Ships "interceptors" to route a stealth browser (cloakbrowser, source-patched Chromium), CLI tools, Docker containers, and Android devices/apps through the proxy, plus Playwright-driven browser automation with locator-based click, typing, scroll, and ARIA snapshots.
71 tools + 6 resources + 3 resource templates. Built on mockttp and cloakbrowser.
claude mcp add proxy-mcp -- npx -y proxy-mcp@latest
This installs proxy-mcp as an MCP server using stdio transport. It auto-updates on every Claude Code restart.
Scopes:
# Per-user (available in all projects)
claude mcp add --scope user proxy-mcp -- npx -y proxy-mcp@latest
# Per-project (shared via .mcp.json, commit to repo)
claude mcp add --scope project proxy-mcp -- npx -y proxy-mcp@latest
git clone https://github.com/yfe404/proxy-mcp.git
cd proxy-mcp
npm install
npm run build
# stdio transport (default) — used by MCP clients like Claude Code
node dist/index.js
# Streamable HTTP transport — exposes /mcp endpoint for scripting
node dist/index.js --transport http --port 3001
--transport and --port also accept env vars TRANSPORT and PORT.
Claude Code CLI:
# stdio (default)
claude mcp add proxy-mcp -- npx -y proxy-mcp@latest
# From local clone
claude mcp add proxy-mcp -- node /path/to/proxy-mcp/dist/index.js
# HTTP transport for scripting
claude mcp add --transport http proxy-mcp http://127.0.0.1:3001/mcp
.mcp.json (project-level, commit to repo):
{
"mcpServers": {
"proxy": {
"command": "npx",
"args": ["-y", "proxy-mcp@latest"]
}
}
}
Streamable HTTP transport:
{
"mcpServers": {
"proxy": {
"type": "streamable-http",
"url": "http://127.0.0.1:3001/mcp"
}
}
}
proxy_start
Use the returned port and endpoint http://127.0.0.1:<port>.
Use the browser interceptor so proxy flags and cert trust are configured automatically. Launches cloakbrowser — a stealth-patched Chromium with source-level C++ fingerprint patches and humanize mode on by default:
interceptor_browser_launch --url "https://example.com"
Drive the page with Playwright-backed tools (no CDP, no sidecar — target_id is all you need):
interceptor_browser_navigate --target_id "browser_<id>" --url "https://apify.com"
interceptor_browser_snapshot --target_id "browser_<id>"
interceptor_browser_screenshot --target_id "browser_<id>" --file_path "/tmp/shot.png"
If launching a browser manually, pass the proxy flag yourself:
google-chrome --proxy-server="http://127.0.0.1:<port>"
Route any process through proxy-mcp by setting proxy env vars:
export HTTP_PROXY="http://127.0.0.1:<port>"
export HTTPS_PROXY="http://127.0.0.1:<port>"
export NO_PROXY="localhost,127.0.0.1"
If the client verifies TLS, trust the proxy-mcp CA certificate (see proxy_get_ca_cert) or use the Terminal interceptor (interceptor_spawn) which sets proxy env vars plus common CA env vars (curl, Node, Python requests, Git, npm/yarn, etc.):
interceptor_spawn --command curl --args '["-s","https://example.com"]'
Explicit curl examples:
curl --proxy http://127.0.0.1:<port> http://example.com
curl --proxy http://127.0.0.1:<port> https://example.com
Set optional proxy chaining from proxy-mcp to another upstream proxy (for geolocation, auth, or IP reputation):
Client/app → proxy-mcp (local explicit proxy) → upstream proxy (optional chaining layer)
proxy_set_upstream --proxy_url "socks5://user:[email protected]:1080"
Supported upstream URL schemes: socks4://, socks5://, http://, https://, pac+http://.
Typical geo-routing examples:
# Route ALL outgoing traffic from proxy-mcp via a geo proxy
proxy_set_upstream --proxy_url "socks5://user:[email protected]:1080"
# Bypass upstream for local/internal hosts
proxy_set_upstream --proxy_url "http://user:[email protected]:8080" --no_proxy '["localhost","127.0.0.1",".corp.local"]'
# Route only one hostname via a dedicated upstream (overrides global)
proxy_set_host_upstream --hostname "api.example.com" --proxy_url "https://user:[email protected]:443"
# Remove overrides when done
proxy_remove_host_upstream --hostname "api.example.com"
proxy_clear_upstream
For HTTPS MITM, the proxy CA must be trusted in the target environment (proxy_get_ca_cert).
proxy_list_traffic --limit 20
proxy_search_traffic --query "example.com"
Common issues:
target_id from interceptor_browser_launch)NO_PROXY bypassing expected hostsImport HAR into a persisted session, then analyze with existing session query/findings tools:
proxy_import_har --har_file "/path/to/capture.har" --session_name "imported-run"
proxy_list_sessions
proxy_query_session --session_id SESSION_ID --hostname_contains "api.example.com"
proxy_get_session_handshakes --session_id SESSION_ID
Replay defaults to dry-run (preview only). Execute requires explicit mode:
# Preview what would be replayed
proxy_replay_session --session_id SESSION_ID --mode dry_run --limit 20
# Execute replay against original hosts
proxy_replay_session --session_id SESSION_ID --mode execute --limit 20
# Optional: override target host/base URL while preserving path+query
proxy_replay_session --session_id SESSION_ID --mode execute --target_base_url "http://127.0.0.1:8081"
Note: imported HAR entries (and entries created by proxy_replay_session) do not carry JA3/JA4/JA3S handshake metadata. Use live proxy-captured traffic to analyze handshake fingerprints.
For mobile apps with custom HTTP stacks that ignore the system proxy (most modern Android apps — Shopee, SHEIN, TikTok, banking, etc.) the explicit proxy won't see their traffic. proxy-mcp ships a transparent listener that sits behind an iptables REDIRECT and MITMs using the TLS SNI — no CONNECT tunnel required.
Pairs with proxy-ap-card — a XIAO ESP32-S3 that broadcasts a WiFi AP (proxy-ap SSID by default) and presents to the laptop as a USB-NCM ethernet adapter. That repo handles the AP + NAPT side; proxy-mcp handles the laptop side.
iptables, sysctl, nmcli (NetworkManager), ip (iproute2), adb. sudo for network configuration (one command per session).--ap_iface / --ap_subnet to override defaults.adb devices (USB at minimum, wireless after pairing).Follow the proxy-ap-card README to build + flash the XIAO. On replug the laptop should show a cdc_ncm interface (verify: ls /sys/class/net/*/device/uevent | xargs grep DRIVER | grep cdc_ncm).
Only needed the first time per device, to push the CA. Verify with adb devices. Copy the serial.
proxy_mobile_setup --android_serial <serial>
Optional arguments:
| Param | Default | When to override |
|---|---|---|
ap_iface |
auto-detect (cdc_ncm) |
Using a different USB-ethernet bridge |
ap_address |
192.168.99.2/24 |
Matches default proxy-ap-card firmware |
ap_subnet |
192.168.4.0/24 |
Matches default proxy-ap-card firmware |
egress_iface |
auto-detect from default route | Multi-homed host, or wanting traffic to exit via a specific iface |
explicit_port |
8080 |
Port collision |
transparent_port |
8443 |
Port collision |
block_quic |
true |
Need QUIC/HTTP3 (no MITM available then) |
upstream_proxy_url |
— | Route outbound through a residential/ISP proxy — see below |
android_serial |
— | Omit to skip CA injection (remote-only setups) |
inject_cert |
true if android_serial set |
Set false to re-use a prior install |
The response is JSON with three key bits:
{
"ap_iface": "enp195s0f3u1u4",
"cert_injected": true,
"android_target_id": "adb_HQ63C81CB2",
"sudo_command": "sudo bash /tmp/proxy-mcp-mobile-setup-<hex>.sh"
}
Keep android_target_id around — you'll need it for teardown.
sudo bash /tmp/proxy-mcp-mobile-setup-<hex>.sh
This is the only sudo required. The script is idempotent, safe to re-run. It plumbs the routing that iptables needs root for:
# Static IP on the AP iface (skipped if already configured).
ip addr add 192.168.99.2/24 dev <ap_iface>
# Forwarding + dedicated nat chain.
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -N PROXY_MCP_PREROUTING
iptables -t nat -A PROXY_MCP_PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
iptables -t nat -A PROXY_MCP_PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 8443
iptables -t nat -A PREROUTING -i <ap_iface> -j PROXY_MCP_PREROUTING
# Block QUIC so apps fall back to TCP/TLS.
iptables -A FORWARD -i <ap_iface> -p udp --dport 443 -j DROP
# Masquerade out through the real egress.
iptables -t nat -A POSTROUTING -s 192.168.4.0/24 -o <egress_iface> -j MASQUERADE
Why a script and not direct execution? MCP runs as your user; iptables needs root; sudo from an MCP tool would require NOPASSWD or polkit policy (fragile, distro-specific). Emitting a script is auditable, reproducible, and portable.
proxy-ap WiFiCredentials are set in the proxy-ap-card firmware (default SSID proxy-ap, default password shown in that repo). After connecting, the phone can be unplugged from USB — future sessions don't need it.
Every HTTP/HTTPS request from the phone now lands in proxy-mcp's ring buffer:
proxy_list_traffic --source_filter transparent # iptables-redirected HTTPS
proxy_list_traffic --source_filter explicit # absolute-URL HTTP that arrived on :80
proxy_get_exchange --exchange_id <id> # full headers + body preview
proxy_search_traffic --query "api.example.com" # full-text search
Each entry carries source: "explicit" | "transparent" + TLS fingerprints (ja3, ja4).
Skip step 2. Run:
proxy_mobile_setup # skip android_serial — cert already installed
sudo bash /tmp/proxy-mcp-mobile-setup-<hex>.sh
Then phone joins the AP and capture resumes.
Set upstream_proxy_url to route outbound traffic through a residential/ISP proxy — the target servers see that proxy's IP, not your laptop's:
proxy_mobile_setup \
--upstream_proxy_url "http://user:[email protected]:8000" \
--android_serial <serial>
Applies to BOTH listeners. Use proxy_set_upstream after the fact to change it without restarting.
| Check | Command | Expected |
|---|---|---|
| Listeners up | proxy_status |
running: true, transparentProxy.running: true |
| Iface detected | proxy_mobile_detect_iface |
found: true, iface name |
| Cert injected | adb shell "su -c 'nsenter --mount=/proc/\$(pidof zygote64)/ns/mnt -- ls /apex/com.android.conscrypt/cacerts/ | wc -l'" |
144 (or 143 + 1) |
| iptables wired | sudo iptables -t nat -L PROXY_MCP_PREROUTING -v -n |
2 REDIRECT rules, non-zero pkts after phone generates traffic |
| Forwarding on | cat /proc/sys/net/ipv4/ip_forward |
1 |
| Phone sees AP | phone Settings → WiFi shows proxy-ap connected, IP in 192.168.4.0/24 |
|
| Traffic flowing | proxy_list_traffic --limit 5 after opening any app |
source: "transparent" entries with status 200 |
proxy_mobile_teardown --android_target_id <from-setup>
sudo bash /tmp/proxy-mcp-mobile-teardown-<hex>.sh
The MCP call stops both listeners and deactivates the Android target. The sudo script removes the iptables rules, disables ip_forward, and hands the AP iface back to NetworkManager. Phone stays connected to the AP until you forget it in phone WiFi settings.
| Symptom | Likely cause | Fix |
|---|---|---|
proxy_mobile_detect_iface returns found: false |
proxy-ap-card not plugged in, or cdc_ncm driver missing |
lsusb | grep '303a:'; dmesg | grep cdc_ncm; re-plug the card |
setup errors No such file or directory: /sys/class/net/.../device/uevent |
iface name passed explicitly but doesn't exist | Use auto-detect or verify with ip link |
Phone connects to AP but zero traffic in proxy_list_traffic |
sudo script not run; or phone on a different WiFi | Verify cat /proc/sys/net/ipv4/ip_forward returns 1; check phone's active SSID |
Phone says "no internet" on proxy-ap |
Forward + MASQUERADE rules missing, OR egress iface down | Re-run the sudo script; check ip route show default |
| HTTPS fails with "connection not private" or similar | Cert not trusted by the app (Chrome bundles its own CAs and ignores system trust, app has cert pinning) | Use another app to verify chain works; Chrome is the exception not the rule (see limitations below) |
| Some apps capture, others don't | Cert pinning in the apps that fail | See limitations below; Frida/LSPosed unpinning module needed |
| Ports 20346/20443/other custom ports not captured | Only :80 and :443 are redirected |
Add extra REDIRECT rules in the sudo script, or pair redsocks to CONNECT-tunnel arbitrary ports through the explicit listener |
cert_injected: false or zygote nsenter failed |
Device not rooted, or SELinux chcon rejected |
adb shell su -c 'id' must return uid=0; confirm zygisksu / Magisk is active |
| Wireless ADB port changes every session | Android's Wireless Debugging randomises the port | Re-pair; or keep phone plugged in for control plane |
Any USB-NCM or USB-ethernet bridge that the phone can route through works:
proxy_mobile_setup --ap_iface eth1 --ap_address 10.0.0.1/24 --ap_subnet 10.0.0.0/24
Or use a laptop-hosted WiFi AP via hostapd on a USB WiFi adapter (MT76x2U, RTL8812AU, etc.) — pass the wlanN interface as ap_iface.
interceptor_frida_attach in the tool reference, or morrownr's USB-WiFi guides for common patterns.block_quic: false if you want QUIC to pass through uncaptured (QUIC content won't appear in traffic logs).:20346, custom gaming protocols, etc. will bypass. Add more REDIRECT rules in the sudo script (or chain redsocks to issue CONNECT tunnels through the explicit listener)..so. Java-layer Frida hooks won't catch these; native hooks needed.network_security_config — which no shipping app does. There's no bypass for that without root.When cloakbrowser is launched via interceptor_browser_launch, proxy-mcp forwards the browser's original TLS ClientHello to the upstream server for document loads and same-origin sub-resource requests. The target server sees an authentic Chrome TLS fingerprint — not the proxy's.
This is a key difference from typical MITM proxies (mitmproxy, Charles, Fiddler) which re-terminate TLS with their own fingerprint, making MITM trivially detectable by anti-bot systems via JA3/JA4 analysis.
How to verify passthrough is working:
proxy_list_tls_fingerprints --hostname_filter "example.com"
When passthrough applies vs. when spoofing is needed:
| Traffic source | TLS behavior | Action needed |
|---|---|---|
cloakbrowser via interceptor_browser_launch (document loads, same-origin) |
Browser's native ClientHello forwarded (passthrough) | None — fingerprint is authentic |
cloakbrowser via interceptor_browser_launch (cross-origin sub-resources, when spoof active) |
Re-issued via impit with spoofed TLS | proxy_set_fingerprint_spoof with a browser preset |
Non-browser clients (curl, Python, interceptor_spawn) |
Proxy's own TLS | proxy_set_fingerprint_spoof or proxy_set_ja3_spoof required |
HAR replay (proxy_replay_session) |
Proxy's own TLS | proxy_set_fingerprint_spoof required |
Browser automation uses cloakbrowser — a stealth-patched Chromium with source-level C++ fingerprint patches — driven via Playwright. There is no CDP surface, no sidecar, no hand-rolled stealth script. One target_id from interceptor_browser_launch is everything downstream tools need.
| Capability | proxy-mcp |
|---|---|
| See/modify DOM, run JS in page | Via interceptor_browser_snapshot + interceptor_browser_list_storage_keys (also reachable from custom scripts via page.evaluate) |
| Read cookies, localStorage, sessionStorage | Yes — interceptor_browser_list_cookies, interceptor_browser_list_storage_keys |
| Capture HTTP request/response bodies | Via the MITM proxy (4 KB preview cap by default; full capture profile on persisted sessions stores complete bodies) |
| Modify requests in-flight (headers, body, mock, drop) | Yes (declarative rules, hot-reload) |
| Upstream proxy chaining (geo, auth) | Global + per-host upstreams across all clients (SOCKS4/5, HTTP, HTTPS, PAC) |
| TLS fingerprint capture (JA3/JA4/JA3S) | Yes |
| JA3 + HTTP/2 fingerprint spoofing | Proxy-side (impit re-issues matching requests with spoofed TLS 1.3, HTTP/2 frames, and header order) |
| Intercept non-browser traffic (curl, Python, Android apps) | Yes (interceptors) |
| Human-like mouse/keyboard/scroll input | humanizer_* tools: Bezier curves + Fitts's law for mouse, WPM + bigram + typo model for typing, eased wheel scroll — layered on top of cloakbrowser's built-in humanize mode |
| Locator-based interaction | humanizer_click accepts CSS/XPath selector, ARIA role + name, visible text, or form label — no pixel guessing |
Standard flow:
proxy_startproxy_set_fingerprint_spoof --preset chrome_136interceptor_browser_launch --url "https://example.com"interceptor_browser_navigate, interceptor_browser_snapshot, humanizer_click --selector "...", humanizer_type --text "..."proxy_search_traffic --query "<hostname>"| Tool | Description |
|---|---|
proxy_start |
Start MITM proxy, auto-generate CA cert |
proxy_stop |
Stop proxy (traffic/cert retained) |
proxy_status |
Running state, port, rule/traffic counts |
proxy_get_ca_cert |
CA certificate PEM + SPKI fingerprint |
| Tool | Description |
|---|---|
proxy_start_transparent |
Start second MITM listener (SNI-based, no CONNECT) on a parallel port; shares CA + rules + ring buffer with the explicit listener |
proxy_stop_transparent |
Stop the transparent listener |
proxy_transparent_status |
Running state + port + dedicated traffic count |
proxy_mobile_setup |
One-command mobile capture: start both listeners, inject CA into Android system store via adb (tmpfs overlay + zygote ns for Android 14+), emit a sudo-runnable iptables/sysctl/nmcli script |
proxy_mobile_teardown |
Reverse setup: deactivate Android target, stop transparent listener, emit teardown script |
proxy_mobile_detect_iface |
Probe /sys/class/net for a cdc_ncm USB interface (matches the proxy-ap-card firmware) |
| Tool | Description |
|---|---|
proxy_set_upstream |
Set global upstream proxy |
proxy_clear_upstream |
Remove global upstream |
proxy_set_host_upstream |
Per-host upstream override |
proxy_remove_host_upstream |
Remove per-host override |
| Tool | Description |
|---|---|
proxy_add_rule |
Add rule with matcher + handler |
proxy_update_rule |
Modify existing rule |
proxy_remove_rule |
Delete rule |
proxy_list_rules |
List all rules by priority |
proxy_test_rule_match |
Test which rules would match a simulated request or captured exchange, with detailed diagnostics |
proxy_enable_rule |
Enable a disabled rule |
proxy_disable_rule |
Disable without removing |
Quick debugging examples:
# Simulate a request and see which rule would win
proxy_test_rule_match --mode simulate --request '{"method":"GET","url":"https://example.com/api/v1/items","headers":{"accept":"application/json"}}'
# Evaluate a real captured exchange by ID
proxy_test_rule_match --mode exchange --exchange_id "ex_abc123"
| Tool | Description |
|---|---|
proxy_list_traffic |
Paginated traffic list with filters |
proxy_get_exchange |
Full exchange details by ID |
proxy_search_traffic |
Full-text search across traffic |
proxy_clear_traffic |
Clear capture buffer |
| Tool | Description |
|---|---|
proxy_inject_headers |
Add/overwrite/delete headers on matching traffic (set value to null to remove a header) |
proxy_rewrite_url |
Rewrite request URLs |
proxy_mock_response |
Return mock response for matched requests |
| Tool | Description |
|---|---|
proxy_get_tls_fingerprints |
Get JA3/JA4 client fingerprints + JA3S for a single exchange |
proxy_list_tls_fingerprints |
List unique JA3/JA4 fingerprints across all traffic with counts |
proxy_set_ja3_spoof |
Legacy: enable JA3 spoofing (deprecated, use proxy_set_fingerprint_spoof) |
proxy_clear_ja3_spoof |
Disable fingerprint spoofing |
proxy_get_tls_config |
Return current TLS config (server capture, JA3 spoof state) |
proxy_enable_server_tls_capture |
Toggle server-side JA3S capture (monkey-patches tls.connect) |
proxy_set_fingerprint_spoof |
Enable full TLS + HTTP/2 fingerprint spoofing via impit. Supports browser presets. |
proxy_list_fingerprint_presets |
List available browser fingerprint presets (e.g. chrome_131, chrome_136, chrome_136_linux, firefox_133) |
proxy_check_fingerprint_runtime |
Check fingerprint spoofing backend readiness |
Fingerprint spoofing works by re-issuing the request from the proxy via impit (native Rust TLS/HTTP2 impersonation via rustls). TLS 1.3 and HTTP/2 fingerprints (SETTINGS, WINDOW_UPDATE, PRIORITY frames) match real browsers by construction. The origin server sees the proxy's spoofed TLS, HTTP/2, and header order — not the original client's. When a user_agent is set (including via presets), proxy-mcp also normalizes Chromium UA Client Hints headers (sec-ch-ua*) to match the spoofed User-Agent (forwarding contradictory hints is a common bot signal). Browser exception: when cloakbrowser is launched via interceptor_browser_launch, document loads and same-origin requests use the browser's native TLS (no impit), preserving fingerprint consistency for bot detection challenges. Only cross-origin sub-resource requests are re-issued with spoofed TLS. Non-browser clients (curl, spawn, HAR replay) get full TLS + UA spoofing on all requests. Use proxy_set_fingerprint_spoof with a browser preset for one-command setup. proxy_set_ja3_spoof is kept for backward compatibility but custom JA3 strings are ignored (the preset's impit browser target is used instead). JA4 fingerprints are captured (read-only) but spoofing is not supported.
Interceptors configure targets (browsers, processes, devices, containers) to route their traffic through the proxy automatically.
| Tool | Description |
|---|---|
interceptor_list |
List all interceptors with availability and active target counts |
interceptor_status |
Detailed status of a specific interceptor |
interceptor_deactivate_all |
Emergency cleanup: kill all active interceptors across all types |
| Tool | Description |
|---|---|
interceptor_browser_launch |
Launch cloakbrowser (stealth Chromium) with proxy flags, SPKI cert trust, built-in humanize mode |
interceptor_browser_navigate |
Navigate the bound page via Playwright page.goto and verify proxy capture |
interceptor_browser_close |
Close a browser instance by target ID |
Stealth is source-level: cloakbrowser ships 48+ C++ patches so ja3n/ja4/akamai match real Chrome, navigator.webdriver is false, audio/canvas/WebGL fingerprints match real hardware. No JS stealth injection needed. First launch downloads a ~200 MB Chromium binary (cached afterwards).
| Tool | Description |
|---|---|
interceptor_spawn |
Spawn a command with proxy env vars pre-configured (HTTP_PROXY, SSL certs, etc.) |
interceptor_kill |
Kill a spawned process and retrieve stdout/stderr |
Sets 18+ env vars covering curl, Node.js, Python requests, Deno, Git, npm/yarn.
| Tool | Description |
|---|---|
interceptor_android_devices |
List connected Android devices via ADB |
interceptor_android_activate |
Full interception: inject CA cert, ADB reverse tunnel, optional Wi-Fi proxy |
interceptor_android_deactivate |
Remove ADB tunnel and clear Wi-Fi proxy |
interceptor_android_setup |
Quick setup: push CA cert + ADB reverse tunnel (no Wi-Fi proxy) |
Caveats: CA cert injection requires root access. Supports Android 14+ (/apex/com.android.conscrypt/cacerts/). Wi-Fi proxy is opt-in (default off).
| Tool | Description |
|---|---|
interceptor_frida_apps |
List running apps on device via Frida |
interceptor_frida_attach |
Attach to app and inject SSL unpinning + proxy redirect scripts |
interceptor_frida_detach |
Detach Frida session from app |
Caveats: Requires frida-server running on device. Uses frida-js (pure JS, no native binaries on host). SSL unpinning covers OkHttp, BoringSSL, TrustManager, system TLS — but may not work against QUIC or custom TLS stacks.
| Tool | Description |
|---|---|
interceptor_docker_attach |
Inject proxy env vars and CA cert into running container |
interceptor_docker_detach |
Remove proxy config from container |
Two modes: exec (live injection, existing processes need restart) and restart (stop + restart container). Uses host.docker.internal for proxy URL.
Playwright-driven tools for the browser target. Each takes a target_id directly — no session binding, no sidecar.
| Tool | Description |
|---|---|
interceptor_browser_snapshot |
ARIA/role YAML snapshot of the page (or selector subtree) — optimized for LLM page reasoning |
interceptor_browser_screenshot |
Screenshot. Writes to file_path if provided; otherwise reports byte count only |
interceptor_browser_list_console |
Buffered console messages since launch, with type/text filters and pagination |
interceptor_browser_list_cookies |
Cookie listing with filters, pagination, truncated value previews |
interceptor_browser_get_cookie |
Get one cookie by cookie_id (value is capped to keep output bounded) |
interceptor_browser_list_storage_keys |
localStorage/sessionStorage key listing with value previews |
interceptor_browser_get_storage_value |
Get one storage value by item_id |
interceptor_browser_list_network_fields |
Header field listing from proxy-captured traffic since the browser was launched |
interceptor_browser_get_network_field |
Get one full header field value by field_id |
Network data is sourced from the MITM proxy rather than a browser-side protocol — the proxy sees every wire request regardless of what the browser reported.
Persistent, queryable on-disk capture for long runs and post-crash analysis.
| Tool | Description |
|---|---|
proxy_session_start |
Start persistent session capture (preview or full-body mode) |
proxy_session_stop |
Stop and finalize the active persistent session |
proxy_session_status |
Runtime status for persistence (active session, bytes, disk cap errors) |
proxy_import_har |
Import a HAR file from disk into a new persisted session |
proxy_list_sessions |
List recorded sessions from disk |
proxy_get_session |
Get manifest/details for one session |
proxy_query_session |
Indexed query over recorded exchanges |
proxy_get_session_handshakes |
Report JA3/JA4/JA3S handshake metadata availability for session entries |
proxy_get_session_exchange |
Fetch one exchange from a session (with optional full bodies) |
proxy_replay_session |
Dry-run or execute replay of selected session requests |
proxy_export_har |
Export full session or filtered subset to HAR |
proxy_delete_session |
Delete a stored session |
proxy_session_recover |
Rebuild indexes from records after unclean shutdown |
proxy_get_session_exchange and proxy_export_har automatically decompress response bodies (gzip, deflate, brotli) based on the stored content-encoding header. The returned responseBodyText and responseBodyBase64 contain the decompressed content. Raw compressed bytes are preserved on disk for exact replay fidelity.
Note on proxy_start with persistence_enabled: true: this auto-creates a session. A subsequent proxy_session_start() call returns the existing active session instead of failing — no need to stop and re-start.
Human-like browser input via Playwright page.mouse / page.keyboard, layered on top of cloakbrowser's built-in humanize mode. Binds to target_id from interceptor_browser_launch.
| Tool | Description |
|---|---|
humanizer_move |
Move mouse along a Bezier curve with Fitts's law velocity scaling and eased timing |
humanizer_click |
Click a locator (selector / role + name / text / label) or raw x,y. Auto-waits for visible + enabled + stable + in-view before clicking |
humanizer_type |
Type text with per-character delays modeled on WPM, bigram frequency, shift penalty, word pauses, and optional typo injection |
humanizer_scroll |
Scroll with easeInOutQuad acceleration/deceleration via multiple wheel events |
humanizer_idle |
Simulate idle behavior with mouse micro-jitter and occasional micro-scrolls to defeat idle detection |
All tools require target_id from a prior interceptor_browser_launch. The engine maintains tracked mouse position across calls, so humanizer_move followed by humanizer_click produces a continuous path.
Behavioral details:
| URI | Description |
|---|---|
proxy://status |
Proxy running state and config |
proxy://ca-cert |
CA certificate PEM |
proxy://traffic/summary |
Traffic stats: method/status breakdown, top hostnames, TLS fingerprint stats |
proxy://interceptors |
All interceptor metadata and activation status |
proxy://sessions |
Persistent session catalog + runtime persistence status |
proxy://browser/primary |
Current page URL/title for the most recently launched browser instance |
proxy://browser/targets |
Current page state for all active browser instances |
proxy://sessions/{session_id}/summary |
Aggregate stats for one recorded session (resource template) |
proxy://sessions/{session_id}/timeline |
Time-bucketed request/error timeline (resource template) |
proxy://sessions/{session_id}/findings |
Top errors/slow exchanges/host error rates (resource template) |
# Start the proxy
proxy_start
# Optional: start persistent session recording
proxy_session_start --capture_profile full --session_name "reverse-run-1"
# Configure device to use proxy (Wi-Fi settings or interceptors)
# Install CA cert on device (proxy_get_ca_cert)
# Or use interceptors to auto-configure targets:
interceptor_browser_launch # Launch stealth browser with proxy
interceptor_spawn --command curl --args '["https://example.com"]' # Spawn proxied process
interceptor_android_activate --serial DEVICE_SERIAL # Android device
# Set upstream proxy for geolocation
proxy_set_upstream --proxy_url socks5://user:pass@geo-proxy:1080
# Mock an API response
proxy_mock_response --url_pattern "/api/v1/config" --status 200 --body '{"feature": true}'
# Inject auth headers (set value to null to delete a header)
proxy_inject_headers --hostname "api.example.com" --headers '{"Authorization": "Bearer token123"}'
# View captured traffic
proxy_list_traffic --hostname_filter "api.example.com"
proxy_search_traffic --query "error"
# TLS fingerprinting
proxy_list_tls_fingerprints # See unique JA3/JA4 fingerprints
proxy_set_ja3_spoof --ja3 "771,4865-..." # Spoof outgoing JA3 (for non-browser clients)
proxy_set_fingerprint_spoof --preset chrome_136 --host_patterns '["example.com"]' # Full fingerprint spoof
proxy_list_fingerprint_presets # Available browser presets
# Human-like browser interaction (requires interceptor_browser_launch target)
humanizer_move --target_id "browser_<id>" --x 500 --y 300
humanizer_click --target_id "browser_<id>" --selector "#login-button"
humanizer_click --target_id "browser_<id>" --role "button" --name "Sign in"
humanizer_type --target_id "browser_<id>" --text "[email protected]" --wpm 45
humanizer_scroll --target_id "browser_<id>" --delta_y 300
humanizer_idle --target_id "browser_<id>" --duration_ms 2000 --intensity subtle
# Query/export recorded session
proxy_list_sessions
proxy_query_session --session_id SESSION_ID --hostname_contains "api.example.com"
proxy_export_har --session_id SESSION_ID
ProxyManager singleton manages mockttp server, rules, trafficstart(), so rule changes trigger stop/recreate/restart cycleon('request') + on('response') events, correlated by request IDtls.connect monkey-patchInterceptorManager, each type registers independentlyBrowserContext / Pagepage.mouse / page.keyboard. Custom timing layer (Bezier paths, Fitts's law, bigram typing) feeds Playwright — sits on top of cloakbrowser's built-in humanize: truenpm test # All tests (unit + integration)
npm run test:unit # Unit tests only
npm run test:integration # Integration tests
npm run test:e2e # E2E fingerprint tests (requires cloakbrowser + internet)
| Project | Role |
|---|---|
| mockttp | MITM proxy engine, rule system, CA generation |
| impit | Native TLS/HTTP2 fingerprint impersonation (Rust via NAPI-RS) |
| frida-js | Pure-JS Frida client for Android instrumentation |
| cloakbrowser | Stealth-patched Chromium with source-level C++ fingerprint patches |
| playwright-core | Browser automation API driving cloakbrowser |
| @modelcontextprotocol/sdk | MCP server framework |
All scripts in src/frida-scripts/vendor/ are derived from httptoolkit/frida-interception-and-unpinning (MIT):
config-template.js — proxy/cert config injectionandroid-certificate-unpinning.js — TrustManager + OkHttp + BoringSSL hooksandroid-system-certificate-injection.js — runtime cert injection via KeyStoreandroid-proxy-override.js — ProxySelector monkey-patchnative-tls-hook.js — BoringSSL/OpenSSL native hooksnative-connect-hook.js — libc connect() redirectДобавь это в claude_desktop_config.json и перезапусти Claude Desktop.
{
"mcpServers": {
"proxy-mcp": {
"command": "npx",
"args": []
}
}
}