75 lines
3 KiB
JavaScript
75 lines
3 KiB
JavaScript
#!/usr/bin/env node
|
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
import { existsSync } from "node:fs";
|
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join, resolve } from "node:path";
|
|
|
|
const workspaceRoot = resolve(process.cwd());
|
|
const serverPath = resolve(workspaceRoot, "apps", "worker", "dist", "mcp-server.js");
|
|
const storageRoot = await mkdtemp(join(tmpdir(), "voidbot-shared-documents-mcp-"));
|
|
if (!existsSync(serverPath)) {
|
|
throw new Error(`MCP server entrypoint is missing at ${serverPath}. Run the build first.`);
|
|
}
|
|
|
|
const expectedTools = ["read_shared_document", "create_shared_document", "update_shared_document"];
|
|
const transport = new StdioClientTransport({
|
|
command: process.execPath,
|
|
args: [serverPath],
|
|
cwd: workspaceRoot,
|
|
env: {
|
|
...process.env,
|
|
STORAGE_ROOT: storageRoot,
|
|
REPO_DISCORD_IDENTITIES_PATH: resolve(workspaceRoot, ".voidbot", "private", "repo-discord-identities.json"),
|
|
VOIDBOT_REPO_FACE_IDENTITY: "nibu",
|
|
VOIDBOT_MCP_TOOL_ALLOWLIST: expectedTools.join(","),
|
|
},
|
|
stderr: "pipe",
|
|
});
|
|
const client = new Client({ name: "voidbot-shared-documents-smoke", version: "0.0.0" });
|
|
|
|
try {
|
|
await client.connect(transport);
|
|
const tools = await client.listTools();
|
|
const names = tools.tools.map((tool) => tool.name).sort();
|
|
if (JSON.stringify(names) !== JSON.stringify([...expectedTools].sort())) {
|
|
throw new Error(`Unexpected shared-document tool surface: ${names.join(", ")}`);
|
|
}
|
|
|
|
const created = await client.callTool({
|
|
name: "create_shared_document",
|
|
arguments: { documentId: "shared-scratch", title: "Shared scratch", body: "First mark" },
|
|
});
|
|
assertOk(created, "create_shared_document");
|
|
if (created.structuredContent?.document?.createdBy !== "nibu") {
|
|
throw new Error("MCP server did not stamp the active Face identity on create.");
|
|
}
|
|
|
|
const read = await client.callTool({ name: "read_shared_document", arguments: { documentId: "shared-scratch" } });
|
|
assertOk(read, "read_shared_document");
|
|
if (read.structuredContent?.document?.version !== 1) {
|
|
throw new Error("MCP read did not return the created revision.");
|
|
}
|
|
|
|
const updated = await client.callTool({
|
|
name: "update_shared_document",
|
|
arguments: { documentId: "shared-scratch", body: "Second mark", expectedVersion: 1 },
|
|
});
|
|
assertOk(updated, "update_shared_document");
|
|
if (updated.structuredContent?.document?.version !== 2) {
|
|
throw new Error("MCP update did not advance the revision.");
|
|
}
|
|
|
|
process.stdout.write(`${JSON.stringify({ ok: true, tools: names, document: updated.structuredContent?.document })}\n`);
|
|
} finally {
|
|
await client.close();
|
|
await rm(storageRoot, { recursive: true, force: true });
|
|
}
|
|
|
|
function assertOk(result, tool) {
|
|
if (result.isError) {
|
|
const text = (result.content ?? []).map((entry) => entry.type === "text" ? entry.text : "").join("\n");
|
|
throw new Error(`${tool} failed: ${text}`);
|
|
}
|
|
}
|