81 lines
3.2 KiB
TypeScript
81 lines
3.2 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { createFrameworkMcpServer } from "../src/index.ts";
|
|
|
|
function fixture() {
|
|
const root = mkdtempSync(join(tmpdir(), "wrnexus-mcp-"));
|
|
for (const dir of ["app/pages", "app/api", "app/components", "app/db/migrations", "docs"])
|
|
mkdirSync(join(root, dir), { recursive: true });
|
|
writeFileSync(join(root, "app/pages/index.wrn"), "<h1>Home</h1>");
|
|
writeFileSync(join(root, "app/api/users.ts"), "export const GET = () => Response.json([])");
|
|
writeFileSync(
|
|
join(root, "app/components/Button.wrn"),
|
|
"prop label: string\nevent click\n<button>{label}</button>",
|
|
);
|
|
writeFileSync(join(root, "app/db/migrations/001.sql"), "CREATE TABLE users(id TEXT);");
|
|
writeFileSync(join(root, "docs/GUIDE.md"), "# Guide");
|
|
writeFileSync(
|
|
join(root, "package.json"),
|
|
JSON.stringify({ dependencies: { "@wrnexus/core": "0.8.0", other: "1.0.0" } }),
|
|
);
|
|
return root;
|
|
}
|
|
|
|
describe("WRNexus MCP", () => {
|
|
test("exposes application framework context through bounded tools", async () => {
|
|
const server = createFrameworkMcpServer(fixture(), {
|
|
fetch: (async (input: URL | RequestInfo) =>
|
|
new Response(null, {
|
|
status: String(input).endsWith("readyz") ? 503 : 200,
|
|
})) as unknown as typeof fetch,
|
|
runtimeErrors: () => [{ message: "bad", token: "secret" }],
|
|
});
|
|
expect(((await server.call("wrnexus_routes")) as any[]).map((route) => route.path)).toEqual([
|
|
"/",
|
|
"/users",
|
|
]);
|
|
expect(await server.call("wrnexus_components")).toEqual([
|
|
{ name: "Button", file: "app/components/Button.wrn", props: ["label"], events: ["click"] },
|
|
]);
|
|
expect(((await server.call("wrnexus_database_schema")) as any[])[0].content).toContain(
|
|
"CREATE TABLE",
|
|
);
|
|
expect(await server.call("wrnexus_packages")).toEqual([
|
|
{ name: "@wrnexus/core", version: "0.8.0" },
|
|
]);
|
|
expect(await server.call("wrnexus_runtime_errors")).toEqual([
|
|
{ message: "bad", token: "[REDACTED]" },
|
|
]);
|
|
expect(await server.call("wrnexus_dev_status")).toMatchObject({
|
|
liveness: { ok: true },
|
|
readiness: { ok: false },
|
|
});
|
|
});
|
|
test("speaks MCP JSON-RPC initialize, list and call", async () => {
|
|
const server = createFrameworkMcpServer(fixture());
|
|
expect(await server.handle({ jsonrpc: "2.0", id: 1, method: "initialize" })).toHaveProperty(
|
|
"result.serverInfo.name",
|
|
"wrnexus",
|
|
);
|
|
expect(await server.handle({ jsonrpc: "2.0", id: 2, method: "tools/list" })).toHaveProperty(
|
|
"result.tools.0.name",
|
|
"wrnexus_routes",
|
|
);
|
|
const result = await server.handle({
|
|
jsonrpc: "2.0",
|
|
id: 3,
|
|
method: "tools/call",
|
|
params: { name: "wrnexus_docs", arguments: {} },
|
|
});
|
|
expect(result).toHaveProperty("result.structuredContent.value.0", "docs/GUIDE.md");
|
|
});
|
|
test("rejects documentation traversal", async () => {
|
|
const server = createFrameworkMcpServer(fixture());
|
|
await expect(server.call("wrnexus_docs", { file: "../secret" })).rejects.toThrow(
|
|
"WRN-MCP-DOC-PATH",
|
|
);
|
|
});
|
|
});
|