[GH-ISSUE #7310] [Bug] binary_session advertises inspect_address_context before a target is open #4344

Closed
opened 2026-10-31 00:49:04 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 26, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/7310

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

In a fresh stdio MCP connection, binary_session {} reports open: false but advertises inspect_address_context with available: true, reason: "available", and remediation: null. Calling it immediately with {"address":"0x1000"} returns isError: true and target_unavailable, directing the caller to open_binary. The sibling get_navigation_context correctly reports target_required in that same connection.

Reproduction

From the built source checkout, save the following as repro.py outside the checkout, then run python3 /path/to/repro.py "$PWD". It uses Python's standard library and the existing node runtime, opens no target, and isolates server configuration in a temporary directory.

import json, os, pathlib, subprocess, sys, tempfile, threading
repo = pathlib.Path(sys.argv[1]).resolve()
with tempfile.TemporaryDirectory(prefix='rea-context-check-') as work:
    env = {'PATH': os.environ['PATH'], 'REA_LOG_LEVEL': 'silent'}
    for key in ['HOME', 'XDG_CONFIG_HOME', 'XDG_DATA_HOME', 'XDG_CACHE_HOME', 'XDG_STATE_HOME', 'TMPDIR']:
        env[key] = str(pathlib.Path(work) / key.lower())
        pathlib.Path(env[key]).mkdir()
    p = subprocess.Popen(['node', str(repo / 'scripts/rea.mjs'), 'mcp'], cwd=work,
                         env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
                         stderr=subprocess.DEVNULL, text=True)
    deadline = threading.Timer(45, p.kill)
    deadline.start()
    def send(message):
        p.stdin.write(json.dumps(message) + '\n')
        p.stdin.flush()
    def request(i, method, params):
        send({'jsonrpc': '2.0', 'id': i, 'method': method, 'params': params})
        for line in p.stdout:
            reply = json.loads(line)
            if reply.get('id') == i:
                return reply['result']
        raise RuntimeError('server ended before response')
    def call(i, name, args):
        reply = request(i, 'tools/call', {'name': name, 'arguments': args})
        return reply, json.loads(reply['content'][0]['text'])
    try:
        request(1, 'initialize', {'protocolVersion': '2025-11-25', 'capabilities': {},
                'clientInfo': {'name': 'context-check', 'version': '1'}})
        send({'jsonrpc': '2.0', 'method': 'notifications/initialized'})
        _, body = call(2, 'binary_session', {})
        status = body['result']
        print(json.dumps({'open': status['open']}))
        for name in ['inspect_address_context', 'get_navigation_context']:
            group = next(g for g in status['tool_availability']['groups'] if name in g['names'])
            print(json.dumps({'name': name, **{k: group[k] for k in ['available', 'reason', 'remediation']}}))
        reply, body = call(3, 'inspect_address_context', {'address': '0x1000'})
        print(json.dumps({'isError': reply.get('isError', False), 'error': body.get('error')}))
    finally:
        p.stdin.close()
        try:
            p.wait(timeout=10)
        except subprocess.TimeoutExpired:
            p.terminate()
            p.wait(timeout=10)
        deadline.cancel()

The reduced script reproduced the mismatch in one fresh process. A fuller replay reproduced it in two additional fresh processes, with both summary and detail: "complete" discovery and with an explicit document as well as the minimal input. Both fuller servers exited 0 after stdin closed; the reduced client script exited 0 but did not record its server's exit code.

Expected behavior

With no target open, discovery should mark inspect_address_context unavailable with target_required and target-opening guidance consistent with its actual invocation. It should remain registered in tools/list.

The applicable discovery contract in docs/mcp-contracts.md:605-618 distinguishes the complete registered catalog from current tool availability and directs clients to use the latter to choose callable operations. The same document at lines 659-663 requires explicit target prerequisites for session-dispatched handlers. This expectation concerns the missing target, rather than a guarantee that every address or provider supports every facet.

Impact and scope

A client following discovery receives a positive readiness fact and then a predictable failure for a valid request. The observed scope is this operation in a fresh no-target session. A practical client-side bypass is to check the correctly reported open flag and withhold this tool when it is false; direct invocation also returns target-opening recovery guidance. No data loss or security boundary crossing was observed. Successful analysis after opening a target, real-provider facets, other hosts, and downstream agent behavior were not tested.

REA version

Server version 6.8.0, existing compiled runtime in a source checkout at e891926534. The runtime was not rebuilt for this report.

Runtime and platform

Node.js v24.22.1; macOS 27.0.1; arm64. Production stdio MCP, isolated HOME/XDG/TMPDIR, REA_LOG_LEVEL=silent. No analysis engine was required.

Target and artifact context

No target or artifact was opened. The address is an input string used to reach the missing-target prerequisite; no memory or artifact bytes are accessed.

Interface

MCP

Earliest failure stage

Transport or result projection

Relevant output or evidence

The reduced script's observed output is:

{"open": false}
{"name": "inspect_address_context", "available": true, "reason": "available", "remediation": null}
{"name": "get_navigation_context", "available": false, "reason": "target_required", "remediation": "Call open_binary with a supported local target."}
{"isError": 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, "remediation": {"action": "No app is open. Ask the user which app to investigate, then call open_binary with its local path."}}}
  • Expected source: the discovery and session-prerequisite passages identified under Expected behavior; src/contracts/sessionToolSchemas.ts:23-26 accepts the reproduction's nonempty address with document omitted.
  • Failure source: the public stdio sequence above; discovery reports available while immediate dispatch returns target_unavailable on the same connection.
  • Evidence provenance: observed for the MCP mismatch; the call path below is source-derived reasoning.
  • Local verification: reproduced.
  • Reproduction completeness: complete for the no-target discovery/invocation mismatch.

Typed outcome or recovery expected

Repeat the same sequence without opening a target: inspect_address_context should report available: false, reason: "target_required", and an open_binary remediation. Preserve the sibling's correct status and the complete tool registration catalog. This is a proposed restoration check; no patch was tested.

Analysis or suspected cause

Source-derived: src/contracts/sessionToolContracts.ts:171-183 explicitly marks navigation as requiring a target but omits that flag for address context. Independently, src/application/CapabilityInventory.ts:401-411,644 returns the generic session workflow's available result before evaluating target availability, whereas its navigation-specific branch at lines 389-396 overlays the target decision. The missing flag alone therefore does not describe the complete path to this result.

Dispatch at src/server/registerSessionTools.ts:256-276 reaches inspectAddressContext. Without an explicit document, src/application/AnalysisDocument.ts:23-40 requests current_document; with a document, src/application/AnalysisContextQueries.ts:98-119,169-172 executes the facets and propagates missing-target errors. The underlying src/application/binary/BinarySessionExecution.ts:66 rejects an absent active target. This explains why unsupported-facet fallback does not make this tool callable without a target.

Additional context

Related closed #5729 fixed navigation's no-target recovery reason; its closure describes navigation-specific target metadata and inventory checks. Navigation now passes the control above while address context still fails, so this report has a different remaining restoration criterion.

Fresh remote-source inspection found the same relevant address-context contract and availability logic on main and the latest published release tag. Those artifacts were not built or executed here. NOT_ENOUGH_INFO: the first affected revision and a last known good version were not established.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: Current machine-readable readiness for one tool contradicts its immediate valid invocation in three fresh processes, causing a bounded discovery-guided planning failure; the handler preserves a typed recovery error.
  • Workaround status: available
  • Workaround basis: The same observed status correctly reports open=false, so a client can gate this tool on that fact and avoid the false readiness entry. Successful post-open provider analysis was not tested.
Originally created by @coygeek on GitHub (Oct 26, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7310 ### 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 Provider or capability discovery ### Observed behavior In a fresh stdio MCP connection, `binary_session {}` reports `open: false` but advertises `inspect_address_context` with `available: true`, `reason: "available"`, and `remediation: null`. Calling it immediately with `{"address":"0x1000"}` returns `isError: true` and `target_unavailable`, directing the caller to `open_binary`. The sibling `get_navigation_context` correctly reports `target_required` in that same connection. ### Reproduction From the built source checkout, save the following as `repro.py` outside the checkout, then run `python3 /path/to/repro.py "$PWD"`. It uses Python's standard library and the existing `node` runtime, opens no target, and isolates server configuration in a temporary directory. ```python import json, os, pathlib, subprocess, sys, tempfile, threading repo = pathlib.Path(sys.argv[1]).resolve() with tempfile.TemporaryDirectory(prefix='rea-context-check-') as work: env = {'PATH': os.environ['PATH'], 'REA_LOG_LEVEL': 'silent'} for key in ['HOME', 'XDG_CONFIG_HOME', 'XDG_DATA_HOME', 'XDG_CACHE_HOME', 'XDG_STATE_HOME', 'TMPDIR']: env[key] = str(pathlib.Path(work) / key.lower()) pathlib.Path(env[key]).mkdir() p = subprocess.Popen(['node', str(repo / 'scripts/rea.mjs'), 'mcp'], cwd=work, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True) deadline = threading.Timer(45, p.kill) deadline.start() def send(message): p.stdin.write(json.dumps(message) + '\n') p.stdin.flush() def request(i, method, params): send({'jsonrpc': '2.0', 'id': i, 'method': method, 'params': params}) for line in p.stdout: reply = json.loads(line) if reply.get('id') == i: return reply['result'] raise RuntimeError('server ended before response') def call(i, name, args): reply = request(i, 'tools/call', {'name': name, 'arguments': args}) return reply, json.loads(reply['content'][0]['text']) try: request(1, 'initialize', {'protocolVersion': '2025-11-25', 'capabilities': {}, 'clientInfo': {'name': 'context-check', 'version': '1'}}) send({'jsonrpc': '2.0', 'method': 'notifications/initialized'}) _, body = call(2, 'binary_session', {}) status = body['result'] print(json.dumps({'open': status['open']})) for name in ['inspect_address_context', 'get_navigation_context']: group = next(g for g in status['tool_availability']['groups'] if name in g['names']) print(json.dumps({'name': name, **{k: group[k] for k in ['available', 'reason', 'remediation']}})) reply, body = call(3, 'inspect_address_context', {'address': '0x1000'}) print(json.dumps({'isError': reply.get('isError', False), 'error': body.get('error')})) finally: p.stdin.close() try: p.wait(timeout=10) except subprocess.TimeoutExpired: p.terminate() p.wait(timeout=10) deadline.cancel() ``` The reduced script reproduced the mismatch in one fresh process. A fuller replay reproduced it in two additional fresh processes, with both summary and `detail: "complete"` discovery and with an explicit `document` as well as the minimal input. Both fuller servers exited 0 after stdin closed; the reduced client script exited 0 but did not record its server's exit code. ### Expected behavior With no target open, discovery should mark `inspect_address_context` unavailable with `target_required` and target-opening guidance consistent with its actual invocation. It should remain registered in `tools/list`. The applicable discovery contract in `docs/mcp-contracts.md:605-618` distinguishes the complete registered catalog from current tool availability and directs clients to use the latter to choose callable operations. The same document at lines 659-663 requires explicit target prerequisites for session-dispatched handlers. This expectation concerns the missing target, rather than a guarantee that every address or provider supports every facet. ### Impact and scope A client following discovery receives a positive readiness fact and then a predictable failure for a valid request. The observed scope is this operation in a fresh no-target session. A practical client-side bypass is to check the correctly reported `open` flag and withhold this tool when it is false; direct invocation also returns target-opening recovery guidance. No data loss or security boundary crossing was observed. Successful analysis after opening a target, real-provider facets, other hosts, and downstream agent behavior were not tested. ### REA version Server version 6.8.0, existing compiled runtime in a source checkout at e89192653402222c5b099216f0d83a2d1bceace0. The runtime was not rebuilt for this report. ### Runtime and platform Node.js v24.22.1; macOS 27.0.1; arm64. Production stdio MCP, isolated HOME/XDG/TMPDIR, `REA_LOG_LEVEL=silent`. No analysis engine was required. ### Target and artifact context No target or artifact was opened. The address is an input string used to reach the missing-target prerequisite; no memory or artifact bytes are accessed. ### Interface MCP ### Earliest failure stage Transport or result projection ### Relevant output or evidence The reduced script's observed output is: ```json {"open": false} {"name": "inspect_address_context", "available": true, "reason": "available", "remediation": null} {"name": "get_navigation_context", "available": false, "reason": "target_required", "remediation": "Call open_binary with a supported local target."} {"isError": 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, "remediation": {"action": "No app is open. Ask the user which app to investigate, then call open_binary with its local path."}}} ``` - Expected source: the discovery and session-prerequisite passages identified under Expected behavior; `src/contracts/sessionToolSchemas.ts:23-26` accepts the reproduction's nonempty address with document omitted. - Failure source: the public stdio sequence above; discovery reports available while immediate dispatch returns `target_unavailable` on the same connection. - Evidence provenance: observed for the MCP mismatch; the call path below is source-derived reasoning. - Local verification: reproduced. - Reproduction completeness: complete for the no-target discovery/invocation mismatch. ### Typed outcome or recovery expected Repeat the same sequence without opening a target: `inspect_address_context` should report `available: false`, `reason: "target_required"`, and an `open_binary` remediation. Preserve the sibling's correct status and the complete tool registration catalog. This is a proposed restoration check; no patch was tested. ### Analysis or suspected cause Source-derived: `src/contracts/sessionToolContracts.ts:171-183` explicitly marks navigation as requiring a target but omits that flag for address context. Independently, `src/application/CapabilityInventory.ts:401-411,644` returns the generic session workflow's `available` result before evaluating target availability, whereas its navigation-specific branch at lines 389-396 overlays the target decision. The missing flag alone therefore does not describe the complete path to this result. Dispatch at `src/server/registerSessionTools.ts:256-276` reaches `inspectAddressContext`. Without an explicit document, `src/application/AnalysisDocument.ts:23-40` requests `current_document`; with a document, `src/application/AnalysisContextQueries.ts:98-119,169-172` executes the facets and propagates missing-target errors. The underlying `src/application/binary/BinarySessionExecution.ts:66` rejects an absent active target. This explains why unsupported-facet fallback does not make this tool callable without a target. ### Additional context Related closed [#5729](https://github.com/morluto/rea/issues/5729) fixed navigation's no-target recovery reason; its closure describes navigation-specific target metadata and inventory checks. Navigation now passes the control above while address context still fails, so this report has a different remaining restoration criterion. Fresh remote-source inspection found the same relevant address-context contract and availability logic on main and the latest published release tag. Those artifacts were not built or executed here. NOT_ENOUGH_INFO: the first affected revision and a last known good version were not established. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: Current machine-readable readiness for one tool contradicts its immediate valid invocation in three fresh processes, causing a bounded discovery-guided planning failure; the handler preserves a typed recovery error. - Workaround status: available - Workaround basis: The same observed status correctly reports open=false, so a client can gate this tool on that fact and avoid the false readiness entry. Successful post-open provider analysis was not tested.
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#4344
No description provided.