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 tools —
browser_goto,browser_click,browser_snapshot, … - Lighthouse verification — scores, performance metrics, gates, HTML/JSON reports
- action↔capture correlation —
flows_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).
-
Clone + install:
Terminal window git clone https://github.com/trongitnlu/proxyprocd proxypro && make bootstrap # Go protoc plugins + pnpm depsmake engine # macOS: universal; Linux: native binary -
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:
npx proxypro-harness# resolves the engine, installs Chromium on first run, then:# [harness] MCP ready at http://127.0.0.1:9091/mcp — engine: runningThe 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):
cd app && pnpm harness# [harness] engine running# [harness] MCP ready at http://127.0.0.1:9091/mcp — engine: runningEither 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:
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 gatenpx proxypro-harness test scenarios/ \ --compare .proxypro/baseline.json \ --max-duration-regression-percent 25
# Validate contract:true assertions against a local OpenAPI documentnpx 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 mappingnpx proxypro-harness test scenarios/ \ --changed=origin/main \ --fail-on-unmapped \ --reporter console,junit
# Audit source ownership without starting the engine or browsernpx proxypro-harness audit scenarios/ \ --reporter console,json,markdown,junit
# Inspect or recover durable dirty-resource quarantinesnpx proxypro-harness quarantine listnpx proxypro-harness quarantine retry db:checkout \ --reporter console,json,markdown,junitnpx proxypro-harness quarantine acknowledge db:checkout --confirmTargets 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-pathresources: [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:
npx proxypro-harness leases list --reporter consolenpx proxypro-harness leases list --reporter json,markdown,junit --output .proxypro/resultsnpx proxypro-harness leases acknowledge db:checkout --confirmThe 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:
npx proxypro-harness plan scenarios/ --concurrency 4npx proxypro-harness plan scenarios/ --concurrency 4 --history .proxypro/results/scenario-history.jsonnpx proxypro-harness plan scenarios/ --reporter json,markdown,junit --output .proxypro/resultsPreflight 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:
npx proxypro-harness schedule analyze scenarios/npx proxypro-harness schedule analyze scenarios/ --history .proxypro/results/scenario-history.json --window 25npx proxypro-harness schedule analyze scenarios/ --reporter json,markdown,junit --output .proxypro/resultsAt 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:
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,junitBaseline 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:
npx proxypro-harness schedule explain scenarios/ \ --baseline .proxypro/results/proxypro-scheduling-analytics.json \ --reporter console,json,markdown,junitFresh 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-healthsteps: - 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
claude mcp add --transport http proxypro http://127.0.0.1:9091/mcpclaude mcp list # proxypro: ... - ✓ ConnectedStart 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:
| Tool | What it does |
|---|---|
browser_launch | Start Chromium (proxied + TLS-ignore). Optional — other browser tools auto-launch. headless:false shows a live desktop window; record:true captures a .webm replay. |
browser_goto | Navigate to a URL. Returns final URL + status + an actionId. |
browser_click / browser_fill | Interact by selector (CSS, text=, role=). |
browser_snapshot | Compact ARIA snapshot of the page (token-cheap — prefer over screenshots). |
browser_screenshot | PNG (base64). Use only when a visual is needed. |
browser_eval | Evaluate a JS expression in the page. |
browser_close | End the session (engine stays up); returns the saved .webm replayPath when launched with record:true. |
run_lighthouse | Audit 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_action | Which captured flows did action N trigger (marker → window). |
wait_for_idle | Wait 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:
-
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.) -
Mock the backend so you can build the frontend before the API exists:
“Mock
GET https://demo.test*/api/ordersto return{orders:[…]}as JSON, and serve an HTML page athttps://demo.test*/.”(Calls
create_map_local_rule— note the*in the pattern, see URL patterns.) -
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_actionand reports the/api/orderscall it caused. -
Inject a fault to test resilience — the thing plain browser automation can’t do without a broken backend:
“Now make
/api/ordersreturn 500 and click again — does the UI handle it?”The agent updates the mock to
500, re-clicks, and reads the error state back frombrowser_snapshot. -
Clean up when done:
“Close the browser and set SSL proxying back to
allowlist.”browser_closeremoves 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:falseso I can watch, then openhttps://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:Goal Pattern The site root only https://demo.test*/One endpoint https://demo.test*/api/ordersEverything under a host https://demo.test*A path subtree https://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_capturesremain 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 testin 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.