Skip to content

Headless AI harness

The headless harness runs ProxyPro’s engine + MCP server without the desktop app, and gives the agent a real Playwright-driven browser routed through the proxy. An AI agent (Claude Code) can then drive a web app, watch the decrypted network traffic, and correlate which requests each UI action caused — the loop you need to develop and test a web app fast against mocked backends.

It’s the same MCP server and tool surface as the in-app integration, packaged as a no-window, scriptable entrypoint with:

  • a headless entrypoint (pnpm harness) — no window, scriptable, CI-friendly
  • browser toolsbrowser_goto, browser_click, browser_snapshot, …
  • Lighthouse verification — scores, performance metrics, gates, HTML/JSON reports
  • action↔capture correlationflows_for_action, wait_for_idle
  • deterministic scenario suites — run YAML files/folders/globs without an AI client

Prerequisites

Two ways to run: the published npx proxypro-harness CLI (no checkout — see Start the harness), or from a source checkout (below, for developing ProxyPro itself).

  1. Clone + install:

    Terminal window
    git clone https://github.com/trongitnlu/proxypro
    cd proxypro && make bootstrap # Go protoc plugins + pnpm deps
    make engine # macOS: universal; Linux: native binary
  2. Install the Chromium the browser tools drive:

    Terminal window
    cd app && pnpm exec playwright install chromium

1. Start the harness

No checkout? Run the published CLI — it boots the same harness on plain Node:

Terminal window
npx proxypro-harness
# resolves the engine, installs Chromium on first run, then:
# [harness] MCP ready at http://127.0.0.1:9091/mcp — engine: running

The npm harness requires Node.js 18.16 or newer.

proxypro-harness resolves proxypro-engine automatically: --engine <path>, PROXYPRO_ENGINE env var, installed ProxyPro.app (macOS, auto-detected), source build, or auto-downloaded on first run from GitHub Releases and cached locally. Auto-download supports macOS and Linux on both x86-64 and arm64; Linux selects the matching linux-amd64 or linux-arm64 asset and caches it at ~/.proxypro/engine/<tag>/<platform>-<arch>/proxypro-engine.

Each packaged Desktop launch records the embedded engine path under ProxyPro’s user data directory. This lets the harness find apps installed outside /Applications or renamed after download, without editing shell profiles. It also attaches to an already-running shared Desktop engine before resolving or downloading any binary.

The repo is private — the auto-download requires a GitHub token with repo read access. Set GITHUB_TOKEN (or GH_TOKEN), or run gh auth login once (the gh CLI token is picked up automatically). Without a token the download returns 404 with an actionable error message. Pass --engine or set PROXYPRO_ENGINE to skip the download entirely.

On Linux, the headless harness needs no desktop app. Minimal server/container images may lack Chromium’s shared libraries; if Playwright reports missing host dependencies, run npx playwright install-deps chromium as root or use a Playwright base image. --headed additionally needs X11/Wayland or Xvfb; the default headless mode does not. Engine data follows XDG ($XDG_DATA_HOME/proxypro or ~/.local/share/proxypro).

Flags: --headed (visible window), --record (save .webm replays), --no-auto-install (skip the Chromium download). See proxypro-harness --help.

From a source checkout (for development on ProxyPro itself):

Terminal window
cd app && pnpm harness
# [harness] engine running
# [harness] MCP ready at http://127.0.0.1:9091/mcp — engine: running

Either way this boots the Go engine (proxy on :9090) and the MCP HTTP server on :9091 — no desktop window. Leave it running; Ctrl-C shuts it down cleanly.

Deterministic scenario suites

Use the test command when the YAML already exists and you want a repeatable local or CI result without starting Claude or connecting an MCP client:

Terminal window
npx proxypro-harness test scenarios/
npx proxypro-harness test 'scenarios/**/*.yaml' \
--retries 1 --fail-fast --concurrency 4 \
--reporter console,json,markdown,junit \
--output .proxypro/results
# Optional explicit baseline and CI duration gate
npx proxypro-harness test scenarios/ \
--compare .proxypro/baseline.json \
--max-duration-regression-percent 25
# Validate contract:true assertions against a local OpenAPI document
npx proxypro-harness test scenarios/ \
--openapi ./openapi.yaml \
--contract-severity error \
--contract-coverage-min 80 \
--contract-coverage-exclusions ./coverage-exclusions.json \
--reporter console,junit
# Run the Git-affected subset and fail if relevant source has no mapping
npx proxypro-harness test scenarios/ \
--changed=origin/main \
--fail-on-unmapped \
--reporter console,junit
# Audit source ownership without starting the engine or browser
npx proxypro-harness audit scenarios/ \
--reporter console,json,markdown,junit
# Inspect or recover durable dirty-resource quarantines
npx proxypro-harness quarantine list
npx proxypro-harness quarantine retry db:checkout \
--reporter console,json,markdown,junit
npx proxypro-harness quarantine acknowledge db:checkout --confirm

Targets may be individual .yaml/.yml files, recursive folders, or globs. They are sorted and run through the same native runner used by Desktop Scenario Studio, so validation, assertions, temporary-rule cleanup, SSL restoration, browser cleanup, and API-client cleanup stay identical. Execution is sequential by default. --concurrency <1-8> opts into duration-aware worker queues using the latest passing stable history. Each worker has its own browser, native API correlation namespace, and engine session-rule namespace. A suite containing decrypt falls back safely to one worker because SSL policy is global, and the fallback reason is retained in every reporter. Exit code 0 means every scenario passed, 1 means the suite failed or was cancelled, and 2 means the command was invalid. --timeout <seconds> overrides the three-minute per-scenario budget. For CI, pass an isolated --data-dir so persisted developer rules cannot affect the run.

Scenario format v1.7 adds optional top-level resource locks for shared local state. Use stable names that describe the dependency, not the worker:

name: checkout-write-path
resources: [db:checkout, backend:payments, port:3000]
steps:
- request: { method: POST, url: http://127.0.0.1:3000/checkout }

ProxyPro acquires the complete resource set atomically before the Scenario and keeps it through every retry. Scenarios sharing a resource run one at a time; disjoint Scenarios and jobs still use available global workers. Requests are FIFO per resource, so a later user cannot starve an older waiter, and atomic acquisition avoids multi-resource deadlocks. All reporters and history retain the resource plan.

Scenario format v1.8 adds setup and teardown arrays for deterministic local test-state lifecycle. Both accept the same bounded native request, extract, and expect_network fields as an API step; browser and shell actions are not allowed:

resources: [db:checkout]
setup:
- request: { method: POST, url: http://127.0.0.1:3000/test/reset }
expect_network: [{ url: "**/test/reset", status: 204 }]
steps:
- request: { method: GET, url: http://127.0.0.1:3000/checkout }
teardown:
- request: { method: DELETE, url: http://127.0.0.1:3000/test/session }

The runner acquires declared resources first, runs setup against the real backend before installing Scenario mocks, and starts the main body only when setup passes. Every suite retry is a fresh attempt and reruns setup. After the body, temporary mock/fault rules are removed and teardown is attempted even for failure, cancellation, or timeout. SSL/API cleanup and resource release happen afterward. Extracted setup variables are available to main and teardown steps; side-effect methods participate in the existing Watch/Impact consent gates. Lifecycle cases appear in Desktop and every CLI reporter/history artifact.

Teardown uses at most three bounded attempts. Exhaustion quarantines the Scenario’s complete declared resource set, so conflicting work cannot inherit dirty test state while disjoint work keeps its available workers. Desktop Verification Jobs exposes the dirty/recovering state, a cleanup-only retry that reuses in-memory extracted variables, and an explicit acknowledge-and-release action for developers who cleaned the resource manually.

A bounded mode-0600 local journal restores dirty resource locks after restart. It stores metadata and an optional Scenario path/hash only—never variables, tokens, headers, or bodies. Restart recovery can replay teardown only when the source is still a regular non-symlink file with the same SHA-256 and cleanup is static without the previous SSL/decrypt lane or lost runtime values. Otherwise the group remains manual-only. The headless harness checks this journal before starting the engine and fails closed with reporter evidence when selected work overlaps dirty resources or the journal is unreadable. Quarantines never expire or release automatically. These controls remain local coding/dev only and intentionally add no authentication.

The standalone quarantine commands use the same journal. list and confirmed manual acknowledge are engine-free. retry starts an isolated headless runtime only after the Scenario remains a bounded regular non-symlink file, its SHA-256 is unchanged, and static teardown is still eligible. A group is released only when teardown returns nonempty passing evidence; manual acknowledgement is clearly recorded as unverified. Cross-process journal transactions merge disjoint Desktop/CLI updates and reject stale changes to the same group. Console, JSON, Markdown, and JUnit reporters expose the operation, while Desktop retains the latest five entries from the bounded local history.

Desktop watches the journal’s directory while it is open. External CLI quarantines, retry results, acknowledgements, and releases reconcile into Scenario Studio without restarting the app. A released group immediately wakes blocked Desktop verification jobs. The UI labels the journal LIVE SYNC and shows when the latest external revision was accepted. Observation cannot weaken Desktop’s compare-and-swap baseline: the exact revision is adopted only after the coordinator accepts it, while revision rollback and same-revision content rewrites fail closed. A same-group change during active Desktop recovery waits until recovery settles; disjoint updates remain live. This is local filesystem coordination and requires no authentication.

Desktop and harness runners share machine-level scheduling state beside the owner-checked engine socket. The default processes share one namespace; --data-dir selects its corresponding isolated namespace. Across every participant, ProxyPro permits at most eight active Scenarios, acquires complete resource sets atomically, keeps FIFO for conflicts, allows disjoint bypass, and runs global SSL/decrypt work behind an exclusive barrier. Scenario Studio shows MACHINE SYNC, external CLI owner/PID/Scenario leases, and queued requests.

If an owner process exits while holding declared resources, its lease becomes an abandoned blocker rather than expiring. No overlapping Scenario can start until cleanup is explicitly confirmed in Desktop, or a linked durable quarantine is released by a successful quarantine retry or confirmed quarantine acknowledge. The durable release is saved before the machine blocker is removed. Invalid or unwritable coordination state fails closed. The journal contains bounded scheduling metadata only, remains mode 0600 in the local owner-only socket directory, and adds no authentication.

Diagnose that machine state without booting the engine, browser, proxy, or MCP server:

Terminal window
npx proxypro-harness leases list --reporter console
npx proxypro-harness leases list --reporter json,markdown,junit --output .proxypro/results
npx proxypro-harness leases acknowledge db:checkout --confirm

The list includes active owner labels/PIDs/heartbeats, waiters, complete resource sets, and abandoned blockers. Acknowledgement resolves exactly one abandoned entry, compares its complete observed fingerprint inside the locked transaction, and rejects stale evidence. It never kills, takes over, or releases a live owner or waiter. Manual cleanup is recorded as CLI/unverified evidence. The bounded journal retains only the newest 100 abandonment, quarantine, and release transitions; Desktop shows the latest five. MCP clients may inspect the same bounded evidence with read-only get_scenario_coordination_status, but no MCP mutation tool exists. These remain local coding/dev surfaces and require no authentication.

Preview duration-aware scheduling without starting the engine, browser, proxy, MCP listener, or any Scenario:

Terminal window
npx proxypro-harness plan scenarios/ --concurrency 4
npx proxypro-harness plan scenarios/ --concurrency 4 --history .proxypro/results/scenario-history.json
npx proxypro-harness plan scenarios/ --reporter json,markdown,junit --output .proxypro/results

Preflight validates the same local YAML, reuses the runtime worker scheduler, and models atomic resource conflicts plus global SSL/decrypt exclusivity. It separates ordinary worker queueing from current active-owner, earlier-waiter, and capacity contention, and fails closed for durable quarantines, abandoned leases, invalid YAML, or unreadable coordination state. Timing is a clean-machine lower bound; completion of an external PID remains explicitly unknown instead of being guessed from heartbeat age.

Scenario Studio offers Preview schedule before Run. An MCP client can inspect that developer-created snapshot through read-only get_scenario_scheduling_preflight, but cannot submit new inputs, start work, or change a lease. Planning and evidence stay local, so no authentication is added.

After a Desktop preview, Run creates a fresh admission plan from the current sources, concurrency, history, leases, and quarantines. SHA-256 source and plan fingerprints classify the handoff as MATCHED, STALE, or NOT-PREVIEWED, with exact drift reasons. A fingerprint is evidence only: it does not reserve capacity and cannot bypass atomic worker/resource/lease acquisition.

Completed suite reports compare planned and actual start, finish, duration, and makespan. Each Scenario records assigned-worker queue time, process-local admission, cross-process lease wait, execution split across setup/body/teardown, and release overhead, then identifies the largest bottleneck. Console, JSON, Markdown, JUnit, Desktop history, and the plan-to-actual timeline retain the same result. MCP exposes the latest bounded completed run through read-only get_scenario_scheduling_execution; it accepts no run or mutation input. The fingerprints and timing record contain no request bodies, headers, tokens, or Scenario variables, and this local development surface adds no authentication.

Analyze the measured history without starting an engine, browser, proxy, MCP listener, or Scenario run:

Terminal window
npx proxypro-harness schedule analyze scenarios/
npx proxypro-harness schedule analyze scenarios/ --history .proxypro/results/scenario-history.json --window 25
npx proxypro-harness schedule analyze scenarios/ --reporter json,markdown,junit --output .proxypro/results

At most 100 recent runs contribute p50/p95 worker-queue, local-admission, cross-process-lease, execution, and actual-makespan evidence. The report tracks preview MATCHED/STALE/NOT-PREVIEWED rates and recurring per-Scenario bottlenecks. It also simulates the current YAML suite at 1–8 workers while respecting declared resource conflicts and exclusive SSL/decrypt fallback. The advisor selects the smallest worker count within 5% of the fastest clean-machine simulation, reports savings versus sequential work, and identifies where marginal improvement first drops below 10%.

Scenario Studio’s Analyze scheduling panel shows the same percentiles, simulation table, and recommendation. The empty-input, read-only get_scenario_scheduling_analytics MCP tool exposes only the latest developer-created snapshot. Recommendations never change concurrency or start work. JSON, Markdown, and JUnit artifacts are mode 0600; this owner-local coding surface intentionally adds no authentication.

Once an analytics snapshot has been reviewed, compare current history against it without starting runtime services:

Terminal window
npx proxypro-harness schedule compare scenarios/ \
--baseline .proxypro/results/proxypro-scheduling-analytics.json
npx proxypro-harness schedule compare scenarios/ \
--baseline .proxypro/results/proxypro-scheduling-analytics.json \
--max-makespan-regression-percent 20 \
--max-process-wait-p95 500 \
--max-preview-stale-percent 25 \
--reporter json,markdown,junit

Baseline and current snapshots must have exactly the same Scenario paths. The report compares p50/p95 metrics, advisor worker/makespan estimates, preview stale rate, and new, resolved, or persistent recurring bottlenecks. Threshold flags are opt-in. Once configured, the exact-suite makespan gate fails closed if either window lacks suitable evidence; JSON, Markdown, and JUnit reflect the same non-zero gate result.

Scenario Studio stores a baseline only after the developer clicks Save baseline or Replace baseline. The atomic mode-0600 file can be compared or cleared through explicit UI actions. MCP exposes the latest developer-created result through empty-input read-only get_scenario_scheduling_comparison; it cannot mutate the baseline, thresholds, worker setting, or run state. No authentication is added to this owner-local coding/dev workflow.

Explain the comparison with bounded per-Scenario attribution, still without starting runtime services:

Terminal window
npx proxypro-harness schedule explain scenarios/ \
--baseline .proxypro/results/proxypro-scheduling-analytics.json \
--reporter console,json,markdown,junit

Fresh Phase 66 analytics and reviewed baselines retain only scheduling profiles: per-Scenario sample counts and p95 worker-queue, local-admission, process-lease, and execution values, plus declared resource IDs and exclusive-lane state. The explainer ranks contributors by p95 growth weighted by current sample count, identifies the dominant wait/execution layer, highlights shared-resource candidates and resource declaration drift, and produces deterministic remediation plus a clean-machine worker what-if. It never edits resource YAML, changes workers, releases leases, replaces a baseline, changes a threshold, or starts a run.

A baseline created before Phase 66 remains valid for schedule compare, but root-cause analysis returns an insufficient result until Analyze scheduling and explicit Replace baseline capture reviewed profiles. Desktop exposes Explain regression after comparison. The empty-input, read-only get_scenario_scheduling_root_cause MCP tool returns only the latest bounded developer-created result. JSON, Markdown, and JUnit artifacts remain mode 0600; no YAML, request bodies, headers, tokens, or variables are retained. No authentication is added to this owner-local coding/dev workflow.

The latest 50 reports are stored locally at .proxypro/results/scenario-history.json by default. Every run compares status with the previous run and duration with the latest passing run; use --history <file> to move that store or --no-history for an ephemeral run. --compare <report.json> uses an explicit JSON report instead. A retry whose attempts disagree is reported as UNSTABLE and returns exit code 1, including as a JUnit failure, so retries cannot hide a regression.

For contract tests, attach contract: true to an expect_network item and pass --openapi <file>. ProxyPro validates the local document with Swagger Parser, then checks captured method, path, status, content type, and JSON bodies with AJV. A contract failure includes its JSON Pointer, schema path, expected value, actual value, and severity in every reporter. HTTP $ref resolution is disabled; the spec and captures stay on the machine.

All flows correlated to suite actions contribute to API coverage, whether or not they have an explicit contract assertion. Coverage is calculated per documented method, path template, and response key, then included in every reporter. --contract-coverage-min <percent> gates the current run. History or --compare also detects previously covered targets that disappeared; pass --allow-contract-coverage-drop only when that regression is intentional. Exact exclusions exported by Desktop include a mandatory reason and can be shared with CI through --contract-coverage-exclusions <json>.

In Desktop Scenario Studio, click any suite result to inspect each retry, case error, and assertion’s expected/actual value. Capture links open only when the flow still exists locally; older history remains readable with unavailable links marked explicitly. The inspector can rerun one scenario, open its YAML, copy the equivalent harness command, or export focused Markdown/JSON evidence. The Workers selector provides the same opt-in locally. Live progress shows each active worker; completed results include requested/effective concurrency, duration-history coverage, estimated makespan, and deterministic worker queues. Multiple Desktop workflows may run together: manual suites, Watch revisions, Git verification, and Debug Impact Gates register independent jobs under one eight-worker local budget backed by the shared eight-worker machine budget. Fair permits rotate at Scenario boundaries, named resource locks serialize only conflicting work both locally and across Desktop/CLI processes, cancel targets only its suite, and global SSL/decrypt work waits for an exclusive machine lane. The Verification Jobs strip shows workflow, owner, active/waiting workers, allocation, held/waiting resources, and per-job cancellation.

After opening a folder, Start watch moves that feedback into the coding loop. ProxyPro watches the local suite plus its attached OpenAPI spec, batches short filesystem bursts, and uses the impact index to rerun only changed and related Scenarios. Fixture/mock-body changes select their owners; contract spec changes select Scenarios with OpenAPI assertions. A newer revision cancels an in-flight stale run, disk YAML refreshes in the editor, and the status strip shows affected paths plus history, duration, instability, and coverage deltas. The selected Workers and Retries values are captured when watch starts. Each revision uses the same duration-aware, isolated 1–8 worker scheduler as a manual suite; a newer revision cancels every active stale worker before the latest affected set runs. Desktop and read-only MCP status show requested and effective concurrency, planned makespan, and safety fallbacks. Watch runs never record video. Side-effect methods stay blocked unless you stop the watcher, enable Allow watch side effects, and start it again.

To include application-source edits, add proxypro.watch.json beside the Scenario files:

{
"version": 1,
"name": "API source",
"projectRoot": "..",
"include": ["src/**"],
"exclude": ["generated/**"],
"mappings": [
{
"id": "users",
"source": ["src/users/**"],
"scenarios": ["users/**"],
"operations": ["GET /users/**", "POST /users"]
}
]
}

include, source, and exclude are relative to projectRoot; scenarios is relative to the opened suite. operations matches the normalized operations extracted from native request steps and mocks. A source match runs its mapped candidates plus impact-index neighbors. Unmapped source changes are visible but do not fall back to the entire suite. The profile, dependencies, build outputs, and coverage folders are bounded or excluded before watching.

For a one-shot gate instead of a live watcher, click Verify changed files in Scenario Studio or pass --changed[=<ref>] to the harness. ProxyPro reads tracked, staged, and (by default) untracked paths from the local Git worktree, then reuses the profile mappings and impact neighbors. --changed compares to HEAD; --changed-from <ref> is an alias, --no-untracked narrows discovery, and --watch-profile <file> overrides automatic profile discovery. --fail-on-unmapped makes a relevant source file with no selected Scenario a failing gate without running the whole suite. Side-effect methods remain blocked unless explicitly allowed. Console, JSON, Markdown, and JUnit retain the base, paths, mapping reasons, selected Scenarios, and gate result.

Run Audit mappings before starting a change, or use proxypro-harness audit <file|folder|glob...> in pre-commit/CI. The audit is engine-free and reports included source files without ownership, mappings whose source globs match nothing, mappings that select no Scenario, and invalid Scenario YAML. include defines the auditable source universe; when omitted, common code extensions are used. The command exits 1 for any coverage issue and emits console, JSON, Markdown, or JUnit evidence. --watch-profile selects an explicit profile and --output chooses the artifact folder.

To close a failed audit without hand-editing the ownership file, pass --fix-plan. The harness writes JSON and Markdown remediation evidence with a ranked existing mapping, an exact exclusion alternative, confidence/reasoning, and a valid Scenario skeleton draft when no mapping selects a valid Scenario. Planning never writes project files. After reviewing those artifacts, rerun with --apply; use --resolution exclude only when every planned path is intentionally outside regression ownership. Apply is rejected if the profile, source universe, or Scenario content changed after planning and validates the complete profile/skeleton set before atomic replacement. A post-write audit failure restores the previous profile.

The same audit command also checks Scenario resource declarations without starting the engine, browser, proxy, or MCP server. Unsafe native requests with no resource and shared mutation scopes with inconsistent resource IDs fail the gate; overbroad or apparently unused declarations are warnings. JSON, Markdown, and JUnit resource-audit artifacts are emitted beside mapping evidence.

Use --resource-fix-plan to export a read-only additive YAML diff. After review, --apply-resource-fixes applies only the selected inferred locks; it never deletes existing declarations and rejects stale hashes, symlinks, changed audit fingerprints, and invalid generated YAML. Desktop Scenario Studio exposes the same workflow through Audit resources, Preview safe fixes, checkboxes, and a second write confirmation. This remains a local coding/dev tool, so the workflow does not add authentication.

Enable Record video before Run scenario or Run all to record every browser-based attempt. ProxyPro finalizes the .webm during normal, failed, cancelled, and timed-out cleanup, includes its path in the report/evidence, and offers Open recording from the result. Desktop stores these videos under ~/Library/Application Support/ProxyPro/scenario-replays/. API-only scenarios remain browser-free and therefore do not create an empty recording.

Scenario YAML opens in a local CodeMirror workbench with syntax highlighting, search, undo, contextual DSL completion, and a mocks/steps/faults outline. Strict validation runs after a short typing debounce and reports syntax or semantic problems at their exact line and column. From the failure inspector, Jump to source selects the corresponding step, fault, or assertion block; switching suite files preserves each in-memory draft.

Native API steps (no Chromium)

Scenario v1.6 can send HTTP(S) directly through ProxyPro. API-only suites do not download or launch Chromium; mixed suites launch it lazily when a browser step is reached. Native requests retain the same capture correlation, variables, mocks, faults, OpenAPI assertions, coverage, and reporters:

name: api-health
steps:
- request:
method: POST
url: http://127.0.0.1:3000/health
headers: { X-Test: scenario }
json: { probe: true }
timeoutMs: 5000
expect_network:
- { url: "**/health", status: 200, contract: true }

request also accepts string query values and a raw body alternative to json. expect_dom/expect_eval stay browser-only. OpenAPI coverage’s Generate Scenario action emits this native form for every HTTP method, avoiding CORS and same-origin setup.

2. Connect Claude Code

Terminal window
claude mcp add --transport http proxypro http://127.0.0.1:9091/mcp
claude mcp list # proxypro: ... - ✓ Connected

Start a Claude Code session after adding the server (MCP servers are picked up at session start), then talk to it in plain language — see the loop below.

3. The agentic loop

Both the harness and Desktop expose the full in-app tool set plus these browser, Lighthouse, and correlation tools:

ToolWhat it does
browser_launchStart Chromium (proxied + TLS-ignore). Optional — other browser tools auto-launch. headless:false shows a live desktop window; record:true captures a .webm replay.
browser_gotoNavigate to a URL. Returns final URL + status + an actionId.
browser_click / browser_fillInteract by selector (CSS, text=, role=).
browser_snapshotCompact ARIA snapshot of the page (token-cheap — prefer over screenshots).
browser_screenshotPNG (base64). Use only when a visual is needed.
browser_evalEvaluate a JS expression in the page.
browser_closeEnd the session (engine stays up); returns the saved .webm replayPath when launched with record:true.
run_lighthouseAudit a public or authenticated URL in separate proxied Chromium processes; optionally select a 3/5-run median, return scores, metrics, gates, findings, and private HTML/JSON report paths. Does not disturb the current browser session.
flows_for_actionWhich captured flows did action N trigger (marker → window).
wait_for_idleWait until an action stops producing new flows (settles async XHRs).

Every browser_* call returns an actionId; hand it to flows_for_action to see exactly which network requests that action caused. ProxyPro binds browser state and correlation to the calling MCP transport automatically: concurrent AI models receive independent pages, snapshot refs, action counters, recording, and close lifecycle. They can both return actionId: 1 without mixing captures, and no session id is required in tool arguments. A typical develop-and-test session:

  1. See everything. Tell the agent to decrypt all HTTPS for the session:

    “Use ProxyPro: set SSL proxying to all.”

    (Calls set_ssl_proxying_mode("all") — see the gotcha below.)

  2. Mock the backend so you can build the frontend before the API exists:

    “Mock GET https://demo.test*/api/orders to return {orders:[…]} as JSON, and serve an HTML page at https://demo.test*/.”

    (Calls create_map_local_rule — note the * in the pattern, see URL patterns.)

  3. Drive the app that’s served entirely from your mocks:

    “Open https://demo.test/, click ‘Load orders’, then tell me which network calls that click triggered.”

    The agent chains browser_goto → browser_click → wait_for_idle → flows_for_action and reports the /api/orders call it caused.

  4. Inject a fault to test resilience — the thing plain browser automation can’t do without a broken backend:

    “Now make /api/orders return 500 and click again — does the UI handle it?”

    The agent updates the mock to 500, re-clicks, and reads the error state back from browser_snapshot.

  5. Clean up when done:

    “Close the browser and set SSL proxying back to allowlist.”

    browser_close removes that MCP transport’s ephemeral rules and mock states. The same cleanup runs on disconnect, idle expiry, and harness shutdown.

4. Verify Lighthouse and performance

run_lighthouse is independent of browser_launch: it starts and cleans up a short-lived audit browser, while an existing visible or recorded browser session keeps running. Its traffic still goes through ProxyPro, including requests to a localhost dev server.

{
"url": "http://localhost:3000/",
"categories": ["performance", "accessibility", "best-practices", "seo"],
"device": "mobile",
"runs": 3,
"thresholds": {
"performance": 90,
"accessibility": 95,
"largestContentfulPaintMs": 2500,
"totalBlockingTimeMs": 200,
"cumulativeLayoutShift": 0.1
}
}

runs accepts 1, 3, or 5. Every run starts a fresh Chrome process. With multiple runs, ProxyPro returns the run at the median Performance score (or median first-category score if Performance is omitted), plus every sample in aggregation.samples. Use runs: 3 for a more stable CI signal and runs: 1 for quick local feedback.

Authenticated pages can receive cookies and localStorage before every run:

{
"url": "https://app.example.com/dashboard",
"runs": 3,
"auth": {
"cookies": [{ "name": "session", "value": "..." }],
"localStorage": { "accessToken": "..." }
}
}

Extra headers are available as auth.extraHeaders, but Lighthouse applies them to every request, including third-party origins. You must explicitly set auth.allowCrossOriginHeaders: true to acknowledge that risk. Auth values are redacted from MCP call logs, omitted from tool results, and removed before the HTML/JSON reports are generated. The reports can still contain private page content, so they remain user-private files.

Category gates are minimum scores from 0–100; duration and CLS gates are maximums. With gates, verification.passed is a boolean and failures explains every miss. Without gates it is null, making the call measurement-only. verdict gives the one-word state, while findingsByCategory and keyFindings keep important SEO/accessibility failures visible even when Performance has many opportunities. Findings include short evidence and estimated savings where Lighthouse provides them; capture contains the audit time window for correlating captured traffic. Full reports land in <cwd>/proxypro-lighthouse/ (or <data-dir>/lighthouse/ with --data-dir); Desktop uses ~/Library/Application Support/ProxyPro/lighthouse/. Lighthouse is a synthetic lab measurement, so keep test conditions stable and leave reasonable headroom in CI thresholds.

Gotchas & tips

Watch it live, or save a replay

The browser is headless by default (unattended/CI). To watch the agent drive it in a real desktop window, have it launch with headless:false:

“Launch the browser with headless:false so I can watch, then open https://demo.test/.”

To review the run afterwards, launch with record:true — ProxyPro records the whole session to a .webm and returns its path when the agent calls browser_close:

“Launch with record:true, run the checkout flow, then close the browser and tell me where the replay was saved.”

For npx proxypro-harness, videos land in proxypro-replays/ under the working directory. When the same MCP browser tools run inside ProxyPro Desktop, videos land in ~/Library/Application Support/ProxyPro/replays/ so a Finder-launched app never depends on an unwritable working directory. In both cases, open the returned path in any video player. Recording finalizes on browser_close (or when ProxyPro shuts down) — there’s no partial mid-session video.

Scenario Studio has its own Record video checkbox and stores its replays in the adjacent scenario-replays/ directory. The headless test command uses the existing --record flag for the same per-scenario behavior.

Capture nothing by default?

ProxyPro ships in allowlist SSL mode — only explicitly allowed hosts are decrypted; everything else is tunnelled (loads fine, but isn’t captured). For an agent session where you want full visibility, switch to decrypt-all once:

set_ssl_proxying_mode("all")

…or add specific hosts with add_ssl_proxying_host. The first SSL mutation acquires a 30-minute lease and snapshots the shared config. ProxyPro restores that snapshot when the owning MCP transport disconnects or the lease expires.

Map Local patterns need a wildcard

urlPattern is an anchored, full-URL glob where * means zero-or-more of any character. Two consequences:

  • A bare host like https://demo.test/ must match the URL exactly — and MITM’d HTTPS URLs carry the port (https://demo.test:443/), so the bare form won’t match.

  • Use a * to absorb the port and any path:

    GoalPattern
    The site root onlyhttps://demo.test*/
    One endpointhttps://demo.test*/api/orders
    Everything under a hosthttps://demo.test*
    A path subtreehttps://api.example.com*/v1/*

Same-origin mocks avoid CORS

Mocking both the page and its API on the same host (https://demo.test*/ and https://demo.test*/api/…) keeps fetches same-origin — no CORS setup. If page and API are on different hosts, add an Access-Control-Allow-Origin response header in the Map Local rule (the engine then auto-handles OPTIONS preflight).

Prefer snapshots over screenshots

browser_snapshot returns a compact ARIA tree — usually enough to locate elements and read page state, at a fraction of a screenshot’s token cost. Reach for browser_screenshot only when you actually need pixels.

Cleanup

Rules and mock states created through MCP are owned by the calling transport. They are memory-only/namespaced and are removed automatically on browser_close, MCP disconnect, 30-minute browser idle expiry, or shutdown. One model cannot list, edit, delete, or match another model’s sandbox. Persistent rules created in Desktop remain global fallback rules and are never removed by agent cleanup.

  • SSL mode/allowlist and clear_captures remain globally visible, but competing agents cannot mutate the same resource while another session holds its lease. SSL restores automatically on disconnect/expiry; cleared captures have no undo.
  • Open Desktop Rules to inspect live Agent badges. Choose Promote to persistent when a useful sandbox rule should survive cleanup.
  • Open Desktop MCP to inventory all active transports and target one browser, sandbox, or connection without stopping the others. Multi-select promotion is ownership-checked and atomic.
  • Desktop reads each MCP client’s reported name/version, supports a temporary alias, attributes request/error/byte totals, and merges tool calls with flows by action ID. View traffic opens an agent: capture filter; Export evidence writes a local JSON summary.
  • Desktop also shows global-lease owners, countdowns, rollback policy, and last mutation, with explicit Release, Restore now, and Force takeover controls.
  • After a Desktop-hosted transport ends, Finished runs retains bounded local evidence (newest 50, 25 MB), reopens archived traffic, compares two runs, and can selectively hand rules/state to another live sandbox or turn selected requests and fixtures into an editable Repro Scenario. Safe methods are the default; side-effect methods require an explicit opt-in. Generated YAML uses archived statuses and bounded exact JSON responses as its baseline, and flattens selected mock state only as a warned static fixture. Open it in Scenario Studio to run/record or save it for proxypro-harness test in CI. Verify stability ×3 compares the archived exact JSON with three fresh captured responses, classifies stable/volatile/flaky baselines, highlights likely IDs, times, tokens, and array-order changes, and prepares bounded stable-field assertions. Review the before/proposed YAML, then explicitly apply, save, and verify the proposal once. Side-effect request methods require a separate opt-in before the three runs; response analysis remains local. Handoff and repro generation never restore process-wide settings. The standalone headless harness keeps its existing ephemeral cleanup lifecycle and does not persist this Desktop run history.
  • A failed or unstable Scenario inspector can assign a bounded local debug task to one active Desktop MCP transport. The selected agent reads YAML/evidence, claims an attempt, and submits a summary plus an optional valid Scenario or owned sandbox-rule IDs. Desktop shows a source/proposal and rule review, then verifies the exact submission once or three times through the native runner. The persisted comparison covers assertions, duration, OpenAPI failures, flows, captures, and replay paths. Analyze impact then indexes the local suite by shared mocks, fixtures, operations, hosts, fault targets, and URL scopes. It proposes a ranked, editable affected set; Run impact gate always runs the candidate plus those selected neighbors through the native suite runner. A source-set hash rejects stale plans, and side-effect methods require a separate opt-in. Acceptance requires both exact-proposal and impacted-suite passes tied to that submission; an override requires a recorded reason. Save/replace, rule promotion, and resolution remain separate explicit actions. Unfinished work becomes unassigned on disconnect; peer agents cannot read it. This inbox is intentionally absent from standalone headless mode.

Where to next