[GH-ISSUE #6135] [Bug] MCP inspect_plist rejects an explicit path with no open target, although its contract accepts any local plist path #3763

Closed
opened 2026-10-31 00:43:48 +00:00 by bsakaguchi · 3 comments
Owner

Originally created by @minjunkim-dev on GitHub (Oct 21, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/6135

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

MCP or agent integration

Observed behavior

The MCP inspect_plist description says it parses Info.plist "from the active artifact by default, or pass any local plist path". In its input schema path is optional, and the only example passes just path. With no target open, a call with an explicit path fails with target_unavailable ("No app is open… call open_binary"). binary_session {} in the same connection also reports inspect_plist as available: false, reason: "target_required".

The open target is not used to resolve an explicit path. After open_binary on /System/Applications/Calculator.app, the same connection reads an unrelated bundle's plist correctly: inspect_plist {"path": "/System/Applications/Chess.app/Contents/Info.plist"} returns CFBundleIdentifier: com.apple.Chess. The session only gates the call.

With no session at all, the call is refused before any provider runs: BinarySession#execute calls prepareSessionExecution (src/application/binary/BinarySessionExecution.ts), which returns NoBinaryOpenError when active === undefined. This is unchanged on main at 01788ba.

Related, but not the same: #1166 (closed; target-dependent tools advertised as available with no target), #5447 and #5729 (discovery prerequisites that don't match dispatch).

Reproduction

No fixture is needed. Python 3 standard library only:

import json, subprocess
p = subprocess.Popen(["npx", "-y", "rea-agents@6.7.0", "mcp"], stdin=subprocess.PIPE,
                     stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True)
def call(i, method, params):
    p.stdin.write(json.dumps({"jsonrpc": "2.0", "id": i, "method": method, "params": params}) + "\n"); p.stdin.flush()
    while True:
        m = json.loads(p.stdout.readline())
        if m.get("id") == i: return m
call(1, "initialize", {"protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": {"name": "repro", "version": "1"}})
p.stdin.write(json.dumps({"jsonrpc": "2.0", "method": "notifications/initialized"}) + "\n"); p.stdin.flush()
r = call(2, "tools/call", {"name": "inspect_plist",
         "arguments": {"path": "/System/Applications/Calculator.app/Contents/Info.plist"}})["result"]
print(r.get("isError"), r["content"][0]["text"])
p.terminate()

Output:

True {"error":{"code":"target_unavailable","category":"unavailable","message":"No app is open. Ask the user which app to investigate, then call open_binary with its local path.","retryable":false,...}}

binary_session {} before the call reports:

{"available": false, "reason": "target_required", "remediation": "Call open_binary with a supported local target."}

Adding open_binary {"path": "/System/Applications/Calculator.app"} before the inspect_plist call makes the same call succeed.

On 6.7.0 the same refusal also reproduced through the Claude Code, Codex (CLI and desktop app) and Cursor CLI MCP clients, and on 6.5.0 through Claude Code.

Expected behavior

With an explicit path and no open target, MCP inspect_plist parses that file, as the tool description and input example state, and discovery reports it available in that state. If an open target is intended to be required, the description and example should say so instead.

Impact and scope

Agents that follow the tool description call inspect_plist with a path first, get target_unavailable, and are directed to open_binary. They then have to open some app, unrelated to the file, only to read one plist by path. The CLI (rea inspect-plist <path>) is not affected because it opens the given path for that one call. I have not checked other session-routed tools that also take an explicit path.

REA version

6.7.0 (npm rea-agents@6.7.0); also 6.5.0. The gate code is unchanged on main at 01788ba; I read it there but did not build and run main.

Runtime and platform

macOS 27.0.1 arm64, Node.js v24.22.0, stdio MCP via npx

Target and artifact context

/System/Applications/Calculator.app/Contents/Info.plist (any readable Info.plist reproduces it)

Interface

MCP

Originally created by @minjunkim-dev on GitHub (Oct 21, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6135 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area MCP or agent integration ### Observed behavior The MCP `inspect_plist` description says it parses Info.plist "from the active artifact by default, or pass any local plist path". In its input schema `path` is optional, and the only example passes just `path`. With no target open, a call with an explicit `path` fails with `target_unavailable` ("No app is open… call open_binary"). `binary_session {}` in the same connection also reports `inspect_plist` as `available: false`, `reason: "target_required"`. The open target is not used to resolve an explicit path. After `open_binary` on `/System/Applications/Calculator.app`, the same connection reads an unrelated bundle's plist correctly: `inspect_plist {"path": "/System/Applications/Chess.app/Contents/Info.plist"}` returns `CFBundleIdentifier: com.apple.Chess`. The session only gates the call. With no session at all, the call is refused before any provider runs: `BinarySession#execute` calls `prepareSessionExecution` (`src/application/binary/BinarySessionExecution.ts`), which returns `NoBinaryOpenError` when `active === undefined`. This is unchanged on `main` at 01788ba. Related, but not the same: #1166 (closed; target-dependent tools advertised as available with no target), #5447 and #5729 (discovery prerequisites that don't match dispatch). ### Reproduction No fixture is needed. Python 3 standard library only: ```python import json, subprocess p = subprocess.Popen(["npx", "-y", "rea-agents@6.7.0", "mcp"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True) def call(i, method, params): p.stdin.write(json.dumps({"jsonrpc": "2.0", "id": i, "method": method, "params": params}) + "\n"); p.stdin.flush() while True: m = json.loads(p.stdout.readline()) if m.get("id") == i: return m call(1, "initialize", {"protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": {"name": "repro", "version": "1"}}) p.stdin.write(json.dumps({"jsonrpc": "2.0", "method": "notifications/initialized"}) + "\n"); p.stdin.flush() r = call(2, "tools/call", {"name": "inspect_plist", "arguments": {"path": "/System/Applications/Calculator.app/Contents/Info.plist"}})["result"] print(r.get("isError"), r["content"][0]["text"]) p.terminate() ``` Output: ``` True {"error":{"code":"target_unavailable","category":"unavailable","message":"No app is open. Ask the user which app to investigate, then call open_binary with its local path.","retryable":false,...}} ``` `binary_session {}` before the call reports: ```json {"available": false, "reason": "target_required", "remediation": "Call open_binary with a supported local target."} ``` Adding `open_binary {"path": "/System/Applications/Calculator.app"}` before the `inspect_plist` call makes the same call succeed. On 6.7.0 the same refusal also reproduced through the Claude Code, Codex (CLI and desktop app) and Cursor CLI MCP clients, and on 6.5.0 through Claude Code. ### Expected behavior With an explicit `path` and no open target, MCP `inspect_plist` parses that file, as the tool description and input example state, and discovery reports it available in that state. If an open target is intended to be required, the description and example should say so instead. ### Impact and scope Agents that follow the tool description call `inspect_plist` with a path first, get `target_unavailable`, and are directed to `open_binary`. They then have to open some app, unrelated to the file, only to read one plist by path. The CLI (`rea inspect-plist <path>`) is not affected because it opens the given path for that one call. I have not checked other session-routed tools that also take an explicit path. ### REA version 6.7.0 (npm `rea-agents@6.7.0`); also 6.5.0. The gate code is unchanged on `main` at 01788ba; I read it there but did not build and run main. ### Runtime and platform macOS 27.0.1 arm64, Node.js v24.22.0, stdio MCP via `npx` ### Target and artifact context `/System/Applications/Calculator.app/Contents/Info.plist` (any readable Info.plist reproduces it) ### Interface MCP
Author
Owner

@XinwangTao commented on GitHub (Oct 22, 2026):

确认,问题出在 session 门控的语义被过度扩大:契约写明"传任意本地路径",显式 path 的调用就不应该依赖 active session 才能执行——"open 了 Calculator 后读 Chess 的 plist 也能成功"恰好证明 open target 根本不参与路径解析,纯是 gate 在拦人。建议修复时把 target_required 的判定拆成两档:无 path 且需解析 active artifact 才算 target_required;有显式 path 就放行。同时值得把其它带 path 参数的 inspect 系工具(inspect_managed_members、inspect_web_network_capture 等)一起审计一遍是否有同款 gate 误拦;顺带优化一下错误文案,在真的需要 open 时提示"传 path 或先 open_binary",而不是笼统的 No app is open。

<!-- gh-comment-id:6330409669 --> @XinwangTao commented on GitHub (Oct 22, 2026): 确认,问题出在 session 门控的语义被过度扩大:契约写明"传任意本地路径",显式 path 的调用就不应该依赖 active session 才能执行——"open 了 Calculator 后读 Chess 的 plist 也能成功"恰好证明 open target 根本不参与路径解析,纯是 gate 在拦人。建议修复时把 target_required 的判定拆成两档:无 path 且需解析 active artifact 才算 target_required;有显式 path 就放行。同时值得把其它带 path 参数的 inspect 系工具(inspect_managed_members、inspect_web_network_capture 等)一起审计一遍是否有同款 gate 误拦;顺带优化一下错误文案,在真的需要 open 时提示"传 path 或先 open_binary",而不是笼统的 No app is open。
Author
Owner

@minjunkim-dev commented on GitHub (Oct 22, 2026):

Thanks for confirming. PR #6139 implements the first point: an absolute path is read without an open target, while a relative or missing selection still requires one, and binary_session reports inspect_plist available in a closed session.

On auditing other path-taking tools: I called all 26 read-only inspect_* tools that accept path with no target open. Only inspect_keyed_archive refused with "No app is open", and its contract reads a path relative to the active app bundle, so that is intended. The managed tools (inspect_managed_artifact, inspect_managed_members, …) already open an explicit path on their own. I found no other contract/behavior mismatch of this kind.

The shared "No app is open" wording is used across many tools, so I've kept it out of this fix; it could be a separate change if maintainers want it.

<!-- gh-comment-id:6331019229 --> @minjunkim-dev commented on GitHub (Oct 22, 2026): Thanks for confirming. PR #6139 implements the first point: an absolute `path` is read without an open target, while a relative or missing selection still requires one, and `binary_session` reports `inspect_plist` available in a closed session. On auditing other path-taking tools: I called all 26 read-only `inspect_*` tools that accept `path` with no target open. Only `inspect_keyed_archive` refused with "No app is open", and its contract reads a path relative to the active app bundle, so that is intended. The managed tools (`inspect_managed_artifact`, `inspect_managed_members`, …) already open an explicit path on their own. I found no other contract/behavior mismatch of this kind. The shared "No app is open" wording is used across many tools, so I've kept it out of this fix; it could be a separate change if maintainers want it.
Author
Owner

@minjunkim-dev commented on GitHub (Oct 24, 2026):

Resolved by aad3d88cc: the inspect_plist contract and docs now state that an open binary or bundle-resource session is required even when path is explicit, and a test pins the target_unavailable result and target_required discovery. The description and behavior now agree, so I'm closing this. PR #6139 took the opposite approach and is closed.

<!-- gh-comment-id:6383573705 --> @minjunkim-dev commented on GitHub (Oct 24, 2026): Resolved by aad3d88cc: the `inspect_plist` contract and docs now state that an open binary or bundle-resource session is required even when `path` is explicit, and a test pins the `target_unavailable` result and `target_required` discovery. The description and behavior now agree, so I'm closing this. PR #6139 took the opposite approach and is closed.
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#3763
No description provided.