/** * MCP tools for rSwag (print-on-demand designs). * * Tools: rswag_list_designs, rswag_get_design */ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; import type { SyncServer } from "../local-first/sync-server"; import { swagDocId } from "../../modules/rswag/schemas"; import type { SwagDoc } from "../../modules/rswag/schemas"; import { resolveAccess, accessDeniedResponse } from "./_auth"; export function registerSwagTools(server: McpServer, syncServer: SyncServer) { server.tool( "rswag_list_designs", "List print-on-demand designs in a space", { space: z.string().describe("Space slug"), token: z.string().optional().describe("JWT auth token"), status: z.string().optional().describe("Filter by status (draft, active, paused, removed)"), }, async ({ space, token, status }) => { const access = await resolveAccess(token, space, false); if (!access.allowed) return accessDeniedResponse(access.reason!); const doc = syncServer.getDoc(swagDocId(space)); if (!doc) return { content: [{ type: "text", text: JSON.stringify({ error: "No swag data found" }) }] }; let designs = Object.values(doc.designs || {}); if (status) designs = designs.filter(d => d.status === status); const summary = designs.map(d => ({ id: d.id, title: d.title, productType: d.productType, source: d.source, status: d.status, imageUrl: d.imageUrl, tags: d.tags, productCount: d.products?.length ?? 0, createdAt: d.createdAt, })); return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] }; }, ); server.tool( "rswag_get_design", "Get full design details with product variants and pricing", { space: z.string().describe("Space slug"), token: z.string().optional().describe("JWT auth token"), design_id: z.string().describe("Design ID"), }, async ({ space, token, design_id }) => { const access = await resolveAccess(token, space, false); if (!access.allowed) return accessDeniedResponse(access.reason!); const doc = syncServer.getDoc(swagDocId(space)); const design = doc?.designs?.[design_id]; if (!design) return { content: [{ type: "text", text: JSON.stringify({ error: "Design not found" }) }] }; return { content: [{ type: "text", text: JSON.stringify(design, null, 2) }] }; }, ); }