[GH-ISSUE #7346] [Bug] MCP HTTP startup recommends changing the port for a host lookup failure #4367

Open
opened 2026-10-31 00:49:15 +00:00 by bsakaguchi · 0 comments
Owner

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

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 public rea mcp --http startup path prints Choose another --port or stop the process using it. when the listener fails with a host lookup error. The listener error owner already classifies that error and supplies guidance naming --host and MCP_HOST, but the MCP startup projection replaces it with port advice.

Independently reproduced once with an injected EAI_NONAME error through scripts/rea.mjs. An injected EADDRINUSE control also exited 1 with the same advice, appropriate for that control. Both injections replaced Server.listen before it opened a socket; no DNS request, bind, MCP request, provider or target operation was performed. A naturally failing resolver was not tested.

Reproduction

Prerequisites: source checkout at the revision below, locked dependencies and its built runtime available. The executed runner launched the public dispatcher with an isolated HOME/XDG environment and the following preload and arguments. This self-contained shell form expresses the same deterministic fixture; the verification used a sequential subprocess runner with a timeout and awaited both child exits.

case_dir="$(mktemp -d)"
mkdir -p "$case_dir/home"
cat > "$case_dir/fake-listen.mjs" <<'JS'
import { Server } from 'node:http';
const code = process.env.LISTEN_FAILURE_CODE;
if (!['EAI_NONAME', 'EADDRINUSE'].includes(code)) throw new Error('unsupported fixture');
Server.prototype.listen = function (options) {
  if (options.host !== '127.0.0.1' || options.port !== 0) throw new Error('fixture requires loopback/ephemeral options');
  process.stderr.write(`fixture: listen host=${options.host} port=${options.port} code=${code}; no socket opened\n`);
  queueMicrotask(() => this.emit('error', Object.assign(new Error(`synthetic ${code}`), {code})));
  return this;
};
JS
for code in EAI_NONAME EADDRINUSE; do
  env -i PATH="$PATH" HOME="$case_dir/home" LISTEN_FAILURE_CODE="$code" \
    node --import "$case_dir/fake-listen.mjs" scripts/rea.mjs \
    mcp --http --host 127.0.0.1 --port 0
  printf 'exit=%s\n' "$?"
done
rm -rf "$case_dir"

Observed for each injected code: exit 1, empty stdout, no listening announcement, and the output below. The fixture makes no real host lookup; the selected host/port are valid configuration. Source tracing establishes that a native lookup failure takes the same error path.

Expected behavior

For a host lookup failure, retain useful failure information and direct the caller to correct --host/MCP_HOST or resolve the lookup condition. Preserve port/process advice for EADDRINUSE.

src/server/http/streamableHttpListenError.ts:48-55,86-100 explicitly owns classification and per-kind recovery, including EAI_NONAME → host_lookup → host-specific recovery. AGENTS.md, Architecture and Cleanup, requires consumers to use the interpretation owner's parsed facts. docs/mcp-contracts.md:748-754 documents this public entry and independent host/port configuration. This report requests a wording correction within that existing contract.

Impact and scope

P3 diagnostic wording defect: changing the port does not resolve a host lookup failure. Startup correctly fails, and the JSON log retains the native failure text, allowing a reader to identify the lookup problem. No additional functional failure, data loss or persistent state change was established. The executed scope is the MCP HTTP startup projection for one injected lookup error plus a port-error control; other listener error kinds were not exercised.

REA version

6.8.0; source revision dbe2c97af34361b11b9504e37611dd47715b52cb.

Runtime and platform

Node.js v24.22.1; macOS 27.0.1, Darwin 27.0.0, arm64. Parent-supplied build receipt reports a successful build of this revision; this verification did not build or install software. No native analysis provider was used.

Target and artifact context

No target or analysis artifact. Synthetic native listener errors in isolated configuration directories.

Interface

CLI

Earliest failure stage

Transport or result projection

Relevant output or evidence

For the EAI_NONAME fixture, the JSON log's error field was:

MCP HTTP listener startup failed: synthetic EAI_NONAME

Its msg field and the standalone stderr line both contained:

REA could not listen for MCP HTTP connections on the selected host and port. Choose another --port or stop the process using it.

The EADDRINUSE control substituted synthetic EADDRINUSE in the underlying error and retained the same advice. Both child processes exited themselves and were awaited; no timeout cleanup ran.

Source reachability: scripts/rea.mjs dispatches mcp --http to runMcpHttpEntrypoint in src/main.ts. Flag parsing and endpoint resolution accept the fixture's nonblank host and decimal port. HTTP selects eager runtime and startMcpTransport, whose serve dependency calls serveStreamableHttp. In src/server/http/serveStreamableHttp.ts:535-545, the native listening rejection is wrapped before any successfully bound-address checks. src/main/transport.ts:171-184 selects the generic MCP_HTTP_LISTEN_FAILED for the classified lookup error; src/main/messages.ts:9-10 supplies the observed port advice. This explains the public runtime observation without requiring a real resolver failure.

Typed outcome or recovery expected

Continue to exit 1 for the injected lookup failure, but make the recovery name --host/MCP_HOST. The EADDRINUSE control should continue to advise changing the port or stopping its owner. No new output schema is requested.

Analysis or suspected cause

Source-confirmed projection mismatch: startMcpTransport retains cause.remediationAction only for one other classification and replaces it with the fixed port message for host_lookup. In contrast, transportError in src/cli/environmentCommands.ts:67-98 already preserves the same owner's recovery text for environment-serve.

Additional context

Related closed issue #5455 reports the environment-serve JSON recovery action. Its saved full body names that command and its restoration check. That consumer now preserves the owner's recovery, while this independently observed MCP stderr case remains. Open #7093 and #7092 concern environment-serve flag parsing, a different failure stage. The complete saved issue-title/body history, final live issue and pull-request searches, related current discussions, and recent new reports were checked. No exact duplicate covers this remaining MCP startup projection.

  • Expected source: shared listener classification/recovery owner, documented HTTP entry, and parsed-fact ownership rule cited above.
  • Failure source: independently observed public CLI stderr and exit status under deterministic native-error injection, corroborated by the MCP startup projection.
  • Evidence provenance: observed for the synthetic public CLI runs; static for application to a real native lookup failure.
  • Local verification: reproduced, once per injected error code. No actual DNS failure or successful listener startup was run.
  • Reproduction completeness: complete for the deterministic public CLI diagnostic fixture; natural resolver behavior was outside the verification scope.
  • Restoration check: the same EAI_NONAME fixture retains failed startup and its useful cause, reports host-specific recovery, and omits port-changing advice; the EADDRINUSE control retains port/process advice. This proposed correction was not implemented or tested.

NOT_ENOUGH_INFO: the last known good version and whether this is a regression were not established.

Triage assessment

  • Impact level: P3
  • Assessment status: supported
  • Impact basis: Incorrect recovery wording follows an otherwise expected startup failure; the underlying error remains available and no additional behavioral consequence was demonstrated.
  • Workaround status: available
  • Workaround basis: Read the retained lookup diagnostic and correct the host or resolver condition instead of changing the port. The diagnostic's availability was observed; successful binding after such a correction was not executed.
Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7346 ## 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 public `rea mcp --http` startup path prints `Choose another --port or stop the process using it.` when the listener fails with a host lookup error. The listener error owner already classifies that error and supplies guidance naming `--host` and `MCP_HOST`, but the MCP startup projection replaces it with port advice. Independently reproduced once with an injected `EAI_NONAME` error through `scripts/rea.mjs`. An injected `EADDRINUSE` control also exited 1 with the same advice, appropriate for that control. Both injections replaced `Server.listen` before it opened a socket; no DNS request, bind, MCP request, provider or target operation was performed. A naturally failing resolver was not tested. ## Reproduction Prerequisites: source checkout at the revision below, locked dependencies and its built runtime available. The executed runner launched the public dispatcher with an isolated HOME/XDG environment and the following preload and arguments. This self-contained shell form expresses the same deterministic fixture; the verification used a sequential subprocess runner with a timeout and awaited both child exits. ```sh case_dir="$(mktemp -d)" mkdir -p "$case_dir/home" cat > "$case_dir/fake-listen.mjs" <<'JS' import { Server } from 'node:http'; const code = process.env.LISTEN_FAILURE_CODE; if (!['EAI_NONAME', 'EADDRINUSE'].includes(code)) throw new Error('unsupported fixture'); Server.prototype.listen = function (options) { if (options.host !== '127.0.0.1' || options.port !== 0) throw new Error('fixture requires loopback/ephemeral options'); process.stderr.write(`fixture: listen host=${options.host} port=${options.port} code=${code}; no socket opened\n`); queueMicrotask(() => this.emit('error', Object.assign(new Error(`synthetic ${code}`), {code}))); return this; }; JS for code in EAI_NONAME EADDRINUSE; do env -i PATH="$PATH" HOME="$case_dir/home" LISTEN_FAILURE_CODE="$code" \ node --import "$case_dir/fake-listen.mjs" scripts/rea.mjs \ mcp --http --host 127.0.0.1 --port 0 printf 'exit=%s\n' "$?" done rm -rf "$case_dir" ``` Observed for each injected code: exit 1, empty stdout, no listening announcement, and the output below. The fixture makes no real host lookup; the selected host/port are valid configuration. Source tracing establishes that a native lookup failure takes the same error path. ## Expected behavior For a host lookup failure, retain useful failure information and direct the caller to correct `--host`/`MCP_HOST` or resolve the lookup condition. Preserve port/process advice for `EADDRINUSE`. `src/server/http/streamableHttpListenError.ts:48-55,86-100` explicitly owns classification and per-kind recovery, including `EAI_NONAME` → `host_lookup` → host-specific recovery. `AGENTS.md`, Architecture and Cleanup, requires consumers to use the interpretation owner's parsed facts. `docs/mcp-contracts.md:748-754` documents this public entry and independent host/port configuration. This report requests a wording correction within that existing contract. ## Impact and scope P3 diagnostic wording defect: changing the port does not resolve a host lookup failure. Startup correctly fails, and the JSON log retains the native failure text, allowing a reader to identify the lookup problem. No additional functional failure, data loss or persistent state change was established. The executed scope is the MCP HTTP startup projection for one injected lookup error plus a port-error control; other listener error kinds were not exercised. ## REA version 6.8.0; source revision `dbe2c97af34361b11b9504e37611dd47715b52cb`. ## Runtime and platform Node.js v24.22.1; macOS 27.0.1, Darwin 27.0.0, arm64. Parent-supplied build receipt reports a successful build of this revision; this verification did not build or install software. No native analysis provider was used. ## Target and artifact context No target or analysis artifact. Synthetic native listener errors in isolated configuration directories. ## Interface CLI ## Earliest failure stage Transport or result projection ## Relevant output or evidence For the `EAI_NONAME` fixture, the JSON log's `error` field was: ```text MCP HTTP listener startup failed: synthetic EAI_NONAME ``` Its `msg` field and the standalone stderr line both contained: ```text REA could not listen for MCP HTTP connections on the selected host and port. Choose another --port or stop the process using it. ``` The `EADDRINUSE` control substituted `synthetic EADDRINUSE` in the underlying error and retained the same advice. Both child processes exited themselves and were awaited; no timeout cleanup ran. Source reachability: `scripts/rea.mjs` dispatches `mcp --http` to `runMcpHttpEntrypoint` in `src/main.ts`. Flag parsing and endpoint resolution accept the fixture's nonblank host and decimal port. HTTP selects eager runtime and `startMcpTransport`, whose serve dependency calls `serveStreamableHttp`. In `src/server/http/serveStreamableHttp.ts:535-545`, the native listening rejection is wrapped before any successfully bound-address checks. `src/main/transport.ts:171-184` selects the generic `MCP_HTTP_LISTEN_FAILED` for the classified lookup error; `src/main/messages.ts:9-10` supplies the observed port advice. This explains the public runtime observation without requiring a real resolver failure. ## Typed outcome or recovery expected Continue to exit 1 for the injected lookup failure, but make the recovery name `--host`/`MCP_HOST`. The `EADDRINUSE` control should continue to advise changing the port or stopping its owner. No new output schema is requested. ## Analysis or suspected cause Source-confirmed projection mismatch: `startMcpTransport` retains `cause.remediationAction` only for one other classification and replaces it with the fixed port message for `host_lookup`. In contrast, `transportError` in `src/cli/environmentCommands.ts:67-98` already preserves the same owner's recovery text for `environment-serve`. ## Additional context Related closed issue [#5455](https://github.com/morluto/rea/issues/5455) reports the environment-serve JSON recovery action. Its saved full body names that command and its restoration check. That consumer now preserves the owner's recovery, while this independently observed MCP stderr case remains. Open [#7093](https://github.com/morluto/rea/issues/7093) and [#7092](https://github.com/morluto/rea/pull/7092) concern environment-serve flag parsing, a different failure stage. The complete saved issue-title/body history, final live issue and pull-request searches, related current discussions, and recent new reports were checked. No exact duplicate covers this remaining MCP startup projection. - Expected source: shared listener classification/recovery owner, documented HTTP entry, and parsed-fact ownership rule cited above. - Failure source: independently observed public CLI stderr and exit status under deterministic native-error injection, corroborated by the MCP startup projection. - Evidence provenance: observed for the synthetic public CLI runs; static for application to a real native lookup failure. - Local verification: reproduced, once per injected error code. No actual DNS failure or successful listener startup was run. - Reproduction completeness: complete for the deterministic public CLI diagnostic fixture; natural resolver behavior was outside the verification scope. - Restoration check: the same `EAI_NONAME` fixture retains failed startup and its useful cause, reports host-specific recovery, and omits port-changing advice; the `EADDRINUSE` control retains port/process advice. This proposed correction was not implemented or tested. NOT_ENOUGH_INFO: the last known good version and whether this is a regression were not established. ## Triage assessment - Impact level: P3 - Assessment status: supported - Impact basis: Incorrect recovery wording follows an otherwise expected startup failure; the underlying error remains available and no additional behavioral consequence was demonstrated. - Workaround status: available - Workaround basis: Read the retained lookup diagnostic and correct the host or resolver condition instead of changing the port. The diagnostic's availability was observed; successful binding after such a correction was not executed.
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#4367
No description provided.