Description
When a request-modifying Scripting rule is active, Proxyman can assign the same flow id to two distinct, concurrent flows. The built-in MCP server then exposes only one of the two: the other is missing from get_flows / filter_flows (by url, host or requestBody) and cannot be fetched via get_flow_detail (the shared id resolves to the sibling). Both flows remain visible, with the same id, in the macOS app UI.
Disabling the request-modifying Scripting rule removes the collision — the same user action then yields unique ids and all flows are exposed by the MCP.
The triggering rule simply reassigns the request body and overrides a header in onRequest:
async function onRequest(context, url, request) {
var body = JSON.parse(request.rawBody);
request.headers["Content-Type"] = "application/json";
request.body = body;
return request;
}
Consequence for MCP consumers (important). The collision is undetectable from the MCP side: a masked flow is indistinguishable from a flow that never happened, and a returned flow gives no hint that a sibling is hidden behind the same id. An automated MCP client / AI agent therefore cannot trust absence or counts and may confidently assert "the app did not send request X" when it actually did — this caused real misdiagnoses on our side before we noticed the duplicate ids in the UI.
Steps to Reproduce
- Add a Scripting rule with a request script (like the one above) scoped to host A.
- Run an app that fires, at nearly the same instant, a request to host A (scripted) and another request to a different host B (not scripted).
- In the macOS app, observe two rows sharing the same flow
id (the host-A and host-B flows).
- From an MCP client, query
get_flows / filter_flows (e.g. by host B) and get_flow_detail(<shared id>) — the host-B flow is absent / unfetchable. Then disable the Scripting rule and repeat → the collision disappears and the flow is exposed normally.
Current Behavior
- Two different concurrent flows are assigned the same
id when a request-modifying Scripting rule is active.
- The MCP server returns only one of them; the other is silently omitted from
get_flows / filter_flows (all keys: url, host, requestBody) and unreachable via get_flow_detail (which returns the sibling).
- The loss is invisible to the MCP client (no error, plausible non-empty results), making it impossible to detect from the MCP alone.
Expected Behavior
- Every captured flow has a unique id, even when modified by a Scripting rule.
get_flows / filter_flows return all matching flows.
get_flow_detail(id) unambiguously returns the requested flow.
Environment
- App version: Proxyman 6.9.0 (build 60900), built-in MCP server
- macOS version: macOS 26.5 (build 25F71), Apple Silicon
- Traffic captured from an iOS Simulator app with SSL proxying enabled
Description
When a request-modifying Scripting rule is active, Proxyman can assign the same flow
idto two distinct, concurrent flows. The built-in MCP server then exposes only one of the two: the other is missing fromget_flows/filter_flows(byurl,hostorrequestBody) and cannot be fetched viaget_flow_detail(the shared id resolves to the sibling). Both flows remain visible, with the same id, in the macOS app UI.Disabling the request-modifying Scripting rule removes the collision — the same user action then yields unique ids and all flows are exposed by the MCP.
The triggering rule simply reassigns the request body and overrides a header in
onRequest:Consequence for MCP consumers (important). The collision is undetectable from the MCP side: a masked flow is indistinguishable from a flow that never happened, and a returned flow gives no hint that a sibling is hidden behind the same id. An automated MCP client / AI agent therefore cannot trust absence or counts and may confidently assert "the app did not send request X" when it actually did — this caused real misdiagnoses on our side before we noticed the duplicate ids in the UI.
Steps to Reproduce
id(the host-A and host-B flows).get_flows/filter_flows(e.g. by host B) andget_flow_detail(<shared id>)— the host-B flow is absent / unfetchable. Then disable the Scripting rule and repeat → the collision disappears and the flow is exposed normally.Current Behavior
idwhen a request-modifying Scripting rule is active.get_flows/filter_flows(all keys:url,host,requestBody) and unreachable viaget_flow_detail(which returns the sibling).Expected Behavior
get_flows/filter_flowsreturn all matching flows.get_flow_detail(id)unambiguously returns the requested flow.Environment