[PR #5793] [MERGED] fix(mcp): report Linux-only integrations as unsupported_host off their hosts #7065

Closed
opened 2026-11-01 21:45:07 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/5793
Author: @Lew1sWong
Created: 10/21/2026
Status: ✅ Merged
Merged: 10/22/2026
Merged by: @morluto

Base: main ← Head: fix/linux-only-tools-unsupported-host


📝 Commits (4)

  • b493848 fix(mcp): report Linux-only integrations as unsupported_host off their hosts
  • 91893fe refactor(mcp): share provider host checks with session discovery
  • e88017c fix(mcp): keep caller host restrictions beside observed ones
  • ba01891 test(pcap): expect unsupported_host for packet tools off Linux

📊 Changes

18 files changed (+531 additions, -89 deletions)

View changed files

📝 src/application/CapabilityInventory.test.ts (+53 -0)
📝 src/application/CapabilityInventory.ts (+80 -51)
📝 src/captures/TsharkCaptureProvider.ts (+5 -1)
📝 src/composition/binaryDiagnostics.ts (+3 -0)
📝 src/composition/captures.ts (+7 -1)
📝 src/composition/evm.ts (+2 -1)
📝 src/composition/firmware.ts (+6 -1)
📝 src/composition/javascriptRecovery.ts (+6 -1)
📝 src/composition/signals.ts (+7 -1)
📝 src/evm/EvmoleInterfaceProvider.ts (+8 -2)
📝 src/firmware/FirmwareCommand.ts (+5 -1)
📝 src/javascript/recovery/WakaruCommand.ts (+7 -2)
📝 src/native/pwntools/PwntoolsDecoder.ts (+7 -1)
📝 src/server/createServer.ts (+79 -14)
📝 src/server/sessionAvailabilityPolicy.ts (+39 -9)
📝 src/signals/SigrokRecordingProvider.ts (+5 -1)
📝 tests/boundary/mcp/packetCaptureAvailability.test.ts (+6 -2)
➕ tests/process-global/hostRestrictedAvailabilityMcp.test.ts (+206 -0)

📄 Description

Summary

Fixes #5730. On hosts outside their verified platforms, target-free binary_session {} discovery now reports the Linux-only optional integrations as reason: "unsupported_host" instead of provider_missing. They stay unavailable and keep their existing remediation.

Problem and expected behavior

installSessionToolAvailability (src/server/createServer.ts) folded the host check into each integration's enabled flag, for example linux && isAbsolute(REA_SIGROK_COMMAND). Discovery could not tell "wrong host" from "not configured", and every disabled branch in CapabilityInventory hard-coded provider_missing. Their execution guards refuse those hosts whatever is configured, so the reason pointed callers to a provider install that cannot help.

Expected, per the issue: the tools stay unavailable, with reason: "unsupported_host" and their host requirements.

Change and scope

  • Host owner. Each provider exports its verified-host predicate and uses it in its own execution guard:

    • tsharkHostSupported
    • sigrokHostSupported
    • pwntoolsHostSupported
    • evmHostSupported (also used by selectEvmLimiter)
    • firmwareHostSupported
    • wakaruHostSupported

    The composition modules re-export them, following the existing evmLimiterAvailability pattern. Discovery and execution therefore read one rule, and createServer no longer has its own linux / linuxX64 checks.

  • Producing boundary. createServer records hostUnsupported per integration from those predicates: true when the host is outside the integration's verified host and no service was injected. Its *Enabled flags use the same predicates; for packet capture the configuration half stays tsharkLocatable, which accepts an absolute REA_TSHARK_COMMAND or a TShark on PATH. Injected services keep owning their availability on any host; the existing caller-injected EVM test covers that.

  • Policy. AvailabilityPolicy.hostUnsupported carries the fact. sessionAvailabilityPolicy merges it into the returned policy whether or not an embedder supplied one, per integration: either the caller or the observed host can mark an integration unsupported, and neither clears the other.

  • Consumer. One hostRestrictedAvailability helper in CapabilityInventory checks the host before configuration, then falls back to the existing available or provider_missing result with the same remediation text. For EVM, the limiter probe is consulted only after the host and profile checks pass.

  • Scope beyond the five reported tools. The issue reported five tools: sigrok, pwntools and EVM. TShark packet inspection, Binwalk/Unblob firmware and Wakaru recovery have the same folded flag and the same Linux execution guards (TsharkCaptureProvider, FirmwareCommand, WakaruCommand), so they are fixed by the same change. That makes 10 tools in 7 discovery groups.

Contribution scope: ordinary fix within existing boundaries; maintainer scope decision not applicable.

Contract and boundary impact

  • Semantic owner and earliest changed stage: each provider owns its host predicate. createServer builds the session availability policy from those predicates, and CapabilityInventory consumes it.

  • Contribution scope fit and linked maintainer decision: not applicable (bug fix).

  • CLI and MCP/tool-catalog contract: no schema change. unsupported_host is an existing tool_availability reason. Only the reported reason changes, and only on hosts the integrations cannot run on.

  • Provider, bridge, target-format, or platform compatibility: Linux (and Linux x64, for the x64-only integrations) behaves as before.

  • Evidence, artifact, provenance, or reconstruction contract: none.

  • Target selection, authority, upstream behavior, and cleanup details: discovery still runs nothing. Execution guards keep their semantics; they now call the shared predicates.

  • Generated metadata, package, or installation impact: none.

  • Documentation or usability only; no target interaction.

Evidence and regression coverage

  • Tests added:

    • tests/process-global/hostRestrictedAvailabilityMcp.test.ts: public MCP workflow through the real createServer and binary_session {}. It emulates process.platform and process.arch for darwin/arm64, linux/arm64 and linux/x64, which is why it lives under tests/process-global/. Every tool's command variable is set to an absolute path. Expected results:

      • outside the verified host: unsupported_host;
      • on it: available;
      • EVM on emulated linux/x64: provider_missing, because its configured limiter is absent.

      It also checks that a configured availability policy keeps both an observed restriction (emulated darwin) and the caller's own restriction (emulated linux/x64), and that the issue's three direct calls are refused on emulated darwin.

    • tests/boundary/mcp/packetCaptureAvailability.test.ts: its host-independent PATH case now expects provider_missing on Linux and unsupported_host elsewhere.

    • src/application/CapabilityInventory.test.ts: host-independent cases for all 10 tools. An unsupported host wins over configuration; otherwise provider_missing or available.

  • Base reproduction:

    • The issue's MCP probe on 7d8e4e433 (macOS arm64) reported the five tools as provider_missing.
    • The extended probe on this branch reports all 10 tools as unsupported_host. The three direct calls still return the same capability_unavailable host refusals.
    • The original MCP test failed on the unmodified source with inspect_packet_capture: "provider_missing" instead of "unsupported_host".
    • Mutation checks on the new test:
      • with the createServer host mapping replaced by {}, 3 of 5 cases fail (darwin, linux/arm64, configured policy);
      • with the merge moved back into the default-policy closure, the configured-policy case fails;
      • with the observed map replacing the caller's map, the caller-restriction case fails.
  • User-visible MCP output (macOS arm64, abridged):

    [decode_signal_recording, inspect_signal_decoders] available=false reason=unsupported_host
    [inspect_binary_layout, inspect_recorded_crash]    available=false reason=unsupported_host
    [inspect_evm_interface]                            available=false reason=unsupported_host
    [inspect_packet_capture, inspect_packet_fields]    available=false reason=unsupported_host
    [inspect_firmware_regions] / [extract_firmware]    available=false reason=unsupported_host
    [recover_javascript_sources]                       available=false reason=unsupported_host
    
  • Remaining proof gaps:

    • Linux hosts are emulated through process.platform and process.arch; no real Linux or Windows run was done locally.
    • The Windows result is source-derived: every predicate requires Linux.

Validation performed

Node 24.18.0, macOS 27.0 arm64. Head ba0189125 on 357100242.

  • npm run check:fast — passed (typecheck, lint 0 errors)
  • npm run knip — passed
  • npm run docs:check — passed
  • npm run test:focused -- on every test under src/application, src/server, src/contracts, src/composition, the six provider directories and tests/boundary/evm, plus every boundary and process-global test that uses createServer, binary_session, tool_availability or one of the six providers — 396 files: 381 passed, 15 skipped by platform, 0 failed.
  • Extended MCP probe from the issue — 10 tools report unsupported_host; the server exits 0.
  • Full npm run check:pr — not run

Compatibility, safety, and release

  • Breaking changes or migration steps: none. Clients that keyed on provider_missing for these tools on non-Linux hosts now see unsupported_host, which the contract already defines.
  • Real Hopper/Ghidra, browser, or OS coverage: real macOS MCP server only.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: discovery only; no execution or authority change.

Author readiness

Human owner: @Lew1sWong

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/5793 **Author:** [@Lew1sWong](https://github.com/Lew1sWong) **Created:** 10/21/2026 **Status:** ✅ Merged **Merged:** 10/22/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/linux-only-tools-unsupported-host` --- ### 📝 Commits (4) - [`b493848`](https://github.com/morluto/rea/commit/b493848db699d3e719278f1c4e0b94038514dd7a) fix(mcp): report Linux-only integrations as unsupported_host off their hosts - [`91893fe`](https://github.com/morluto/rea/commit/91893fe50ddf17671ce965136b3416b1311efbea) refactor(mcp): share provider host checks with session discovery - [`e88017c`](https://github.com/morluto/rea/commit/e88017cbd0c8b3ebe07781bae09980676971e6df) fix(mcp): keep caller host restrictions beside observed ones - [`ba01891`](https://github.com/morluto/rea/commit/ba018912557f765849cf3d08d2c353538bb39e92) test(pcap): expect unsupported_host for packet tools off Linux ### 📊 Changes **18 files changed** (+531 additions, -89 deletions) <details> <summary>View changed files</summary> 📝 `src/application/CapabilityInventory.test.ts` (+53 -0) 📝 `src/application/CapabilityInventory.ts` (+80 -51) 📝 `src/captures/TsharkCaptureProvider.ts` (+5 -1) 📝 `src/composition/binaryDiagnostics.ts` (+3 -0) 📝 `src/composition/captures.ts` (+7 -1) 📝 `src/composition/evm.ts` (+2 -1) 📝 `src/composition/firmware.ts` (+6 -1) 📝 `src/composition/javascriptRecovery.ts` (+6 -1) 📝 `src/composition/signals.ts` (+7 -1) 📝 `src/evm/EvmoleInterfaceProvider.ts` (+8 -2) 📝 `src/firmware/FirmwareCommand.ts` (+5 -1) 📝 `src/javascript/recovery/WakaruCommand.ts` (+7 -2) 📝 `src/native/pwntools/PwntoolsDecoder.ts` (+7 -1) 📝 `src/server/createServer.ts` (+79 -14) 📝 `src/server/sessionAvailabilityPolicy.ts` (+39 -9) 📝 `src/signals/SigrokRecordingProvider.ts` (+5 -1) 📝 `tests/boundary/mcp/packetCaptureAvailability.test.ts` (+6 -2) ➕ `tests/process-global/hostRestrictedAvailabilityMcp.test.ts` (+206 -0) </details> ### 📄 Description ## Summary Fixes #5730. On hosts outside their verified platforms, target-free `binary_session {}` discovery now reports the Linux-only optional integrations as `reason: "unsupported_host"` instead of `provider_missing`. They stay unavailable and keep their existing remediation. ## Problem and expected behavior `installSessionToolAvailability` (`src/server/createServer.ts`) folded the host check into each integration's enabled flag, for example `linux && isAbsolute(REA_SIGROK_COMMAND)`. Discovery could not tell "wrong host" from "not configured", and every disabled branch in `CapabilityInventory` hard-coded `provider_missing`. Their execution guards refuse those hosts whatever is configured, so the reason pointed callers to a provider install that cannot help. Expected, per the issue: the tools stay unavailable, with `reason: "unsupported_host"` and their host requirements. ## Change and scope - **Host owner.** Each provider exports its verified-host predicate and uses it in its own execution guard: - `tsharkHostSupported` - `sigrokHostSupported` - `pwntoolsHostSupported` - `evmHostSupported` (also used by `selectEvmLimiter`) - `firmwareHostSupported` - `wakaruHostSupported` The composition modules re-export them, following the existing `evmLimiterAvailability` pattern. Discovery and execution therefore read one rule, and `createServer` no longer has its own `linux` / `linuxX64` checks. - **Producing boundary.** `createServer` records `hostUnsupported` per integration from those predicates: true when the host is outside the integration's verified host and no service was injected. Its `*Enabled` flags use the same predicates; for packet capture the configuration half stays `tsharkLocatable`, which accepts an absolute `REA_TSHARK_COMMAND` or a TShark on `PATH`. Injected services keep owning their availability on any host; the existing caller-injected EVM test covers that. - **Policy.** `AvailabilityPolicy.hostUnsupported` carries the fact. `sessionAvailabilityPolicy` merges it into the returned policy whether or not an embedder supplied one, per integration: either the caller or the observed host can mark an integration unsupported, and neither clears the other. - **Consumer.** One `hostRestrictedAvailability` helper in `CapabilityInventory` checks the host before configuration, then falls back to the existing `available` or `provider_missing` result with the same remediation text. For EVM, the limiter probe is consulted only after the host and profile checks pass. - **Scope beyond the five reported tools.** The issue reported five tools: sigrok, pwntools and EVM. TShark packet inspection, Binwalk/Unblob firmware and Wakaru recovery have the same folded flag and the same Linux execution guards (`TsharkCaptureProvider`, `FirmwareCommand`, `WakaruCommand`), so they are fixed by the same change. That makes 10 tools in 7 discovery groups. Contribution scope: ordinary fix within existing boundaries; maintainer scope decision not applicable. ## Contract and boundary impact - Semantic owner and earliest changed stage: each provider owns its host predicate. `createServer` builds the session availability policy from those predicates, and `CapabilityInventory` consumes it. - Contribution scope fit and linked maintainer decision: not applicable (bug fix). - CLI and MCP/tool-catalog contract: no schema change. `unsupported_host` is an existing `tool_availability` reason. Only the reported reason changes, and only on hosts the integrations cannot run on. - Provider, bridge, target-format, or platform compatibility: Linux (and Linux x64, for the x64-only integrations) behaves as before. - Evidence, artifact, provenance, or reconstruction contract: none. - Target selection, authority, upstream behavior, and cleanup details: discovery still runs nothing. Execution guards keep their semantics; they now call the shared predicates. - Generated metadata, package, or installation impact: none. - [x] Documentation or usability only; no target interaction. ## Evidence and regression coverage - Tests added: - `tests/process-global/hostRestrictedAvailabilityMcp.test.ts`: public MCP workflow through the real `createServer` and `binary_session {}`. It emulates `process.platform` and `process.arch` for darwin/arm64, linux/arm64 and linux/x64, which is why it lives under `tests/process-global/`. Every tool's command variable is set to an absolute path. Expected results: - outside the verified host: `unsupported_host`; - on it: `available`; - EVM on emulated linux/x64: `provider_missing`, because its configured limiter is absent. It also checks that a configured availability policy keeps both an observed restriction (emulated darwin) and the caller's own restriction (emulated linux/x64), and that the issue's three direct calls are refused on emulated darwin. - `tests/boundary/mcp/packetCaptureAvailability.test.ts`: its host-independent PATH case now expects `provider_missing` on Linux and `unsupported_host` elsewhere. - `src/application/CapabilityInventory.test.ts`: host-independent cases for all 10 tools. An unsupported host wins over configuration; otherwise `provider_missing` or `available`. - Base reproduction: - The issue's MCP probe on `7d8e4e433` (macOS arm64) reported the five tools as `provider_missing`. - The extended probe on this branch reports all 10 tools as `unsupported_host`. The three direct calls still return the same `capability_unavailable` host refusals. - The original MCP test failed on the unmodified source with `inspect_packet_capture: "provider_missing"` instead of `"unsupported_host"`. - Mutation checks on the new test: - with the `createServer` host mapping replaced by `{}`, 3 of 5 cases fail (darwin, linux/arm64, configured policy); - with the merge moved back into the default-policy closure, the configured-policy case fails; - with the observed map replacing the caller's map, the caller-restriction case fails. - User-visible MCP output (macOS arm64, abridged): ```text [decode_signal_recording, inspect_signal_decoders] available=false reason=unsupported_host [inspect_binary_layout, inspect_recorded_crash] available=false reason=unsupported_host [inspect_evm_interface] available=false reason=unsupported_host [inspect_packet_capture, inspect_packet_fields] available=false reason=unsupported_host [inspect_firmware_regions] / [extract_firmware] available=false reason=unsupported_host [recover_javascript_sources] available=false reason=unsupported_host ``` - Remaining proof gaps: - Linux hosts are emulated through `process.platform` and `process.arch`; no real Linux or Windows run was done locally. - The Windows result is source-derived: every predicate requires Linux. ## Validation performed Node 24.18.0, macOS 27.0 arm64. Head `ba0189125` on `357100242`. - `npm run check:fast` — passed (typecheck, lint 0 errors) - `npm run knip` — passed - `npm run docs:check` — passed - `npm run test:focused --` on every test under `src/application`, `src/server`, `src/contracts`, `src/composition`, the six provider directories and `tests/boundary/evm`, plus every boundary and process-global test that uses `createServer`, `binary_session`, `tool_availability` or one of the six providers — 396 files: 381 passed, 15 skipped by platform, 0 failed. - Extended MCP probe from the issue — 10 tools report `unsupported_host`; the server exits 0. - Full `npm run check:pr` — not run ## Compatibility, safety, and release - Breaking changes or migration steps: none. Clients that keyed on `provider_missing` for these tools on non-Linux hosts now see `unsupported_host`, which the contract already defines. - Real Hopper/Ghidra, browser, or OS coverage: real macOS MCP server only. - Package or release metadata impact: none. - Security, privacy, process, or containment review: discovery only; no execution or authority change. ## Author readiness Human owner: @Lew1sWong - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-11-01 21:45:07 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#7065
No description provided.