Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Changelog

## 3.0.0

### New Features

- **Camoufox interceptor — anti-detect Firefox via Playwright WS.** New `CamoufoxInterceptor` (id `camoufox`) spawns `camoufox.server.launch_server()` as a Python subprocess, parses the emitted Websocket endpoint, and exposes it. Caller drives pages with `await firefox.connect(wsUrl)` instead of going through MCP page tools. Proxy + NSS CA trust are pre-wired at launch time so `geoip: true` resolves locale/timezone from the proxy exit IP.
- **4 new tools:** `interceptor_camoufox_launch`, `interceptor_camoufox_info`, `interceptor_camoufox_list`, `interceptor_camoufox_close`. Launch params expose camoufox's full fingerprint surface: `os`, `webgl_config`, `fonts`, `humanize`, `headless`, `addons`, `main_world_eval`, `enable_cache`, `disable_coop`, `block_webrtc`, `block_webgl`, `block_images`, `locale`, `geoip`, `port`, `ws_path`, `python_executable`, `trust_proxy_cert`, plus a raw `config` escape hatch.
- **New resource `proxy://camoufox/targets`.** Mirror of `proxy://browser/targets` for camoufox instances.

### Notes

- Host requirements (only when using camoufox): Python 3 + `pip install "camoufox[geoip]"` + `python3 -m camoufox fetch` + NSS `certutil` (`libnss3-tools`/`nss-tools`/`brew install nss`). If `certutil` is missing the launcher still runs but the proxy CA is not trusted — HTTPS pages show cert errors and proxy traffic is still captured.
- No new npm dependencies. `playwright-core` (already a runtime dep for cloakbrowser) provides the `firefox.connect(wsUrl)` client.
- All proxy-side capabilities — traffic capture, TLS fingerprint capture, rules, header injection, mocks, sessions, replay, upstream chaining, JA3 spoofing — apply to camoufox automatically because the proxy sits in front of it.

## 2.3.0

### New Features

- **Transparent proxy + one-command mobile capture setup.** New `transparent` and `mobile` tool groups for Wi-Fi-AP-based mobile capture (DHCP/DNS/iptables redirect to the MITM proxy). Documented in the README "Mobile Capture (Transparent Proxy)" section.

## 2.2.0

### Breaking Changes
Expand Down
47 changes: 44 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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](https://github.com/httptoolkit/mockttp) and [cloakbrowser](https://cloakbrowser.dev/).
75 tools + 7 resources + 3 resource templates. Built on [mockttp](https://github.com/httptoolkit/mockttp), [cloakbrowser](https://cloakbrowser.dev/), and [camoufox](https://github.com/daijro/camoufox).

## Table of Contents

Expand All @@ -19,7 +19,7 @@ proxy-mcp is an MCP server that runs an explicit HTTP/HTTPS MITM proxy (L7). It
- [Traffic Capture](#traffic-capture-4)
- [Modification Shortcuts](#modification-shortcuts-3)
- [TLS Fingerprinting](#tls-fingerprinting-9)
- [Interceptors](#interceptors-17)
- [Interceptors](#interceptors-21)
- [Browser DevTools-equivalents](#browser-devtools-equivalents-9)
- [Sessions](#sessions-13)
- [Humanizer](#humanizer--playwright-input-5)
Expand Down Expand Up @@ -564,7 +564,7 @@ proxy_test_rule_match --mode exchange --exchange_id "ex_abc123"

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 (17)
### Interceptors (21)

Interceptors configure targets (browsers, processes, devices, containers) to route their traffic through the proxy automatically.

Expand All @@ -586,6 +586,46 @@ Interceptors configure targets (browsers, processes, devices, containers) to rou

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).

#### Camoufox (4) — anti-detect Firefox

| Tool | Description |
|------|-------------|
| `interceptor_camoufox_launch` | Spawn camoufox as a Playwright WebSocket server, proxy + NSS CA pre-wired. Returns `wsUrl` |
| `interceptor_camoufox_info` | Get the wsUrl + ready-to-paste TS / Python `firefox.connect()` snippets |
| `interceptor_camoufox_list` | List active camoufox instances and their fingerprint details |
| `interceptor_camoufox_close` | Stop the launcher, remove the temp launcher dir + NSS profile |

Camoufox is a patched Firefox with source-level fingerprint controls (OS, WebGL vendor/renderer, fonts, locale, geoip-derived timezone, WebRTC blocking, humanize cursor). Unlike the Chromium path, camoufox runs as an external Python process and exposes a Playwright WS endpoint — the caller drives pages with `await firefox.connect(wsUrl)` instead of going through MCP page tools.

**Host requirements:**

```bash
pip install "camoufox[geoip]"
python3 -m camoufox fetch # downloads patched Firefox binary (~200 MB)

# For TLS MITM trust (NSS profile is created per-launch and the proxy CA is imported):
sudo apt install libnss3-tools # Debian/Ubuntu
sudo dnf install nss-tools # Fedora/RHEL
# macOS: brew install nss (or use /Applications/Firefox.app/Contents/MacOS/certutil)
```

If `certutil` is missing, the launch still succeeds but the proxy CA is not trusted — HTTPS pages will show certificate errors. Proxy traffic is still captured.

**Usage:**

```text
proxy_start // start the MITM proxy
interceptor_camoufox_launch { headless: true } // returns { targetId, wsUrl, playwright_connect, ... }
// in your own Node code:
// import { firefox } from 'playwright-core';
// const browser = await firefox.connect(wsUrl);
// const page = await (await browser.newContext()).newPage();
// await page.goto('https://example.com');
interceptor_camoufox_close { target_id } // when done
```

`playwright-core` is already a proxy-mcp dependency — Camoufox uses its `firefox` namespace via WebSocket; no extra Node packages needed. Traffic capture, TLS fingerprinting, rules, mocks, sessions, upstream chaining, and JA3/JA4 spoofing all apply to camoufox automatically because the proxy sits in front of it.

#### Terminal / Process (2)

| Tool | Description |
Expand Down Expand Up @@ -698,6 +738,7 @@ All tools require `target_id` from a prior `interceptor_browser_launch`. The eng
| `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://camoufox/targets` | Active camoufox instances with their wsUrl and fingerprint details |
| `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) |
Expand Down
44 changes: 16 additions & 28 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# proxy-mcp Roadmap

Last updated: 2026-02-11
Current shipped baseline: commit `ec28255`
Last updated: 2026-04-19
Current shipped baseline: v2.2.0 (commit `e93804f`)

## Current Baseline (Already Shipped)

Expand All @@ -21,6 +21,8 @@ These are implemented and in the repo now:
- `proxy_search_session_bodies`
- `proxy_get_session_exchange`
- `proxy_export_har`
- `proxy_import_har`
- `proxy_replay_session`
- `proxy_delete_session`
- `proxy_session_recover`
- Session resources/templates:
Expand All @@ -42,33 +44,19 @@ These are implemented and in the repo now:

## Phase 1 (High ROI / Next)

### 1) Replay Engine (`proxy_replay_session`)
Problem solved:
- Turn observed traffic into reusable, high-throughput extraction.
### 1) ~~Replay Engine (`proxy_replay_session`)~~ — SHIPPED in 2.x

Planned interface additions:
- Tool: `proxy_replay_session`
- Tool: `proxy_replay_status`
- Resource: `proxy://replay/{replay_id}/summary`
Implemented at `src/tools/sessions.ts` (`proxy_replay_session`). Ships with:
- Filter-based selection (`hostname_contains`, `url_contains`, `status_code`, `exchange_ids`)
- `mode: "dry_run"` (plan-only, no outbound) and `mode: "execute"`
- `target_base_url` override (redirect replay to staging/local)
- `limit` / `offset` / `timeout_ms` controls
- Per-request result capture on execute

Functional requirements:
- Replay selected session traffic by filter and/or explicit sequence list
- Variable substitution (`{timestamp}`, `{nonce}`, captured token refs)
- Concurrency control, rate limiting, retry policy
- Per-request result capture (status, latency, error class)

Edge cases/failure modes:
- Token/session expiry during replay
- Target-side throttling/429 storms
- Non-idempotent endpoints replayed by mistake

Acceptance criteria:
- Can replay at least 1,000 selected requests with bounded concurrency
- Replay report includes success/failure counts and error buckets
- Supports dry-run mode (plan only, no outbound send)

Effort: M
Dependencies: session query engine (already shipped)
Deferred (not blocking POC workflows):
- `proxy_replay_status` streaming status (currently returns all results synchronously)
- `proxy://replay/{replay_id}/summary` resource (dedicated replay run tracking)
- Variable substitution (`{timestamp}`, `{nonce}`, captured token refs) — currently replays recorded bodies verbatim

### 2) Session Diffing (`proxy_diff_sessions`)
Problem solved:
Expand Down Expand Up @@ -231,7 +219,7 @@ Dependencies: replay engine + diff logic

| Priority | Feature | Phase | Effort | Dependencies | Status |
|---|---|---|---|---|---|
| P1 | Replay engine | 1 | M | Session query (shipped) | Planned |
| P1 | Replay engine | 1 | M | Session query (shipped) | **Shipped (v2.x, minus replay-status + variable substitution)** |
| P2 | Session diffing | 1 | M | Replay/query schema | Planned |
| P3 | Decoder pipeline | 1 | M | Persisted exchange access (shipped) | Planned |
| P4 | WebSocket/SSE capture | 2 | L | Capture layer extensions | Planned |
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "proxy-mcp",
"version": "2.3.0",
"version": "3.0.0",
"description": "MCP server for HTTP/HTTPS MITM proxy via mockttp",
"type": "module",
"engines": {
Expand Down
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { registerSessionTools } from "./tools/sessions.js";
import { registerHumanizerTools } from "./tools/humanizer.js";
import { registerTransparentTools } from "./tools/transparent.js";
import { registerMobileTools } from "./tools/mobile.js";
import { registerCamoufoxTools } from "./tools/camoufox.js";
import { registerResources } from "./resources.js";
import { initInterceptors } from "./interceptors/init.js";

Expand All @@ -54,7 +55,7 @@ function arg(name: string, fallback: string): string {
/* ------------------------------------------------------------------ */

function createMcpServer(): McpServer {
const server = new McpServer({ name: "proxy", version: "2.0.0" });
const server = new McpServer({ name: "proxy", version: "3.0.0" });

initInterceptors();

Expand All @@ -70,6 +71,7 @@ function createMcpServer(): McpServer {
registerHumanizerTools(server);
registerTransparentTools(server);
registerMobileTools(server);
registerCamoufoxTools(server);
registerResources(server);

return server;
Expand Down
Loading
Loading