[GH-ISSUE #8281] [Bug] build_call_path cannot reuse retained function dossiers within default MCP limits #6520

Closed
opened 2026-11-01 21:11:53 +00:00 by bsakaguchi · 3 comments
Owner

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

Before submitting

  • I searched 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

With the default MCP input allowance, build_call_path rejected two complete function dossiers produced by the same REA/Ghidra session, before schema validation or execution. The dossiers were for small, 7- and 2-instruction functions in a source-owned arm64 Mach-O.

build_call_path requires full Evidence objects in functions; it rejected retained-Evidence references. This is consistent with its current schema, but leaves an agent unable to reuse these two retained results within the default limit. compare_functions already supports Evidence references.

Reproduction

Using stdio MCP and Ghidra on the fixture below:

  1. open_binary with provider_id: "ghidra".
  2. Obtain dispatch and initial from analyze_function with detail: "complete" for _audit_dispatch and _audit_initial.
  3. Call build_call_path with functions: [dispatch, initial], start: {address: "0x1000003e4"}, and goal: {address: "0x1000003c0"} (addresses are for this build). The response is resource_constraint, max_input_elements: 1024; schema validation and execution did not start.
  4. A call using only [dispatch] succeeds and finds the observed edge. Passing [{kind: "retained-evidence", evidence_id: dispatch.evidence_id}, {kind: "retained-evidence", evidence_id: initial.evidence_id}] instead returns invalid_request, because the schema expects full Evidence.
  5. Restarting with REA_MCP_MAX_INPUT_ELEMENTS=10000 and repeating the same two-dossier call succeeds. The error correctly offers this restart as a workaround.

These controls were each run once. Fixture, compiled for arm64 Mach-O and analyzed statically (not executed):

__attribute__((noinline)) int audit_initial(int x) { return x + 1; }
__attribute__((noinline)) int audit_alternate(int x) { return x - 1; }
int (*volatile audit_slot)(int) = audit_initial;
__attribute__((noinline)) void audit_select_alternate(void) { audit_slot = audit_alternate; }
__attribute__((noinline)) int audit_dispatch(int x) { return audit_slot(x); }
__attribute__((noinline)) int audit_sequence(int x) {
  audit_select_alternate();
  return audit_dispatch(x);
}
int main(void) { return audit_sequence(7); }

Expected behavior

An agent should be able to compose multiple already-retained dossiers without copying them back through the MCP input budget. Consider accepting the existing Evidence-reference contract alongside full inline Evidence, preserving offline inputs, provenance, identity checks, and meaningful errors for unavailable references. This is a proposed design, not a claim that the current schema promises references.

Impact and scope

The two-dossier workflow requires a server restart with a larger configured limit or a different workflow. Other providers, target sizes, CLI behavior, and frequency are untested. The input limit itself remains useful; this report does not propose removing it. Related verifier issue: #8172. A separate computed-call coverage concern is tracked in #8277.

REA version

b43c329df779708e43ae297f498a844e45d9c923 (source build). The call-path schema is unchanged on origin/main at 23de10bb2849cdce8ddbe70504aa7cc57de75a98 (source checked; runtime not rerun there).

Runtime and platform

Node 24.22.1, macOS 26.3 arm64, Ghidra 12.1.4, JDK 21, compact MCP output schema profile.

Target and artifact context

Source-owned arm64 Mach-O executable, SHA-256 f771508a5d2a8afee3419ad1a075c6f4ad499fbb91b2584f49c9c006fb908e05. Digest unchanged after the probes.

Interface

MCP

Earliest failure stage

Request parsing or validation

Relevant output or evidence

The two-dossier default call returned: The MCP tool arguments exceed the configured input element allowance; schema validation and tool execution did not start. Its remediation suggests reducing inputs or restarting with a larger REA_MCP_MAX_INPUT_ELEMENTS.

Source: callPathInputSchema uses an array of full evidenceSchema; compare_functions accepts evidenceInputSchema.

Originally created by @morluto on GitHub (Oct 31, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8281 ### Before submitting - [x] I searched 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 With the default MCP input allowance, `build_call_path` rejected two complete function dossiers produced by the same REA/Ghidra session, before schema validation or execution. The dossiers were for small, 7- and 2-instruction functions in a source-owned arm64 Mach-O. `build_call_path` requires full Evidence objects in `functions`; it rejected retained-Evidence references. This is consistent with its current schema, but leaves an agent unable to reuse these two retained results within the default limit. `compare_functions` already supports Evidence references. ### Reproduction Using stdio MCP and Ghidra on the fixture below: 1. `open_binary` with `provider_id: "ghidra"`. 2. Obtain `dispatch` and `initial` from `analyze_function` with `detail: "complete"` for `_audit_dispatch` and `_audit_initial`. 3. Call `build_call_path` with `functions: [dispatch, initial]`, `start: {address: "0x1000003e4"}`, and `goal: {address: "0x1000003c0"}` (addresses are for this build). The response is `resource_constraint`, `max_input_elements: 1024`; schema validation and execution did not start. 4. A call using only `[dispatch]` succeeds and finds the observed edge. Passing `[{kind: "retained-evidence", evidence_id: dispatch.evidence_id}, {kind: "retained-evidence", evidence_id: initial.evidence_id}]` instead returns `invalid_request`, because the schema expects full Evidence. 5. Restarting with `REA_MCP_MAX_INPUT_ELEMENTS=10000` and repeating the same two-dossier call succeeds. The error correctly offers this restart as a workaround. These controls were each run once. Fixture, compiled for arm64 Mach-O and analyzed statically (not executed): ```c __attribute__((noinline)) int audit_initial(int x) { return x + 1; } __attribute__((noinline)) int audit_alternate(int x) { return x - 1; } int (*volatile audit_slot)(int) = audit_initial; __attribute__((noinline)) void audit_select_alternate(void) { audit_slot = audit_alternate; } __attribute__((noinline)) int audit_dispatch(int x) { return audit_slot(x); } __attribute__((noinline)) int audit_sequence(int x) { audit_select_alternate(); return audit_dispatch(x); } int main(void) { return audit_sequence(7); } ``` ### Expected behavior An agent should be able to compose multiple already-retained dossiers without copying them back through the MCP input budget. Consider accepting the existing Evidence-reference contract alongside full inline Evidence, preserving offline inputs, provenance, identity checks, and meaningful errors for unavailable references. This is a proposed design, not a claim that the current schema promises references. ### Impact and scope The two-dossier workflow requires a server restart with a larger configured limit or a different workflow. Other providers, target sizes, CLI behavior, and frequency are untested. The input limit itself remains useful; this report does not propose removing it. Related verifier issue: #8172. A separate computed-call coverage concern is tracked in #8277. ### REA version `b43c329df779708e43ae297f498a844e45d9c923` (source build). The call-path schema is unchanged on `origin/main` at `23de10bb2849cdce8ddbe70504aa7cc57de75a98` (source checked; runtime not rerun there). ### Runtime and platform Node 24.22.1, macOS 26.3 arm64, Ghidra 12.1.4, JDK 21, compact MCP output schema profile. ### Target and artifact context Source-owned arm64 Mach-O executable, SHA-256 `f771508a5d2a8afee3419ad1a075c6f4ad499fbb91b2584f49c9c006fb908e05`. Digest unchanged after the probes. ### Interface MCP ### Earliest failure stage Request parsing or validation ### Relevant output or evidence The two-dossier default call returned: `The MCP tool arguments exceed the configured input element allowance; schema validation and tool execution did not start.` Its remediation suggests reducing inputs or restarting with a larger `REA_MCP_MAX_INPUT_ELEMENTS`. Source: [`callPathInputSchema`](https://github.com/morluto/rea/blob/b43c329df779708e43ae297f498a844e45d9c923/src/domain/callPathSchemas.ts) uses an array of full `evidenceSchema`; [`compare_functions`](https://github.com/morluto/rea/blob/b43c329df779708e43ae297f498a844e45d9c923/src/domain/functionComparisonSchemas.ts) accepts `evidenceInputSchema`.
bsakaguchi 2026-11-01 21:11:53 +00:00
  • closed this issue
  • added the
    bug
    triage
    labels
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

Looping in @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0 for visibility on the REA tool-design investigation.

<!-- gh-comment-id:6541369885 --> @morluto commented on GitHub (Oct 31, 2026): Looping in @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0 for visibility on the REA tool-design investigation.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

Offline handoff control and limits of the one-dossier workaround

On REA b43c329df779708e43ae297f498a844e45d9c923, I captured the two original real Ghidra 12.1.4 dossiers, ran build_call_path with the larger allowance, exported the Evidence bundle and closed the provider. Two fresh MCP servers then imported the bundle; binary_session reported open: false in each. No provider was reopened for the offline checks.

At the default allowance, the single dispatch dossier produced a found one-edge path, while both complete dossiers were rejected by the input-element allowance and both retained references were rejected by the current schema. The single-dossier answer had a null name for the goal node and cited the dispatch dossier; it did not contain the separately observed goal dossier as a source. With the temporary 10,000-element allowance, both complete dossiers succeeded offline, named the goal _audit_initial, cited both sources and produced the same Evidence ID as the earlier live-session two-dossier call. The target SHA-256 stayed unchanged; no target execution occurred.

So, for this particular one-hop observation, supplying only the dispatch dossier can answer the narrower path question within the default budget, but it is not the same result or provenance as supplying both. A fresh server plus the existing larger-limit option permits the fuller offline handoff after bundle import; it requires a server configuration change, not a provider restart. The observed edge is a static computed-call candidate, not proof of runtime execution or exhaustive possible targets; #8277 tracks that separate coverage issue. This is one bounded example, not a general rule for dropping dossiers.

<!-- gh-comment-id:6544454719 --> @morluto commented on GitHub (Oct 31, 2026): ### Offline handoff control and limits of the one-dossier workaround On REA `b43c329df779708e43ae297f498a844e45d9c923`, I captured the two original real Ghidra 12.1.4 dossiers, ran `build_call_path` with the larger allowance, exported the Evidence bundle and closed the provider. Two fresh MCP servers then imported the bundle; `binary_session` reported `open: false` in each. No provider was reopened for the offline checks. At the default allowance, the single dispatch dossier produced a `found` one-edge path, while both complete dossiers were rejected by the input-element allowance and both retained references were rejected by the current schema. The single-dossier answer had a null name for the goal node and cited the dispatch dossier; it did not contain the separately observed goal dossier as a source. With the temporary 10,000-element allowance, both complete dossiers succeeded offline, named the goal `_audit_initial`, cited both sources and produced the **same Evidence ID** as the earlier live-session two-dossier call. The target SHA-256 stayed unchanged; no target execution occurred. So, for this particular one-hop observation, supplying only the dispatch dossier can answer the narrower path question within the default budget, but it is not the same result or provenance as supplying both. A fresh server plus the existing larger-limit option permits the fuller offline handoff after bundle import; it requires a server configuration change, not a provider restart. The observed edge is a static computed-call candidate, not proof of runtime execution or exhaustive possible targets; #8277 tracks that separate coverage issue. This is one bounded example, not a general rule for dropping dossiers.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

Verified the original fixture on merged main a989c0e458c91af177e097abd7be0fd021b0401d, with real Ghidra 12.1.4, compact stdio MCP and the default input allowance. Two analyze_function(detail: "summary") calls returned parent Evidence IDs; passing those IDs as retained references to build_call_path succeeded and found the observed edge with both source links. No enlarged input setting was used.

After exporting the bundle and closing that connection, a fresh target-free MCP server correctly rejected the references before import, then accepted the original bundle and returned an exactly equal path Evidence object. binary_session remained open: false throughout the offline check. The target and bundle hashes were unchanged; the target was not executed. This independently checks the reported workflow on one fixture and host, not all input profiles or providers. The separate computed-call completeness question in #8277 remains distinct.

<!-- gh-comment-id:6544949685 --> @morluto commented on GitHub (Oct 31, 2026): Verified the original fixture on merged main `a989c0e458c91af177e097abd7be0fd021b0401d`, with real Ghidra 12.1.4, compact stdio MCP and the default input allowance. Two `analyze_function(detail: "summary")` calls returned parent Evidence IDs; passing those IDs as retained references to `build_call_path` succeeded and found the observed edge with both source links. No enlarged input setting was used. After exporting the bundle and closing that connection, a fresh target-free MCP server correctly rejected the references before import, then accepted the original bundle and returned an exactly equal path Evidence object. `binary_session` remained `open: false` throughout the offline check. The target and bundle hashes were unchanged; the target was not executed. This independently checks the reported workflow on one fixture and host, not all input profiles or providers. The separate computed-call completeness question in #8277 remains distinct.
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#6520
No description provided.