npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mockpro-mcp

v4.19.0

Published

MCP server for MockPro — API mocking, browser debugging, Lighthouse audits, and local image tools

Readme

mockpro-mcp

An MCP server that lets Claude Code (and Claude Desktop) mock APIs AND debug any web app in your browser — official Lighthouse audits, console logs, full network/CDP telemetry, WebSocket frames, DOM inspection, browser-level input, and WebM replay recording.

Browser workflows use a local WebSocket (127.0.0.1:27319), with no Native Messaging host to install. Chrome Debug Mode is explicitly attached per tab and off by default; Chrome shows its debugging indicator only while a CDP session is active. Every MCP call is shown live in the extension's MCP Activity tab. Lighthouse and local image workflows run directly in the MCP process and do not require the extension connection.

You need: Node.js 18.17+ · Chrome 136+ · the MockPro extension (free, Chrome Web Store) · an MCP client (Claude Code or Claude Desktop).


Install

Step 1 — Install the MockPro extension (Chrome Web Store)

Open the listing and click Add to Chrome:

https://chromewebstore.google.com/detail/mockpro-api-stream-mocker/liiljkbdpenmgpclbekenhlgpedbcbec

Then grab your extension id (the MCP server needs it):

  1. Go to chrome://extensions.
  2. Toggle Developer mode (top-right) on.
  3. Find the MockPro card and copy the ID — 32 characters, a–p (e.g. liiljkbdpenmgpclbekenhlgpedbcbec).

Don't want to hunt for the id? Open the MockPro Dashboard → MCP Activity tab — it shows the full claude mcp add command with your id already filled in, plus a Copy button.

Step 2 — Register the MCP server (user scope)

Run this once. --scope user writes to ~/.claude.json so every Claude Code project on your machine inherits it — no per-project re-registration:

claude mcp add --scope user --transport stdio mockpro -- npx -y mockpro-mcp \
  --extension-id <YOUR_MOCKPRO_EXTENSION_ID>

Drop --scope user if you'd rather scope it to the current project only.

First time / cautious? Append --readonly to disable the write tools until you trust it:

claude mcp add --scope user --transport stdio mockpro -- npx -y mockpro-mcp \
  --extension-id <ID> --readonly

Turning readonly off later? Re-run without --readonly (it overwrites the entry), or remove first: claude mcp remove mockpro --scope user.

Step 3 — Verify

Open Claude Code and ask it to call get_capabilities. It reports connection/version compatibility, browser and local feature flags, trust mode, limits, blockers, and next actions; MCP-local settings remain visible even while the extension is offline. Call get_state next when you need the enabled flag plus rule, group, and log counts, then list_tabs for a browser target. Watch Dashboard → MCP Activity to confirm calls are reaching the extension.


Quickstart

Mock an API while building the frontend

You: "Mock GET /api/users to return 3 fake users, then add a 500 variant I can toggle."
Claude: → add_rule × 2 → toggle_rule to flip

Organize a generated rule set

You: "Create an Authentication group, then add tagged success and error mocks for login."
Claude: → list_rule_groups → create_rule_group → add_rule × 2 → list_rules to verify priority

Debug a failing UI flow on localhost

You: "The checkout button on localhost:3000 isn't responding — figure out why."
Claude: → list_tabs → start_chrome_debug → snapshot_page → click → read_console_logs(level:'error') → read_network_logs(statusFilter:'4xx,5xx') → prepare_request_replay(networkEntryId, overrides) → replay_request(previewId) → compare_request_replay(replayId) → assert_request_replay(replayId, expect) → assert_request_replay_matrix(cases) → export_request_replay_matrix_playwright(cases) → suggest_mock_from_replay(replayId) → stop_chrome_debug

Debug a control inside a cross-origin iframe

You: "Inspect the embedded checkout and click its retry button."
Claude: → list_tabs → list_page_frames({tabId}) → snapshot_page({tabId,frameId})
        → click({tabId,ref:'f12:e7'}) → query_dom({tabId,frameId:12,selector:'#status'})

Audit one form before editing it

You: "Check the checkout form for missing labels and broken error associations without reading its values."
Claude: → list_tabs → snapshot_page → audit_form_accessibility({selector:'#checkout'})

Record a replayable WebM with its network timeline

You: "Record the checkout failure and save a replay I can inspect later."
Claude: → start_chrome_debug → start_chrome_recording → reproduce the flow
        → stop_chrome_recording → get_session → get_session_video

CDP recording captures the active page viewport without a display-sharing picker and confirms the first encoded frame before start succeeds. If screencast events stall in a visible Chrome window, MockPro uses bounded active-tab screenshot polling; HeadlessChrome returns recording_headless_unsupported because its extension capture APIs expose no compositor frames. Use start_session when a video-less network timeline is sufficient. For audio, first click the MockPro toolbar icon on the target tab and Arm tab audio for recording, then call start_chrome_recording({audio:true}); Chrome deliberately prevents MCP from granting this permission. The resulting WebM Blob stays local in the extension's IndexedDB until explicitly exported.

Profile and alter a live page

Claude: → start_chrome_debug → start_performance_trace + start_cpu_profile
        → reproduce → stop_cpu_profile + stop_performance_trace
        → inspect_cdp_dom / set_cdp_css_rule / set_request_interception
        → set_device_emulation / set_network_emulation → reset_emulation

Trace and profile artifacts are streamed to local files in chunks. Chrome's extension debugger blocks HeapProfiler on tested builds, so heap tools transparently return clearly labeled Runtime.getHeapUsage/performance-metrics JSON instead of pretending the fallback is a DevTools heap snapshot.

Audit Lighthouse scores and enforce budgets

You: "Run Lighthouse three times on localhost:3000 and require performance ≥80 and accessibility ≥90."
Claude: → run_lighthouse({url:"http://localhost:3000", runs:3,
          categories:["performance","accessibility"],
          budgets:{performance:80, accessibility:90}})

run_lighthouse launches a fresh dedicated headless Chrome for every run, returns median category scores and Core Web performance metrics, selects the real run nearest those medians, and writes official HTML/JSON reports. It accepts HTTP(S) URLs including localhost and does not require the MockPro extension to be connected. By default it runs once in mobile mode and saves reports in a unique OS temporary directory; set formFactor:"desktop", outputDir, reportName, or saveHtml/saveJson as needed.

Inspect a remote WebSocket

You: "What WebSocket frames is termix.app receiving right now?"
Claude: → list_tabs → read_websocket_logs(urlContains:'ssh', direction:'in')

Capture a lazy-loaded full page

You: "Capture the full page after giving lazy images one second to load."
Claude: → list_tabs → capture_screenshot({fullPage:true, delayMs:1000, savePath:"./full-page.png"})

delayMs accepts 0–3000ms and waits after every scroll step. Use a larger value for image-heavy pages with entrance animations.

Inspect and drive a form deterministically

You: "Fill the signup form on localhost:3000/signup with test data and submit."
Claude: → snapshot_page                       # ~2KB tree: textbox "Email" [ref=e1], … button "Sign up" [ref=e3]
       → inspect_form_state({ref:'e1'})       # live/default values, validity, constraints, selection
       → inspect_code_editor({ref:'e5'})      # Monaco/CodeMirror metadata/version/hash; text is opt-in
       → edit_input({ref:'e1', operation:'fill', text:'[email protected]'})
       → edit_input({ref:'e2', operation:'fill', text:'secret'}) # value is redacted in the reply
       → edit_contenteditable({ref:'e4', operation:'append', text:'Notes'})
       → edit_code_editor({ref:'e5', operation:'replace_range', text:'42', start:15, end:17,
                           expectedModelId:'m1', expectedVersionId:1, expectedSha256:'…'})
       → edit_code_editor_batch({ref:'e5', edits:[{start:0,end:0,text:'// fixed\n'},…],
                                 expectedModelId:'m1', expectedVersionId:2, expectedSha256:'…'})
       → prepare_code_editor_patch({ref:'e5', edits:[…], expectedModelId:'m1',
                                    expectedVersionId:3, expectedSha256:'…'}) # preview only
       → apply_code_editor_patch({patchToken:'…'}) # exact preview, one approval + Undo
       → create_code_fix_session({debugCaseId:'…', patchToken:'…', appTabId:7, editorTabId:8})
       → apply_code_fix_patch({codeFixSessionId:'…'}) # does not save/reload/HMR
       # explicitly refresh/HMR app, snapshot again, resolve recipe binding
       → verify_code_fix_session({codeFixSessionId:'…', bindingToken:'…', slotValues:{…}})
       → verify_code_fix_session({codeFixSessionId:'…', bindingToken:'fresh-…', slotValues:{…}})
       → assess_code_fix_readiness({codeFixSessionId:'…'}) # two consecutive fixed required
       → export_code_fix_regression_playwright({codeFixSessionId:'…',baseUrlEnv:'APP_BASE_URL'})
       → prepare_code_fix_regression_test({codeFixSessionId:'…',targetPath:'/project/tests/fix.spec.ts'})
       → apply_code_fix_regression_test({materializationToken:'…',confirmWrite:true}) # writes only; does not run
       → prepare_code_fix_regression_run({materializedTestId:'…'}) # command/env-name preview only
       → run_code_fix_regression_test({runToken:'…',confirmRun:true,environment:{APP_BASE_URL:'…',…}})
       → get_code_fix_regression_run({runId:'…'}) # poll; cancel_code_fix_regression_run is explicit
       # if still failing/changed/regression, preview a new contiguous patch
       → create_code_fix_successor({previousCodeFixSessionId:'…', patchToken:'…', editorTabId:8})
       # or inspect the unchanged post-patch editor and explicitly recover
       → rollback_code_fix_patch({codeFixSessionId:'…', ref:'e5', expectedModelId:'m1',
                                  expectedVersionId:4, expectedSha256:'…'})
       → click({ref:'e3'})                    # reply snapshot shows the success page
       → wait_for_element_state({selector:'.success', predicate:{visible:true}})

For a failing interaction, replace the standalone action with one correlated call:

act_and_observe({
  action: { type: 'click', ref: 'e3' },
  settleMs: 1000,
  includeInputEvents: true
}) // action result + state/snapshot + bounded input events + only new console/network entries

For several deterministic control changes, use one bounded plan after taking a fresh snapshot:

run_form_action_plan({
  tabId: 42,
  diagnostics: { onFailure: true, includeInputEvents: true, consoleLimit: 10, networkLimit: 10 },
  steps: [
    { type: 'edit_input', ref: 'e1', operation: 'fill', text: '[email protected]' },
    { type: 'edit_contenteditable', ref: 'e4', operation: 'fill', text: 'Signup notes' },
    { type: 'set_checked', ref: 'e2', checked: true },
    { type: 'wait_for_state', ref: 'e2', predicate: { valid: true }, timeoutMs: 2000 },
    { type: 'select_option', ref: 'e3', value: 'vn' },
    { type: 'press_key', ref: 'e1', key: 'Tab' },
    { type: 'assert_state', ref: 'e4', predicate: { text: 'Signup notes' } }
  ]
}) // ordered step results + final state + one final snapshot

Inspect, crop, and compress local images with AI

You: "Crop the subject from ./screenshots/hero.png to 16:9, export WebP, then compress every PNG in ./screenshots."
Claude: → inspect_image (sees the source) → edit_image (returns edited preview) → compress_images (batch result)

Image processing is local and does not require the Chrome extension to be connected.

Open an authorized source file in MockPro

Local file access is off by default. Register the daemon with one or more project roots, then an MCP client can open any regular file inside them in the dashboard without first selecting a browser workspace:

claude mcp add --scope user --transport stdio mockpro -- npx -y mockpro-mcp \
  --extension-id <ID> \
  --allow-file-root /absolute/path/to/project \
  --allow-source-context \
  --runtime-source-root http://localhost:5173/src/=/absolute/path/to/project/src
You: "Open src/server.ts at line 42 in MockPro."
Claude: → open_local_file({path:"/absolute/path/to/project/src/server.ts", line:42})
Claude: → open_local_files({paths:["/absolute/path/to/project/package.json","/absolute/path/to/project/src/server.ts"]})
Claude: → read_console_logs({level:"error"})
        → open_runtime_source({runtimeUrl:"http://localhost:5173/src/App.tsx",line:42,column:9})
Claude: → open_runtime_source({runtimeUrl:"http://localhost:5173/assets/app.js",line:1,column:128,sourceMap:true})
Claude: → resolve_runtime_stack({tabId:7,entryId:42})
        → read_runtime_source_context({tabId:7,entryId:42,frameIndex:0})
Claude: → capture_runtime_baseline({tabId:7,entryId:42})
        → [fix code, reload explicitly, take a fresh snapshot]
        → verify_runtime_fix({baselineId:"…",steps:[…, {type:"assert_state",ref:"e9",predicate:{text:"Order complete"}}]})
Claude: → capture_reproduction_recipe({tabId:7,steps:[…, {type:"assert_state",ref:"e9",predicate:{text:"Order complete"}}]})
        → create_debug_case({baselineId:"…",recipeId:"…",sourceFingerprint:"<sha256>",sourceFrameIndex:0})
        → [reload explicitly]
        → resolve_reproduction_recipe({recipeId:"…",tabId:7})
        → resolve_reproduction_recipe({recipeId:"…",tabId:7,bindings:[{targetId:"target_1",ref:"e17"},…]})
        → record_fix_attempt({debugCaseId:"…",bindingToken:"…",slotValues:{step_0_text:"…",step_1_predicate_text:"Order complete"},sourceFingerprint:"<new-sha256>",idempotencyKey:"attempt-1"})
        → get_debug_case({debugCaseId:"…"})
        → export_debug_case_playwright({debugCaseId:"…",testName:"checkout regression",baseUrlEnv:"APP_BASE_URL"})

The dashboard creates session-only, read-only Loose Files tabs and derives a collapsible cross-platform virtual Explorer only from their paths. Single calls and ordered batches add tabs without a directory workspace or directory enumeration. A batch accepts 1–20 paths, transfers at most 40 MiB of actual content, and reports each path independently; the daemon still reads at most 32 MiB per file and opens larger files as metadata only. Content is not persisted, and both read tools remain available with --readonly.

read_console_logs and Chrome Debug network initiators expose a normalized 1-based sourceLocation. resolve_runtime_source maps an HTTP(S) location to existing authorized files without opening anything; open_runtime_source opens only one unique result. Longest prefix wins, query/fragment values are ignored, and ambiguous direct mappings return candidates. Direct mapping remains the content-free default. Passing sourceMap:true with a generated line opts into bounded Source Map v3 resolution for local .js, .mjs, .cjs, and .css bundles: relative local map files and inline base64 JSON maps are supported, while HTTP(S) maps, indexed maps, virtual URL schemes, and sourcesContent-only originals are not fetched or opened.

A runtime mapping never grants file access: its canonical localRoot, generated bundle, map, and resolved original must all remain covered by --allow-file-root (or the broader explicit --allow-file-access). Generated bundles are capped at 32 MiB and only their final 64 KiB is scanned for sourceMappingURL; maps are capped at 8 MiB and 10,000 sources, with a 500 ms post-stage processing budget check. When a request passes through MockPro's page wrapper, Chrome may expose only its truthful chrome-extension://…/injected.js initiator; this non-HTTP location is not guessed or mapped to an app caller.

read_console_logs also returns up to 20 structured stackFrames when CDP supplies them, or derives a bounded list from common V8/Firefox error-stack lines. resolve_runtime_stack accepts either those frames directly or tabId + entryId, resolves all frames in original order, and adds deterministic app/dependency/internal/unresolved classification plus rank metadata. It never hides a frame or opens a file. Source maps are attempted by default only for mapped JS/CSS bundles; an unavailable map keeps the authorized direct bundle candidate with an explicit direct_fallback reason. Parsed maps use a 32-entry in-memory LRU keyed by canonical bundle and external-map size/mtime; embedded sourcesContent text is removed before caching, and every map policy/final original path is still revalidated.

read_runtime_source_context is a separate content-egress opt-in. It requires --allow-source-context plus existing file authority and a caller-supplied frameIndex; it never follows recommendedFrameIndex automatically. The selected UTF-8 file is revalidated before/after descriptor-based reading, capped at 8 MiB, fingerprinted with SHA-256, and returned as at most 100 lines/64 KiB (4 KiB per line). Console-entry mode may add up to 10 failed/4xx/5xx requests within a configurable 0–30 second window, but includes no bodies, headers, or initiator stacks and labels the relationship as temporal rather than causal. Direct frame input has no buffered evidence.

capture_runtime_baseline stores one recent error as hashes and numeric metadata only in the MCP process: no raw message, source, URL, body, header, or input value. At most 20 baselines survive for 1–60 minutes (15 minutes by default) and none survive process exit. verify_runtime_fix reuses the baseline tab and runs an explicit run_form_action_plan; it never reloads or navigates automatically, so take a fresh snapshot/ref set after any reload. The final step must be assert_state. Buffer-ID cursors isolate entries that arrived after the verification boundary, but their relationship remains temporal. Results are deliberately conservative: verified_fixed, still_failing, behavior_changed, or inconclusive when approval, refs, evidence, or FIFO completeness prevent proof.

For repeated checks, capture_reproduction_recipe converts refs to role/name/type/landmark descriptors and replaces every entered text, option value, key and expected value/text with a named slot; captured values are never stored. resolve_reproduction_recipe reports resolved, ambiguous, changed, or missing candidates from a fresh semantic snapshot and still requires an explicit target/ref confirmation for every target. The resulting five-minute binding is tied to that tab and page lifetime, is revalidated without remapping, and is consumed by the first valid verify_runtime_fix attempt. Direct steps remain supported for backward compatibility; provide exactly one of steps or bindingToken.

create_debug_case adds a bounded coordination handle without copying source or inputs. It links one live baseline, an optional same-tab recipe and an optional sourceContext.sha256; dependency TTLs continue independently. record_fix_attempt always invokes the existing conservative verifier using the case baseline—callers cannot insert a claimed result. Recipe cases require a confirmed binding from that recipe; direct-step cases cannot switch to an unrelated recipe. Each case retains at most 20 content-free attempts and classifies their transition as first_attempt, same_failure, changed_failure, fixed, regression, or inconclusive. same_failure means the sanitized outcome fingerprint matched; it does not prove identical inputs because slot/input values are deliberately neither stored nor hashed. Optional idempotency keys are hashed and prevent the same retained attempt from executing twice. Cases default to 30 minutes, are capped at 20, never survive process exit, and can be removed individually or together with forget_debug_case.

export_debug_case_playwright turns one live recipe-linked case into a deterministic TypeScript draft without contacting the extension. Captured edit/select/key/expected values remain absent: the generated test requires named MOCKPRO_STEP_* environment variables, while navigation requires MOCKPRO_BASE_URL or a validated alternate environment-variable name. Targets use the stored semantic role, accessible name and optional context; unnamed, duplicate, unsupported and selection-dependent translations are reported as warnings rather than silently claimed stable. A latest verified_fixed attempt marks the export regression_ready; otherwise it is a draft. Neither status proves the generated test passes. The tool returns code and a SHA-256 only—it never saves or runs the test.

For a fix-session handoff, assess_code_fix_readiness uses a stronger policy than the direct debug-case export: the applied leaf needs two consecutive fixed links, the newest linked attempt must still be the live case's newest attempt, every retained link must still resolve, and the baseline plus value-free recipe must remain live. The first fixed result is provisional. A later regression, rollback, live successor, stale evidence, or expired dependency produces revoked after prior qualification. get_code_fix_handoff returns lineage/fingerprints/attempt classifications/dependency states/warnings only. export_code_fix_regression_playwright rechecks readiness and then reuses the same placeholder-only generator; it does not write, contact Chrome, execute the draft, prove causality, or prove the generated test passes.

To materialize a reviewed draft, restart the daemon with one or more --allow-file-write-root /absolute/project flags. This authority is separate from --allow-file-root/--allow-file-access, has no write-everything form, and does not change local-file read behavior. prepare_code_fix_regression_test accepts an absolute .spec.ts/.test.ts target whose parent already exists, rechecks current readiness, reports a nearby Playwright config when found, and returns generated code plus a bounded diff and five-minute single-use token without writing. Existing files require overwrite:true and their exact SHA-256. apply_code_fix_regression_test is unavailable under --readonly, requires confirmWrite:true, consumes the token, regenerates the artifact, and refuses changed readiness, code, canonical parent, target identity or target hash. It publishes new files exclusively or performs a guarded same-directory atomic overwrite. It never creates directories, contacts Chrome, runs a command/test, commits, pushes or publishes.

Optional execution requires another independently configured --allow-test-run-root /absolute/project; neither read nor write roots imply it. A successful materialization returns a process-local materializedTestId valid for 30 minutes. prepare_code_fix_regression_run rechecks live code-fix readiness, the exact materialized SHA-256, Playwright config and project-local @playwright/test package/CLI inside the same run root. Its five-minute token previews the exact Node argv, working directory, one-worker/zero-retry policy, timeout and required environment-variable names without starting a process. run_code_fix_regression_test is absent under --readonly, requires confirmRun:true plus exactly those environment keys, consumes the token, repeats every identity/hash check, and starts an asynchronous shell:false job for that one anchored file filter. Poll get_code_fix_regression_run; use cancel_code_fix_regression_run({runId,confirmCancel:true}) to terminate the detached process group on POSIX or direct child on Windows. Runs default to two minutes, cap at five, allow at most two concurrently, place Playwright output in a temporary directory, and retain only counts/status/duration plus an 8 KiB environment-redacted diagnostic excerpt. Raw output, environment values and temporary artifacts are discarded. The test and Playwright config still execute with the local user's permissions and can perform network/application side effects; review both before confirmation. No tool accepts arbitrary commands/arguments, reruns automatically, or commits, pushes, or publishes.


Install the Claude Code skill (optional, recommended)

The package bundles a skill that teaches Claude how to use these tools — mocking (missing endpoints, error states, OpenAPI scaffolding), debugging (console + network + WS logs, DOM inspection, clicks/typing/navigation), and UI memory (remember a site's controls and deterministically detect what changed across visits, via a bundled snapshot-diff.cjs helper). Install it once:

npx -y mockpro-mcp install-skill            # → ~/.claude/skills/mockpro (current user, recommended)
npx -y mockpro-mcp install-skill --project  # → ./.claude/skills/mockpro (this repo only)

Restart Claude Code afterward. The skill auto-activates when you ask Claude to mock an API, debug a failing UI flow, drive a form end-to-end, or inspect what a tab is doing.

Flags: --user (default), --project, --dir <path>, --force (overwrite).

Already have an older skill installed? Re-run with --force to pick up the latest (v2.9 adds bounded cross-frame discovery and interaction alongside the guarded AI coding workflows): npx -y mockpro-mcp install-skill --force.


Claude Desktop

Edit Claude Desktop's MCP config (this is global per OS user — equivalent to --scope user for Claude Code):

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
{
  "mcpServers": {
    "mockpro": {
      "command": "npx",
      "args": ["-y", "mockpro-mcp", "--extension-id", "<YOUR_MOCKPRO_EXTENSION_ID>"]
    }
  }
}

Restart Claude Desktop after editing.


How it works

Claude Code A (stdio) ── mockpro-mcp A ──┐
Claude Code B (stdio) ── mockpro-mcp B ──┼── private same-user IPC
Claude Desktop (stdio) ─ mockpro-mcp C ──┘            │
                                                       ▼
                                         shared local broker :27319
                                                       │ WebSocket
                                                       ▼
                              MockPro extension service worker ── self.handleMessage

The first MCP session auto-starts a detached local broker; later sessions join it through an authenticated Unix socket (macOS/Linux) or named pipe (Windows). The broker owns the single extension WebSocket, fans resource notifications out to every client, and exits shortly after the last MCP session disconnects.

Concurrent sessions must use the same --extension-id and access mode (--readonly, --approve, or normal write). A mismatched client is rejected explicitly rather than inheriting another session's security posture. Rule state and browser tabs are shared, so coordinate destructive writes; import_rules({mode:"merge"}) retains the concurrency caveat below.


Tools

Mocking

  • Read (6): get_capabilities, get_state, list_rules, list_rule_groups, get_rule, get_logs (headers redacted by default: Authorization, Cookie, Set-Cookie, Proxy-Authorization; reveal: true asks the user in an MCP elicitation dialog before showing them in full, for one request or 15 minutes; get_session and read_network_logs accept the same flag. With Chrome Debug attached, read_network_logs also returns the wire headers Chrome really sent and received, so Cookie and Set-Cookie are there too).
  • Write (13): set_enabled, add_rule, update_rule, delete_rule, toggle_rule, clear_logs, import_rules (merge | replace | append), export_rules, create_rule_group, update_rule_group, delete_rule_group, move_rule, reorder_rule_groups.
  • Generate (2): mock_from_openapi, record_then_replay — both return suggested rules; commit via import_rules.

Groups, tags, and priority

Requires MockPro extension 3.8.0+ with mockpro-mcp 4.9.0+. Groups are persistent priority blocks; tags are searchable labels. Named groups match from top to bottom, rules match from top to bottom inside each group, and Ungrouped rules match last.

Recommended workflow:

  1. Call list_rule_groups and reuse a suitable group when one exists.
  2. Call create_rule_group if a new domain or feature needs its own block.
  3. Pass the returned group.id and concise tags to every related add_rule or import_rules item.
  4. Call list_rules with group/tag/query filters and inspect its zero-based priority values.
// 1. Create a priority block.
create_rule_group({
  "name": "Authentication",
  "color": "#8b5cf6"
})

// 2. Use the returned group.id.
add_rule({
  "name": "Login success",
  "type": "rest",
  "method": "POST",
  "urlPattern": "*/api/login",
  "groupId": "<GROUP_ID>",
  "tags": ["auth", "happy-path"],
  "response": { "status": 200, "body": "{\"token\":\"mock-token\"}" }
})

// 3. Find and verify the result.
list_rules({
  "groupId": "<GROUP_ID>",
  "tag": "auth",
  "query": "login"
})

| Tool | Behavior | |---|---| | list_rule_groups({includeRuleIds?}) | Ordered groups, member counts, and Ungrouped count | | create_rule_group({name,color?}) | Creates a unique group and returns its generated ID | | update_rule_group({id,name?,color?}) | Renames or recolors without changing members | | delete_rule_group({id}) | Deletes only the group; member rules move to Ungrouped | | move_rule({id,groupId,beforeRuleId?}) | Moves or reorders one rule; groupId:null means Ungrouped | | reorder_rule_groups({orderedIds}) | Changes both section order and first-match priority blocks |

list_rules combines supplied filters with AND semantics. tag is an exact case-insensitive match. query is a case-insensitive substring search across ID, name, URL pattern, group name, and tags. Use groupId:null to select Ungrouped rules.

export_rules returns {format:"mockpro-rules", version:2, groups, rules} and includes only referenced groups. Pass both arrays to import_rules to preserve organization. Legacy rule arrays remain accepted. See the full Rule Groups and Tags guide for Dashboard drag/drop behavior, limits, migration, and import remapping.

Debug

  • Read: get_capabilities, list_tabs, list_page_frames, read_console_logs, read_network_logs, prepare_request_replay, compare_request_replay, assert_request_replay, assert_request_replay_matrix, export_request_replay_matrix_playwright, suggest_mock_from_replay, read_websocket_logs, query_dom, inspect_form_state, audit_form_accessibility, inspect_code_editor, prepare_code_editor_patch, create_code_fix_session, create_code_fix_successor, list_code_fix_sessions, get_code_fix_session, assess_code_fix_readiness, get_code_fix_handoff, export_code_fix_regression_playwright, prepare_code_fix_regression_test, prepare_code_fix_regression_run, get_code_fix_regression_run, forget_code_fix_session, start_input_trace, stop_input_trace, get_dom_snapshot, wait_for_selector, wait_for_element_state, snapshot_page, resolve_runtime_source, open_runtime_source, resolve_runtime_stack, read_runtime_source_context, capture_runtime_baseline, get_chrome_debug_status, get_chrome_response_body, inspect_cdp_dom, get_request_interception_status, get_emulation_status, list_chrome_artifacts, export_chrome_artifact.
  • Write/page-driving: verify_runtime_fix runs the existing approval-gated form-plan envelope and is absent under --readonly.
  • Write: run_lighthouse, clear_console_logs, clear_network_logs, clear_websocket_logs, click, type, edit_input, edit_contenteditable, edit_code_editor, edit_code_editor_batch, apply_code_editor_patch, apply_code_fix_patch, verify_code_fix_session, rollback_code_fix_patch, apply_code_fix_regression_test, run_code_fix_regression_test, cancel_code_fix_regression_run, set_file_input_files, set_checked, press_key, select_option, run_form_action_plan, act_and_observe, replay_request, scroll, hover, navigate, Chrome Debug/recording lifecycle, performance/CPU/heap profiling, edit_cdp_dom, CSS rules, Fetch interception, device/network emulation, and delete_chrome_artifact.

start_chrome_debug enables Network, Runtime, Log, Page, Target and Input capabilities for one tab, with advanced domains enabled only when their tools are used. While attached, existing log tools automatically use richer CDP entries and top-frame click/type/press_key use browser-level input. Child-frame actions deliberately retain the synthetic page-world path because their rectangles are frame-local. Sessions default to a 30-minute expiry (configurable from 1 minute to 4 hours). Opening DevTools on the same tab may detach MockPro; query get_chrome_debug_status and reattach if needed.

list_page_frames({tabId?}) returns at most 20 frames where MockPro's content script is active. snapshot_page defaults to the top frame and legacy eN refs, accepts frameId for one child, or allFrames:true for a 600-node/128 KiB aggregate. Child refs such as f12:e7 route automatically in supported ref tools and expire when that child navigates. Selector-based DOM/form/wait tools accept frameId. Mixed-frame form plans, child-frame element screenshots, and child-frame file-input assignment fail explicitly rather than guessing a target.

Cross-frame entry points negotiate cross_frame_v1 through GET_CAPABILITIES before sending a child frameId or allFrames:true. Extension 3.21.x uses the legacy GET_STATE.extensionVersion fallback; an older/unknown extension returns extension_upgrade_required instead of silently treating the request as top-frame work. Existing top-frame tool calls remain compatible and do not add the preflight RPC.

inspect_form_state reads live DOM state rather than only HTML attributes and caps forms at 100 controls. Password and secret-like fields return lengths and metadata, never their value. edit_input supports fill, append, clear, insert, and replace_range for text-like inputs/textarea; range offsets follow DOM UTF-16 selection semantics and are adjusted away from the middle of surrogate pairs. It dispatches beforeinput → input → change and reports the resulting caret. set_checked is idempotent, rejects direct radio uncheck, and verifies ARIA switches. wait_for_element_state requires a ref or selector plus at least one exact value, checked, enabled, visible, valid, or text predicate; all supplied predicates must match.

audit_form_accessibility({tabId?,ref?,selector?}) inspects exactly one current form or control and returns deterministic findings for missing accessible names, missing or ambiguous ARIA ID references, duplicate control ids, unassociated explicit aria-invalid state, and invalid/mismatched autocomplete purpose. It reads no live/default input values, returns only refs plus structural evidence, audits at most 100 controls, returns at most 200 of the disclosed total findings, and scans at most 5,000 document nodes for duplicate ids. conformanceClaimed:false is intentional: use this focused diagnostic while debugging forms, not as a replacement for a full WCAG audit.

inspect_code_editor({tabId?,ref,includeText?}) supports Monaco Standalone through window.monaco.editor and CodeMirror 6 through public EditorView state/transactions. It returns opaque model id, version, SHA-256, language (or null when unavailable), length, line count and UTF-16 selection metadata by default. includeText:true explicitly returns non-sensitive text only when it is at most 1 MiB. edit_code_editor supports fill, selection insert, clear, and one UTF-16 replace_range. edit_code_editor_batch accepts 1–100 {start,end,text} entries, canonicalizes them against the same original document, permits touching half-open ranges, rejects overlap or equal starts, and applies one verified native-Undo transaction. For review first, pass the same guards and edits to prepare_code_editor_patch: it performs no mutation, returns complete counts/before-after hashes and at most 20 source diff hunks/64 KiB, and stores only the canonical edits plus guards in a 20-entry process-local FIFO. Its single-use token defaults to two minutes (configurable from 30 seconds to five minutes). apply_code_editor_patch consumes the token before invoking the existing approval/per-tab-FIFO batch path; stale or denied attempts cannot reuse it, and success requires the final hash to match the preview. Activity logs redact preview edits/ranges and apply tokens. ProseMirror, ambiguous/private instances, readonly/secret editors, switched/reconfigured documents and over-budget content are refused rather than guessed.

For an end-to-end agent fix loop, create a live debug case first, prepare the editor patch, then call create_code_fix_session({debugCaseId,patchToken,appTabId,editorTabId}). Both tab IDs are explicit and independently checked; same-tab and cross-tab workflows are supported. The 20-entry process-local session store defaults to 30 minutes and keeps only IDs, fingerprints, counts, apply/rollback metadata, linear lineage and at most 20 sanitized verification links. apply_code_fix_patch consumes the claimed preview through the existing approval/FIFO/one-Undo path and removes the private token after either success or terminal failure. It never saves the editor, reloads the app, triggers HMR, or runs a command. Perform that lifecycle step explicitly, take a fresh snapshot, and for recipe cases call resolve_reproduction_recipe twice to inspect then confirm current refs. verify_code_fix_session delegates to record_fix_attempt and can be repeated with a fresh binding without applying again; direct cases instead supply fresh-ref steps. After two consecutive fresh-bound fixed results, call assess_code_fix_readiness; only a live, latest-aligned case/baseline/recipe without a successor is regression_ready, after which get_code_fix_handoff and export_code_fix_regression_playwright provide content-free/generate-only artifacts. After still-failing, changed or regression, prepare a new patch against the exact current after-fingerprint and call create_code_fix_successor; only one live successor on the same tab/adapter/model is allowed per attempt. To discard an unchanged applied patch instead, inspect the editor again and call rollback_code_fix_patch with that exact model/version/post-hash guard. A live successor blocks rollback. The page adapter invokes one native Undo and accepts success only when the resulting SHA-256 equals the stored pre-patch fingerprint; pre-mutation guard failures are retryable, while an ambiguous post-mutation mismatch is terminal and requires inspection. The workflow always labels patch/outcome linkage as temporal correlation—not causality. Activity records redact patch/binding tokens, rollback refs, steps, slot values and idempotency keys; session and handoff output contain no source, replacement edits, refs, inputs or raw runtime evidence.

CodeMirror applications that keep EditorView in module scope should explicitly register each live instance after MockPro's document-start injection, and unregister it before destruction. Inspection/editing need only the view; safe code-fix rollback additionally requires public Undo and full history-isolation callbacks:

import { isolateHistory, undo } from '@codemirror/commands';

const mockproEditors = window[Symbol.for('mockpro.code-editors.v1')];
mockproEditors?.registerCodeMirror(view, {
  undo: () => undo(view),
  historyIsolation: () => isolateHistory.of('full'),
});
// Later, before view.destroy():
mockproEditors?.unregisterCodeMirror(view);

historyIsolation is attached to each MockPro batch so adjacent patches cannot merge into one Undo. Without both callbacks rollback returns rollback_unsupported before mutation. Alternatively, a page may expose its public constructor as window.CodeMirror6.EditorView, allowing MockPro to call EditorView.findFromDOM for inspection/editing. MockPro does not require or inspect a private cmView DOM property.

set_file_input_files({tabId?,ref,paths,includeSnapshot?}) sets authorized local fixtures on one top-frame input[type=file]; child-scoped refs fail explicitly, and paths:[] clears the top-frame target. Start Chrome Debug explicitly first. Non-empty paths reuse the canonical --allow-file-root/--allow-file-access policy, are revalidated immediately before the local bridge call, and are capped at 10 files, 32 MiB each and 64 MiB total. The tool never reads file contents, never guesses a selector, never attaches/detaches Chrome Debug, rejects disabled/stale/single-file targets as appropriate, reports accept and browser-MIME mismatches, and verifies bounded name/size/type/count metadata after CDP.

prepare_request_replay({tabId?,networkEntryId,overrides?,timeoutMs?,maxResponseBytes?,ttlMs?}) reads one recent network-ring entry and returns an expiring preview without sending. Use the stable numeric id from read_network_logs, not the CDP requestId. URL overrides may change path/query only within the captured origin; embedded credentials and captured sensitive query values require replacement. Captured authorization, cookies and browser-controlled headers are stripped even with global redaction disabled. A captured body is never silently reused: provide overrides.body, explicitly set reuseCapturedBody:true when it is complete, or use body:null to clear it. Cookie headers are rejected; explicit non-cookie authorization headers are allowed but redacted in preview/history.

replay_request({previewId,confirmNonIdempotent?}) consumes that preview exactly once before entering the normal write/approval gate and per-tab FIFO. POST/PUT/PATCH/DELETE require confirmNonIdempotent:true; the extension verifies that flag again. Execution uses the page's native fetch with credentials:'omit', cache:'no-store', referrerPolicy:'no-referrer', a 20-second maximum and a 1 MiB maximum streaming text preview. Response headers retain mandatory credential redaction. A metadata-only network entry with transport:'mockpro-replay', replayId, and sourceNetworkEntryId distinguishes the replay; it never stores request headers/body. Navigation, ring eviction or expiry requires a fresh preview. v1 cannot retarget another origin or replay cookie-authenticated behavior.

compare_request_replay({tabId?,replayId}) is readonly and sends nothing. It resolves the synthetic replay marker and linked source entry from the current network ring, then reads the source body through the existing bounded CDP body API only when Chrome Debug has no preview in the ring. Status, content type, duration and body metadata are compared; valid JSON produces at most 200 added/removed/changed JSON Pointers with types but no values, while text produces SHA-256/length metadata and the first 1-based UTF-16 difference coordinate without returning either body. Comparison is capped at 1 MiB and 5,000 JSON nodes. Missing/evicted, truncated, binary or over-budget evidence is explicit; equivalent is returned only when status, content type and body are all conclusive.

assert_request_replay({tabId?,replayId,expect}) is readonly and reuses that same linked evidence without sending, refetching, or persisting. Expectations can cover exact replay status, normalized media type (parameters ignored), equivalent/different outcome, body comparability, required changed JSON Pointers, absence of changes outside that allow-list, and replay maxDurationMs. Checks are returned in deterministic order as passed, failed, or inconclusive; overall is failed on any definitive failure, inconclusive when no check failed but evidence is incomplete, and passed only when every configured check passes. JSON values and response bodies are neither accepted as expectations nor returned. Missing/evicted evidence and unavailable, binary, truncated, or capped body/diff evidence never become guessed passes.

assert_request_replay_matrix({tabId?,cases}) applies the same contract to 1–20 labelled cases in caller order. All cases share one bounded network-ring snapshot and repeated cases linked to the same source share its optional on-demand CDP body read. The aggregate reports total/pass/fail/inconclusive counts and is failed if any case definitively fails, otherwise inconclusive if any case lacks evidence, and passed only when every case passes. A missing or evicted replay affects only its case; an operational ring-read failure remains a tool error. The matrix never prepares or sends replays—each replayId must already exist from the separately approved single-replay flow.

export_request_replay_matrix_playwright({tabId?,cases,testName?}) re-evaluates the same matrix and returns a deterministic Playwright API TypeScript draft plus SHA-256, request-slot metadata and warnings. The generated file accepts runtime request specs only through per-case MOCKPRO_REPLAY_CASE_*_{SOURCE,REPLAY}_REQUEST_JSON variables containing {url,method?,headers?,body?}; captured URLs/query values, headers, cookies, bodies, response values and replay IDs are never embedded. Source request JSON is required only for comparison/body/JSON expectations. At test runtime, each request gets a fresh Playwright request context so source response cookies cannot flow implicitly into replay; caller-supplied URL, method, body and headers are validated against explicit scheme, method, count and byte budgets. The generator translates status, normalized content type, comparison outcome, body comparability, JSON Pointer allow-lists and replay duration, with the same 5,000-node/200-change/512-character JSON budgets. Exporting itself sends no HTTP request, writes no file and runs no code. The returned regression_ready means only that the current MockPro matrix passed; generated requests can be state-changing when the user later runs the test, and provesGeneratedTestPasses therefore remains false until CI executes it with reviewed runtime values.

suggest_mock_from_replay({tabId?,replayId,includeResponseBody?}) is also readonly and performs no import. It requires conclusive comparable evidence, creates one AddRuleInputSchema-validated REST draft, preserves the exact origin/path and ordered query keys while replacing every query value with *, and rejects literal wildcard characters in paths/keys rather than broadening the match silently. MockPro wildcard values are greedy, so extra query text may also match; inspect the pattern before import. Request headers/body and credentials are never copied; response headers are limited to content-type. The captured textual response body is omitted unless includeResponseBody:true, remains capped at 1 MiB, and is explicitly warned as captured data. Inspect rules[0], then call import_rules({rules,mode:'append'}) separately to persist it.

edit_contenteditable({ref,operation,text?,start?,end?,includeSnapshot?}) provides the same five UTF-16-aware operations for an element whose own contenteditable value is true or plaintext-only. The MVP accepts only direct text and <br> children, writes text nodes and line breaks rather than HTML, rejects nested/rich structures before mutation, and dispatches cancelable beforeinput followed by input with a deterministic caret. Sensitive targets return only redaction metadata and length. The action uses the page-world implementation in both attached and detached Chrome Debug modes, passes through the existing write/approval gate and per-tab FIFO, and can be used standalone, as an act_and_observe action, or as a verified run_form_action_plan step.

start_input_trace({ref,durationMs?}) begins one page-lifetime trace for a form/control and returns immediately, allowing any MockPro action or user interaction to occur before stop_input_trace({traceId}). Start returns the resolved tabId; pass it to later action/stop calls if the active tab might change. It records capture/bubble order for beforeinput, input, change, focus, blur, invalid, submit, and composition events. The default duration is 10 seconds, maximum 30 seconds, and the trace retains at most 200 plain projections—never Event objects. Only one trace may be active per tab. Timeout removes all listeners but leaves the bounded result consumable until stop or the next start; stop consumes it. Navigation invalidates the trace. Secret targets expose lengths/change metadata rather than values or composition/input data. Both tools remain available with --readonly.

act_and_observe accepts one click, edit_input, edit_contenteditable, set_checked, select_option, or press_key action. The private broker serializes the entire envelope against other MCP page actions on that tab. The extension records exact pre-action ring-buffer cursors, executes the existing action implementation once, observes for 0–3000ms (default 500ms), then returns bounded before/after control state, a final snapshot, up to 20 new console entries and 30 new network entries. Set includeInputEvents:true to bracket the same action with the input trace; actions without a ref report a recoverable trace error while still running. These entries are timestamp-window correlation candidates, not proof of causality—user activity can occur in the same window. Failed actions remain normal diagnostic results with ok:false. Value-bearing actions against sensitive or unresolved targets suppress console/network contents and force-redact trace values or contenteditable text plus event data; network headers retain the standard MockPro redaction policy.

run_form_action_plan({tabId,steps,diagnostics?}) accepts 1–20 ordered edit_input, edit_contenteditable, set_checked, select_option, ref-targeted press_key, wait_for_state, or assert_state steps. Both state steps accept any non-empty combination of exact value, text, checked, valid, enabled, and visible predicates. wait_for_state uses the existing MutationObserver/property poll, defaults to 5 seconds, is capped at 20 seconds, and is further bounded by the remaining plan budget; assert_state samples immediately. The explicit tab is required, all steps and the shared 1 MiB aggregate UTF-8 text budget—including expected value/text—are validated before mutation, and the entire envelope receives one approval and one per-tab serialization slot. Each completed mutation returns its reused action result plus a fresh bounded target state; contenteditable mutations additionally verify the observed text length, bounded text or redaction metadata, and caret range against the action result. State steps return the matched/observed projection, including bounded text length and selection where applicable.

Set diagnostics:{onFailure:true} to receive failureEvidence only when the plan stops. It contains the failed step/timestamp, a best-effort target/validation state, up to 10 new warn/error console entries, up to 10 new failed or HTTP 4xx/5xx requests, the most recent mutation input trace by default, and a reference to the top-level final snapshot timestamp/error. Set includeInputEvents:false or reduce either limit to zero to lower overhead while retaining matching counts. Cursors exclude entries that existed before the plan. Sensitive or unresolved value-bearing targets force-redact the trace and suppress console/network bodies while preserving counts; MCP applies header and trace redaction again. A navigation can make target inspection or trace stop unavailable, which is reported as best-effort diagnostic error rather than replacing the original plan failure.

The first action error, stale ref, wait_timeout, assertion_failed, verification failure, navigation, or 25-second execution deadline stops the plan and marks later steps skipped. The deadline reserves its final three seconds for target verification; one final snapshot is attempted afterward. There is no rollback, ref remapping, click, retry, branching, loop, or direct submit in this MVP; a key action that navigates terminates the plan. The result contains ordered counts/status and one final snapshot. Approval summaries expose only step types and refs; expected predicate values and diagnostic configuration do not expose content, and password/secret observations retain only redaction metadata.

run_lighthouse({url,formFactor?,categories?,runs?,timeoutMs?,budgets?,outputDir?,reportName?,saveHtml?,saveJson?,overwrite?}) is separate from the attached-tab profiler: it uses an isolated Chrome profile for reproducible navigation audits. runs is capped at 5. Score budgets use 0–100 category scores; a missed budget returns auditCompleted:true, ok:false, and failure details rather than discarding the audit. Existing report files are protected unless overwrite:true is explicit.

Local image workflow

  • Read: inspect_image — returns exact image metadata plus an AI-visible, size-limited preview. Available in --readonly mode and does not require Chrome.
  • Write: edit_image — crop, resize, rotate, flip, adjust, convert, and return the edited preview in one pipeline.
  • Batch write: compress_images — process 1–100 files with quality or target-KB settings, max dimensions, collision-safe output names, and per-file results.

Image write tools never overwrite an existing file unless overwrite:true is explicit. Relative paths resolve from the MCP process working directory. targetKB is best-effort; targetReached reports whether each result met it.

Local file workspace

  • Read: open_local_file({path,line?,column?}) opens one authorized regular file in MockPro as a read-only Loose Files snapshot. Relative paths resolve from the MCP process working directory; returned positions disclose any line/column clamping.
  • Batch read: open_local_files({paths}) opens 1–20 authorized paths sequentially and returns ordered per-path results. One path failure does not undo earlier successes; content transfer stops at 40 MiB for the batch, while files above the per-file cap can still open as metadata.
  • Fixture input write: set_file_input_files({tabId?,ref,paths,includeSnapshot?}) attaches 0–10 authorized regular files to a ref-targeted file input through an already-active Chrome Debug session. It does not open a workspace or read file contents; paths:[] clears the control.
  • Runtime source read: resolve_runtime_source({runtimeUrl,line?,column?,sourceMap?}) returns zero, one, or multiple authorized candidates without opening a file. The default is a content-free direct mapping. sourceMap:true requires line, treats column as 1 when omitted, and returns generatedLocation, originalLocation, and bounded local/inline Source Map v3 metadata when successful. open_runtime_source opens only the unique existing authorized result and otherwise returns a recoverable reason/candidates.
  • Runtime stack read: resolve_runtime_stack({frames?,tabId?,entryId?,sourceMap?}) requires exactly one source: 1–20 structured frames, or one buffered console entryId (with optional active-tab default). It preserves original order and every internal/vendor/unresolved frame while adding 1-based rank, classification, ignore reasons, and recommendedFrameIndex. Source maps default on for generated JS/CSS; pass sourceMap:false for direct-only triage. The tool never opens a file—use open_local_file on the chosen authorized candidate.
  • Runtime context read: read_runtime_source_context({frames?,tabId?,entryId?,frameIndex,sourceMap?,beforeLines?,afterLines?,includeEvidence?,evidenceWindowMs?}) requires the separate allowSourceContext opt-in and reads only the explicitly selected resolved frame. It returns a stable bounded excerpt/fingerprint without opening a tab. Evidence is metadata-only and temporally correlated, never causal.
  • Fix baseline read: capture_runtime_baseline({tabId?,entryId,ttlMs?,evidenceWindowMs?}) stores one recent error fingerprint plus at most 10 nearby failed-request fingerprints in a 20-entry process-local FIFO. It stores no raw source/log/request text.
  • Recipe capture read: capture_reproduction_recipe({tabId,steps,ttlMs?}) stores only the semantic plan skeleton; every value-bearing field becomes a required named slot and the last step must be assert_state.
  • Recipe resolution read: resolve_reproduction_recipe({recipeId,tabId,bindings?}) first reports fresh candidates, then creates a five-minute single-use binding only after one explicit current ref is confirmed per target. Ambiguous and changed candidates may be selected explicitly; missing targets cannot be guessed.
  • Debug-case lifecycle read: create_debug_case({baselineId,recipeId?,sourceFingerprint?,sourceFrameIndex?,ttlMs?}) links live dependencies without extending them. list_debug_cases, get_debug_case, and forget_debug_case({debugCaseId}|{all:true}) expose or clear only bounded process-local metadata and remain available under --readonly.
  • Playwright export read: export_debug_case_playwright({debugCaseId,testName?,baseUrlEnv?}) requires a live recipe-linked case and returns deterministic placeholder-only TypeScript plus locator/slot/warning metadata. It does not connect to Chrome, write a file, run a test, or persist values, and remains available under --readonly.
  • Verified fix handoff reads: assess_code_fix_readiness({codeFixSessionId}), get_code_fix_handoff({codeFixSessionId}), and export_code_fix_regression_playwright({codeFixSessionId,testName?,baseUrlEnv?}) require two consecutive latest-aligned fixed attempts for export, disclose only content-free workflow metadata around the existing placeholder-only artifact, and remain available under --readonly.
  • Regression materialization preview: prepare_code_fix_regression_test({codeFixSessionId,targetPath,overwrite?,expectedSha256?,testName?,baseUrlEnv?,ttlMs?}) requires a scoped write root but performs no write; it returns the placeholder-only artifact, bounded diff and short-lived token. Under --readonly, preview remains available while apply is absent.
  • Regression materialization write: apply_code_fix_regression_test({materializationToken,confirmWrite:true}) consumes and revalidates one reviewed token before exclusive create or exact-hash guarded overwrite. It never runs the generated test.
  • Regression-run preview/result reads: prepare_code_fix_regression_run({materializedTestId,timeoutMs?,ttlMs?}) binds one live receipt to exact test/config/CLI hashes and fixed shell-free argv without execution. get_code_fix_regression_run({runId}) returns only the bounded retained job summary. Both remain available under --readonly, but cannot start or cancel a process there.
  • Regression-run start/cancel writes: run_code_fix_regression_test({runToken,confirmRun:true,environment}) accepts exactly the generated environment slots and starts one asynchronous bounded job; cancel_code_fix_regression_run({runId,confirmCancel:true}) terminates its POSIX process group or direct Windows child. Environment values and raw process output never enter activity history or retained job state.
  • Fix verification write: verify_runtime_fix({baselineId,steps?,bindingToken?,slotValues?,consumeBaseline?}) accepts either direct steps or one confirmed binding plus its exact slot map, and requires the last step to be assert_state. Recipe execution rechecks page identity and every selected descriptor without remapping. consumeBaseline:true forgets the baseline after the attempt.
  • Recorded fix attempt write: record_fix_attempt({debugCaseId,steps?|bindingToken?,slotValues?,sourceFingerprint?,idempotencyKey?,consumeBaseline?}) derives the baseline and allowed reproduction mode from the case, executes verify_runtime_fix, and appends a sanitized attempt. Source, refs, raw runtime evidence, plan values and slot values are not retained or written to activity history.
  • Open snapshots are grouped into a virtual POSIX/Windows/UNC/relative Explorer in the dashboard. This hierarchy reflects only paths already opened by these tools and grants no directory-listing authority.
  • Access is denied unless the process/config explicitly sets allowFileAccess or at least one allowFileRoots entry. Prefer scoped roots; repeat --allow-file-root for multiple projects.
  • Regression-test writes are denied unless allowFileWriteRoots or --allow-file-write-root is configured separately. A write root authorizes only the targeted preview/materialization flow and does not grant broad local-file reads or writes.
  • Regression-test execution is denied unless allowTestRunRoots or --allow-test-run-root is configured independently. It authorizes only exact live materialization receipts and never exposes a generic command or argument surface.
  • Canonical target checks prevent .. and symlink escapes from an allowed root. Files above 32 MiB are not read and open as metadata; content is transferred only through the private same-user IPC and localhost extension bridge, then discarded from the service-worker inbox.

v4.0.0 BREAKING: click/type/press_key take ref (from snapshot_page) instead of selector. Requires MockPro extension ≥ 3.0.0. Action replies include a fresh page snapshot (includeSnapshot: false to skip); on stale_ref, call snapshot_page again.

Resources (subscribable)

  • mockpro:rule://{id}, mockpro:logs://recent
  • mockpro:console://{tabId} + mockpro:console://active alias
  • mockpro:network://{tabId} + mockpro:network://active alias
  • mockpro:websocket://{tabId} + mockpro:websocket://active alias

--readonly de-registers all write tools at the MCP capability level (debug observation tools stay available).

import_rules merge caveat: merge upserts by reading then writing, non-atomically. Under interleaved writes from another tab/the Dashboard/a parallel client it can degrade to append. Serialize MCP writes client-side, or use replace/append when atomicity matters.

Debug tools require a freshly-loaded tab. Content script is injected at page load; tabs opened BEFORE you installed/reloaded the extension return tab_no_injector. Reload those tabs once.

WebSocket buffer is chatty. Terminals fire 10-20 frames/sec; per-tab cap 500 fills in ~30s. Read with sinceTs or clear_websocket_logs between snapshots.

Native passthrough compatibility: Without Chrome Debug, MockPro records lifecycle and inbound frames without replacing a real socket's send method, so outbound entries are available only for mocked sockets. CDP mode records both native inbound and outbound frames.


CLI flags

--extension-id <id>      MockPro extension id (or env MOCKPRO_EXTENSION_ID). Required.
--readonly               Refuse all write tools.
--approve                Require in-browser approval for page-driving actions.
--allow-file-access      Let local-file tools read any regular file visible to this daemon.
--allow-file-root <path> Let local-file tools read only inside this canonical directory; repeatable.
--allow-file-write-root <path>
                         Let guarded regression materialization write only inside this canonical directory; repeatable.
--allow-test-run-root <path>
                         Let guarded regression jobs execute only reviewed materialized tests inside this canonical directory; repeatable.
--allow-source-context   Let read_runtime_source_context return bounded source excerpts; requires file access.
--runtime-source-root <url-prefix>=<local-root>
                         Map one HTTP(S) runtime prefix to an already-authorized local root; repeatable.
--allow-pattern <regex>  Only allow add/update/import for rules whose urlPattern matches.
--redact-headers <list>  Extra header names to redact, comma-separated.
--config <path>          JSON config file (CLI > env > file > defaults).
-h, --help

stdout is reserved for MCP JSON-RPC frames; all logs go to stderr. redactionDisabled is config-file-only. JSON config uses allowFileAccess: true or allowFileRoots: ["/absolute/project"] for read authority, allowFileWriteRoots: ["/absolute/project"] for separately scoped regression-test materialization, allowTestRunRoots: ["/absolute/project"] for separately scoped guarded execution, and allowSourceContext: true for excerpt egress. Runtime mappings use runtimeSourceRoots: [{"urlPrefix":"http://localhost:5173/src/","localRoot":"/absolute/project/src"}]; mappings, read roots, write roots, run roots and source-context opt-in do not silently grant one another.


Threat model

The WS transport is designed for a trusted single-user host (your personal dev machine):

  • Binds 127.0.0.1 only — not reachable from the network.
  • Accepts exactly one Origin: chrome-extension://<your extension id>. HTTPS pages can't reach it (Chrome blocks mixed-content ws://); HTTP pages send Origin: null and are rejected.
  • MCP peer p