[GH-ISSUE #7372] [Bug] MCP doctor writes non-JSON stdout for tool-family scopes without prompts #4379

Open
opened 2026-10-31 00:49:22 +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/7372

Before submitting

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

Area

CLI

Observed behavior

With REA_MCP_TOOL_FAMILIES=browser, node scripts/rea.mjs mcp doctor --json writes an SDK debug line before its JSON report. The same prefix appears with --format jsonl, so neither complete stdout capture parses as JSON. The diagnostic itself correctly reports an empty prompt inventory and exits 1 because this scope omits the session family.

Reproduction

From a checkout of the source commit below with Node 24.22.1, prepare with npm ci && npm run build:cached, then run these target-free commands. Each browser variant was observed twice at that commit, including a replay of this reproduction; the same pair also failed on the earlier main snapshot checked during verification. The dependency install is fresh-checkout preparation; the verified checkout already had the unchanged locked dependencies installed.

WORK=$(mktemp -d)
mkdir -p "$WORK"/{home,config,data,cache,state,tmp}
export HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config" XDG_DATA_HOME="$WORK/data"
export XDG_CACHE_HOME="$WORK/cache" XDG_STATE_HOME="$WORK/state" TMPDIR="$WORK/tmp"
REA_MCP_TOOL_FAMILIES=browser node scripts/rea.mjs mcp doctor --json > "$WORK/browser-json.stdout" 2> "$WORK/browser-json.stderr"
echo "json exit=$?"
REA_MCP_TOOL_FAMILIES=browser node scripts/rea.mjs mcp doctor --format jsonl > "$WORK/browser-jsonl.stdout" 2> "$WORK/browser-jsonl.stderr"
echo "jsonl exit=$?"
python3 -I - "$WORK" <<'CHECK'
import json, pathlib, sys
for name in ["browser-json", "browser-jsonl"]:
    text = (pathlib.Path(sys.argv[1]) / (name + ".stdout")).read_text()
    print(name + ": " + text.splitlines()[0])
    try:
        json.loads(text)
        print("parse=ok")
    except ValueError as error:
        print("parse=" + str(error))
    json.loads(text.split("\n", 1)[1])
    print("after-first-line parse=ok")
CHECK

Expected behavior

Both captures should contain only the selected structured document, including when doctor reports an unhealthy scope. docs/cli.md:144-145 promises a single JSON document for MCP doctor in JSON Lines mode, and docs/cli.md:954-962 recommends --json for JSON consumers. docs/mcp-contracts.md:1408-1412 explicitly allows scopes with no guided prompts and says doctor treats absent prompts capability as an empty inventory.

Impact and scope

P2: supported scoped diagnostics break JSON consumers, while removing the known first line recovers the complete report in the observed captures. Independently executed native and application JSON commands showed the same failure once each. Default-catalog and session JSON controls each parsed successfully and exited 0, with prompt counts 6/6 and 3/3 respectively. No external analysis provider was started; other platforms were not tested.

REA version

Exact node scripts/rea.mjs --version output: 6.8.0. Verified source commit: ec40c10749b5c4091fb08bc28c6f3f38c2a6968e.

Runtime and platform

Node.js v24.22.1; macOS 27.0.1; darwin arm64. Locked MCP client SDK 2.3.1.

Target and artifact context

Not applicable. This uses the local production stdio diagnostic without a binary, device, analysis provider, or target fixture.

Interface

CLI

Earliest failure stage

Transport or result projection

Relevant output or evidence

Both browser commands exited 1 with empty stderr. Their first stdout line was:

Client.listPrompts() called but server does not advertise prompts capability - returning empty list

Parsing each complete capture produced Expecting value: line 1 column 1 (char 0); parsing after that line succeeded. The JSON report retained inventory.prompts as {"expected":0,"observed":0,"missing":[],"unexpected":[],"duplicates":[]}. JSONL stdout had two lines: the debug text and one valid {"$rea":"jsonl/v1","type":"error","ok":false,"result":...} record containing the same inventory.

Typed outcome or recovery expected

Preserve the empty prompt inventory, health checks and exit status, with no debug text on structured stdout. Retain prompt discovery for scopes that advertise prompts.

Analysis or suspected cause

Source-derived: src/mcpDoctor.ts:258-261 calls client.listPrompts without checking whether the server advertises prompts. The locked SDK emits the observed line with console.debug while normalizing absent capability to an empty list. This runs in the parent doctor process before the returned report is written by scripts/rea.mjs:79-89, so it bypasses report formatting and child-stderr capture.

Additional context

The merged tool-family scoping PR #7228 establishes the supported empty-prompt case. Closed issue #5435 and merged PR #5514 concern JSON indentation; their reports remained parseable, unlike this unsolicited prefix. No exact open duplicate was found. NOT_ENOUGH_INFO: no last-known-good version was established.

Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7372 ## 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 CLI ## Observed behavior With `REA_MCP_TOOL_FAMILIES=browser`, `node scripts/rea.mjs mcp doctor --json` writes an SDK debug line before its JSON report. The same prefix appears with `--format jsonl`, so neither complete stdout capture parses as JSON. The diagnostic itself correctly reports an empty prompt inventory and exits 1 because this scope omits the session family. ## Reproduction From a checkout of the source commit below with Node 24.22.1, prepare with `npm ci && npm run build:cached`, then run these target-free commands. Each browser variant was observed twice at that commit, including a replay of this reproduction; the same pair also failed on the earlier main snapshot checked during verification. The dependency install is fresh-checkout preparation; the verified checkout already had the unchanged locked dependencies installed. ```sh WORK=$(mktemp -d) mkdir -p "$WORK"/{home,config,data,cache,state,tmp} export HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config" XDG_DATA_HOME="$WORK/data" export XDG_CACHE_HOME="$WORK/cache" XDG_STATE_HOME="$WORK/state" TMPDIR="$WORK/tmp" REA_MCP_TOOL_FAMILIES=browser node scripts/rea.mjs mcp doctor --json > "$WORK/browser-json.stdout" 2> "$WORK/browser-json.stderr" echo "json exit=$?" REA_MCP_TOOL_FAMILIES=browser node scripts/rea.mjs mcp doctor --format jsonl > "$WORK/browser-jsonl.stdout" 2> "$WORK/browser-jsonl.stderr" echo "jsonl exit=$?" python3 -I - "$WORK" <<'CHECK' import json, pathlib, sys for name in ["browser-json", "browser-jsonl"]: text = (pathlib.Path(sys.argv[1]) / (name + ".stdout")).read_text() print(name + ": " + text.splitlines()[0]) try: json.loads(text) print("parse=ok") except ValueError as error: print("parse=" + str(error)) json.loads(text.split("\n", 1)[1]) print("after-first-line parse=ok") CHECK ``` ## Expected behavior Both captures should contain only the selected structured document, including when doctor reports an unhealthy scope. `docs/cli.md:144-145` promises a single JSON document for MCP doctor in JSON Lines mode, and `docs/cli.md:954-962` recommends `--json` for JSON consumers. `docs/mcp-contracts.md:1408-1412` explicitly allows scopes with no guided prompts and says doctor treats absent prompts capability as an empty inventory. ## Impact and scope P2: supported scoped diagnostics break JSON consumers, while removing the known first line recovers the complete report in the observed captures. Independently executed `native` and `application` JSON commands showed the same failure once each. Default-catalog and `session` JSON controls each parsed successfully and exited 0, with prompt counts 6/6 and 3/3 respectively. No external analysis provider was started; other platforms were not tested. ## REA version Exact `node scripts/rea.mjs --version` output: `6.8.0`. Verified source commit: `ec40c10749b5c4091fb08bc28c6f3f38c2a6968e`. ## Runtime and platform Node.js v24.22.1; macOS 27.0.1; darwin arm64. Locked MCP client SDK 2.3.1. ## Target and artifact context Not applicable. This uses the local production stdio diagnostic without a binary, device, analysis provider, or target fixture. ## Interface CLI ## Earliest failure stage Transport or result projection ## Relevant output or evidence Both browser commands exited 1 with empty stderr. Their first stdout line was: ```text Client.listPrompts() called but server does not advertise prompts capability - returning empty list ``` Parsing each complete capture produced `Expecting value: line 1 column 1 (char 0)`; parsing after that line succeeded. The JSON report retained `inventory.prompts` as `{"expected":0,"observed":0,"missing":[],"unexpected":[],"duplicates":[]}`. JSONL stdout had two lines: the debug text and one valid `{"$rea":"jsonl/v1","type":"error","ok":false,"result":...}` record containing the same inventory. ## Typed outcome or recovery expected Preserve the empty prompt inventory, health checks and exit status, with no debug text on structured stdout. Retain prompt discovery for scopes that advertise prompts. ## Analysis or suspected cause Source-derived: `src/mcpDoctor.ts:258-261` calls `client.listPrompts` without checking whether the server advertises prompts. The locked SDK emits the observed line with `console.debug` while normalizing absent capability to an empty list. This runs in the parent doctor process before the returned report is written by `scripts/rea.mjs:79-89`, so it bypasses report formatting and child-stderr capture. ## Additional context The merged [tool-family scoping PR #7228](https://github.com/morluto/rea/pull/7228) establishes the supported empty-prompt case. Closed [issue #5435](https://github.com/morluto/rea/issues/5435) and merged [PR #5514](https://github.com/morluto/rea/pull/5514) concern JSON indentation; their reports remained parseable, unlike this unsolicited prefix. No exact open duplicate was found. NOT_ENOUGH_INFO: no last-known-good version was established.
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#4379
No description provided.