MCP Tool Reference
probe-mcp exposes 117 tools, all prefixed probe_…. They're grouped here by feature. For each tool: a one-line description, the input schema, and what comes back. Every result is wrapped in MCP's content: [{type: "text", text: "..."}] envelope; for tools that return structured data, the text is compact JSON from the underlying REST API.
Need wiring? See MCP Setup.
Conventions
Section titled “Conventions”- Required parameters are marked. Everything else is optional.
- Type is the JSON Schema type accepted by the MCP
inputSchema. - Returns describes what the AI sees in
content[0].textafter the call resolves. - IDs returned by
probe_list_trafficare integers; collection / session / script-rule / flow / remote-fs connection IDs are strings. max_body_chars— tools that return bodies accept this optional integer:probe_get_request,probe_export_curl,probe_export_raw,probe_replay_request,probe_diff_traffic,probe_get_session_tab,probe_get_saved_session,probe_get_collection,probe_send_compose_request,probe_send_request,probe_list_compose_history,probe_get_flow,probe_run_flow,probe_ws_get_frames,probe_export_collectionandprobe_execute_script. Every body or other long string in the result is cut after that many characters (default8000) and ends with a…[truncated: showing N of M chars; …]marker; JSON results stay valid JSON. Pass0for no limit (a captured body can be up to 512 KB). It isn't repeated in the tables below. A write tool refuses any argument that still carries that marker (writing it back would save the marker instead of the real content): read the value again withmax_body_chars: 0before you send it.- Result size — a whole result is capped at 200,000 characters after the per-string cut. A JSON result over it keeps the head of its largest list (at any depth) and says how many items were left out (
result_truncatedin an object, a final…[N item(s) left out …]string in a list). A cut page stays complete: itsnext_cursor/next_offsetis moved back to the first item left out (a tool that takesoffsetbut returns no continuation gets anext_offset), so following it skips nothing and never moves back. The paged list is the page's own list (entries), even when a list beside it is bigger. An item kept only in part (a list inside it cut) counts as left out and comes again on the next page — except the page's first item: it is moved past and not sent again, and the note says it was cut short. The count names items of the paged list, and items cut from other or nested lists are counted apart. When not even one item fits, the continuation stays as it was and the note asks for smaller items. Several big lists are cut in turn, none emptied for the others. A result that is one JSON string is cut inside the string, so it stays valid JSON. Otherwise narrow the call with the tool's filters orlimit; a tool that takesmax_body_charscan also pass0(lifts both caps) — the note only names arguments the tool accepts. - Compact results — JSON results come without pretty-printing (no indentation or spaces), in a stable key order, to keep token cost down. Tool descriptions in
tools/listare kept short; this page holds the longer explanations and examples. - Strict arguments — every call is checked against the tool's
inputSchemabefore it runs: an argument the tool doesn't have (Unknown argumentx… Valid arguments: …), a value of the wrong JSON type (Argumentlimitmust be integer, got string.), a value outside anenum,minimumormaximum, a negative integer, or a missing required argument is an error (isError: true) that names the argument — also inside objects and lists, by path (Argumentvariables.tokenmust be string, got integer.,headers[0][1],minItems/maxItems). A nested object whose members the schema lists refuses any other member (Unknown memberpaths[0].dir. Valid members: …), so a misspelled flag is never dropped silently; the value itself is never echoed.nullfor an optional argument means "not given". Calling a tool that doesn't exist is a JSON-RPC-32602error. - Annotations — every tool carries MCP
readOnlyHintandopenWorldHint, and every tool that changes something also carriesdestructiveHint. The rule: a write is destructive unless it only adds, or the opposite call with the same arguments undoes it. So deletes, clears (turning the throttle off included), updates that overwrite saved content (everyupdatetool, the throttle setting and creating a breakpoint for a pattern that already has one), cancelling a Files transfer, installing the CA (it changes the computer's trust store and removes retired Probe CAs from it) and the Files rename/upload/download/delete tools are marked destructive, and so areprobe_execute_script,probe_replay_request,probe_send_compose_request,probe_send_request,probe_run_flowandprobe_resume_intercept, which can send a request of any method (DELETEincluded) to a real server. Those six and the Files tools that reach a remote server are marked open-world. Creates, adds, making a Files folder, blocking and unblocking a host or client, adding and removing an intercept host, and enable/disable switches are not marked destructive. - Where writes go — with the Probe app open, rule and setting writes (Map Local, Map Remote, Mock rules and server, script rules, breakpoints, ignored hosts and clients, the global throttle) are handed to the app, which applies them as if you had made them in its UI and shows them there. Rules, master switches, breakpoints and ignored lists are saved; the global throttle, the scripting switch and the Mock server's running state reset on restart, as they do in the app. The intercept-host allowlist is the exception: it lives in the proxy for the current run only.
Traffic inspection
Section titled “Traffic inspection”probe_list_traffic
Section titled “probe_list_traffic”List recent HTTP/HTTPS traffic, newest first. Use filters to narrow the result. CONNECT tunnel rows (status 0, no response) are left out unless include_connect is true.
| Parameter | Type | Description |
|---|---|---|
limit | integer | Max entries (default 20, at most 500 — more is refused). |
offset | integer | Pagination offset. |
host | string | Case-insensitive substring match against host. |
method | string | HTTP method filter (e.g. GET). |
status | integer | Exact status code (overrides status_min / status_max). |
status_min | integer | Minimum status code. |
status_max | integer | Maximum status code. |
path | string | Substring match against the whole URL. |
include_connect | boolean | Also list CONNECT tunnel rows (default false). |
has_error | boolean | Only entries with status ≥ 400 (requests still waiting for a response have status 0 and aren't counted). |
since_id | integer | Only entries with id > since_id (poll for new traffic). |
since | integer | Only entries with timestamp >= since (ms since epoch). |
fields | string[] | Keep only these row keys, e.g. ["id","status_code"]. Any name outside the row keys below is refused with the valid list. |
summary | boolean | true returns counts over every match instead of rows (see below). Can't be combined with fields, limit or offset. |
test_run_id | string | Only the requests of this test run (see Test runs); the result gains a test_run object with the run's stats. |
client | string | Substring of the client label (client_addr: process or IP), case-insensitive. |
header | string | Request header Name:value (exact value) or Name (present). |
Returns: {items, total, offset, limit} (plus capture_note when no new traffic is being captured — proxy stopped or capture off) where items[] are summaries — id, method, url, host, status_code, content_type, duration_ms, timestamp, client_addr, has_response. With fields, each row holds only the keys you named.
With summary: true: {total, counted, by_host, by_status, by_method} — counts per host (the 100 biggest; the rest are counted in other_hosts), per status code and per method, over every entry the filters match (the API copy holds up to 10,000). No rows are returned.
Paging 5,000 captured requests costs about 1.34 MB (~336k tokens) with full rows, about 0.15 MB (~37k tokens) with fields: ["id","status_code"], and a summary of all of them is about 110 bytes.
probe_get_request
Section titled “probe_get_request”Full detail of a single entry, including headers and bodies. A 502 row with an x-probe-upstream-error header means Probe could not reach the server: that header and the error-text body are Probe's own diagnostics, not wire data (the client received an empty 502).
| Parameter | Type | Required | Description |
|---|---|---|---|
id | integer | yes | Traffic entry id from probe_list_traffic. |
Returns: the full entry — request and response headers as [[key, value], …], request and response bodies as strings (or null), timing, content type, client address. Bodies longer than max_body_chars are cut. A captured body over 512 KB is stored as [body too large: N bytes, not shown], a binary one as [binary N bytes], and a response the proxy streamed to the client without keeping it as [binary <type>, <size>, not captured] or [streaming <type>, not captured]: placeholders, not content, which the write tools refuse.
probe_search_traffic
Section titled “probe_search_traffic”Search by URL path or body content.
| Parameter | Type | Required | Description |
|---|---|---|---|
query | string | yes | Substring matched against URL and body. |
limit | integer | Default 20, at most 500 (more is refused). | |
offset | integer | Pagination offset (see total). | |
fields | string[] | Keep only these row keys (as in probe_list_traffic). | |
summary | boolean | Counts by host / status / method over every match, no rows (as in probe_list_traffic). | |
test_run_id | string | Only this test run's requests (as in probe_list_traffic). | |
client | string | Client label substring (as in probe_list_traffic). | |
header | string | Request header Name:value or Name (as in probe_list_traffic). |
Returns: the same shape as probe_list_traffic.
probe_get_session_summary
Section titled “probe_get_session_summary”Quick health snapshot — uptime, entry count, capture status, API port, version. No parameters.
Returns: {status, version, capturing, entry_count, uptime_secs, api_port}.
probe_clear_traffic
Section titled “probe_clear_traffic”Clear captured traffic: the Probe app's own log list (the current recording tab, as its Clear button does) and the copy the REST API and these tools read. No parameters. Returns: a sentence saying whether the app's list was cleared too — without the app UI connected only the API's copy is cleared.
probe_delete_traffic
Section titled “probe_delete_traffic”Delete one entry by id from the API traffic copy. The app's own log keeps it.
| Parameter | Type | Required |
|---|---|---|
id | integer | yes |
Returns: "Traffic entry <id> deleted.". An unknown id is an error.
probe_get_capture_status
Section titled “probe_get_capture_status”Whether new traffic is stored in the API copy these tools read (see probe_toggle_capture) and how many entries that copy holds. app_connected says whether the Probe app UI is connected (then probe_toggle_capture and probe_clear_traffic act on the app too). No parameters.
Returns: {capturing, entry_count, proxy_running, app_connected}. With proxy_running false nothing new arrives even while capturing is true; the REST API and every non-traffic tool keep working.
Capture control
Section titled “Capture control”probe_toggle_capture
Section titled “probe_toggle_capture”Start or stop capturing — the same as the Start/Stop button in the Probe app: stopping stops the proxy (and turns off the system proxy if Probe turned it on), starting starts it again, and the app shows it. Without the app UI connected only the REST API's copy of the traffic is paused (traffic still flows, unrecorded).
| Parameter | Type | Required |
|---|---|---|
enabled | boolean | yes |
Returns: a sentence saying whether the change was made in the app or only in the API's copy.
Certificate
Section titled “Certificate”probe_get_ca
Section titled “probe_get_ca”Probe's root CA, so an agent can make a client trust it without reading these docs. Works without the app UI. No parameters.
Returns: {pem, sha256, spki_sha256, proxy, proxy_running, downloads, trusted, hints}. pem is the certificate the proxy signs with, read from memory (the same bytes the certificate server hands to devices). sha256 is the fingerprint as colon-separated hex; spki_sha256 is the base64 SHA-256 of its public key, the value Chromium's --ignore-certificate-errors-spki-list takes. downloads holds the certificate server's URLs (pem, der, android, ios, macos, on the proxy port minus one). trusted is the app's last trust check (true / false, with trusted_age_s: how many seconds ago it ran; the app re-checks when it comes to the front and after an install), or "unknown" without the app. hints gives one line per client: NODE_EXTRA_CA_CERTS, REQUESTS_CA_BUNDLE and SSL_CERT_FILE for Python, CURL_CA_BUNDLE / --cacert, the Chromium flag, xcrun simctl keychain booted add-root-cert for the iOS simulator, http://10.0.2.2:<port>/download/android for the Android emulator, and probe_install_ca for this computer. While the proxy is stopped a note says the download URLs don't answer. Before the proxy has started once in this Probe process the call fails with caNotLoaded.
probe_install_ca
Section titled “probe_install_ca”Install and trust the CA on this Mac or PC through the Probe app's own Install button, so every app on the computer trusts Probe. A person must approve the operating system's prompt on screen (the macOS administrator dialog, or the Windows security warning): the tool takes no password or other credential and never bypasses the prompt. Right before the prompt the app shows a notice that an AI agent asked for the install (approve only if you expected it). On macOS the install needs Probe's other windows (Scripting, Breakpoints and the like) closed, because the administrator prompt would freeze them: while one is open the tool closes nothing and shows no prompt, fails with 409 childWindowsOpen (listing the open windows), and the app asks the person to close them; call it again afterwards. Afterwards it shows its usual result dialog, with a line saying an AI agent asked. No parameters.
Returns: {outcome, trusted, reason?}. outcome is installed, already_trusted (the CA was trusted already: no prompt is shown), cancelled (the person dismissed the prompt) or failed with a reason (osError, trustNotVerified, unsupportedPlatform); the error text itself stays in the app's dialog. The call waits up to 120 s for the person; after that it fails with 504 timeout and the prompt may still be open, so read trusted with probe_get_ca instead of calling again. A second call while one is waiting fails with 409 installInProgress instead of showing a second prompt. Without the app UI it fails with 503 uiNotRunning, and with 503 windowNotOpen when the app runs without its main window: trust the CA per process with the hints of probe_get_ca.
Replay
Section titled “Replay”probe_replay_request
Section titled “probe_replay_request”Re-send a captured request, optionally edited, and return the response. By default the replay goes through Probe's proxy, so it is captured as a new traffic entry and Map Local, Map Remote, breakpoints and scripts apply to it (a matching breakpoint pauses it until you resume it: the call then fails after 60 s with an error naming the paused intercept id, and probe_resume_intercept releases it; through_proxy: false skips breakpoints). The captured accept-encoding header is dropped so the body comes back readable.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
id | integer | yes | Traffic entry to replay. | |
method | string | captured | Override the HTTP method. | |
url | string | captured | Override the full URL. | |
headers | object | Header edits by name, case-insensitive: a string sets or replaces the header, null removes it. Other captured headers are kept. | ||
body | string | captured | Replace the request body. | |
through_proxy | boolean | true | false sends straight to the origin, so nothing is captured. |
Returns: {status_code, headers, body, body_truncated, duration_ms, new_id, through_proxy}. Probe reads at most 2 MiB of the response body: past that the body is cut, ends in a …[truncated: replay response cut at 2097152 bytes] marker and body_truncated is true (the whole response is in the captured entry new_id when the replay went through the proxy). new_id is the traffic id of the captured replay (compare it with probe_diff_traffic), or null when the replay went direct or wasn't captured. An unknown id or a failed send is an error with the reason.
If the captured request body is only a placeholder — binary ([binary N bytes]), too large to keep ([body too large: …]) or cut — the replay is refused (422) unless you pass body: re-sending it would send the placeholder text to the server instead of the real body. Pass the exact body to send (an empty string sends none).
probe_diff_traffic
Section titled “probe_diff_traffic”Compare two captured entries — method, URL, status, headers, body. Useful for "did the replay match the original?" or "what changed between two similar calls?".
| Parameter | Type | Required | Description |
|---|---|---|---|
left_id | integer | yes | The "before" entry id. |
right_id | integer | yes | The "after" entry id. |
Returns: a JSON diff — added/removed/changed fields per section.
Export
Section titled “Export”probe_export_curl
Section titled “probe_export_curl”Export an entry as a runnable cURL command.
| Parameter | Type | Required |
|---|---|---|
id | integer | yes |
Returns: the cURL string. The body is written with --data-raw, so a body starting with @ never makes cURL read a local file. An entry whose captured request body is only a placeholder (binary, too large, or cut) is refused (422): the command would send the placeholder instead of the body. Use probe_replay_request with an explicit body, or read it with probe_export_raw.
probe_export_raw
Section titled “probe_export_raw”Export an entry as raw HTTP text — request line + headers + body, then the response if there is one.
| Parameter | Type | Required |
|---|---|---|
id | integer | yes |
Returns: the raw HTTP text.
Breakpoints
Section titled “Breakpoints”Breakpoint rules pause matching traffic so the AI (or you) can edit it before it continues. Use probe_list_intercepts to see what's currently paused, then probe_resume_intercept to release it.
probe_create_breakpoint
Section titled “probe_create_breakpoint”| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
pattern | string | yes | An exact host (api.example.com, no subdomains) or a host+path pattern (api.example.com/v1/*; scheme optional, * matches anything). A pattern that can never match (empty, a bare path like /v1/users, a host-only pattern with a port or wildcard, or no host) is refused with a hint. | |
intercept_request | boolean | true | Pause matching requests. | |
intercept_response | boolean | true | Pause matching responses. |
Returns: "Breakpoint created for '<pattern>'.". The app saves it like a breakpoint added in its UI.
probe_delete_rule
Section titled “probe_delete_rule”Remove one breakpoint by its exact pattern (breakpoints only, not Map Local/Remote, Mock or script rules). An unknown pattern is an error.
| Parameter | Type | Required |
|---|---|---|
pattern | string | yes |
probe_list_rules
Section titled “probe_list_rules”List every active breakpoint. No parameters. Returns: array of breakpoint definitions.
probe_clear_breakpoints
Section titled “probe_clear_breakpoints”Remove all breakpoints in one call. No parameters.
probe_list_intercepts
Section titled “probe_list_intercepts”List paused messages waiting for a decision. No parameters. Returns: an array of {id, phase, method, url, status_code}. phase is request (you can edit url, headers, body), response (you can edit status_code, headers, body) or unknown when the API's traffic capture is off; status_code is set for responses. A paused message resumes unchanged after 5 minutes.
probe_resume_intercept
Section titled “probe_resume_intercept”Release a paused request or response, optionally edited.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | integer | yes | Intercepted message id. |
abort | boolean | If true, answer the client with 502. | |
status_code | integer | Override the response status (response phase). | |
headers | array of [key, value] | Replace the whole header list. Omit it to keep the captured headers. | |
body | string | Replace the body of the paused request or response. | |
url | string | Override the request URL (request phase). |
Omitting headers keeps the captured ones, so a body-only or status-only edit doesn't strip Host, Authorization or cookies. If the API's traffic capture is off, the captured headers are unknown and such an edit is refused until you pass headers. An unknown id is an error. With the app open, its paused-request dialog for that message closes when you resume it here.
Returns: "Intercept <id> resumed." (or aborted).
Intercept hosts
Section titled “Intercept hosts”These tools manage the SSL-proxying allowlist. They don't pause anything (use probe_create_breakpoint for that). While the allowlist is empty, every HTTPS host is decrypted. As soon as it has one entry, only the listed hosts and their subdomains are decrypted and logged with bodies; every other HTTPS host is tunnelled without decryption. With the app open, it saves the list (it survives a restart) and shows a banner above the traffic list naming the hosts while the list isn't empty; Decrypt All Hosts in that banner empties it. Without the app (headless), the list lives in the proxy for that run only.
probe_add_intercept_host
Section titled “probe_add_intercept_host”| Parameter | Type | Required | Description |
|---|---|---|---|
host | string | yes | Bare hostname or IP to decrypt, subdomains included (api.example.com). A scheme (https://…), port (:443), *. wildcard or path can never match, so it is refused with the bare host to send instead; nothing is stored. |
probe_remove_intercept_host
Section titled “probe_remove_intercept_host”Remove a host from the allowlist. When the list becomes empty, every HTTPS host is decrypted again. An unknown host is an error.
| Parameter | Type | Required |
|---|---|---|
host | string | yes |
probe_list_intercept_hosts
Section titled “probe_list_intercept_hosts”List the allowlist. Empty means every HTTPS host is decrypted. No parameters. Entries that can never match (saved before adds were checked) are named in a warning: remove them and add the bare hostname.
Blocked hosts
Section titled “Blocked hosts”Traffic to a blocked host is tunnelled without decryption or logging. Use this to silence noise from analytics or telemetry hosts. Matching is case-insensitive, and the app saves the list in its Ignored hosts.
probe_block_host
Section titled “probe_block_host”Ignore a host: its traffic is tunnelled without decryption or logging. Send a bare hostname or IP: it covers the host and every subdomain on every port (case-insensitive). A scheme, port, path or wildcard can never match and is refused with the host to send instead, like intercept hosts.
| Parameter | Type | Required |
|---|---|---|
host | string | yes |
probe_unblock_host
Section titled “probe_unblock_host”Remove a host from the list so it is decrypted and logged again. An unknown host is an error.
| Parameter | Type | Required |
|---|---|---|
host | string | yes |
probe_list_blocked_hosts
Section titled “probe_list_blocked_hosts”No parameters. Returns: array of host strings.
Blocked clients
Section titled “Blocked clients”Block by client label — a process name (loopback) or IP address (remote phone). The client's traffic is forwarded without logging. Matching is case-insensitive, and the app saves the list in its ignored clients.
probe_block_client
Section titled “probe_block_client”Ignore a client. A remote device (IP address) is matched at once: its HTTPS connections are tunnelled without decryption and its plain-HTTP requests are forwarded, neither logged. A local process is matched only once Probe has identified it (a background lookup, usually within seconds): until then its requests — plain HTTP and HTTPS alike — are decrypted and logged as usual; after that, its new HTTPS connections are tunnelled undecrypted and its further requests are forwarded without logging. Matching is case-insensitive, and an entry also covers the app's helper processes (Slack covers Slack Helper).
| Parameter | Type | Required | Description |
|---|---|---|---|
label | string | yes | Process name or IP. |
probe_unblock_client
Section titled “probe_unblock_client”Remove a client from the list (case-insensitive) so its traffic is logged again. An unknown label is an error.
| Parameter | Type | Required |
|---|---|---|
label | string | yes |
probe_list_blocked_clients
Section titled “probe_list_blocked_clients”No parameters. Returns: array of label strings.
Throttle
Section titled “Throttle”Probe has two throttle layers. The global throttle applies to every request; the scoped throttle rules apply per host/url-glob/app and run on top of it. The MCP can read both, and write the global one; the app's toolbar throttle icon then shows throttling is on (like a profile picked in the UI, it resets to Off on restart). Scoped rules are read-only here — Probe's UI owns them and pushes the list on every change.
probe_set_throttle
Section titled “probe_set_throttle”Set the global download bandwidth cap for all proxied traffic. Upload, latency, DNS delay and packet loss keep their current values. Returns: "Throttle set to <n> bytes/sec.".
| Parameter | Type | Required | Description |
|---|---|---|---|
bytes_per_second | integer | yes | Bandwidth in bytes/sec. |
probe_disable_throttle
Section titled “probe_disable_throttle”Turn off the whole global throttle: bandwidth both ways, latency, DNS delay and packet loss. Scoped throttle rules are not affected. No parameters.
probe_get_throttle
Section titled “probe_get_throttle”Read the whole global throttle profile. No parameters.
Returns: {enabled, bytes_per_second, up_bytes_per_second, down_delay_ms, up_delay_ms, dns_delay_ms, down_loss_pct, up_loss_pct}. bytes_per_second is the download cap; enabled is true when any of the values is non-zero.
probe_list_throttle_rules
Section titled “probe_list_throttle_rules”List the scoped throttle rules. Each rule has its own profile (down/up bps, DNS delay, loss percentage) and matches by host, url glob, or app. No parameters.
Returns: [{id, name, enabled, matcher: {type, pattern}, profile: {down_bps, up_bps, down_delay_ms, up_delay_ms, dns_delay_ms, down_loss_pct, up_loss_pct}}] in list order. With the app open this is every rule, disabled ones too; without it, only the enabled rules the proxy holds.
probe_add_throttle_rule
Section titled “probe_add_throttle_rule”Add a scoped throttle rule. Matching requests get its profile instead of the global throttle; the first enabled rule that matches wins and the new rule goes last. The app saves the rule and shows it in its Throttle window, so the app must be open (503 uiNotRunning otherwise).
| Parameter | Type | Required |
|---|---|---|
name | string | yes |
matcher | object {type, pattern} | yes — type is host (a bare host, api.example.com or *.example.com), urlGlob (the full URL with *, default ports ignored) or app (the client app name) |
profile | object | no — down_bps, up_bps (bytes/s), down_delay_ms, up_delay_ms, dns_delay_ms, down_loss_pct, up_loss_pct (0–100); a missing key is 0, no limit |
enabled | boolean | no — default true |
A pattern that can never match is refused with the form that would: a host pattern with a scheme, port or path (https://api.example.com:443/v1 → send api.example.com), a host wildcard anywhere but a leading *., whitespace, or a URL glob for a scheme other than http/https. Host patterns are stored lower-case.
Returns: the stored rule with its id.
probe_update_throttle_rule
Section titled “probe_update_throttle_rule”Change a rule by rule_id. Only the fields you send change: inside matcher and profile each key is merged on its own, so {"profile": {"up_bps": 1000}} changes only the upload limit. The merged matcher passes the same checks as add. Needs the app open; an unknown id is a 404.
Returns: the stored rule.
probe_delete_throttle_rule
Section titled “probe_delete_throttle_rule”Delete a rule by rule_id. Needs the app open; an unknown id is a 404.
Scripting
Section titled “Scripting”Run JS through Probe's embedded QuickJS engine (probe_execute_script, the pro.* API), or manage the script rules that rewrite matching traffic. Script rules themselves run handleRequest / handleResponse in an external runtime — see Scripting.
probe_execute_script
Section titled “probe_execute_script”Run a script once in Probe's embedded QuickJS engine (10 s timeout, 64 MB) and return what it did. Nothing is sent unless the script calls pro.sendRequest, which sends a real request (up to 5 per run); the script's variable and request changes are returned, not applied.
| Parameter | Type | Required | Description |
|---|---|---|---|
script | string | yes | JS source. |
phase | string | pre-request or test (pro.response available). Default: test when response is given, else pre-request. Any other value is an error. | |
variables | object | Environment variables (string values), readable with pro.environment.get and {{name}}. | |
globals | object | Global variables, readable with pro.globals.get. | |
request | object | Optional request context: method, url, headers (an object {name: value} or [[name, value], …]), body (a string, or any JSON value, sent as its JSON text). | |
response | object | Optional response context: status (or its alias code), status_text, time_ms, headers (same shapes as above), body. In the script status is pro.response.code; pro.response.status is the reason text — status_text, or the standard one for status (200 → "OK"). |
Returns: {console_logs, test_results, variable_mutations, request_mutations, local_variables, script_failed, error, next_request, skip_request}, with the log, test and mutation fields decoded into JSON arrays and objects (console_logs is [{level, message}], test_results is [{name, passed, error?}]). A script that throws is a failed call (isError: true): the text starts Script failed: <message> and carries the full output (console logs and test results up to the throw) after Output:. A run that timed out shows empty lists / objects, not empty strings.
probe_list_script_rules
Section titled “probe_list_script_rules”List every script rule and the global scripting on/off flag. No parameters.
probe_add_script_rule
Section titled “probe_add_script_rule”Add a rule that auto-applies JS to matching traffic. A rule's scripts are not pro.* scripts like probe_execute_script: the app runs them in an external runtime (osascript -l JavaScript on macOS, otherwise node/bun/deno from your PATH), 5 seconds per run, with no pro global. request_script defines function handleRequest(request) { …; return request; } (request is {url, method, headers, body}); response_script defines function handleResponse(request, response) { …; return response; } (response is {statusCode, headers, body}). See Scripting.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | yes | Human-readable name. | |
url_pattern | string | yes | Unanchored match against the URL with and without its scheme: without * a plain substring, with * a wildcard that can match anywhere inside the URL (api.x.com also matches evil-api.x.com.io). | |
method | string | * | HTTP method (case-insensitive), or * for all. | |
request_script | string | "" | Runs on requests. | |
response_script | string | "" | Runs on responses. | |
apply_to_request | boolean | true | ||
apply_to_response | boolean | true |
Rules are checked in list order and only the first matching rule runs; new rules are appended. The new rule's id is generated as mcp_<ms>_<n> and returned in the result. The app saves the rule and shows it in its Scripting list; it runs on matching traffic while the app is running and scripting is on.
probe_update_script_rule
Section titled “probe_update_script_rule”Patch an existing rule — only fields you pass are changed.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | yes | Rule id. |
name | string | ||
method | string | ||
url_pattern | string | ||
request_script | string | ||
response_script | string | ||
apply_to_request | boolean | ||
apply_to_response | boolean | ||
enabled | boolean |
probe_delete_script_rule
Section titled “probe_delete_script_rule”An unknown id is an error.
| Parameter | Type | Required |
|---|---|---|
id | string | yes |
probe_toggle_scripting
Section titled “probe_toggle_scripting”Master switch. When off, no script rules fire.
| Parameter | Type | Required |
|---|---|---|
enabled | boolean | yes |
Sessions
Section titled “Sessions”Probe organises captured traffic into session tabs in the UI. The active recording tab fills with new traffic; other tabs are read-only snapshots. Saved sessions are the ones you saved, kept in the local database ~/.probe/probe.db. With the app open, these tools are answered by the app from its live tabs and saved sessions.
probe_list_session_tabs
Section titled “probe_list_session_tabs”List every open tab. No parameters.
Returns: {tabs, active_tab_id, recording_tab_id}; each tab is {id, name, entry_count, is_recording, is_dirty, is_saved, created_at, hidden_by_domain_watch}. hidden_by_domain_watch counts requests the tab never captured because their root domain is not watched (Probe keeps only the first request per unwatched root).
probe_get_session_tab
Section titled “probe_get_session_tab”Fetch one page of the entries inside a specific tab (oldest id first).
| Parameter | Type | Required |
|---|---|---|
id | string | yes |
offset | integer | no — entries to skip (default 0) |
limit | integer | no — entries to return (default 50, max 500) |
Returns: {id, name, created_at, entry_count, offset, limit, entries} — entry_count is the total; each entry uses snake_case keys like the traffic tools (status_code, client_addr, req_headers, req_body, res_headers, res_body, content_type, duration_ms, req_size, res_size, request_end_ts, response_start_ts, http_version). The page also carries hidden_by_domain_watch; when it is above 0 it adds hidden_domains ([{domain, count}], top 20) and a hint: watch the domain in the app (right-click the domain, then Watch, or View, then Watched Domains). Requests already dropped are not recovered.
probe_list_saved_sessions
Section titled “probe_list_saved_sessions”List your saved sessions, newest first. No parameters.
Returns: {sessions}; each is {id, name, entry_count, created_at}.
probe_get_saved_session
Section titled “probe_get_saved_session”Fetch one page of the entries inside a saved session. Each entry's id is session-scoped (<session>#<n>), not a traffic id: the log-id counter restarts with the app, so the number it had at capture time (kept as original_log_id_not_live) now names a different request. probe_get_request, replay and diff refuse such an id with a hint.
| Parameter | Type | Required |
|---|---|---|
id | string | yes |
offset | integer | no — entries to skip (default 0) |
limit | integer | no — entries to return (default 50, max 500) |
Returns: the same shape as probe_get_session_tab.
probe_save_session
Section titled “probe_save_session”Save captured traffic as a saved session, the way Cmd+S does: it shows up under SAVED and survives a restart. Saves a live tab (the recording tab unless you pass tab_id); the tabs themselves are left as they are. Needs the app open (503 uiNotRunning otherwise).
| Parameter | Type | Required |
|---|---|---|
name | string | yes |
tab_id | string | no — default the recording tab |
host | string | no — keep only this host and its subdomains |
ids | integer[] | no — keep only these entry ids (at most 10,000) |
Returns: {id, name, entry_count, created_at, source_tab_id}, plus missing_ids and missing_reason for ids the tab does not hold. The Domain Watch teaser keeps only the first request per unwatched root domain, so an id probe_list_traffic shows may never have reached the tab: when it dropped requests, the answer also carries hidden_by_domain_watch, hidden_domains and a hint. Nothing matching is an error, and nothing is saved. Read it back with probe_get_saved_session.
Compose
Section titled “Compose”The Composer is Probe's request builder — Postman-like collections, environments, and inline auth. The compose tools are how the AI builds and fires off requests against your saved targets.
The write tools accept the shapes an AI tends to send and store them in the shape the app loads: headers, query_params/queryParams and cookies may be an object {name: value}, a list of {key, value, enabled} or a list of [name, value] pairs; request keys may be snake_case or camelCase; a non-string body is stored as its JSON text. Anything else is rejected with an error naming the field, instead of writing a collection the app would silently skip. A collection id may contain only letters, digits, ., _ and -, and may not start with . or contain ...
probe_list_collections
Section titled “probe_list_collections”List every collection — name, request/folder/environment counts. No parameters.
probe_get_collection
Section titled “probe_get_collection”Full collection content.
| Parameter | Type | Required |
|---|---|---|
id | string | yes |
probe_create_collection
Section titled “probe_create_collection”Create a collection. Saves to disk and shows up immediately in Probe (its compose watcher reloads).
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | yes | Collection name. |
requests | array | Inline requests (each {name, method, url, headers, queryParams, body, contentType}; snake_case keys work too). | |
folders | array | Folders with nested requests ({name, requests, folders}). | |
environments | array | Environments with {name, variables: [{key, defaultValue, currentValue?, enabled?, isSecret?, type?}]}. Any other member (e.g. a misspelled secret: true) is refused by path, so a secret is never stored as plain text by mistake. | |
default_headers | object or array | Headers applied to every request: {name: value} or [{key, value, enabled}]. | |
default_auth | object | Default auth (e.g. {type: 'bearer', token: '...'}). |
Returns: {id, name, requests, folders, environments} — the new collection's id and every created item as {id, name} (folders also carry their own requests / folders), so later calls can address them. The file path is not returned.
probe_import_compose
Section titled “probe_import_compose”Import into Composer as a new collection, through the importers of the app's Import menu: the collection is saved and opened in the app, so the app must be open (503 uiNotRunning otherwise).
| Parameter | Type | Required |
|---|---|---|
format | postman | curl | probe | yes — a Postman Collection v2.1 JSON, one cURL command (a one-request collection), or a Probe-format export (probe_export_collection) |
content | string | yes — the JSON text or the command, at most 1 MiB |
name | string | no — default the collection's own name, Imported for cURL |
Postman variables of type secret are stored in the OS keychain, never in the collection file. An unreadable document, a collection with no requests or a cURL command without a URL is a 400.
Returns: {id, name, request_count}.
probe_add_compose_request
Section titled “probe_add_compose_request”Add a single request to an existing collection.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
collection_id | string | yes | ||
name | string | yes | ||
method | string | GET | ||
url | string | Supports {{variable}} syntax. | ||
headers | object or array | {name: value} or [{key, value, enabled}]. | ||
query_params | object or array | Same shapes as headers. | ||
cookies | object or array | Same shapes as headers. | ||
body | any | A string; any other JSON value is stored as its JSON text. | ||
content_type | string | application/json | ||
graphql_variables | string | JSON object of GraphQL variables. | ||
description | string | |||
timeout_seconds | integer | 30 | Send timeout, 1–110 (outside is refused, not clamped). | |
pre_request_script | string | JS run before the request is sent. | ||
test_script | string | JS run after the response arrives. | ||
folder_id | string | Subfolder placement. | ||
auth | object | Per-request auth override; type is one of none (Postman's noauth is accepted and stored as none), bearer, basic, apikey (any other, such as apiKey, is refused with a hint). |
Returns: the new request's {id, name}.
probe_add_compose_environment
Section titled “probe_add_compose_environment”Add an environment with variables.
| Parameter | Type | Required | Description |
|---|---|---|---|
collection_id | string | yes | |
name | string | yes | e.g. Development. |
variables | array | yes | [{key, defaultValue, currentValue?, enabled?, isSecret?}]. |
probe_send_compose_request
Section titled “probe_send_compose_request”Resolve variables and send a saved request through the real Composer send path — pre-request/test scripts run, auth and the cookie jar are applied, and a GraphQL content type is wrapped in the {query, variables} envelope. A pre-request script's pro.request edits change what is sent, and the scripts' variable writes are saved, as in the app. When the proxy is running, the request is routed through it and the resulting traffic also lands in the log. Requires the Probe app UI to be running — 503 uiNotRunning if it's not, 504 timeout if it never answers. The request's own timeout must be 1-110 s (outside is refused), and the whole send is stopped waiting for after 115 s with an error result.
| Parameter | Type | Required | Description |
|---|---|---|---|
collection_id | string | yes | |
request_id | string | yes | |
environment | string | Env name or id. Backs every variable variables doesn't set, and receives the scripts' environment writes (default: the active environment). An unknown one is an error listing the valid names; nothing is sent. | |
variables | object | Per-call overrides: beat every environment and the globals, in the request and in the scripts' pro.variables reads (only a script's pro.variables.set locals rank higher). |
Returns: {status_code, status_text, headers, body, duration_ms, resolved_url, error, test_results, console_logs}. resolved_url is the URL as sent. Secret variable values are masked (••••••••) in resolved_url, error, test error messages, console logs, and in the response headers and body when the server echoes one back — as typed, URL-encoded, or JSON-escaped (\", \\, \/, \uXXXX). Masking prevents accidental exposure only: the captured traffic of the send (probe_list_traffic, probe_get_request) is not masked — see What a connected AI can reach.
probe_send_request
Section titled “probe_send_request”Send an ad-hoc HTTP request — no saved collection needed. Runs through the same Composer send path as probe_send_compose_request (auth, cookie jar, GraphQL envelope, proxy routing). Pass collection_id to borrow that collection's auth, cookie jar and variables; an unknown one is an error and nothing is sent. environment needs collection_id, and an unknown environment is an error listing the valid names (no fallback to the active one). Requires the Probe app UI to be running — 503 uiNotRunning if it's not, 504 timeout after 120 s.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | yes | Supports {{variable}} syntax. | |
method | string | GET | ||
headers | array or object | [{key, value, enabled}] or a plain {key: value} object. | ||
query_params | array or object | Same shapes as headers. | ||
cookies | array or object | Same shapes as headers. | ||
body | string | |||
content_type | string | e.g. application/json, application/graphql+json. | ||
auth | object | {type: "bearer", token: "..."}; type is one of none (Postman's noauth is accepted and stored as none), bearer, basic, apikey, any other is refused. | ||
timeout_seconds | integer | 30 | 1–110; a value outside that range is refused with an error naming the range, never clamped (the bridge gives the app 120 s). | |
graphql_variables | string | JSON object of GraphQL variables (only used with the GraphQL content type). | ||
collection_id | string | Borrow this collection's auth, cookie jar and variables. | ||
environment | string | Environment name or id of collection_id to resolve variables against. | ||
variables | object | {{variable}} overrides. |
Returns: {status_code, status_text, headers, body, duration_ms, resolved_url, error, test_results, console_logs}.
probe_delete_collection
Section titled “probe_delete_collection”Delete a collection by id (removes its JSON file). The app picks up the change automatically via its file watcher.
| Parameter | Type | Required |
|---|---|---|
id | string | yes |
404 if the id doesn't exist.
probe_update_compose_request
Section titled “probe_update_compose_request”Partially update a saved request — only the fields you provide are changed. Searches the collection root and every nested folder.
| Parameter | Type | Required | Description |
|---|---|---|---|
collection_id | string | yes | |
request_id | string | yes | |
name | string | ||
method | string | ||
url | string | ||
headers | object or array | {name: value} or [{key, value, enabled}]; replaces the whole list. | |
query_params | object or array | Same shapes; replaces the whole list. | |
cookies | object or array | Same shapes; replaces the whole list. | |
body | any | A string; any other JSON value is stored as its JSON text. | |
content_type | string | ||
graphql_variables | string | JSON object of GraphQL variables. | |
description | string | ||
timeout_seconds | integer | 1–110 (outside is refused) | |
pre_request_script | string | ||
test_script | string | ||
auth | object or null | null clears the request's auth so it inherits from the collection; type is one of none (Postman's noauth is accepted and stored as none), bearer, basic, apikey. |
404 if the collection or request doesn't exist. Error if no updatable field is provided.
probe_delete_compose_request
Section titled “probe_delete_compose_request”Delete a saved request — searches the root and every nested folder.
| Parameter | Type | Required |
|---|---|---|
collection_id | string | yes |
request_id | string | yes |
404 if the collection or request doesn't exist.
probe_update_compose_environment
Section titled “probe_update_compose_environment”Update an environment's name and/or variables. environment_id may be the environment's id or its name.
| Parameter | Type | Required | Description |
|---|---|---|---|
collection_id | string | yes | |
environment_id | string | yes | Id or name. |
name | string | ||
variables | array | Full replacement list: [{key, defaultValue, currentValue?, enabled?, isSecret?}]. |
Replacing variables replaces the whole array — but a variable whose stored value is the secret-keychain marker keeps that marker when the incoming value for it is blank, so you can't accidentally wipe out a secret by omitting its value. A new value for a secret variable is stored in the OS keychain by the running Probe app and the file keeps only the marker; if the app window isn't open the call fails with 409 secretNeedsApp and nothing changes. 404 if the collection or environment doesn't exist.
probe_delete_compose_environment
Section titled “probe_delete_compose_environment”Delete an environment. environment_id may be the environment's id or its name. If it was the active environment, the collection falls back to the first remaining one.
| Parameter | Type | Required |
|---|---|---|
collection_id | string | yes |
environment_id | string | yes |
404 if the collection or environment doesn't exist.
probe_add_compose_folder
Section titled “probe_add_compose_folder”Create a folder in a collection, optionally nested under an existing folder.
| Parameter | Type | Required | Description |
|---|---|---|---|
collection_id | string | yes | |
name | string | yes | |
folder_id | string | Parent folder to nest under (omit for collection root). |
Returns: the new folder's id. 404 if folder_id doesn't resolve to an existing folder.
probe_list_compose_history
Section titled “probe_list_compose_history”List the app's Composer send history — every request/response sent from the Composer editor, newest first, including REST- and MCP-initiated sends recorded by the send bridge (probe_send_compose_request, probe_send_request); collection runs aren't recorded. Distinct from probe_list_collections/probe_get_collection, which are saved requests, not send history. Read-only.
| Parameter | Type | Description |
|---|---|---|
limit | integer | Max entries, newest first (default 20, 1–200; a value outside that is refused). |
offset | integer | Entries to skip from the newest (default 0). |
include_bodies | boolean | Include response bodies and request bodies, as composed (snapshot.body) and as sent (sentBody) (default false, which strips them along with responseBody and the editor snapshot's snapshot.resBody). |
Returns: {entries, total, offset, next_offset} where total is the full count of entries in the history file (independent of limit) and next_offset is the offset of the next page, null on the last one. A response body over 256 KB is kept cut, with responseBodyTruncated: true and responseBodyOriginalBytes, so it is not the whole body.
probe_export_collection
Section titled “probe_export_collection”Export a saved Composer collection (or a single request) to a shareable format. Pure data transform — works headless, no Probe UI required. Secret variable values are blanked in every format. Read-only.
| Parameter | Type | Description |
|---|---|---|
collection_id | string | Required. Collection ID (from probe_list_collections). |
format | string | postman (default), curl, probe, or postman-environment. |
request_id | string | Export only this request (postman and curl). |
environment | string | Environment ID or name (postman-environment); defaults to the active environment. |
Returns: the exported text. postman is Postman Collection v2.1 JSON including auth, cookies, and GraphQL bodies; curl is one command for a request, or a script with one command per request (with # folder/name comments) for the whole collection; probe is the Probe-native .pro envelope that Probe can import again; postman-environment is a Postman environment file with secret variables typed secret and left empty. 404 if the collection, request, or environment is not found.
Map Local
Section titled “Map Local”Map Local rules serve a canned response from disk or an inline string instead of contacting the origin. See Map Local for the full feature doc.
probe_list_map_local_rules
Section titled “probe_list_map_local_rules”List every rule and the master enable flag. No parameters.
probe_check_map_local_match
Section titled “probe_check_map_local_match”Preview which rule (if any) would intercept a given request — no side effects.
| Parameter | Type | Required |
|---|---|---|
method | string | yes |
url | string | yes |
Returns: {matched: true, rule: {…}}, or {matched: false, reason, checks}; every answer also carries host_decrypted and, when it is false, a decryption_hint: the proxy never processes that request — an ignored host or one of Probe's built-in background hosts (certificate checks, OS telemetry) is forwarded untouched for every scheme, and an HTTPS host outside the intercept-host allowlist is tunnelled undecrypted — so a matching rule never fires. reason says why nothing matched (for example the master switch is off, or no rules exist) and checks gives each rule's reason — disabled, the method filter, or the pattern and the form of the URL it was compared with.
A url_pattern without a scheme (api.example.com/users/*) matches host + path over HTTP and HTTPS; with a scheme (https://api.example.com/users/*) it matches only that scheme. The default port (:443/:80) is ignored in both the request URL and your pattern, so you can paste a captured URL as is, and so is the query string unless the pattern contains ?.
probe_get_map_local_rule
Section titled “probe_get_map_local_rule”Read one Map Local rule by id, in full (bodies are never cut to fit a list). Read-only. 404 if the id does not exist.
| Parameter | Type | Required |
|---|---|---|
id | string | yes |
probe_create_map_local_rule
Section titled “probe_create_map_local_rule”Create a new rule. id is optional — generated as mcp_<ms>_<n> if you don't supply one.
| Parameter | Type | Required | Description |
|---|---|---|---|
url_pattern | string | yes | Wildcard *, e.g. api.example.com/users/*. |
source | string | yes | local_file or inline_body. |
id | string | ||
method | string | Default GET. | |
match_all_methods | boolean | ||
enabled | boolean | ||
file_path | string | Absolute path. Required when source is local_file. Must be an existing regular file of at most 50 MiB inside ~/Downloads, ~/.probe/transfers or ~/.probe/map-local — any other path (or a symlink, .., a directory, a device file) is refused on create and on update, whatever the source, with an error naming the allowed folders. Put the body file in ~/.probe/map-local first. Rules you create in the app may point anywhere, but editing one over MCP needs its file in one of those folders. The file is served to every client whose request matches — including phones on your network. | |
inline_body | string | Required when source is inline_body. | |
inline_format | string | json, xml, html, or text. | |
status_code | integer | Default 200. | |
response_headers | object | String → string map. probe-mcp reads tool arguments as JSON objects, which it keeps sorted by key, so the headers are saved in name order. To keep your own order, edit the rule in the app or use the REST API. | |
delay_ms | integer | Artificial latency. |
probe_update_map_local_rule
Section titled “probe_update_map_local_rule”Patch by id: only the fields you send change, every omitted field keeps its stored value (a disabled rule stays disabled, a body stays put). id is the only required field. The merged rule passes the same checks as create; an unknown id is 404. Read the rule first with probe_get_map_local_rule. Rules are checked in list order, the first match wins, and new rules are appended (there is no reorder tool).
probe_delete_map_local_rule
Section titled “probe_delete_map_local_rule”| Parameter | Type | Required |
|---|---|---|
id | string | yes |
404 if id doesn't exist.
probe_toggle_map_local_rule
Section titled “probe_toggle_map_local_rule”Flip a single rule's enabled flag.
| Parameter | Type | Required |
|---|---|---|
id | string | yes |
probe_set_map_local_enabled
Section titled “probe_set_map_local_enabled”Master switch. When off, no rule matches.
| Parameter | Type | Required |
|---|---|---|
enabled | boolean | yes |
Map Remote
Section titled “Map Remote”Map Remote rules redirect matching requests to a different upstream — same shape as Map Local rules but the destination is another origin instead of a canned body. See Map Remote.
As with Map Local, a rule written here is saved by the app and shown in its Map Remote window, and rules only fire while the master switch (off by default) is on.
probe_list_map_remote_rules
Section titled “probe_list_map_remote_rules”List every rule and the master enable flag. No parameters.
probe_check_map_remote_match
Section titled “probe_check_map_remote_match”Preview which rule would redirect a given request, plus the rewritten URL.
| Parameter | Type | Required |
|---|---|---|
method | string | yes |
url | string | yes |
Returns: the matching rule and the resolved destination URL, or {matched: false, reason, checks} (why nothing matched, and each rule's reason). Like the Map Local check, every answer carries host_decrypted and, when false, a decryption_hint.
probe_get_map_remote_rule
Section titled “probe_get_map_remote_rule”Read one Map Remote rule by id, in full. Read-only. 404 if the id does not exist.
| Parameter | Type | Required |
|---|---|---|
id | string | yes |
probe_create_map_remote_rule
Section titled “probe_create_map_remote_rule”| Parameter | Type | Required | Description |
|---|---|---|---|
source_scheme | string | yes | http or https. |
source_host | string | yes | Host only, matched exactly (case-insensitive; no wildcards). A wildcard host such as *.example.com is refused: add one rule per host. |
source_path | string | yes | Starts with /. Wildcards * are captured in order. |
dest_scheme | string | yes | http or https. |
dest_host | string | yes | Host only: the port goes in dest_port, the scheme in dest_scheme. localhost:3000, http://x or x.com/v2 is refused with a hint naming the right field. |
dest_path | string | yes | Starts with / (or *). Each * is filled with captures from source_path. |
id | string | Generated as mcp_mr_<ms>_<n> if omitted. | |
source_port | integer | Defaults to 443/80 by scheme. | |
dest_port | integer | ||
method | string | Default GET. | |
match_all_methods | boolean | ||
enabled | boolean | ||
preserve_original_host_header | boolean | Not supported yet: true is refused on create and update (the forwarded request always carries Host: dest_host). Omit it or send false. |
probe_update_map_remote_rule
Section titled “probe_update_map_remote_rule”Patch by id: only the fields you send change, omitted fields keep their stored value; id is the only required field and an unknown id is 404. The merged rule is checked like a create: an empty source_host/dest_host, a scheme other than http/https, a host carrying a scheme, port or path, a wildcard source_host, or a path without a leading / is rejected.
probe_delete_map_remote_rule
Section titled “probe_delete_map_remote_rule”| Parameter | Type | Required |
|---|---|---|
id | string | yes |
probe_toggle_map_remote_rule
Section titled “probe_toggle_map_remote_rule”| Parameter | Type | Required |
|---|---|---|
id | string | yes |
probe_set_map_remote_enabled
Section titled “probe_set_map_remote_enabled”| Parameter | Type | Required |
|---|---|---|
enabled | boolean | yes |
Mock Server
Section titled “Mock Server”The Mock server is a standalone HTTP listener (default port 9100) that serves canned responses to clients that hit it directly — unlike Map Local, there's no proxying involved. See Mock Server for the full feature doc.
probe_list_mock_rules
Section titled “probe_list_mock_rules”List every Mock rule and the master enable flag. No parameters.
probe_get_mock_status
Section titled “probe_get_mock_status”Get the Mock server listener status: whether it is running and on which port. No parameters.
probe_check_mock_match
Section titled “probe_check_mock_match”Check whether a given method+path would be served by any active Mock rule — no side effects.
| Parameter | Type | Required |
|---|---|---|
method | string | yes |
path | string | yes |
Returns: {matched: true, rule: {…}} or {matched: false, reason, checks} (why nothing matched — such as the master switch being off — and each rule's reason). The mock server is called directly, not through the proxy, so this check carries no host_decrypted.
probe_get_mock_rule
Section titled “probe_get_mock_rule”Read one Mock rule by id, in full. Read-only. 404 if the id does not exist.
| Parameter | Type | Required |
|---|---|---|
id | string | yes |
probe_create_mock_rule
Section titled “probe_create_mock_rule”Create a new rule. id is optional — generated as mcp_<ms>_<n> if you don't supply one.
| Parameter | Type | Required | Description |
|---|---|---|---|
url_pattern | string | yes | Path with * wildcards, e.g. /api/users/*. |
id | string | ||
name | string | ||
method | string | Empty matches any method. | |
enabled | boolean | ||
status_code | integer | Default 200. | |
status_text | string | Optional custom reason phrase. | |
headers | array of [name, value] | ||
body | string | ||
body_is_base64 | boolean | Decode body from base64 for binary responses. | |
latency_ms | integer | Artificial delay before responding. |
probe_update_mock_rule
Section titled “probe_update_mock_rule”Patch by id: only the fields you send change, omitted fields keep their stored value; id is the only required field and an unknown id is 404. The merged rule passes the same checks as create, including body_is_base64: true with a body that is not valid base64, which is refused at write time. New rules are appended and the first matching rule wins. While the Mock master switch is off, the server's 404 hint names probe_set_mock_enabled.
probe_delete_mock_rule
Section titled “probe_delete_mock_rule”| Parameter | Type | Required |
|---|---|---|
id | string | yes |
404 if id doesn't exist.
probe_toggle_mock_rule
Section titled “probe_toggle_mock_rule”Flip a single rule's enabled flag.
| Parameter | Type | Required |
|---|---|---|
id | string | yes |
probe_set_mock_enabled
Section titled “probe_set_mock_enabled”Master switch. When off, no rule matches and the server answers 404 for everything.
| Parameter | Type | Required |
|---|---|---|
enabled | boolean | yes |
probe_start_mock_server
Section titled “probe_start_mock_server”Start the standalone listener.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
port | integer | 9100 | Port to listen on (1–65535). |
Errors if the port is 0, already in use, or the server is already running.
probe_stop_mock_server
Section titled “probe_stop_mock_server”Stop the standalone listener. No parameters.
API Flows are Probe's node-based request chains — build once in the app (like Postman Flows), then drive them from the AI. Flows are Dart-owned: the two list/get tools read what the app has persisted; the create, update, graph and delete tools and probe_run_flow ask the running app to save or execute the chain. See Flows in CI for the headless-automation angle these tools plug into.
probe_list_flows
Section titled “probe_list_flows”List every saved flow — id, name, node count, edge count, created/updated timestamps. No parameters.
Returns: each flow's id, name, nodeCount, edgeCount, createdAt, updatedAt. Use the id with probe_get_flow / probe_run_flow.
probe_get_flow
Section titled “probe_get_flow”Full flow definition: nodes (start, request, condition, loop, delay, subflow and script, with extractions and assertions), edges, and canvas viewport.
| Parameter | Type | Required | Description |
|---|---|---|---|
flow_id | string | yes | Id from probe_list_flows. |
Returns: the stored flow JSON, with revision (send it back to probe_set_flow_graph), plus a derived subflowIds array — the deduped target ids of every subflow node, so a client can discover a flow's sub-flow dependencies without walking node payloads itself.
probe_create_flow
Section titled “probe_create_flow”Create a flow. Send only name to get an empty flow with one start node (like New Flow in the app), or a whole graph in probe_get_flow's shape.
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | yes | Up to 200 characters. |
nodes | array | Every node: id, name, type (start, request, condition, loop, delay, subflow, script), position, and the type's config. | |
edges | array | {id, fromNodeId, toNodeId, fromPort?}. | |
viewport | object | Canvas pan and zoom. |
The app checks the graph before saving anything and refuses it (400, with the reason) when there is no start node or more than one, an edge points at a node that doesn't exist, a node type is unknown, two nodes share an id or a name, the graph has a cycle, a condition port drives two edges, a sub-flow points at an unknown flow or would run itself, or the flow has more than 500 nodes or 2,000 edges. Nodes at negative positions move into view together (the layout is kept). Literal secrets in a request (an Authorization header, an API-key parameter) become {{variables}} and are listed in requiredInputs: pass their values in probe_run_flow's environment.
Returns: the stored flow, with its revision. Needs the Probe app (503 uiNotRunning otherwise).
probe_update_flow
Section titled “probe_update_flow”Rename a flow.
| Parameter | Type | Required |
|---|---|---|
flow_id | string | yes |
name | string | yes |
probe_set_flow_graph
Section titled “probe_set_flow_graph”Replace a flow's whole graph: read it with probe_get_flow, change the JSON, send nodes, edges (and viewport) back with the revision it carried.
| Parameter | Type | Required | Description |
|---|---|---|---|
flow_id | string | yes | |
revision | integer | yes | revision from probe_get_flow. |
nodes | array | yes | Every node (nodes left out are removed). |
edges | array | Every edge. | |
viewport | object |
If the flow changed since your read (someone edited it on the canvas, or another agent wrote it), the answer is 409 and nothing changes: read it again and reapply your change. The checks are the same as probe_create_flow's; a request sent back unchanged keeps what is stored. An open canvas shows the new graph at once.
probe_delete_flow
Section titled “probe_delete_flow”Delete a flow and its file. This cannot be undone.
| Parameter | Type | Required |
|---|---|---|
flow_id | string | yes |
probe_get_flow_run
Section titled “probe_get_flow_run”Fetch the report of a flow run that outlived probe_run_flow's 120 s wait, by the run_id that the 504 answer carried. Read-only.
| Parameter | Type | Required |
|---|---|---|
run_id | string | yes |
Returns: {status: "running"} while the app is still running it, then {status: "finished", report}. 404 for an unknown id: only the last 32 timed-out runs are kept, and a run that finished in time returned its report directly.
probe_run_flow
Section titled “probe_run_flow”Execute a flow end-to-end and return its run report.
| Parameter | Type | Required | Description |
|---|---|---|---|
flow_id | string | yes | Id from probe_list_flows. |
environment | object | Variable overrides for this run (name → value), forwarded to the executor. It is not an environment name: anything other than an object (such as a name string) is rejected. |
Returns: per-node results (status, extracted values, assertion outcomes, and the request's resolved URL: the URL as sent, with its enabled Params rows), overall passed/failed/skipped counts, and total duration. Secret variable values (and environment overrides of secret variables) are masked (••••••••) everywhere in the report.
The Probe app must be running — this bridges to the UI to fire the flow's real HTTP requests. Fails with 503 if the app isn't running, 504 if it doesn't answer in time (runs can take up to two minutes); the 504 carries a run_id and status: "running": the run may still be going and still sending its requests, so fetch its report with probe_get_flow_run instead of running it again. A report with an error (unknown flow, already running, or the run threw) is returned as a tool error, and so is a run that ran but ended failed (a node errored or an assertion failed): the error names the failing nodes and the full report follows.
Files (remote-fs)
Section titled “Files (remote-fs)”Thin wrappers over the Files feature's remote-fs REST routes — the same SFTP/FTP/FTPS/S3/WebDAV engine backing the app's Files browser. There is no connect tool: credentials stay entirely in the Probe UI path. Open a connection in the app first, then drive it from here by connection_id (see probe_list_remote_fs_connections). These calls don't move the folder you're looking at in the app's Files browser.
probe_list_remote_fs_connections
Section titled “probe_list_remote_fs_connections”List every open Files connection. No parameters.
Returns: each connection's id, protocol, host, server label, home path, and whether the transport is encrypted.
probe_remote_fs_list_dir
Section titled “probe_remote_fs_list_dir”List a directory's entries on an open connection, one page at a time.
| Parameter | Type | Required | Description |
|---|---|---|---|
connection_id | string | yes | Id from probe_list_remote_fs_connections. |
path | string | yes | Absolute remote directory path, e.g. /var/www. |
cursor | string | next_cursor from the previous page; omit it for the first page. | |
limit | integer | Entries per page, 1–5000 (default 500). |
Returns: {path, entries, total, next_cursor}: each entry's name, path, isDir, size, and (when the backend reports them) modifiedMs, permissions, owner, symlinkTarget; total entries in the directory; next_cursor to pass back for the next page, null on the last one. The cursor is a position in the listing, so a directory that changes between calls can skip or repeat an entry.
probe_remote_fs_mkdir
Section titled “probe_remote_fs_mkdir”Create a directory.
| Parameter | Type | Required | Description |
|---|---|---|---|
connection_id | string | yes | |
path | string | yes | Absolute path of the directory to create. |
probe_remote_fs_rename
Section titled “probe_remote_fs_rename”Rename or move an entry.
| Parameter | Type | Required | Description |
|---|---|---|---|
connection_id | string | yes | |
from | string | yes | Current absolute path. |
to | string | yes | New absolute path. |
probe_remote_fs_delete
Section titled “probe_remote_fs_delete”Delete one or more entries in a single call.
| Parameter | Type | Required | Description |
|---|---|---|---|
connection_id | string | yes | |
paths | array of {path, is_dir} | yes | Entries to delete. is_dir (or isDir, the shape probe_remote_fs_list_dir returns) defaults to false — needed by backends like S3 that distinguish an object from a prefix. A probe_remote_fs_list_dir entry can be passed as-is (name, size, modifiedMs, permissions, owner, symlinkTarget are ignored); any other member is refused. On S3 a file delete of a key that doesn't exist fails notFound; when the path is a folder sent without is_dir, the message adds "is it a directory? pass isDir: true". Under a delete-only IAM policy (HeadObject forbidden) the file is still deleted and listed in deleted, but also in unconfirmed with a note: its existence couldn't be checked. |
Directory deletes are recursive on S3 (every object under the prefix) and WebDAV (the server deletes the whole collection), but not on SFTP and FTP/FTPS (a non-empty directory fails). Every path is attempted even if an earlier one fails.
Returns: {ok, deleted}. When some paths could not be deleted (REST answers 207, ok is false) the tool reports an error that still lists deleted and failed: [{path, error: {code, message}}].
probe_remote_fs_download
Section titled “probe_remote_fs_download”Enqueue a download from the connection to a local file.
| Parameter | Type | Required | Description |
|---|---|---|---|
connection_id | string | yes | |
remote_path | string | yes | Absolute remote source path. |
local_path | string | yes | Absolute local destination path inside ~/Downloads or Probe's transfers folder ~/.probe/transfers (Windows: %USERPROFILE%\Downloads, %USERPROFILE%\.probe\transfers). A relative path, a .., a symbolic link, a directory, a missing folder or a path outside those folders is refused. |
overwrite | boolean | Replace local_path if it already exists. Default false: an existing file is refused. |
This writes a file on your own machine, so only use a path you asked for. Returns: {transferId} immediately — poll probe_remote_fs_transfers to watch progress and completion, or stop it with probe_remote_fs_cancel_transfer. The transfer also shows in the app's transfer queue, where the user can pause or cancel it.
probe_remote_fs_upload
Section titled “probe_remote_fs_upload”Enqueue an upload of a local file to the connection.
| Parameter | Type | Required | Description |
|---|---|---|---|
connection_id | string | yes | |
local_path | string | yes | Absolute path of an existing regular file inside ~/Downloads or Probe's transfers folder ~/.probe/transfers (Windows: %USERPROFILE%\Downloads, %USERPROFILE%\.probe\transfers). Symbolic links are refused. |
remote_path | string | yes | Absolute remote destination path. |
This reads a file on your own machine and sends it to the server, so only upload a file you asked for. Returns: {transferId}, same as probe_remote_fs_download.
probe_remote_fs_transfers
Section titled “probe_remote_fs_transfers”List the Files transfer queue. No parameters.
Returns: every download/upload the engine is tracking — the active ones plus the 100 most recently finished — with transferId, connectionId, kind, state (queued/running/paused/done/cancelled/error), remote/local paths, byte offset, and, in the error state, error: {code, message} saying why it failed. Cancelled transfers stay listed with state cancelled.
probe_remote_fs_cancel_transfer
Section titled “probe_remote_fs_cancel_transfer”Cancel a queued, running or paused transfer, whether it was started from the app or through MCP. It stays in probe_remote_fs_transfers with state cancelled; a partly written destination file is left in place.
| Parameter | Type | Required | Description |
|---|---|---|---|
transfer_id | string | yes | transferId from probe_remote_fs_download/upload or probe_remote_fs_transfers. |
Returns: {ok: true, transferId}. An unknown id or a transfer that already finished is an error.
Test runs
Section titled “Test runs”Group the requests one test produces, then read exactly those. Flow: begin, drive the app (when several shards share one Probe, have each send a header such as X-Probe-Test: shard-1 and pass header_value), list or search traffic with test_run_id, end. A run lives in Probe's memory only: it never touches your saved rules or any file, and it is gone when Probe restarts (a stale id answers runFromPreviousInstance). A run you forget ends itself after ttl_secs without use.
probe_begin_test_run
Section titled “probe_begin_test_run”Start a run. Requests that start from now on belong to it.
| Parameter | Type | Description |
|---|---|---|
name | string | A label. |
client | string | Only clients whose label (process name or IP) contains this. |
host | string | Only this host and its subdomains. |
header_value | string | Only requests whose header_name header has exactly this value. |
header_name | string | Default X-Probe-Test; without header_value, the header only has to be present. |
expect_hosts | string[] | Hosts you expect traffic for; each gets a host_checks verdict. |
ttl_secs | integer | Lease, default 900, at most 86400; every use renews it. |
Returns: the run: id, state: "running", start_id, scope, ttl_secs, expires_at, and host_checks (host_decrypted: false plus a decryption_hint when Probe cannot see that host's requests).
probe_wait_for_request
Section titled “probe_wait_for_request”Wait for traffic instead of polling. Returns as soon as min_count matching responses exist (or requests, with phase: "request").
| Parameter | Type | Description |
|---|---|---|
test_run_id | string | Only this run's requests; the run's existing traffic counts. |
host | string | Host substring. |
method | string | HTTP method. |
path | string | URL substring. |
phase | string | response (default) or request. |
cursor | integer | cursor of a previous answer: only later events count. Without a run, the default is "only traffic from now on". |
min_count | integer | Rows needed, default 1, at most 100. |
timeout_ms | integer | Default 25000, at most 55000. |
Returns: {matched: true, items, cursor} (at most 100 items, oldest event first), or after the timeout {matched: false, cursor, waited_ms} (not an error: call again with the same cursor), with capture_note / decryption_hint when they explain the silence. When capture is off or the proxy is stopped and nothing matching is there, it is an error (captureOff). With test_run_id the wait keeps the run's lease alive, never returns requests started after the run ended, and is an error (runExpired) if the lease ran out meanwhile.
probe_add_test_rule
Section titled “probe_add_test_rule”Add a rule that applies to one test run only. It lives in Probe's memory with the run: it never appears in your saved Map Local / Map Remote / Mock rules, is never saved, and is removed when the run ends. It is tried before your own rules, for requests inside the run's scope. The run must have a scope (begin it with header_value, recommended, or client / host); a run without one refuses test rules with runScopeRequired, since its rules would rewrite every client's traffic.
| Parameter | Type | Required | Description |
|---|---|---|---|
test_run_id | string | yes | A running run. |
kind | string | yes | map_local, map_remote or mock. |
rule | object | yes | The fields of probe_create_map_local_rule / probe_create_map_remote_rule / probe_create_mock_rule (same checks). |
Returns: {kind, rule}; for mock also mock_base_url, the run's own listener (127.0.0.1, free port; separate from the Mock server): point the app under test at it. A response served or rewritten by the rule carries X-Probe-Test-Run and X-Probe-Rule headers.
probe_reset_test_rules
Section titled “probe_reset_test_rules”Remove a run's test rules (the run stays), or with all: true and no test_run_id end and delete every run and test rule. It never touches your saved rules.
| Parameter | Type | Description |
|---|---|---|
test_run_id | string | The run whose rules go. Wins over all. |
all | boolean | true: remove every run. |
probe_get_test_run
Section titled “probe_get_test_run”| Parameter | Type | Required | Description |
|---|---|---|---|
test_run_id | string | yes | id from probe_begin_test_run. |
Returns: the run with stats: count, pending_responses, evicted (a request of the run may have been dropped by the 10,000-row limit or deleted), cleared, first_available_id, capture_paused (capture is off now) and capture_interrupted (capture stopped at some point since the run began).
probe_end_test_run
Section titled “probe_end_test_run”End a run: later requests no longer belong to it.
| Parameter | Type | Required | Description |
|---|---|---|---|
test_run_id | string | yes | The run to end. |
settle_ms | integer | Wait this long for requests already sent to land (default 300, at most 5000). |
Returns: the ended run with stats. Its traffic stays listable for an hour.
Traffic checks
Section titled “Traffic checks”Verify what a test sent, or hand the capture to other tools. Both accept the run from Test runs.
probe_assert_traffic
Section titled “probe_assert_traffic”Check captured traffic against assertions. The call fails (an MCP error) when any assertion fails; the error lists only the failed results with their reason. See POST /api/v1/traffic/assert in the REST API for the targets, operators and result fields.
| Parameter | Type | Required | Description |
|---|---|---|---|
assertions | object[] | yes | Each {target, op, value?, quantifier?}; quantifier is all (default), any or none. For order, value is [{method?, path?, host?}]. |
test_run_id | string | Only this run's requests. | |
filter | object | The traffic filters: host, method, path, status, search, client, header... |
Returns: {passed: true, matched_count, results}. A bad target, operator or quantifier is an error naming the valid choices.
probe_export_har
Section titled “probe_export_har”Export traffic as HAR 1.2.
| Parameter | Type | Description |
|---|---|---|
test_run_id, host, method, path, status | Filters, as in probe_list_traffic. | |
max_body_bytes | integer | Cut each body to this many bytes. Inline the default is 4096; with output_path it is the server default (262144). |
output_path | string | Write the HAR to this file instead of returning it. Absolute path only; the directory must exist; an existing file is refused unless overwrite is true; a path inside Probe's data directory (~/.probe or PROBE_DATA_DIR) is refused. The file is written by the probe-mcp process. |
overwrite | boolean | Replace an existing output_path. Default false. |
Returns: the HAR document, or {path, bytes, entries} when output_path is given. See GET /api/v1/traffic/export/har for _probe details (bodies Probe did not keep, cut bodies, pending requests).
WebSocket
Section titled “WebSocket”Inspect WebSocket frames Probe captured through the proxy. These are read-only snapshots of a bounded in-memory store — the proxy observes frames MITM'd through it; it does not open sockets. See WebSocket for the UI side.
probe_ws_list_connections
Section titled “probe_ws_list_connections”List captured WebSocket connections. No parameters.
Returns: each connection's conn_id, log_id (the traffic entry of the upgrade handshake, or null if uncorrelated), url, opened_ts, closed_ts, closed, and frame_count. Use conn_id with probe_ws_get_frames.
probe_ws_get_frames
Section titled “probe_ws_get_frames”Get the captured frames for one connection.
| Parameter | Type | Required | Description |
|---|---|---|---|
conn_id | integer | yes | conn_id from probe_ws_list_connections. |
limit | integer | Return only the newest N frames (default 100; the store keeps up to 500 per connection). |
Returns: {conn_id, url, items, total, returned}. items holds the newest limit frames, oldest first; total is how many frames are stored and returned how many are in items. Each frame has dir (in = server → client, out = client → server), opcode (text/binary/ping/pong/close), text (text payload, or base64 for binary — capped at 64 KB), size_bytes (true payload size), truncated (true when text holds only the first 64 KB of the payload, so it is not the whole message) and ts.
Errors
Section titled “Errors”Every tool returns the same MCP envelope on failure:
{ "content": [{"type": "text", "text": "Error: <reason>"}], "isError": true}Common reasons:
Missing required parameter: <name>— schema violation.Probe is not running (no valid …/api-handshake.json). Start Probe, then retry.— there's no handshake file, or the process it names has exited. Start Probe and call the tool again; you don't need to restart your AI client.<METHOD> <path>: cannot reach Probe (…). Is the Probe app running?— Probe was reachable earlier but isn't now, and the handshake hasn't changed (for example, the app quit or crashed). The API does not depend on the proxy: it answers whenever the app is open.<METHOD> <path> timed out after 150s— the app didn't answer a call within the 150-second limit.- HTTP-status messages from the underlying REST API (400, 404, 500, 503, 504, …), with the API's error message. A bare
404adds which list tool (such asprobe_list_traffic) gives the valid ids. Error texts are cut after 4,000 characters, so an echoed request body can't flood the conversation. - A call the server answered but that didn't do its job is an error too: a Composer send with no response or an empty
502from Probe's own proxy (the host could not be reached;probe_send_compose_request,probe_send_request), a flow-run report with anerroror a run that endedfailed(the error names the failing nodes), and a partial Files delete. The error text carries the result data. A401or a refused connection makesprobe-mcpre-read the handshake and retry once before it reports anything. The send tools andprobe_run_flowanswer503/504when the app UI isn't there to run them; a rule or setting write answers504if the app didn't confirm it in time (the proxy applied it, but it may not be saved). After a send's504the request may still have been sent: checkprobe_list_compose_historybefore sending it again.
Next steps
Section titled “Next steps”- MCP Setup — wire
probe-mcpinto your client. - Internal REST API — what each tool calls under the hood.
- Scripting — what
pro.*exposes insideprobe_execute_script. - Flows in CI — running
probe_run_flowunattended, outside an interactive AI session.