105 lines
2.5 KiB
JavaScript

#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/server";
import { serveStdio } from "@modelcontextprotocol/server/stdio";
import * as z from "zod/v4";
import {
applyCanvasOperation,
getCanvas,
getCurrentUser,
listCanvases,
} from "./api-client.mjs";
function toolResult(payload) {
return {
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
structuredContent: payload,
};
}
function toolError(error) {
return {
isError: true,
content: [
{
type: "text",
text: JSON.stringify({
success: false,
error: error instanceof Error ? error.message : String(error),
status: Number(error?.status) || undefined,
details: error?.payload || undefined,
}),
},
],
};
}
function register(server, name, definition, handler) {
server.registerTool(name, definition, async (input) => {
try {
return toolResult(await handler(input));
} catch (error) {
return toolError(error);
}
});
}
function buildServer() {
const server = new McpServer({
name: "yedir-canvas",
version: "0.1.0",
});
register(
server,
"yedir_get_current_user",
{
description: "Verify the configured Yedir Access Key and return its user and scopes.",
inputSchema: z.object({}),
},
() => getCurrentUser()
);
register(
server,
"yedir_list_canvases",
{
description: "List canvases owned by the authenticated user.",
inputSchema: z.object({
workspaceType: z.enum(["canvas", "agent", "video"]).default("canvas"),
limit: z.number().int().min(1).max(50).default(24),
}),
},
(input) => listCanvases(input)
);
register(
server,
"yedir_get_canvas",
{
description: "Read one canvas including its current revision, nodes, edges, and viewport.",
inputSchema: z.object({ canvasId: z.string().uuid() }),
},
({ canvasId }) => getCanvas(canvasId)
);
register(
server,
"yedir_apply_canvas_operation",
{
description:
"Apply one versioned semantic CanvasOperationPlan. Moving, deleting, or replacing content requires confirmed=true after explicit user confirmation.",
inputSchema: z.object({
canvasId: z.string().uuid(),
operationPlan: z.record(z.string(), z.unknown()),
}),
},
({ canvasId, operationPlan }) =>
applyCanvasOperation(canvasId, operationPlan)
);
return server;
}
await serveStdio(() => buildServer());