Files
584937c761 feat(mcp): make MCP startup phase budgets configurable (#6304)
* feat(mcp): make MCP startup phase budgets configurable

REA_MCP_INITIALIZE_BUDGET_MS, REA_MCP_TOOLS_LIST_BUDGET_MS,
REA_MCP_FIRST_CATALOG_BUDGET_MS, and REA_MCP_DOCTOR_DEADLINE_MS keep
today's defaults and refuse values outside 1 to 2147483647 ms. Codex's
30 second startup figure stays client guidance.

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

* fix(mcp): enforce the first-catalog budget while phases are pending

The packaged startup probe applied each phase timeout on its own and
checked REA_MCP_FIRST_CATALOG_BUDGET_MS only after both requests
finished. A shorter first-catalog budget now clamps the in-flight
request and cancels it from one deadline measured at startup.

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 23:54:01 +08:00

79 lines
2.1 KiB
JavaScript

import { writeFileSync } from "node:fs";
import { writeFile } from "node:fs/promises";
import { createInterface } from "node:readline";
const mode = process.env.REA_MCP_PROBE_MODE ?? "serve";
if (mode === "fail") {
console.error("unrelated probe failure");
process.exit(1);
}
const respond = (id, result) => {
const response =
result === undefined
? {
error: {
code: -32601,
message:
process.env.REA_MCP_PROBE_ERROR_MESSAGE ??
"unrelated fixture method refusal",
},
}
: { result };
process.stdout.write(
`${JSON.stringify({ jsonrpc: "2.0", id, ...response })}\n`,
);
};
const input = createInterface({ input: process.stdin });
input.on("line", (line) => {
let request;
try {
request = JSON.parse(line);
} catch {
return;
}
if (request.id === undefined) return;
if (mode === "hang") return;
if (mode === "initialize-then-hang" && request.method !== "initialize")
return;
if (mode === "hang-on-call" && request.method === "tools/call") {
const readyPath = process.env.REA_MCP_PROBE_READY_PATH;
if (readyPath !== undefined) void writeFile(readyPath, "ready");
return;
}
if (mode === "refuse-call" && request.method === "tools/call") {
respond(request.id, undefined);
return;
}
let result;
switch (request.method) {
case "initialize":
result = {
protocolVersion: request.params?.protocolVersion ?? "2025-11-25",
capabilities: { tools: {}, prompts: {} },
serverInfo: { name: "probe-fixture", version: "1" },
};
// Synchronous so a parent can observe initialize before the next phase hangs.
if (process.env.REA_MCP_PROBE_INITIALIZED_PATH !== undefined)
writeFileSync(process.env.REA_MCP_PROBE_INITIALIZED_PATH, "ready");
break;
case "tools/list":
result = { tools: [] };
break;
case "prompts/list":
result = { prompts: [] };
break;
case "ping":
result = {};
break;
default:
result = undefined;
}
respond(request.id, result);
});
input.on("close", () => {
process.exit(0);
});