Files
rea/tests/boundary/mcp/mcpStartupPolicy.test.ts
T
morluto bdf0be87c6 fix(mcp): name response-byte and startup ceilings in recovery (#6005)
* fix(mcp): name response-byte and startup ceilings in recovery

Name REA_MCP_MAX_RESPONSE_BYTES, its effective value, the 10485760 byte
floor, and process restart when the stdio response budget is hit, and
state that the setting does not raise Node's string ceiling. Name fixed
MCP startup phase budgets when those deadlines fire, and keep Codex's
30 second startup figure as client guidance.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(mcp): distinguish string ceilings and keep dossier recovery

Name REA's reserved string limit separately from Node's ceiling, restore
detail:summary discovery for an oversized complete evidence bundle, and
apply the doctor deadline sentence when binary_session itself times out.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(mcp): keep retained SDK errors inside the text budget

Quoted SDK validation diagnostics expand when recovery JSON is escaped
into MCP text. Shorten only that preview so the retained-evidence
reference still arrives as parseable error content.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(mcp): keep export advice when a summary exceeds the response budget

An oversized get_evidence_bundle summary no longer repeats detail: summary.
export_evidence_bundle still writes the retained bundle outside one MCP frame,
including when a larger byte budget cannot raise the string ceiling.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* style(mcp): format the SDK diagnostic preview return

oxfmt rejected the fitted-preview ternary in EvidenceMcpServer.ts, which failed Static checks and the CI required gate.

Co-authored-by: morluto <morluto@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
2026-10-22 05:48:56 +08:00

224 lines
7.2 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { resolve } from "node:path";
import {
createEsmModuleProfileCollector,
fixedMcpStartupPhaseBudgetRecovery,
measureMcpStartup,
parseLinuxVmRssBytes,
profileMcpModuleLoading,
} from "../../../scripts/lib/mcp-startup-probe.mjs";
import {
fixedMcpPhaseBudgetRecovery,
mcpDoctorDeadlineRecovery,
MCP_STARTUP_POLICY,
} from "../../../src/mcpStartupPolicy.js";
describe("MCP startup policy", () => {
it("names fixed phase budgets without turning Codex's 30s into a REA knob", () => {
const initialize = fixedMcpPhaseBudgetRecovery(
"MCP initialize phase budget",
MCP_STARTUP_POLICY.initializeBudgetMs,
"ms",
);
expect(initialize).toBe(
"REA's fixed MCP initialize phase budget is 15000 ms and this release has no runtime override.",
);
expect(initialize).toBe(
fixedMcpStartupPhaseBudgetRecovery(
"MCP initialize phase budget",
MCP_STARTUP_POLICY.initializeBudgetMs,
"ms",
),
);
expect(
fixedMcpStartupPhaseBudgetRecovery(
"MCP tools/list phase budget",
MCP_STARTUP_POLICY.toolsListBudgetMs,
"ms",
),
).toContain("5000 ms");
expect(
fixedMcpStartupPhaseBudgetRecovery(
"MCP first-catalog phase budget",
MCP_STARTUP_POLICY.firstCatalogBudgetMs,
"ms",
),
).toContain("20000 ms");
const doctor = mcpDoctorDeadlineRecovery(
MCP_STARTUP_POLICY.doctorDeadlineMs,
);
expect(doctor).toContain("30000 ms");
expect(doctor).toContain("no runtime override");
expect(doctor).toContain(
"Codex startup_timeout_sec of 30 seconds is client guidance",
);
expect(doctor).toContain("does not enforce");
expect(doctor).not.toContain("REA_MCP_STARTUP");
});
it("parses Linux resident memory without accepting other fields", () => {
expect(
parseLinuxVmRssBytes("Name:\tnode\nVmRSS:\t 12345 kB\nThreads:\t7\n"),
).toBe(12_641_280);
expect(parseLinuxVmRssBytes("VmSize:\t12345 kB\n")).toBeNull();
});
it("profiles unique file-backed ESM modules without retaining paths", () => {
const collector = createEsmModuleProfileCollector();
collector.append(
"ESM 1: Storing file:///opt/rea/dist/main.js\n" +
"ESM 1: Translating StandardModule file:///opt/rea/dist/main.js\n" +
"ESM 1: Storing file:///opt/rea/node_modules/zod/index.js",
);
expect(collector.result()).toEqual({
supported: true,
method: "node-debug-esm",
unique_file_modules: 2,
unique_package_modules: 0,
unique_dependency_modules: 1,
debug_lines: 3,
truncated: false,
});
});
});
const probeChild = resolve("tests/fixtures/mcpStartupProbeChild.mjs");
const probePolicy = (
overrides: Partial<{
initializeBudgetMs: number;
toolsListBudgetMs: number;
firstCatalogBudgetMs: number;
doctorDeadlineMs: number;
}> = {},
) => ({
initializeBudgetMs: 30_000,
toolsListBudgetMs: 30_000,
firstCatalogBudgetMs: 30_000,
doctorDeadlineMs: 30_000,
...overrides,
});
const errorMessage = (cause: unknown): string =>
cause instanceof Error ? cause.message : String(cause);
describe("packaged MCP startup probe failures", () => {
it("names the initialize budget when that phase times out", async () => {
const budgetMs = 200;
await expect(
measureMcpStartup({
command: process.execPath,
args: [probeChild],
environment: { ...process.env, REA_MCP_PROBE_MODE: "hang" },
policy: probePolicy({ initializeBudgetMs: budgetMs }),
}),
).rejects.toThrow(
`MCP initialize phase budget is ${String(budgetMs)} ms and this release has no runtime override.`,
);
});
it("names the tools/list budget when that phase times out", async () => {
const budgetMs = 200;
await expect(
measureMcpStartup({
command: process.execPath,
args: [probeChild],
environment: {
...process.env,
REA_MCP_PROBE_MODE: "initialize-then-hang",
},
policy: probePolicy({ toolsListBudgetMs: budgetMs }),
}),
).rejects.toThrow(
`MCP tools/list phase budget is ${String(budgetMs)} ms and this release has no runtime override.`,
);
});
it("names the first-catalog budget when startup exceeds it", async () => {
const budgetMs = 1;
await expect(
measureMcpStartup({
command: process.execPath,
args: [probeChild],
environment: { ...process.env, REA_MCP_PROBE_MODE: "serve" },
policy: probePolicy({ firstCatalogBudgetMs: budgetMs }),
}),
).rejects.toThrow(
`MCP first-catalog phase budget is ${String(budgetMs)} ms and this release has no runtime override.`,
);
});
it("does not add timeout guidance to an unrelated startup failure", async () => {
try {
await measureMcpStartup({
command: process.execPath,
args: [probeChild],
environment: { ...process.env, REA_MCP_PROBE_MODE: "fail" },
policy: probePolicy(),
});
throw new Error("expected the unrelated probe failure");
} catch (cause) {
const message = errorMessage(cause);
expect(message).toContain("unrelated probe failure");
expect(message).not.toContain("expected the unrelated probe failure");
expect(message).not.toContain("no runtime override");
expect(message).not.toContain("phase budget");
}
});
it("names the doctor deadline when module profiling cannot initialize", async () => {
const budgetMs = 200;
await expect(
profileMcpModuleLoading({
command: process.execPath,
args: [probeChild],
environment: { ...process.env, REA_MCP_PROBE_MODE: "hang" },
policy: probePolicy({ doctorDeadlineMs: budgetMs }),
packageName: "rea-agents",
}),
).rejects.toThrow(
`MCP doctor startup deadline is ${String(budgetMs)} ms and this release has no runtime override.`,
);
});
it("names the tools/list budget when module profiling passes initialize", async () => {
const budgetMs = 200;
await expect(
profileMcpModuleLoading({
command: process.execPath,
args: [probeChild],
environment: {
...process.env,
REA_MCP_PROBE_MODE: "initialize-then-hang",
},
policy: probePolicy({ toolsListBudgetMs: budgetMs }),
packageName: "rea-agents",
}),
).rejects.toThrow(
`MCP tools/list phase budget is ${String(budgetMs)} ms and this release has no runtime override.`,
);
});
it("does not add timeout guidance to an unrelated module-profile failure", async () => {
try {
await profileMcpModuleLoading({
command: process.execPath,
args: [probeChild],
environment: { ...process.env, REA_MCP_PROBE_MODE: "fail" },
policy: probePolicy(),
packageName: "rea-agents",
});
throw new Error("expected the unrelated probe failure");
} catch (cause) {
const message = errorMessage(cause);
expect(message).not.toContain("expected the unrelated probe failure");
expect(message).not.toContain("no runtime override");
expect(message).not.toContain("phase budget");
expect(message).not.toContain("MCP doctor startup deadline");
}
});
});