Files
rea/src/mcpStartupPolicy.test.ts

86 lines
2.9 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { parseClientConfiguration } from "./application/ClientConfigurationDocument.js";
import { clientRegistrationEnvironmentDetails } from "./application/ClientRegistrationEnvironment.js";
import { explicitSetupRegistrationEnvironment } from "./application/SetupRegistrationEnvironment.js";
import {
mcpProviderDeadlineAllowanceMs,
recommendedMcpToolTimeoutSeconds,
} from "./mcpStartupPolicy.js";
const inputs = {
ghidraStartupTimeoutMs: 330_000,
hopperStartupTimeoutMs: 120_000,
} as const;
describe("MCP tool deadline allowance for a Ghidra decompile limit", () => {
it.each([
["ghidra", 930_000],
["auto", 930_000],
["hopper", 120_000],
] as const)(
"allows %s cold startup plus the selected decompile limit",
(analysisProvider, expected) => {
expect(
mcpProviderDeadlineAllowanceMs({
...inputs,
analysisProvider,
ghidraDecompileTimeoutMs: 600_000,
}),
).toBe(expected);
},
);
it("keeps the startup-only allowance when no decompile limit is set", () => {
const allowance = { ...inputs, analysisProvider: "ghidra" } as const;
expect(mcpProviderDeadlineAllowanceMs(allowance)).toBe(330_000);
expect(recommendedMcpToolTimeoutSeconds(allowance)).toBe(450);
});
it("derives the registration allowance from REA_GHIDRA_DECOMPILE_TIMEOUT_SECONDS", () => {
const details = clientRegistrationEnvironmentDetails(
parseClientConfiguration(
JSON.stringify({
mcpServers: {
rea: {
command: "rea",
args: ["mcp"],
env: {
REA_ANALYSIS_PROVIDER: "ghidra",
REA_GHIDRA_DECOMPILE_TIMEOUT_SECONDS: "600",
},
},
},
}),
"json",
),
);
if (!details.ok) throw details.error;
expect(details.value.timeoutInputs).toMatchObject({
analysisProvider: "ghidra",
ghidraDecompileTimeoutMs: 600_000,
});
// 330 s default startup + 600 s limit + 120 s operation headroom.
const timeoutInputs = details.value.timeoutInputs;
if (timeoutInputs === undefined)
throw new Error("Expected resolved decompile timeout inputs");
expect(recommendedMcpToolTimeoutSeconds(timeoutInputs)).toBe(1050);
});
it("forwards selected launch and response limits without copying transport credentials or unrelated settings", () => {
expect(
explicitSetupRegistrationEnvironment({
REA_GHIDRA_DECOMPILE_TIMEOUT_SECONDS: "600",
REA_ASAR_MAX_HEADER_BYTES: "33554432",
REA_MCP_MAX_RESPONSE_BYTES: "20971520",
REA_TOKEN: "transport-only",
UNRELATED: "dropped",
}),
).toEqual({
REA_GHIDRA_DECOMPILE_TIMEOUT_SECONDS: "600",
REA_ASAR_MAX_HEADER_BYTES: "33554432",
REA_MCP_MAX_RESPONSE_BYTES: "20971520",
});
});
});