Repository navigation
[Bug] binary_session advertises pcap capture inspection as available on macOS #5711
Description
Before submitting
- I searched the open and closed issues for a related report.
- I removed credentials, tokens, private paths, and sensitive target data.
Area
Provider or capability discovery
Observed behavior
On macOS, binary_session {} advertises inspect_pcap_capture as available even though capture inspection is unsupported on this host. In the same stdio MCP session, inspect_pcap_client {} succeeds, but inspect_pcap_capture returns a non-retryable capability_unavailable / unsupported_provider host refusal. A subsequent binary_session {} still advertises both tools as available. No binary target is open.
Reproduction
From a built source checkout with locked dependencies installed, run this on macOS. The fixture executables answer only version probes; Wireshark and live traffic are unnecessary.
work_dir="$(mktemp -d)"
mkdir -p "$work_dir/bin" "$work_dir/home" "$work_dir/cfg" "$work_dir/data" "$work_dir/cache" "$work_dir/state" "$work_dir/tmp"
cat > "$work_dir/bin/tshark" <<'SH'
#!/bin/sh
if [ "$1" = "--version" ]; then printf 'TShark (Wireshark) 4.0.17\n'; exit 0; fi
exit 1
SH
cat > "$work_dir/bin/capinfos" <<'SH'
#!/bin/sh
if [ "$1" = "--version" ]; then printf 'Capinfos (Wireshark) 4.0.17\n'; exit 0; fi
exit 1
SH
chmod 755 "$work_dir/bin/tshark" "$work_dir/bin/capinfos"
printf '\324\303\262\241\002\000\004\000\000\000\000\000\000\000\000\000\377\377\000\000\001\000\000\000' > "$work_dir/capture.pcap"
cat > "$work_dir/probe.py" <<'PYTHON'
import json, os, subprocess, sys
from pathlib import Path
s=Path(os.environ["HOME"]).parent
p=subprocess.Popen(["node","scripts/rea.mjs","mcp"],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=(s/"mcp-stderr.txt").open("w"),text=True)
transcript=(s/"mcp-transcript.jsonl").open("w")
def send(msg):
transcript.write(json.dumps({"direction":"request","message":msg})+"\n");transcript.flush()
p.stdin.write(json.dumps(msg)+"\n");p.stdin.flush()
def request(i, method, params):
send({"jsonrpc":"2.0","id":i,"method":method,"params":params})
for line in p.stdout:
msg=json.loads(line)
transcript.write(json.dumps({"direction":"response","message":msg})+"\n");transcript.flush()
if msg.get("id")==i:
(s/f"response-{i}.json").write_text(json.dumps(msg,indent=2))
return msg
raise RuntimeError("server exited")
try:
init=request(1,"initialize",{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"pcap-host-verifier","version":"1"}})
send({"jsonrpc":"2.0","method":"notifications/initialized"})
for i,name,args in [(2,"binary_session",{}),(3,"inspect_pcap_client",{}),(4,"inspect_pcap_capture",{"path":str(s/"capture.pcap")}),(5,"binary_session",{})]:
response=request(i,"tools/call",{"name":name,"arguments":args})
result=response.get("result",{})
blocks=result.get("content",[])
body=next((json.loads(b["text"]) for b in blocks if b["type"]=="text"),result)
if name=="binary_session":
status=body.get("result",body)
groups=status.get("tool_availability",{}).get("groups",[])
print(json.dumps({"request":i,"name":name,"open":status.get("open"),"groups":[g for g in groups if any(n in g["names"] for n in ["inspect_pcap_client","inspect_pcap_capture"])]}))
else:
print(json.dumps({"request":i,"name":name,"body":body}))
finally:
p.stdin.close()
try: p.wait(timeout=20)
except subprocess.TimeoutExpired:
p.terminate();p.wait(timeout=10)
transcript.close()
PYTHON
env -i PATH="$work_dir/bin:$PATH" HOME="$work_dir/home" XDG_CONFIG_HOME="$work_dir/cfg" XDG_DATA_HOME="$work_dir/data" XDG_CACHE_HOME="$work_dir/cache" XDG_STATE_HOME="$work_dir/state" TMPDIR="$work_dir/tmp" REA_LOG_LEVEL=silent python3 "$work_dir/probe.py"The independent verifier executed this sequence at the baseline below. Before submission, I built current main with npm run build:cached and reran the same sequence there, changing only the disposable work-directory location. Both runs show the mismatch before and after the capture refusal. The probe retains exact JSON-RPC messages in mcp-transcript.jsonl under its generated work directory.
Expected behavior
Report capture inspection unavailable with an explanatory host limitation, while keeping the host-independent client version probe available. Preserve both tools in the complete catalog. docs/mcp-contracts.md:465-480 distinguishes complete tools/list membership from tool_availability, which callers use to choose a callable operation for the current host. docs/pcap-analysis.md:20-24 explicitly excludes macOS capture inspection while retaining version probes.
Impact and scope
P2: the documented operation-selection signal causes an avoidable failed call and remains wrong after the host refusal. Capture execution correctly refuses unsupported work; no data loss or security boundary violation was observed. A practical workaround is to consult the documented host requirements and omit capture inspection on macOS; performing capture analysis still requires a supported host. Linux/Windows execution and downstream client selection frequency were not tested.
REA version
rea-agents 6.7.0, verified source baseline 9d8e7803326a382cbbb3ffdb900f5e93e5442d68. Rechecked after a fresh runtime build of origin/main ccc7da309d7db385d5c6d73b0a3a8e093be33504 (also 6.7.0): still reproduces. The only change to the cited files between these revisions adds unrelated app-resource-session documentation; the cited pcap implementation is unchanged.
Runtime and platform
Node.js v26.12.0; macOS 27.0.1 arm64. Private HOME/XDG/TMPDIR; fixture TShark and Capinfos 4.0.17 version banners. Hopper/Ghidra are not involved.
Target and artifact context
No active binary target. A self-created 24-byte empty little-endian pcap header supplies the required capture path. Source inspection shows the unsupported-host refusal occurs before snapshot acquisition or capture reading, so it does not depend on packet contents. These fixtures establish version admission and the host refusal, not real Wireshark dissection.
Interface
MCP
Earliest failure stage
Setup or provider admission
Relevant output or evidence
Observed before and after capture invocation, with unrelated discovery metadata omitted:
{"open":false,"group":{"names":["inspect_pcap_capture","inspect_pcap_client"],"available":true,"reason":"available","remediation":null}}The client probe succeeds and reports both supplied version banners. Capture invocation returns this error subset:
{
"error": {
"code": "capability_unavailable",
"category": "unsupported_provider",
"message": "Packet summaries require an enforceable native memory bound: Linux with util-linux prlimit, or Windows with owned Job Objects. This host's capture boundary remains unsupported.",
"retryable": false
}
}The CLI control, node scripts/rea.mjs inspect-pcap-capture "$work_dir/capture.pcap" --json under the same isolated environment, exits 1 with the same typed refusal at both revisions. Evidence provenance: observed; local verification: independently reproduced.
Typed outcome or recovery expected
Before execution and after a refused call, discovery should distinguish unsupported capture inspection from the available client probe. Return the host limitation as availability remediation. Proposed restoration check: repeat this MCP sequence on macOS, preserve client-probe success and complete catalog membership, and separately confirm capture inspection remains available on a supported host satisfying its prerequisites. No patch or successful restoration was tested.
Analysis or suspected cause
Source-derived reasoning: src/application/CapabilityInventory.ts:583-584 unconditionally marks pcap-provider tools available. The capture handler at src/server/registerPcapTools.ts:45-81 reaches src/pcap/PcapProvider.ts:519-543, which probes the clients and then calls native-bound preparation before reading the capture. src/pcap/PcapNativeBound.ts:19-35 produces the observed unsupported-host error. The separate readiness check at src/pcap/PcapProvider.ts:314-327 also recognizes the host constraint, but is not the producer of this execution refusal.
Additional context
Related: #5447 concerns the opposite discovery mismatch, where target-independent session tools are advertised unavailable until open_binary. This report concerns capture availability advertised on a host that cannot execute it. #3403 and PR #3407 concern shared TShark selection/version ownership, rather than this operation-specific host fact. The broader lifecycle audit in #4227 requests focused reports for confirmed defects.
Prepared with AI assistance and an independent verifier. NOT_ENOUGH_INFO: last known good version and first affected version were not established.
Activity
Iyanuoluwa007 commentedon Oct 21, 2026
Fix is ready:
fix/pcap-capture-host-availability(commit 49a1c60). The capability inventory treated everypcap-providertool as available. The provider and native-bound checks and the default availability policy now share one host predicate (pcapCaptureHostSupported: Linux or Windows), sobinary_sessionreportsinspect_pcap_captureasunsupported_hoston macOS, whileinspect_pcap_clientstays available. Covered by a CapabilityInventory regression test that fails without the change. I'll open the PR as soon as one of my open PR slots frees up (the 3-open-PR limit).fix(pcap): report capture summaries unsupported where their bound is …
fix(pcap): report capture summaries unsupported where their bound is …
coygeek commentedon Oct 24, 2026
Checked the reported fix on
mainat d87e73f.CapabilityInventory handles inspect_pcap_capture separately through hostRestrictedAvailability with pcapCapture host policy, while inspect_pcap_client remains in the available generic pcap group. The policy and provider use the shared supported-host predicate. A Darwin/Linux/Windows inventory matrix asserts capture unsupported_host on Darwin and client available.
Implementation: CapabilityInventory.ts, CapabilityInventory.test.ts.
The relevant regression checks in CapabilityInventory.test.ts passed in the focused test run on this revision. This closure is based on the current source and those checks; provider fixtures do not establish a real-engine run. Closing as completed on main.