[GH-ISSUE #3335] [Bug] analyze_function repeats the initial MCP progress number #1205

Closed
opened 2026-10-15 18:31:59 +00:00 by bsakaguchi · 0 comments
Owner

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

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

An analyze_function MCP request with a progress token emits progress: 1 for both its start and completion notifications, even when the function result succeeds. The same connection's current_address request emits the expected sequence 1, 2. The command exits successfully and both tool results succeed.

Reproduction

  1. Start from a clean checkout and install the locked dependencies and build the runtime:
git clone https://github.com/morluto/rea.git
cd rea
git checkout 8dde6370d0809ad04cda3342d4e6f290f48aa063
npm ci
npm run build:cached
  1. From the checkout root, run the following exact command. It calls the registered MCP tools through the pinned SDK using a local injected provider that returns the repository's canonical complete function dossier. All input is inline or imported from the built repository example; no additional input file or analysis engine is required.
node --input-type=module <<'JS'
import { Client, InMemoryTransport } from '@modelcontextprotocol/client';
import { createServer } from './dist/server/createServer.js';
import { createAnalysisExecution } from './dist/application/AnalysisProvider.js';
import { FUNCTION_COMPARISON_EXAMPLE } from './dist/contracts/functionComparisonExample.js';
const analysis = {
  execute: async operation => ({
    ok: true,
    value: createAnalysisExecution(
      operation === 'analyze_function'
        ? FUNCTION_COMPARISON_EXAMPLE.left.normalized_result : '0x1000',
      { id: 'fixture', name: 'Fixture', version: '1' }
    )
  })
};
const server = createServer({ kind: 'fixed', analysis });
const client = new Client({ name: 'progress-reproduction', version: '1' });
const [ct, st] = InMemoryTransport.createLinkedPair();
try {
  await server.connect(st);
  await client.connect(ct);
  for (const name of ['current_address', 'analyze_function']) {
    const updates = [];
    const result = await client.callTool({
      name, arguments: name === 'analyze_function' ? { procedure: 'main' } : {}
    }, { onprogress: u => updates.push({ progress: u.progress, message: u.message }) });
    console.log(JSON.stringify({ name, isError: result.isError === true, updates }));
  }
} finally {
  await Promise.allSettled([client.close(), server.close()]);
}
JS
  1. Compare the updates for the two successful replies. current_address emits 1, 2, while analyze_function emits 1, 1.

The observed reproduction used dependencies and the compiled runtime that were already present. The installation and build commands above are clean-checkout prerequisites.

Expected behavior

docs/mcp-contracts.md:410 promises that numeric progress strictly increases for ordinary tool requests, including waiting phases. Each notification for one request must have a progress number greater than the preceding notification. The completed analyze_function call should emit a terminal value greater than its initial 1, just as the current_address control does.

Impact and scope

P2, provisional. Callers requesting function-analysis progress receive a sequence that violates the documented protocol behavior. The pinned SDK delivered both updates and the result in this reproduction; the effect on other clients' progress handling has not been measured.

A workaround is available: omit the progress callback/token when progress is unnecessary; the reproduced function call itself returns successful Evidence. Clients that need progress can use messages and the final tool result, but cannot rely on the promised increasing number until this is restored.

REA version

6.4.0 (main at 8dde6370d0)

Runtime and platform

Node.js v26.10.0 on macOS 27.0.1. Architecture was not recorded. Dependencies and the compiled runtime were already present.

Target and artifact context

The repository's canonical complete function dossier, FUNCTION_COMPARISON_EXAMPLE.left.normalized_result, supplied by a local injected provider, with procedure: 'main' for analyze_function and 0x1000 returned for current_address. The reproduction uses linked in-memory MCP transports and runs no analysis engine.

Interface

MCP

Earliest failure stage

Transport or result projection

Relevant output or evidence

The reproduced command exits successfully and prints:

{"name":"current_address","isError":false,"updates":[{"progress":1,"message":"current_address: started"},{"progress":2,"message":"current_address: completed"}]}
{"name":"analyze_function","isError":false,"updates":[{"progress":1,"message":"analyze_function: started"},{"progress":1,"message":"analyze_function: completed"}]}

Typed outcome or recovery expected

Repeat the reproduction and require strictly increasing progress values within both requests while preserving successful function Evidence. Also exercise a provider that emits intermediate progress and a provider failure: neither path may restart the request's sequence. Calls without a progress token must still return their result without progress notifications. The current_address request is the discriminating control.

Analysis or suspected cause

Source-derived reasoning: src/server/registerEnhancedTools.ts:221 creates the start reporter. Its analyze_function branch reaches another reporter at src/server/registerEnhancedTools.ts:315 before delivering the terminal update. Creating a separate reporter for the same request explains the repeated initial number in the observed MCP notifications.

Additional context

Related to #98, closed as completed, which required bounded monotonic MCP progress; this report identifies a reproduced violation of that completed contract in the function-analysis branch.

Related to #3169, which reports omitted cleanup states in capture-progress messages; this report concerns repeated numeric progress in a successful analyze_function request and requires a different fix.

Originally created by @coygeek on GitHub (Oct 14, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3335 ### 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 An `analyze_function` MCP request with a progress token emits `progress: 1` for both its start and completion notifications, even when the function result succeeds. The same connection's `current_address` request emits the expected sequence `1`, `2`. The command exits successfully and both tool results succeed. ### Reproduction 1. Start from a clean checkout and install the locked dependencies and build the runtime: ```sh git clone https://github.com/morluto/rea.git cd rea git checkout 8dde6370d0809ad04cda3342d4e6f290f48aa063 npm ci npm run build:cached ``` 2. From the checkout root, run the following exact command. It calls the registered MCP tools through the pinned SDK using a local injected provider that returns the repository's canonical complete function dossier. All input is inline or imported from the built repository example; no additional input file or analysis engine is required. ```sh node --input-type=module <<'JS' import { Client, InMemoryTransport } from '@modelcontextprotocol/client'; import { createServer } from './dist/server/createServer.js'; import { createAnalysisExecution } from './dist/application/AnalysisProvider.js'; import { FUNCTION_COMPARISON_EXAMPLE } from './dist/contracts/functionComparisonExample.js'; const analysis = { execute: async operation => ({ ok: true, value: createAnalysisExecution( operation === 'analyze_function' ? FUNCTION_COMPARISON_EXAMPLE.left.normalized_result : '0x1000', { id: 'fixture', name: 'Fixture', version: '1' } ) }) }; const server = createServer({ kind: 'fixed', analysis }); const client = new Client({ name: 'progress-reproduction', version: '1' }); const [ct, st] = InMemoryTransport.createLinkedPair(); try { await server.connect(st); await client.connect(ct); for (const name of ['current_address', 'analyze_function']) { const updates = []; const result = await client.callTool({ name, arguments: name === 'analyze_function' ? { procedure: 'main' } : {} }, { onprogress: u => updates.push({ progress: u.progress, message: u.message }) }); console.log(JSON.stringify({ name, isError: result.isError === true, updates })); } } finally { await Promise.allSettled([client.close(), server.close()]); } JS ``` 3. Compare the updates for the two successful replies. `current_address` emits `1`, `2`, while `analyze_function` emits `1`, `1`. The observed reproduction used dependencies and the compiled runtime that were already present. The installation and build commands above are clean-checkout prerequisites. ### Expected behavior `docs/mcp-contracts.md:410` promises that numeric progress strictly increases for ordinary tool requests, including waiting phases. Each notification for one request must have a progress number greater than the preceding notification. The completed `analyze_function` call should emit a terminal value greater than its initial `1`, just as the `current_address` control does. ### Impact and scope P2, provisional. Callers requesting function-analysis progress receive a sequence that violates the documented protocol behavior. The pinned SDK delivered both updates and the result in this reproduction; the effect on other clients' progress handling has not been measured. A workaround is available: omit the progress callback/token when progress is unnecessary; the reproduced function call itself returns successful Evidence. Clients that need progress can use messages and the final tool result, but cannot rely on the promised increasing number until this is restored. ### REA version 6.4.0 (main at 8dde6370d0809ad04cda3342d4e6f290f48aa063) ### Runtime and platform Node.js v26.10.0 on macOS 27.0.1. Architecture was not recorded. Dependencies and the compiled runtime were already present. ### Target and artifact context The repository's canonical complete function dossier, `FUNCTION_COMPARISON_EXAMPLE.left.normalized_result`, supplied by a local injected provider, with `procedure: 'main'` for `analyze_function` and `0x1000` returned for `current_address`. The reproduction uses linked in-memory MCP transports and runs no analysis engine. ### Interface MCP ### Earliest failure stage Transport or result projection ### Relevant output or evidence The reproduced command exits successfully and prints: ```text {"name":"current_address","isError":false,"updates":[{"progress":1,"message":"current_address: started"},{"progress":2,"message":"current_address: completed"}]} {"name":"analyze_function","isError":false,"updates":[{"progress":1,"message":"analyze_function: started"},{"progress":1,"message":"analyze_function: completed"}]} ``` ### Typed outcome or recovery expected Repeat the reproduction and require strictly increasing progress values within both requests while preserving successful function Evidence. Also exercise a provider that emits intermediate progress and a provider failure: neither path may restart the request's sequence. Calls without a progress token must still return their result without progress notifications. The `current_address` request is the discriminating control. ### Analysis or suspected cause Source-derived reasoning: `src/server/registerEnhancedTools.ts:221` creates the start reporter. Its `analyze_function` branch reaches another reporter at `src/server/registerEnhancedTools.ts:315` before delivering the terminal update. Creating a separate reporter for the same request explains the repeated initial number in the observed MCP notifications. ### Additional context Related to [#98](https://github.com/morluto/rea/issues/98), closed as completed, which required bounded monotonic MCP progress; this report identifies a reproduced violation of that completed contract in the function-analysis branch. Related to [#3169](https://github.com/morluto/rea/issues/3169), which reports omitted cleanup states in capture-progress messages; this report concerns repeated numeric progress in a successful `analyze_function` request and requires a different fix.
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#1205
No description provided.