[GH-ISSUE #7437] [Bug] Five MCP tools advertise relative paths that their handlers reject #4441

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

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

For inspect_apple_ips, inspect_elf_notes, inspect_kernel_module, export_web_scripts, and recover_javascript_sources, Ajv accepts relative filesystem paths against the real stdio server’s advertised input schemas, but the same MCP calls return invalid_request requiring absolute paths. This reproduces with both compact and full input profiles. JavaScript recovery’s optional additional_paths entries have the same mismatch even when its primary and output paths are absolute.

Reproduction

From a fresh checkout at the commit below with Node 24.22.1, run npm ci && npm run build:cached. Then run this from the repository root, using a disposable working directory. This exact harness was executed once and tests each profile once; an earlier default-profile replay independently confirmed the original five cases.

WORK="$PWD/work" node --input-type=module <<'JS'
import { Client } from "@modelcontextprotocol/client";
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
import { Ajv2020 } from "ajv/dist/2020.js";
import { mkdir, writeFile } from "node:fs/promises";
import { join, resolve } from "node:path";
const root = resolve(process.env.WORK);
const env = { PATH: process.env.PATH, REA_LOG_LEVEL: "silent" };
for (const key of ["HOME", "XDG_CONFIG_HOME", "XDG_DATA_HOME", "XDG_CACHE_HOME", "XDG_STATE_HOME", "TMPDIR"]) {
  env[key] = join(root, key);
  await mkdir(env[key], { recursive: true });
}
await writeFile(join(root, "report.ips"), '{"bug_type":"309"}\n{}\n');
for (const profile of ["compact", "full"]) {
  const transport = new StdioClientTransport({ command: process.execPath,
    args: [resolve("scripts/rea.mjs"), "mcp"], cwd: root,
    env: { ...env, REA_MCP_INPUT_SCHEMA_PROFILE: profile }, stderr: "pipe" });
  transport.stderr?.on("data", () => {});
  const client = new Client({ name: "path-schema-check", version: "1" });
  try {
    await client.connect(transport);
    const tools = (await client.listTools()).tools;
    const ajv = new Ajv2020({ strict: false, validateFormats: false });
    const cases = [
      ["inspect_apple_ips", { path: "report.ips" }],
      ["inspect_elf_notes", { path: "program.elf" }],
      ["inspect_kernel_module", { path: "module.ko" }],
      ["export_web_scripts", { capture_path: "capture.json", output_directory: "out" }],
      ["recover_javascript_sources", { path: "a.js", output_directory: "out" }],
      ["recover_javascript_sources", { path: join(root, "a.js"), output_directory: join(root, "out"), additional_paths: ["chunk.js"] }],
      ["inspect_apple_ips", { path: join(root, "report.ips") }],
    ];
    for (const [name, args] of cases) {
      const schema = tools.find(tool => tool.name === name).inputSchema;
      const valid = ajv.compile(schema)(args);
      const response = await client.callTool({ name, arguments: args });
      const body = response.structuredContent ?? JSON.parse(response.content[0].text);
      console.log(JSON.stringify({ profile, name, schema_valid: valid,
        code: body.error?.code ?? "Evidence", issues: body.error?.details?.issues }));
    }
  } finally { await client.close(); }
}
JS

Expected behavior

The advertised schemas should reject relative values for these absolute-path selections, while accepting absolute paths. docs/apple-ips.md:14-15 explicitly requires absolute MCP paths and permits relative CLI paths. The field descriptions in src/domain/native/appleIps.ts:54-58, src/domain/native/elfNotes.ts:68-72, src/domain/native/kernelModule.ts:199-203, src/domain/webScriptExport.ts:9-16, and src/domain/javascript/javascriptRecovery.ts:7-20 specify absolute inputs. Existing advertised-schema parity coverage is in tests/boundary/mcp/absoluteLocalPathSchema.test.ts:235-285.

Impact and scope

P2: schema-driven callers can construct accepted requests that these workflows refuse, requiring correction and retry. Supplying absolute paths is a practical workaround; the synthetic IPS absolute control returned Evidence in both profiles. No wrong-file selection or security-boundary crossing was observed. Relative CLI IPS inspection also succeeded in a separate control. Other host platforms and successful JavaScript provider execution were not tested.

REA version

Exact node scripts/rea.mjs --version output: 6.8.0. Built current-main source commit: a6a69ec63e0b9f2742d9b39534e2dfc02b6a0814.

Runtime and platform

Node.js v24.22.1; macOS 27.0.1; Darwin 27.0.0; arm64.

Target and artifact context

Synthetic two-line Apple IPS fixture with metadata {"bug_type":"309"} and body {}, plus inert relative path strings. HOME, XDG directories, TMPDIR, and the server working directory were isolated. No external analysis engine, browser, device, or live service was used.

Interface

MCP

Earliest failure stage

Request parsing or validation

Relevant output or evidence

Observed for each profile:

inspect_apple_ips          schema_valid=true code=invalid_request path=["path"]
inspect_elf_notes          schema_valid=true code=invalid_request path=["path"]
inspect_kernel_module     schema_valid=true code=invalid_request path=["path"]
export_web_scripts        schema_valid=true code=invalid_request path=[]
recover_javascript_sources schema_valid=true code=invalid_request paths=["path"],["output_directory"]
recover_javascript_sources schema_valid=true code=invalid_request path=["additional_paths"]
inspect_apple_ips absolute schema_valid=true code=Evidence

The first three failures say Expected an absolute filesystem path on this host. The export failure requires absolute capture_path and output_directory; recovery names its relative fields. The advertised primary path property contains only string type, minimum length 1, and the NUL-exclusion pattern. Absolute nonexistent files can still produce invalid_request for file admission, so the issue details and a valid fixture distinguish path-shape admission from later errors.

Analysis or suspected cause

Source-derived: the five shared input schemas use localPathStringSchema, which only checks nonempty and NUL-free strings (src/domain/localPath.ts:19-20). Their services separately enforce isAbsolute, including additional_paths in src/application/javascript/JavaScriptRecoveryService.ts:41-63. The advertised contract therefore omits a constraint that is enforced later. The host-absolute schema helper already exists in src/domain/localPath.ts:30-34.

Additional context

Closed #5493 reports the same schema-omission behavior for an earlier cohort and is marked fixed, but the five tools above still reproduce on current main. Closed #3924 and #5450 concern runtime acceptance of relative paths in different tools. Open PR #7097 improves export error field attribution; its described change does not fix advertised-schema acceptance. No open exact duplicate was found.

Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7437 ## 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 For `inspect_apple_ips`, `inspect_elf_notes`, `inspect_kernel_module`, `export_web_scripts`, and `recover_javascript_sources`, Ajv accepts relative filesystem paths against the real stdio server’s advertised input schemas, but the same MCP calls return `invalid_request` requiring absolute paths. This reproduces with both compact and full input profiles. JavaScript recovery’s optional `additional_paths` entries have the same mismatch even when its primary and output paths are absolute. ## Reproduction From a fresh checkout at the commit below with Node 24.22.1, run `npm ci && npm run build:cached`. Then run this from the repository root, using a disposable working directory. This exact harness was executed once and tests each profile once; an earlier default-profile replay independently confirmed the original five cases. ```sh WORK="$PWD/work" node --input-type=module <<'JS' import { Client } from "@modelcontextprotocol/client"; import { StdioClientTransport } from "@modelcontextprotocol/client/stdio"; import { Ajv2020 } from "ajv/dist/2020.js"; import { mkdir, writeFile } from "node:fs/promises"; import { join, resolve } from "node:path"; const root = resolve(process.env.WORK); const env = { PATH: process.env.PATH, REA_LOG_LEVEL: "silent" }; for (const key of ["HOME", "XDG_CONFIG_HOME", "XDG_DATA_HOME", "XDG_CACHE_HOME", "XDG_STATE_HOME", "TMPDIR"]) { env[key] = join(root, key); await mkdir(env[key], { recursive: true }); } await writeFile(join(root, "report.ips"), '{"bug_type":"309"}\n{}\n'); for (const profile of ["compact", "full"]) { const transport = new StdioClientTransport({ command: process.execPath, args: [resolve("scripts/rea.mjs"), "mcp"], cwd: root, env: { ...env, REA_MCP_INPUT_SCHEMA_PROFILE: profile }, stderr: "pipe" }); transport.stderr?.on("data", () => {}); const client = new Client({ name: "path-schema-check", version: "1" }); try { await client.connect(transport); const tools = (await client.listTools()).tools; const ajv = new Ajv2020({ strict: false, validateFormats: false }); const cases = [ ["inspect_apple_ips", { path: "report.ips" }], ["inspect_elf_notes", { path: "program.elf" }], ["inspect_kernel_module", { path: "module.ko" }], ["export_web_scripts", { capture_path: "capture.json", output_directory: "out" }], ["recover_javascript_sources", { path: "a.js", output_directory: "out" }], ["recover_javascript_sources", { path: join(root, "a.js"), output_directory: join(root, "out"), additional_paths: ["chunk.js"] }], ["inspect_apple_ips", { path: join(root, "report.ips") }], ]; for (const [name, args] of cases) { const schema = tools.find(tool => tool.name === name).inputSchema; const valid = ajv.compile(schema)(args); const response = await client.callTool({ name, arguments: args }); const body = response.structuredContent ?? JSON.parse(response.content[0].text); console.log(JSON.stringify({ profile, name, schema_valid: valid, code: body.error?.code ?? "Evidence", issues: body.error?.details?.issues })); } } finally { await client.close(); } } JS ``` ## Expected behavior The advertised schemas should reject relative values for these absolute-path selections, while accepting absolute paths. `docs/apple-ips.md:14-15` explicitly requires absolute MCP paths and permits relative CLI paths. The field descriptions in `src/domain/native/appleIps.ts:54-58`, `src/domain/native/elfNotes.ts:68-72`, `src/domain/native/kernelModule.ts:199-203`, `src/domain/webScriptExport.ts:9-16`, and `src/domain/javascript/javascriptRecovery.ts:7-20` specify absolute inputs. Existing advertised-schema parity coverage is in `tests/boundary/mcp/absoluteLocalPathSchema.test.ts:235-285`. ## Impact and scope P2: schema-driven callers can construct accepted requests that these workflows refuse, requiring correction and retry. Supplying absolute paths is a practical workaround; the synthetic IPS absolute control returned Evidence in both profiles. No wrong-file selection or security-boundary crossing was observed. Relative CLI IPS inspection also succeeded in a separate control. Other host platforms and successful JavaScript provider execution were not tested. ## REA version Exact `node scripts/rea.mjs --version` output: `6.8.0`. Built current-main source commit: `a6a69ec63e0b9f2742d9b39534e2dfc02b6a0814`. ## Runtime and platform Node.js `v24.22.1`; macOS `27.0.1`; Darwin `27.0.0`; `arm64`. ## Target and artifact context Synthetic two-line Apple IPS fixture with metadata `{"bug_type":"309"}` and body `{}`, plus inert relative path strings. HOME, XDG directories, TMPDIR, and the server working directory were isolated. No external analysis engine, browser, device, or live service was used. ## Interface MCP ## Earliest failure stage Request parsing or validation ## Relevant output or evidence Observed for each profile: ```text inspect_apple_ips schema_valid=true code=invalid_request path=["path"] inspect_elf_notes schema_valid=true code=invalid_request path=["path"] inspect_kernel_module schema_valid=true code=invalid_request path=["path"] export_web_scripts schema_valid=true code=invalid_request path=[] recover_javascript_sources schema_valid=true code=invalid_request paths=["path"],["output_directory"] recover_javascript_sources schema_valid=true code=invalid_request path=["additional_paths"] inspect_apple_ips absolute schema_valid=true code=Evidence ``` The first three failures say `Expected an absolute filesystem path on this host.` The export failure requires absolute `capture_path` and `output_directory`; recovery names its relative fields. The advertised primary path property contains only string type, minimum length 1, and the NUL-exclusion pattern. Absolute nonexistent files can still produce `invalid_request` for file admission, so the issue details and a valid fixture distinguish path-shape admission from later errors. ## Analysis or suspected cause Source-derived: the five shared input schemas use `localPathStringSchema`, which only checks nonempty and NUL-free strings (`src/domain/localPath.ts:19-20`). Their services separately enforce `isAbsolute`, including `additional_paths` in `src/application/javascript/JavaScriptRecoveryService.ts:41-63`. The advertised contract therefore omits a constraint that is enforced later. The host-absolute schema helper already exists in `src/domain/localPath.ts:30-34`. ## Additional context Closed [#5493](https://github.com/morluto/rea/issues/5493) reports the same schema-omission behavior for an earlier cohort and is marked fixed, but the five tools above still reproduce on current main. Closed [#3924](https://github.com/morluto/rea/issues/3924) and [#5450](https://github.com/morluto/rea/issues/5450) concern runtime acceptance of relative paths in different tools. Open [PR #7097](https://github.com/morluto/rea/pull/7097) improves export error field attribution; its described change does not fix advertised-schema acceptance. No open exact duplicate was found.
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#4441
No description provided.