Files
rea/experiments/atomic-codemode/server.mjs
T
af53e0fbe5 fix(experiment): retain ownership after tagged cleanup failures
Check the native cleanup Result before clearing the lease and preserve cleanup resources through the MCP error adapter. Reproduce the old false success, then verify real SDK close/replacement ownership and both MCP retry paths with explicit fault injection.

Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
2026-10-16 10:25:17 +00:00

124 lines
4.5 KiB
JavaScript

// Complete experimental catalog; it does not truncate the production REA catalog.
import { McpServer } from "@modelcontextprotocol/server";
import { serveStdio } from "@modelcontextprotocol/server/stdio";
import { z } from "zod";
import { AtomicSession, methods, reference } from "./api.mjs";
import { executeJavaScript } from "./executor.mjs";
import { TARGET_CONTENT_RESULT_META } from "../../dist/server/toolResultEncoding.js";
import { appendFile } from "node:fs/promises";
const session = new AtomicSession();
const createServer = () => {
const server = new McpServer({ name: "rea-codemode", version: "0.1.0" });
const encode = (value) => ({
content: [{ type: "text", text: JSON.stringify(value) }],
_meta: TARGET_CONTENT_RESULT_META,
});
const register = (name, description, inputSchema, handler) =>
server.registerTool(
name,
{ description, inputSchema, annotations: { readOnlyHint: true } },
async (input, request) => {
try {
const result = await handler(input, request.mcpReq.signal);
if (process.env.REA_ATOMIC_TRACE)
await appendFile(
process.env.REA_ATOMIC_TRACE,
JSON.stringify({ tool: name, input, result }) + "\n",
{ mode: 0o600 },
);
if (name === "execute_javascript") {
const { calls, ...answer } = result;
return encode({
...answer,
execution: { host_calls: calls?.length ?? 0 },
authority: "script-derived",
context: answer.context ?? null,
});
}
return encode(result);
} catch (error) {
return encode({
ok: false,
context: session.context,
error: {
code: error.code ?? "analysis_failed",
message: error.message,
details: error.details ?? {},
},
});
}
},
);
register(
"open_binary",
"Open one local binary for static Kuna analysis. Returns artifact/engine identity and a target lease. Does not execute or modify the target.",
z.strictObject({ path: z.string().min(1) }),
(input) => session.open(input.path),
);
register(
"close_binary",
"Close this target lease and owned native resources; retained snapshots and Evidence expire.",
z.strictObject({}),
() => session.close(),
);
register(
"reference",
"Look up the rea JavaScript API by method name or analyst concept before writing Code Mode calls. Empty query returns the complete API reference.",
z.strictObject({ query: z.string().default("") }),
(input) => {
const docs = reference(input.query);
if (process.env.REA_ATOMIC_ADAPTER === "direct") {
docs.language =
"Direct MCP calls: use facts_<method> with the same JSON arguments; results have {ok,context,data}.";
docs.methods = docs.methods.map((method) => ({
...method,
name: method.name.replace("rea.", "facts_"),
example: undefined,
}));
}
return docs;
},
);
if (process.env.REA_ATOMIC_ADAPTER === "direct") {
for (const [name, contract] of Object.entries(methods))
register(
`facts_${name}`,
contract.description,
contract.input,
(input, signal) => session.call(name, input, signal),
);
} else {
register(
"execute_javascript",
"Execute a JavaScript async function body against the open binary's atomic rea API. Use reference first. Await rea methods, compose/filter locally, and return a small JSON answer with evidence IDs and unknowns. No Node/filesystem/network APIs. Fresh JS environment per call; analysis facts are reused across calls.",
z.strictObject({
code: z.string().min(1).max(32768),
timeout_ms: z.number().int().min(100).max(120000).default(120000),
}),
(input, signal) =>
executeJavaScript(session, input.code, {
signal,
timeoutMs: input.timeout_ms,
}),
);
}
return server;
};
const handle = serveStdio(createServer, {
onerror: (error) => process.stderr.write(`${error.message}\n`),
});
let closing;
const shutdown = () =>
(closing ??= (async () => {
session.abort();
await session.close();
await handle.close();
})().catch((error) => {
process.stderr.write(`${error.message}\n`);
process.exitCode = 1;
}));
process.once("SIGTERM", shutdown);
process.once("SIGINT", shutdown);
process.stdin.once("end", shutdown);