@creatica/mcp 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/stdio.js +6 -3
- package/dist/stdio.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -119,7 +119,8 @@ var generateOutputShape = {
|
|
|
119
119
|
savedTo: z.string().optional().describe("Local only: absolute path the file was written to."),
|
|
120
120
|
bytes: z.number().optional().describe("Local only: bytes written to disk."),
|
|
121
121
|
warnings: z.array(z.string()).optional().describe("Options that were ignored or clamped, and why."),
|
|
122
|
-
note: z.string().optional().describe("Anything else worth knowing.")
|
|
122
|
+
note: z.string().optional().describe("Anything else worth knowing."),
|
|
123
|
+
hint: z.string().optional().describe("Hosted, no API key: how to get permanent URLs.")
|
|
123
124
|
};
|
|
124
125
|
function createMcpServer(options = {}) {
|
|
125
126
|
const { hosted } = options;
|
|
@@ -306,7 +307,7 @@ function createMcpServer(options = {}) {
|
|
|
306
307
|
title: "Generate a background",
|
|
307
308
|
description: [
|
|
308
309
|
"Render a background as SVG or PNG. Deterministic: the same structure, options and seed always give the same image, so store the returned seed.",
|
|
309
|
-
hosted ? "
|
|
310
|
+
hosted ? "With an API key, returns a permanent, cacheable image URL you can use directly in <img>/CSS, plus an inline PNG preview." : "Returns the image inline (PNG previews are visible to you); pass saveTo to also write the file to disk.",
|
|
310
311
|
"Call describe_background first to learn which shape options the structure honours."
|
|
311
312
|
].join(" "),
|
|
312
313
|
inputSchema: {
|
|
@@ -397,7 +398,9 @@ function createMcpServer(options = {}) {
|
|
|
397
398
|
request: { ...request, seed: result.seed },
|
|
398
399
|
...warnings.length ? { warnings } : {}
|
|
399
400
|
};
|
|
400
|
-
if (hosted) {
|
|
401
|
+
if (hosted && hosted.hostedUrls === false) {
|
|
402
|
+
meta.hint = `Permanent hosted URLs need an API key (free keys include 200 renders a month and brand kits)${hosted.keysUrl ? ": " + hosted.keysUrl : ""}.`;
|
|
403
|
+
} else if (hosted) {
|
|
401
404
|
meta.url = renderUrl(
|
|
402
405
|
hosted.publicBaseUrl,
|
|
403
406
|
{ ...request, seed: result.seed },
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["import {\n ENGINE_VERSION,\n renderPng,\n renderSvg,\n type RenderRequest,\n type RenderResult,\n} from '@creatica/engine';\nimport {\n catalog,\n describe,\n jsonSchemaFor,\n listPalettes,\n normalizeRequest,\n styleCard,\n suggest,\n} from '@creatica/schema';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, resolve } from 'node:path';\nimport { z } from 'zod';\n\nexport interface BrandKitSummary {\n slug: string;\n name: string;\n colors: string[];\n backgroundColor?: string;\n defaultStructure?: string;\n}\n\nexport interface HostedOptions {\n /** Public origin of the API, e.g. https://api.creatica.app */\n publicBaseUrl: string;\n /** Brand kits of the calling account; enables `brand` on generate and list_brand_kits. */\n listBrandKits?: () => Promise<BrandKitSummary[]>;\n /**\n * Called before rendering. Throw to refuse (e.g. quota exhausted); the\n * message is returned to the model as a tool error, so discovery tools keep\n * working and the model can explain what to do next.\n */\n beforeRender?: (request: RenderRequest) => void | Promise<void>;\n /** Called after a successful render so the host can meter usage. */\n onRender?: (\n result: RenderResult,\n format: 'svg' | 'png',\n ) => void | Promise<void>;\n}\n\nexport interface McpServerOptions {\n /**\n * Local mode (default) renders in-process and can write files to disk.\n * Hosted mode additionally returns permanent, cacheable image URLs and\n * never touches the filesystem.\n */\n hosted?: HostedOptions;\n /** Inline PNG previews above this many bytes are downscaled. */\n maxInlineBytes?: number;\n}\n\nconst hexColor = z\n .string()\n .regex(\n /^#?([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,\n 'hex colour like #1e90ff',\n );\n\nconst paletteShape = z\n .object({\n colors: z\n .array(hexColor)\n .min(1)\n .max(12)\n .optional()\n .describe(\n 'Explicit hex colours to draw from (best for brand matching). Overrides palette/scheme.',\n ),\n palette: z\n .string()\n .optional()\n .describe(\n 'Id of a built-in palette from list_palettes, e.g. \"underTheSea\".',\n ),\n primaryColor: hexColor\n .optional()\n .describe('Main hex colour when not passing colors/palette.'),\n secondaryColor: hexColor\n .optional()\n .describe('Second hex colour for two-tone structures.'),\n backgroundColor: hexColor\n .optional()\n .describe('Hex colour of the canvas behind the shapes.'),\n gradientColor: z\n .boolean()\n .optional()\n .describe('Gradient fills instead of flat colour.'),\n useMultiColor: z\n .boolean()\n .optional()\n .describe('false = everything in primaryColor.'),\n colorSchemeType: z\n .enum(['Mono', 'Tetrade', 'Analogic'])\n .optional()\n .describe('Derive a palette from primaryColor.'),\n opaqueColors: z\n .boolean()\n .optional()\n .describe('true = no transparency in the shape fills.'),\n })\n .strict();\n\n// Shape options are a loose record: which keys apply depends on the structure\n// (see describe_background). normalizeRequest() validates against that.\nconst shapeShape = z\n .record(z.string(), z.union([z.number(), z.boolean(), z.string()]))\n .describe(\n 'Structure-specific options; call describe_background for the exact keys, ranges and what they do.',\n );\n\nconst SERVER_DESCRIPTION =\n 'Deterministic procedural SVG/PNG backgrounds for websites, slides, social cards and apps: 58 generators, curated palettes and brand kits, every render reproducible from its seed.';\n\n// Output schemas: what each tool puts in structuredContent (the text content\n// carries the same JSON, so clients without structured-output support lose\n// nothing).\nconst sizeShape = z.object({\n width: z.number().describe('Native frame width in px.'),\n height: z.number().describe('Native frame height in px.'),\n});\n\nconst catalogEntryShape = z.looseObject({\n name: z\n .string()\n .describe('Structure id for describe_background / generate_background.'),\n title: z.string().describe('Human-readable name.'),\n summary: z.string().describe('One-line description of the look.'),\n tags: z.array(z.string()).describe('Style tags, e.g. geometric, organic.'),\n mood: z.array(z.string()).describe('Mood words, e.g. calm, playful, dark.'),\n useCases: z.array(z.string()).describe('Where it works well.'),\n previewUrl: z.string().describe('Preview image of the default render.'),\n defaultSize: sizeShape,\n});\n\nconst suggestionShape = z.looseObject({\n name: z.string().describe('Structure id.'),\n title: z.string(),\n summary: z.string(),\n score: z.number().describe('Relevance to the brief; higher is better.'),\n matched: z.array(z.string()).describe('Why it matched, for explaining.'),\n example: z\n .looseObject({ structure: z.string() })\n .describe('A ready-to-run generate_background request for this brief.'),\n palettes: z\n .array(z.string())\n .describe('Built-in palette ids whose mood fits the brief, best first.'),\n});\n\nconst paletteDescriptionShape = z.looseObject({\n id: z.string().describe('Value to pass as palette.palette.'),\n name: z.string(),\n colors: z.array(z.string()).describe('Hex colours.'),\n mood: z.array(z.string()).describe('Derived mood tags.'),\n lightness: z.number().describe('Average perceived lightness 0-1.'),\n saturation: z.number().describe('Average saturation 0-1.'),\n});\n\nconst paramDocShape = z.looseObject({\n key: z.string().describe('Option key to pass under shape/palette.'),\n group: z.enum(['shape', 'palette', 'frame']),\n title: z.string(),\n type: z.string(),\n description: z.string(),\n default: z.unknown().optional(),\n min: z.number().optional(),\n max: z.number().optional(),\n step: z.number().optional(),\n enum: z.array(z.string()).optional(),\n});\n\nconst structureDescriptionShape = z.looseObject({\n name: z.string(),\n title: z.string(),\n summary: z.string(),\n description: z.string(),\n tags: z.array(z.string()),\n mood: z.array(z.string()),\n useCases: z.array(z.string()),\n tips: z.array(z.string()),\n defaultSize: sizeShape,\n previewUrl: z.string(),\n params: z\n .array(paramDocShape)\n .describe('Every option this structure honours.'),\n});\n\nconst brandKitShape = z.looseObject({\n slug: z.string().describe('Value to pass as brand to generate_background.'),\n name: z.string(),\n colors: z.array(z.string()).describe('Hex colours.'),\n backgroundColor: z.string().optional(),\n defaultStructure: z.string().optional(),\n});\n\nconst generateOutputShape = {\n structure: z.string().describe('Structure that was rendered.'),\n seed: z\n .union([z.string(), z.number()])\n .describe('Seed used; reuse it to reproduce the exact image.'),\n width: z.number().describe('Render width in px.'),\n height: z.number().describe('Render height in px.'),\n format: z.enum(['svg', 'png']).describe('Delivered format.'),\n svgBytes: z.number().describe('Size of the SVG source in bytes.'),\n renderMs: z.number().describe('Render time in milliseconds.'),\n request: z\n .looseObject({ structure: z.string() })\n .describe('Resolved request incl. seed; replay it to reproduce or tweak.'),\n url: z\n .string()\n .optional()\n .describe(\n 'Hosted only: permanent, cacheable image URL in the requested format.',\n ),\n svgUrl: z\n .string()\n .optional()\n .describe('Hosted only: permanent URL of the SVG source.'),\n savedTo: z\n .string()\n .optional()\n .describe('Local only: absolute path the file was written to.'),\n bytes: z.number().optional().describe('Local only: bytes written to disk.'),\n warnings: z\n .array(z.string())\n .optional()\n .describe('Options that were ignored or clamped, and why.'),\n note: z.string().optional().describe('Anything else worth knowing.'),\n};\n\nexport function createMcpServer(options: McpServerOptions = {}): McpServer {\n const { hosted } = options;\n const maxInline = options.maxInlineBytes ?? 600_000;\n\n const server = new McpServer(\n {\n name: 'creatica-backgrounds',\n title: 'Creatica Backgrounds',\n version: ENGINE_VERSION,\n description: SERVER_DESCRIPTION,\n websiteUrl: 'https://creatica.app',\n icons: [\n {\n src: 'https://creatica.app/site/android-chrome-512x512.png',\n mimeType: 'image/png',\n sizes: ['512x512'],\n },\n {\n src: 'https://creatica.app/site/android-chrome-192x192.png',\n mimeType: 'image/png',\n sizes: ['192x192'],\n },\n ],\n },\n {\n instructions: [\n 'Creatica generates abstract, procedural SVG/PNG backgrounds (waves, blobs, bauhaus grids, topo lines, aurora glows…) for websites, slides, social cards and apps.',\n 'Workflow: suggest_backgrounds (or list_backgrounds) with the brief → describe_background for the chosen one → generate_background with a seed. Every render is deterministic: same structure + params + seed = identical image, so keep the seed to reproduce or make on-brand variants.',\n 'For brand colours pass palette.colors as hex. For a curated look pass palette.palette from list_palettes. Prefer PNG when you need a preview; SVG for the final asset.',\n ].join('\\n'),\n },\n );\n\n server.registerTool(\n 'list_backgrounds',\n {\n title: 'List backgrounds',\n description:\n 'Browse the catalog of background structures. Optionally filter by a free-text query, tag or mood word. Returns name, one-line summary, mood, use cases and a preview URL for each.',\n inputSchema: {\n query: z\n .string()\n .optional()\n .describe('Free text, e.g. \"calm waves\" or \"geometric poster\".'),\n mood: z\n .string()\n .optional()\n .describe('A mood word, e.g. dark, playful, minimal, retro.'),\n tag: z\n .string()\n .optional()\n .describe('A style tag, e.g. geometric, organic, grid, gradient.'),\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .describe('Maximum number of results (default 100).'),\n },\n outputSchema: {\n count: z.number().describe('Number of backgrounds returned.'),\n backgrounds: z.array(catalogEntryShape),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ query, mood, tag, limit }) => {\n let items = catalog();\n if (mood)\n items = items.filter((c) =>\n c.mood.some((m) => m.toLowerCase().includes(mood.toLowerCase())),\n );\n if (tag)\n items = items.filter((c) =>\n c.tags.some((t) => t.toLowerCase().includes(tag.toLowerCase())),\n );\n if (query) {\n const ranked = suggest(query, { limit: 100 }).map((s) => s.name);\n items = items\n .filter((c) => ranked.includes(c.name))\n .sort((a, b) => ranked.indexOf(a.name) - ranked.indexOf(b.name));\n }\n items = items.slice(0, limit ?? 100);\n return json({ count: items.length, backgrounds: items });\n },\n );\n\n server.registerTool(\n 'suggest_backgrounds',\n {\n title: 'Suggest backgrounds for a brief',\n description:\n 'Rank structures for a natural-language brief (\"dark aurora glow for an AI landing page\"). Returns why each matched, matching built-in palettes, and a ready-to-run example request for generate_background.',\n inputSchema: {\n brief: z\n .string()\n .min(2)\n .describe(\n 'What the background is for, in plain words: subject, mood, colours, where it goes.',\n ),\n limit: z\n .number()\n .int()\n .min(1)\n .max(20)\n .optional()\n .describe('How many suggestions to return (default 5).'),\n },\n outputSchema: {\n suggestions: z.array(suggestionShape).describe('Best match first.'),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ brief, limit }) =>\n json({ suggestions: suggest(brief, { limit: limit ?? 5 }) }),\n );\n\n server.registerTool(\n 'describe_background',\n {\n title: 'Describe a background',\n description:\n 'Full style card for one structure: what it looks like, mood, where text can go, tips, and every parameter it honours with ranges, defaults and the visual effect of low/high values. Also returns the JSON Schema for a generate request.',\n inputSchema: {\n name: z\n .string()\n .describe('Structure name from list_backgrounds, e.g. \"wave\".'),\n format: z\n .enum(['markdown', 'json'])\n .optional()\n .describe(\n 'markdown (default) is best for reading; json includes the JSON Schema.',\n ),\n },\n outputSchema: {\n name: z.string().describe('Structure id.'),\n format: z\n .enum(['markdown', 'json'])\n .describe('Which form was returned.'),\n card: z\n .string()\n .optional()\n .describe('markdown format: the style card as Markdown.'),\n description: structureDescriptionShape\n .optional()\n .describe('json format: the structured description.'),\n jsonSchema: z\n .looseObject({})\n .optional()\n .describe('json format: JSON Schema for a generate request.'),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ name, format }) => {\n try {\n if (format === 'json')\n return json({\n name,\n format: 'json',\n description: describe(name),\n jsonSchema: jsonSchemaFor(name),\n });\n const card = styleCard(name);\n return {\n content: [{ type: 'text', text: card }],\n structuredContent: { name, format: 'markdown', card },\n };\n } catch (e) {\n return error((e as Error).message);\n }\n },\n );\n\n server.registerTool(\n 'list_palettes',\n {\n title: 'List palettes',\n description:\n 'Built-in curated colour palettes with their hex colours and derived mood tags (dark, pastel, vivid, warm, cool…). Pass the id as palette.palette to generate_background.',\n inputSchema: {\n mood: z\n .string()\n .optional()\n .describe('Filter by a mood tag, e.g. \"dark\" or \"pastel\".'),\n },\n outputSchema: {\n count: z.number().describe('Number of palettes returned.'),\n palettes: z.array(paletteDescriptionShape),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ mood }) => {\n let items = listPalettes();\n if (mood)\n items = items.filter((p) => p.mood.includes(mood.toLowerCase()));\n return json({ count: items.length, palettes: items });\n },\n );\n\n if (hosted?.listBrandKits) {\n server.registerTool(\n 'list_brand_kits',\n {\n title: 'List brand kits',\n description:\n \"Saved brand palettes on this account. Pass a kit's slug as `brand` to generate_background to render on-brand without repeating hex colours.\",\n inputSchema: {},\n outputSchema: {\n brandKits: z\n .array(brandKitShape)\n .describe('Saved kits, may be empty.'),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async () => json({ brandKits: await hosted.listBrandKits!() }),\n );\n }\n\n server.registerTool(\n 'generate_background',\n {\n title: 'Generate a background',\n description: [\n 'Render a background as SVG or PNG. Deterministic: the same structure, options and seed always give the same image, so store the returned seed.',\n hosted\n ? 'Returns a permanent, cacheable image URL you can use directly in <img>/CSS, plus an inline PNG preview.'\n : 'Returns the image inline (PNG previews are visible to you); pass saveTo to also write the file to disk.',\n 'Call describe_background first to learn which shape options the structure honours.',\n ].join(' '),\n inputSchema: {\n structure: z.string().describe('Structure name, e.g. \"wave\".'),\n seed: z\n .string()\n .optional()\n .describe(\n 'Any string. Omit for a fresh random seed (returned in the result).',\n ),\n width: z\n .number()\n .int()\n .min(1)\n .max(8192)\n .optional()\n .describe(\n \"Frame width in px. Defaults to the structure's native size (see describe_background).\",\n ),\n height: z\n .number()\n .int()\n .min(1)\n .max(8192)\n .optional()\n .describe('Frame height in px. Defaults to the native size.'),\n palette: paletteShape\n .optional()\n .describe(\n 'Colour choices: explicit hex colours, a built-in palette id, or a primary colour to derive from.',\n ),\n shape: shapeShape.optional(),\n format: z\n .enum(['svg', 'png'])\n .optional()\n .describe(\n 'png (default) returns a viewable image; svg returns the vector source.',\n ),\n pngWidth: z\n .number()\n .int()\n .min(16)\n .max(8192)\n .optional()\n .describe(\n 'Raster width for PNG output/preview. Defaults to the render width, capped for inline previews.',\n ),\n ...(hosted?.listBrandKits\n ? {\n brand: z\n .string()\n .optional()\n .describe(\n 'Slug of a saved brand kit (see list_brand_kits); its colours become the palette baseline.',\n ),\n }\n : {}),\n ...(hosted\n ? {}\n : {\n saveTo: z\n .string()\n .optional()\n .describe(\n 'Local file path to write the result to (extension decides svg/png if format is omitted).',\n ),\n }),\n },\n outputSchema: generateOutputShape,\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (args) => {\n const input = { ...(args as Record<string, unknown>) };\n const brandSlug =\n typeof input.brand === 'string' ? input.brand : undefined;\n delete input.brand;\n if (brandSlug) {\n const kit = (await hosted?.listBrandKits?.())?.find(\n (k) => k.slug === brandSlug,\n );\n if (!kit)\n return error(\n `Unknown brand kit \"${brandSlug}\". Call list_brand_kits to see the available ones.`,\n );\n const basePalette: Record<string, unknown> = { colors: kit.colors };\n if (kit.backgroundColor)\n basePalette.backgroundColor = kit.backgroundColor;\n input.palette = {\n ...basePalette,\n ...((input.palette as Record<string, unknown>) ?? {}),\n };\n if (!input.structure && kit.defaultStructure)\n input.structure = kit.defaultStructure;\n }\n let normalized;\n try {\n normalized = normalizeRequest(input);\n } catch (e) {\n return error((e as Error).message);\n }\n const { request, warnings } = normalized;\n const saveTo = hosted ? undefined : (args as { saveTo?: string }).saveTo;\n const format: 'svg' | 'png' =\n (args.format as 'svg' | 'png' | undefined) ??\n (saveTo?.toLowerCase().endsWith('.svg') ? 'svg' : 'png');\n\n try {\n await hosted?.beforeRender?.(request);\n } catch (e) {\n return error((e as Error).message);\n }\n const result = await renderSvg(request);\n await hosted?.onRender?.(result, format);\n\n const content: CallToolResult['content'] = [];\n const meta: Record<string, unknown> = {\n structure: result.structure,\n seed: result.seed,\n width: result.width,\n height: result.height,\n format,\n svgBytes: result.svg.length,\n renderMs: result.durationMs,\n // Echo the resolved options so the caller can reproduce or tweak.\n request: { ...request, seed: result.seed },\n ...(warnings.length ? { warnings } : {}),\n };\n\n if (hosted) {\n meta.url = renderUrl(\n hosted.publicBaseUrl,\n { ...request, seed: result.seed },\n format,\n );\n meta.svgUrl = renderUrl(\n hosted.publicBaseUrl,\n { ...request, seed: result.seed },\n 'svg',\n );\n }\n\n if (saveTo) {\n const path = resolve(saveTo);\n await mkdir(dirname(path), { recursive: true });\n const bytes =\n format === 'png'\n ? await renderPng(result.svg, {\n width: args.pngWidth ?? result.width,\n })\n : Buffer.from(result.svg, 'utf8');\n await writeFile(path, bytes);\n meta.savedTo = path;\n meta.bytes = bytes.length;\n }\n\n if (format === 'svg') {\n if (result.svg.length <= maxInline && !saveTo) {\n content.push({\n type: 'resource',\n resource: {\n uri: `creatica://render/${result.structure}/${result.seed}.svg`,\n mimeType: 'image/svg+xml',\n text: result.svg,\n },\n });\n } else if (!saveTo && !hosted) {\n meta.note = `SVG is ${result.svg.length} bytes; pass saveTo to write it to disk instead of returning it inline.`;\n }\n }\n\n // Always attach a PNG preview so the model can see what it made. Keep\n // it modest: previews are for judging composition, not final delivery.\n const previewWidth = Math.min(args.pngWidth ?? 800, 1200);\n const png = await renderPng(result.svg, { width: previewWidth });\n if (png.length <= maxInline) {\n content.push({\n type: 'image',\n data: png.toString('base64'),\n mimeType: 'image/png',\n });\n } else {\n const small = await renderPng(result.svg, { width: 480 });\n content.push({\n type: 'image',\n data: small.toString('base64'),\n mimeType: 'image/png',\n });\n meta.note = `Preview downscaled to 480px (full PNG would be ${png.length} bytes).`;\n }\n\n content.unshift({ type: 'text', text: JSON.stringify(meta, null, 2) });\n return { content, structuredContent: meta };\n },\n );\n\n return server;\n}\n\nexport function renderUrl(\n baseUrl: string,\n req: RenderRequest,\n format: 'svg' | 'png',\n): string {\n const u = new URL(\n `/v1/render/${encodeURIComponent(req.structure)}.${format}`,\n baseUrl,\n );\n if (req.seed !== undefined) u.searchParams.set('seed', String(req.seed));\n if (req.width) u.searchParams.set('width', String(req.width));\n if (req.height) u.searchParams.set('height', String(req.height));\n for (const [k, v] of Object.entries(req.palette ?? {})) {\n if (v === undefined) continue;\n u.searchParams.set(k, Array.isArray(v) ? v.join(',') : String(v));\n }\n for (const [k, v] of Object.entries(req.shape ?? {})) {\n if (v !== undefined) u.searchParams.set(k, String(v));\n }\n return u.toString();\n}\n\nfunction json(value: Record<string, unknown>): CallToolResult {\n return {\n content: [{ type: 'text', text: JSON.stringify(value, null, 2) }],\n structuredContent: value,\n };\n}\nfunction error(message: string): CallToolResult {\n return { isError: true, content: [{ type: 'text', text: message }] };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["import {\n ENGINE_VERSION,\n renderPng,\n renderSvg,\n type RenderRequest,\n type RenderResult,\n} from '@creatica/engine';\nimport {\n catalog,\n describe,\n jsonSchemaFor,\n listPalettes,\n normalizeRequest,\n styleCard,\n suggest,\n} from '@creatica/schema';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, resolve } from 'node:path';\nimport { z } from 'zod';\n\nexport interface BrandKitSummary {\n slug: string;\n name: string;\n colors: string[];\n backgroundColor?: string;\n defaultStructure?: string;\n}\n\nexport interface HostedOptions {\n /** Public origin of the API, e.g. https://api.creatica.app */\n publicBaseUrl: string;\n /** Return permanent hosted URLs (default true). Hosts set false for anonymous callers. */\n hostedUrls?: boolean;\n /** Where to get a free key; mentioned when hostedUrls is false. */\n keysUrl?: string;\n /** Brand kits of the calling account; enables `brand` on generate and list_brand_kits. */\n listBrandKits?: () => Promise<BrandKitSummary[]>;\n /**\n * Called before rendering. Throw to refuse (e.g. quota exhausted); the\n * message is returned to the model as a tool error, so discovery tools keep\n * working and the model can explain what to do next.\n */\n beforeRender?: (request: RenderRequest) => void | Promise<void>;\n /** Called after a successful render so the host can meter usage. */\n onRender?: (\n result: RenderResult,\n format: 'svg' | 'png',\n ) => void | Promise<void>;\n}\n\nexport interface McpServerOptions {\n /**\n * Local mode (default) renders in-process and can write files to disk.\n * Hosted mode additionally returns permanent, cacheable image URLs and\n * never touches the filesystem.\n */\n hosted?: HostedOptions;\n /** Inline PNG previews above this many bytes are downscaled. */\n maxInlineBytes?: number;\n}\n\nconst hexColor = z\n .string()\n .regex(\n /^#?([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,\n 'hex colour like #1e90ff',\n );\n\nconst paletteShape = z\n .object({\n colors: z\n .array(hexColor)\n .min(1)\n .max(12)\n .optional()\n .describe(\n 'Explicit hex colours to draw from (best for brand matching). Overrides palette/scheme.',\n ),\n palette: z\n .string()\n .optional()\n .describe(\n 'Id of a built-in palette from list_palettes, e.g. \"underTheSea\".',\n ),\n primaryColor: hexColor\n .optional()\n .describe('Main hex colour when not passing colors/palette.'),\n secondaryColor: hexColor\n .optional()\n .describe('Second hex colour for two-tone structures.'),\n backgroundColor: hexColor\n .optional()\n .describe('Hex colour of the canvas behind the shapes.'),\n gradientColor: z\n .boolean()\n .optional()\n .describe('Gradient fills instead of flat colour.'),\n useMultiColor: z\n .boolean()\n .optional()\n .describe('false = everything in primaryColor.'),\n colorSchemeType: z\n .enum(['Mono', 'Tetrade', 'Analogic'])\n .optional()\n .describe('Derive a palette from primaryColor.'),\n opaqueColors: z\n .boolean()\n .optional()\n .describe('true = no transparency in the shape fills.'),\n })\n .strict();\n\n// Shape options are a loose record: which keys apply depends on the structure\n// (see describe_background). normalizeRequest() validates against that.\nconst shapeShape = z\n .record(z.string(), z.union([z.number(), z.boolean(), z.string()]))\n .describe(\n 'Structure-specific options; call describe_background for the exact keys, ranges and what they do.',\n );\n\nconst SERVER_DESCRIPTION =\n 'Deterministic procedural SVG/PNG backgrounds for websites, slides, social cards and apps: 58 generators, curated palettes and brand kits, every render reproducible from its seed.';\n\n// Output schemas: what each tool puts in structuredContent (the text content\n// carries the same JSON, so clients without structured-output support lose\n// nothing).\nconst sizeShape = z.object({\n width: z.number().describe('Native frame width in px.'),\n height: z.number().describe('Native frame height in px.'),\n});\n\nconst catalogEntryShape = z.looseObject({\n name: z\n .string()\n .describe('Structure id for describe_background / generate_background.'),\n title: z.string().describe('Human-readable name.'),\n summary: z.string().describe('One-line description of the look.'),\n tags: z.array(z.string()).describe('Style tags, e.g. geometric, organic.'),\n mood: z.array(z.string()).describe('Mood words, e.g. calm, playful, dark.'),\n useCases: z.array(z.string()).describe('Where it works well.'),\n previewUrl: z.string().describe('Preview image of the default render.'),\n defaultSize: sizeShape,\n});\n\nconst suggestionShape = z.looseObject({\n name: z.string().describe('Structure id.'),\n title: z.string(),\n summary: z.string(),\n score: z.number().describe('Relevance to the brief; higher is better.'),\n matched: z.array(z.string()).describe('Why it matched, for explaining.'),\n example: z\n .looseObject({ structure: z.string() })\n .describe('A ready-to-run generate_background request for this brief.'),\n palettes: z\n .array(z.string())\n .describe('Built-in palette ids whose mood fits the brief, best first.'),\n});\n\nconst paletteDescriptionShape = z.looseObject({\n id: z.string().describe('Value to pass as palette.palette.'),\n name: z.string(),\n colors: z.array(z.string()).describe('Hex colours.'),\n mood: z.array(z.string()).describe('Derived mood tags.'),\n lightness: z.number().describe('Average perceived lightness 0-1.'),\n saturation: z.number().describe('Average saturation 0-1.'),\n});\n\nconst paramDocShape = z.looseObject({\n key: z.string().describe('Option key to pass under shape/palette.'),\n group: z.enum(['shape', 'palette', 'frame']),\n title: z.string(),\n type: z.string(),\n description: z.string(),\n default: z.unknown().optional(),\n min: z.number().optional(),\n max: z.number().optional(),\n step: z.number().optional(),\n enum: z.array(z.string()).optional(),\n});\n\nconst structureDescriptionShape = z.looseObject({\n name: z.string(),\n title: z.string(),\n summary: z.string(),\n description: z.string(),\n tags: z.array(z.string()),\n mood: z.array(z.string()),\n useCases: z.array(z.string()),\n tips: z.array(z.string()),\n defaultSize: sizeShape,\n previewUrl: z.string(),\n params: z\n .array(paramDocShape)\n .describe('Every option this structure honours.'),\n});\n\nconst brandKitShape = z.looseObject({\n slug: z.string().describe('Value to pass as brand to generate_background.'),\n name: z.string(),\n colors: z.array(z.string()).describe('Hex colours.'),\n backgroundColor: z.string().optional(),\n defaultStructure: z.string().optional(),\n});\n\nconst generateOutputShape = {\n structure: z.string().describe('Structure that was rendered.'),\n seed: z\n .union([z.string(), z.number()])\n .describe('Seed used; reuse it to reproduce the exact image.'),\n width: z.number().describe('Render width in px.'),\n height: z.number().describe('Render height in px.'),\n format: z.enum(['svg', 'png']).describe('Delivered format.'),\n svgBytes: z.number().describe('Size of the SVG source in bytes.'),\n renderMs: z.number().describe('Render time in milliseconds.'),\n request: z\n .looseObject({ structure: z.string() })\n .describe('Resolved request incl. seed; replay it to reproduce or tweak.'),\n url: z\n .string()\n .optional()\n .describe(\n 'Hosted only: permanent, cacheable image URL in the requested format.',\n ),\n svgUrl: z\n .string()\n .optional()\n .describe('Hosted only: permanent URL of the SVG source.'),\n savedTo: z\n .string()\n .optional()\n .describe('Local only: absolute path the file was written to.'),\n bytes: z.number().optional().describe('Local only: bytes written to disk.'),\n warnings: z\n .array(z.string())\n .optional()\n .describe('Options that were ignored or clamped, and why.'),\n note: z.string().optional().describe('Anything else worth knowing.'),\n hint: z\n .string()\n .optional()\n .describe('Hosted, no API key: how to get permanent URLs.'),\n};\n\nexport function createMcpServer(options: McpServerOptions = {}): McpServer {\n const { hosted } = options;\n const maxInline = options.maxInlineBytes ?? 600_000;\n\n const server = new McpServer(\n {\n name: 'creatica-backgrounds',\n title: 'Creatica Backgrounds',\n version: ENGINE_VERSION,\n description: SERVER_DESCRIPTION,\n websiteUrl: 'https://creatica.app',\n icons: [\n {\n src: 'https://creatica.app/site/android-chrome-512x512.png',\n mimeType: 'image/png',\n sizes: ['512x512'],\n },\n {\n src: 'https://creatica.app/site/android-chrome-192x192.png',\n mimeType: 'image/png',\n sizes: ['192x192'],\n },\n ],\n },\n {\n instructions: [\n 'Creatica generates abstract, procedural SVG/PNG backgrounds (waves, blobs, bauhaus grids, topo lines, aurora glows…) for websites, slides, social cards and apps.',\n 'Workflow: suggest_backgrounds (or list_backgrounds) with the brief → describe_background for the chosen one → generate_background with a seed. Every render is deterministic: same structure + params + seed = identical image, so keep the seed to reproduce or make on-brand variants.',\n 'For brand colours pass palette.colors as hex. For a curated look pass palette.palette from list_palettes. Prefer PNG when you need a preview; SVG for the final asset.',\n ].join('\\n'),\n },\n );\n\n server.registerTool(\n 'list_backgrounds',\n {\n title: 'List backgrounds',\n description:\n 'Browse the catalog of background structures. Optionally filter by a free-text query, tag or mood word. Returns name, one-line summary, mood, use cases and a preview URL for each.',\n inputSchema: {\n query: z\n .string()\n .optional()\n .describe('Free text, e.g. \"calm waves\" or \"geometric poster\".'),\n mood: z\n .string()\n .optional()\n .describe('A mood word, e.g. dark, playful, minimal, retro.'),\n tag: z\n .string()\n .optional()\n .describe('A style tag, e.g. geometric, organic, grid, gradient.'),\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .describe('Maximum number of results (default 100).'),\n },\n outputSchema: {\n count: z.number().describe('Number of backgrounds returned.'),\n backgrounds: z.array(catalogEntryShape),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ query, mood, tag, limit }) => {\n let items = catalog();\n if (mood)\n items = items.filter((c) =>\n c.mood.some((m) => m.toLowerCase().includes(mood.toLowerCase())),\n );\n if (tag)\n items = items.filter((c) =>\n c.tags.some((t) => t.toLowerCase().includes(tag.toLowerCase())),\n );\n if (query) {\n const ranked = suggest(query, { limit: 100 }).map((s) => s.name);\n items = items\n .filter((c) => ranked.includes(c.name))\n .sort((a, b) => ranked.indexOf(a.name) - ranked.indexOf(b.name));\n }\n items = items.slice(0, limit ?? 100);\n return json({ count: items.length, backgrounds: items });\n },\n );\n\n server.registerTool(\n 'suggest_backgrounds',\n {\n title: 'Suggest backgrounds for a brief',\n description:\n 'Rank structures for a natural-language brief (\"dark aurora glow for an AI landing page\"). Returns why each matched, matching built-in palettes, and a ready-to-run example request for generate_background.',\n inputSchema: {\n brief: z\n .string()\n .min(2)\n .describe(\n 'What the background is for, in plain words: subject, mood, colours, where it goes.',\n ),\n limit: z\n .number()\n .int()\n .min(1)\n .max(20)\n .optional()\n .describe('How many suggestions to return (default 5).'),\n },\n outputSchema: {\n suggestions: z.array(suggestionShape).describe('Best match first.'),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ brief, limit }) =>\n json({ suggestions: suggest(brief, { limit: limit ?? 5 }) }),\n );\n\n server.registerTool(\n 'describe_background',\n {\n title: 'Describe a background',\n description:\n 'Full style card for one structure: what it looks like, mood, where text can go, tips, and every parameter it honours with ranges, defaults and the visual effect of low/high values. Also returns the JSON Schema for a generate request.',\n inputSchema: {\n name: z\n .string()\n .describe('Structure name from list_backgrounds, e.g. \"wave\".'),\n format: z\n .enum(['markdown', 'json'])\n .optional()\n .describe(\n 'markdown (default) is best for reading; json includes the JSON Schema.',\n ),\n },\n outputSchema: {\n name: z.string().describe('Structure id.'),\n format: z\n .enum(['markdown', 'json'])\n .describe('Which form was returned.'),\n card: z\n .string()\n .optional()\n .describe('markdown format: the style card as Markdown.'),\n description: structureDescriptionShape\n .optional()\n .describe('json format: the structured description.'),\n jsonSchema: z\n .looseObject({})\n .optional()\n .describe('json format: JSON Schema for a generate request.'),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ name, format }) => {\n try {\n if (format === 'json')\n return json({\n name,\n format: 'json',\n description: describe(name),\n jsonSchema: jsonSchemaFor(name),\n });\n const card = styleCard(name);\n return {\n content: [{ type: 'text', text: card }],\n structuredContent: { name, format: 'markdown', card },\n };\n } catch (e) {\n return error((e as Error).message);\n }\n },\n );\n\n server.registerTool(\n 'list_palettes',\n {\n title: 'List palettes',\n description:\n 'Built-in curated colour palettes with their hex colours and derived mood tags (dark, pastel, vivid, warm, cool…). Pass the id as palette.palette to generate_background.',\n inputSchema: {\n mood: z\n .string()\n .optional()\n .describe('Filter by a mood tag, e.g. \"dark\" or \"pastel\".'),\n },\n outputSchema: {\n count: z.number().describe('Number of palettes returned.'),\n palettes: z.array(paletteDescriptionShape),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ mood }) => {\n let items = listPalettes();\n if (mood)\n items = items.filter((p) => p.mood.includes(mood.toLowerCase()));\n return json({ count: items.length, palettes: items });\n },\n );\n\n if (hosted?.listBrandKits) {\n server.registerTool(\n 'list_brand_kits',\n {\n title: 'List brand kits',\n description:\n \"Saved brand palettes on this account. Pass a kit's slug as `brand` to generate_background to render on-brand without repeating hex colours.\",\n inputSchema: {},\n outputSchema: {\n brandKits: z\n .array(brandKitShape)\n .describe('Saved kits, may be empty.'),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async () => json({ brandKits: await hosted.listBrandKits!() }),\n );\n }\n\n server.registerTool(\n 'generate_background',\n {\n title: 'Generate a background',\n description: [\n 'Render a background as SVG or PNG. Deterministic: the same structure, options and seed always give the same image, so store the returned seed.',\n hosted\n ? 'With an API key, returns a permanent, cacheable image URL you can use directly in <img>/CSS, plus an inline PNG preview.'\n : 'Returns the image inline (PNG previews are visible to you); pass saveTo to also write the file to disk.',\n 'Call describe_background first to learn which shape options the structure honours.',\n ].join(' '),\n inputSchema: {\n structure: z.string().describe('Structure name, e.g. \"wave\".'),\n seed: z\n .string()\n .optional()\n .describe(\n 'Any string. Omit for a fresh random seed (returned in the result).',\n ),\n width: z\n .number()\n .int()\n .min(1)\n .max(8192)\n .optional()\n .describe(\n \"Frame width in px. Defaults to the structure's native size (see describe_background).\",\n ),\n height: z\n .number()\n .int()\n .min(1)\n .max(8192)\n .optional()\n .describe('Frame height in px. Defaults to the native size.'),\n palette: paletteShape\n .optional()\n .describe(\n 'Colour choices: explicit hex colours, a built-in palette id, or a primary colour to derive from.',\n ),\n shape: shapeShape.optional(),\n format: z\n .enum(['svg', 'png'])\n .optional()\n .describe(\n 'png (default) returns a viewable image; svg returns the vector source.',\n ),\n pngWidth: z\n .number()\n .int()\n .min(16)\n .max(8192)\n .optional()\n .describe(\n 'Raster width for PNG output/preview. Defaults to the render width, capped for inline previews.',\n ),\n ...(hosted?.listBrandKits\n ? {\n brand: z\n .string()\n .optional()\n .describe(\n 'Slug of a saved brand kit (see list_brand_kits); its colours become the palette baseline.',\n ),\n }\n : {}),\n ...(hosted\n ? {}\n : {\n saveTo: z\n .string()\n .optional()\n .describe(\n 'Local file path to write the result to (extension decides svg/png if format is omitted).',\n ),\n }),\n },\n outputSchema: generateOutputShape,\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (args) => {\n const input = { ...(args as Record<string, unknown>) };\n const brandSlug =\n typeof input.brand === 'string' ? input.brand : undefined;\n delete input.brand;\n if (brandSlug) {\n const kit = (await hosted?.listBrandKits?.())?.find(\n (k) => k.slug === brandSlug,\n );\n if (!kit)\n return error(\n `Unknown brand kit \"${brandSlug}\". Call list_brand_kits to see the available ones.`,\n );\n const basePalette: Record<string, unknown> = { colors: kit.colors };\n if (kit.backgroundColor)\n basePalette.backgroundColor = kit.backgroundColor;\n input.palette = {\n ...basePalette,\n ...((input.palette as Record<string, unknown>) ?? {}),\n };\n if (!input.structure && kit.defaultStructure)\n input.structure = kit.defaultStructure;\n }\n let normalized;\n try {\n normalized = normalizeRequest(input);\n } catch (e) {\n return error((e as Error).message);\n }\n const { request, warnings } = normalized;\n const saveTo = hosted ? undefined : (args as { saveTo?: string }).saveTo;\n const format: 'svg' | 'png' =\n (args.format as 'svg' | 'png' | undefined) ??\n (saveTo?.toLowerCase().endsWith('.svg') ? 'svg' : 'png');\n\n try {\n await hosted?.beforeRender?.(request);\n } catch (e) {\n return error((e as Error).message);\n }\n const result = await renderSvg(request);\n await hosted?.onRender?.(result, format);\n\n const content: CallToolResult['content'] = [];\n const meta: Record<string, unknown> = {\n structure: result.structure,\n seed: result.seed,\n width: result.width,\n height: result.height,\n format,\n svgBytes: result.svg.length,\n renderMs: result.durationMs,\n // Echo the resolved options so the caller can reproduce or tweak.\n request: { ...request, seed: result.seed },\n ...(warnings.length ? { warnings } : {}),\n };\n\n if (hosted && hosted.hostedUrls === false) {\n meta.hint = `Permanent hosted URLs need an API key (free keys include 200 renders a month and brand kits)${hosted.keysUrl ? ': ' + hosted.keysUrl : ''}.`;\n } else if (hosted) {\n meta.url = renderUrl(\n hosted.publicBaseUrl,\n { ...request, seed: result.seed },\n format,\n );\n meta.svgUrl = renderUrl(\n hosted.publicBaseUrl,\n { ...request, seed: result.seed },\n 'svg',\n );\n }\n\n if (saveTo) {\n const path = resolve(saveTo);\n await mkdir(dirname(path), { recursive: true });\n const bytes =\n format === 'png'\n ? await renderPng(result.svg, {\n width: args.pngWidth ?? result.width,\n })\n : Buffer.from(result.svg, 'utf8');\n await writeFile(path, bytes);\n meta.savedTo = path;\n meta.bytes = bytes.length;\n }\n\n if (format === 'svg') {\n if (result.svg.length <= maxInline && !saveTo) {\n content.push({\n type: 'resource',\n resource: {\n uri: `creatica://render/${result.structure}/${result.seed}.svg`,\n mimeType: 'image/svg+xml',\n text: result.svg,\n },\n });\n } else if (!saveTo && !hosted) {\n meta.note = `SVG is ${result.svg.length} bytes; pass saveTo to write it to disk instead of returning it inline.`;\n }\n }\n\n // Always attach a PNG preview so the model can see what it made. Keep\n // it modest: previews are for judging composition, not final delivery.\n const previewWidth = Math.min(args.pngWidth ?? 800, 1200);\n const png = await renderPng(result.svg, { width: previewWidth });\n if (png.length <= maxInline) {\n content.push({\n type: 'image',\n data: png.toString('base64'),\n mimeType: 'image/png',\n });\n } else {\n const small = await renderPng(result.svg, { width: 480 });\n content.push({\n type: 'image',\n data: small.toString('base64'),\n mimeType: 'image/png',\n });\n meta.note = `Preview downscaled to 480px (full PNG would be ${png.length} bytes).`;\n }\n\n content.unshift({ type: 'text', text: JSON.stringify(meta, null, 2) });\n return { content, structuredContent: meta };\n },\n );\n\n return server;\n}\n\nexport function renderUrl(\n baseUrl: string,\n req: RenderRequest,\n format: 'svg' | 'png',\n): string {\n const u = new URL(\n `/v1/render/${encodeURIComponent(req.structure)}.${format}`,\n baseUrl,\n );\n if (req.seed !== undefined) u.searchParams.set('seed', String(req.seed));\n if (req.width) u.searchParams.set('width', String(req.width));\n if (req.height) u.searchParams.set('height', String(req.height));\n for (const [k, v] of Object.entries(req.palette ?? {})) {\n if (v === undefined) continue;\n u.searchParams.set(k, Array.isArray(v) ? v.join(',') : String(v));\n }\n for (const [k, v] of Object.entries(req.shape ?? {})) {\n if (v !== undefined) u.searchParams.set(k, String(v));\n }\n return u.toString();\n}\n\nfunction json(value: Record<string, unknown>): CallToolResult {\n return {\n content: [{ type: 'text', text: JSON.stringify(value, null, 2) }],\n structuredContent: value,\n };\n}\nfunction error(message: string): CallToolResult {\n return { isError: true, content: [{ type: 'text', text: message }] };\n}\n"],"mappings":"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","names":[]}
|
package/dist/stdio.js
CHANGED
|
@@ -124,7 +124,8 @@ var generateOutputShape = {
|
|
|
124
124
|
savedTo: z.string().optional().describe("Local only: absolute path the file was written to."),
|
|
125
125
|
bytes: z.number().optional().describe("Local only: bytes written to disk."),
|
|
126
126
|
warnings: z.array(z.string()).optional().describe("Options that were ignored or clamped, and why."),
|
|
127
|
-
note: z.string().optional().describe("Anything else worth knowing.")
|
|
127
|
+
note: z.string().optional().describe("Anything else worth knowing."),
|
|
128
|
+
hint: z.string().optional().describe("Hosted, no API key: how to get permanent URLs.")
|
|
128
129
|
};
|
|
129
130
|
function createMcpServer(options = {}) {
|
|
130
131
|
const { hosted } = options;
|
|
@@ -311,7 +312,7 @@ function createMcpServer(options = {}) {
|
|
|
311
312
|
title: "Generate a background",
|
|
312
313
|
description: [
|
|
313
314
|
"Render a background as SVG or PNG. Deterministic: the same structure, options and seed always give the same image, so store the returned seed.",
|
|
314
|
-
hosted ? "
|
|
315
|
+
hosted ? "With an API key, returns a permanent, cacheable image URL you can use directly in <img>/CSS, plus an inline PNG preview." : "Returns the image inline (PNG previews are visible to you); pass saveTo to also write the file to disk.",
|
|
315
316
|
"Call describe_background first to learn which shape options the structure honours."
|
|
316
317
|
].join(" "),
|
|
317
318
|
inputSchema: {
|
|
@@ -402,7 +403,9 @@ function createMcpServer(options = {}) {
|
|
|
402
403
|
request: { ...request, seed: result.seed },
|
|
403
404
|
...warnings.length ? { warnings } : {}
|
|
404
405
|
};
|
|
405
|
-
if (hosted) {
|
|
406
|
+
if (hosted && hosted.hostedUrls === false) {
|
|
407
|
+
meta.hint = `Permanent hosted URLs need an API key (free keys include 200 renders a month and brand kits)${hosted.keysUrl ? ": " + hosted.keysUrl : ""}.`;
|
|
408
|
+
} else if (hosted) {
|
|
406
409
|
meta.url = renderUrl(
|
|
407
410
|
hosted.publicBaseUrl,
|
|
408
411
|
{ ...request, seed: result.seed },
|
package/dist/stdio.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/stdio.ts","../src/server.ts"],"sourcesContent":["#!/usr/bin/env node\n// Local MCP server over stdio. Runs the whole engine on this machine; no\n// network, no account. Add to Claude Desktop / Claude Code / Cursor as:\n// { \"command\": \"npx\", \"args\": [\"-y\", \"@creatica/mcp\"] }\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { createMcpServer } from './server.js';\n\nif (process.argv.includes('--help') || process.argv.includes('-h')) {\n process.stdout.write(\n [\n 'creatica-mcp — Model Context Protocol server for Creatica backgrounds (stdio).',\n '',\n 'Tools: list_backgrounds, suggest_backgrounds, describe_background, list_palettes, generate_background',\n '',\n 'Claude Code: claude mcp add creatica -- npx -y @creatica/mcp',\n 'Claude Desktop: add {\"mcpServers\":{\"creatica\":{\"command\":\"npx\",\"args\":[\"-y\",\"@creatica/mcp\"]}}}',\n '',\n ].join('\\n'),\n );\n process.exit(0);\n}\n\nconst server = createMcpServer();\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n","import {\n ENGINE_VERSION,\n renderPng,\n renderSvg,\n type RenderRequest,\n type RenderResult,\n} from '@creatica/engine';\nimport {\n catalog,\n describe,\n jsonSchemaFor,\n listPalettes,\n normalizeRequest,\n styleCard,\n suggest,\n} from '@creatica/schema';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, resolve } from 'node:path';\nimport { z } from 'zod';\n\nexport interface BrandKitSummary {\n slug: string;\n name: string;\n colors: string[];\n backgroundColor?: string;\n defaultStructure?: string;\n}\n\nexport interface HostedOptions {\n /** Public origin of the API, e.g. https://api.creatica.app */\n publicBaseUrl: string;\n /** Brand kits of the calling account; enables `brand` on generate and list_brand_kits. */\n listBrandKits?: () => Promise<BrandKitSummary[]>;\n /**\n * Called before rendering. Throw to refuse (e.g. quota exhausted); the\n * message is returned to the model as a tool error, so discovery tools keep\n * working and the model can explain what to do next.\n */\n beforeRender?: (request: RenderRequest) => void | Promise<void>;\n /** Called after a successful render so the host can meter usage. */\n onRender?: (\n result: RenderResult,\n format: 'svg' | 'png',\n ) => void | Promise<void>;\n}\n\nexport interface McpServerOptions {\n /**\n * Local mode (default) renders in-process and can write files to disk.\n * Hosted mode additionally returns permanent, cacheable image URLs and\n * never touches the filesystem.\n */\n hosted?: HostedOptions;\n /** Inline PNG previews above this many bytes are downscaled. */\n maxInlineBytes?: number;\n}\n\nconst hexColor = z\n .string()\n .regex(\n /^#?([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,\n 'hex colour like #1e90ff',\n );\n\nconst paletteShape = z\n .object({\n colors: z\n .array(hexColor)\n .min(1)\n .max(12)\n .optional()\n .describe(\n 'Explicit hex colours to draw from (best for brand matching). Overrides palette/scheme.',\n ),\n palette: z\n .string()\n .optional()\n .describe(\n 'Id of a built-in palette from list_palettes, e.g. \"underTheSea\".',\n ),\n primaryColor: hexColor\n .optional()\n .describe('Main hex colour when not passing colors/palette.'),\n secondaryColor: hexColor\n .optional()\n .describe('Second hex colour for two-tone structures.'),\n backgroundColor: hexColor\n .optional()\n .describe('Hex colour of the canvas behind the shapes.'),\n gradientColor: z\n .boolean()\n .optional()\n .describe('Gradient fills instead of flat colour.'),\n useMultiColor: z\n .boolean()\n .optional()\n .describe('false = everything in primaryColor.'),\n colorSchemeType: z\n .enum(['Mono', 'Tetrade', 'Analogic'])\n .optional()\n .describe('Derive a palette from primaryColor.'),\n opaqueColors: z\n .boolean()\n .optional()\n .describe('true = no transparency in the shape fills.'),\n })\n .strict();\n\n// Shape options are a loose record: which keys apply depends on the structure\n// (see describe_background). normalizeRequest() validates against that.\nconst shapeShape = z\n .record(z.string(), z.union([z.number(), z.boolean(), z.string()]))\n .describe(\n 'Structure-specific options; call describe_background for the exact keys, ranges and what they do.',\n );\n\nconst SERVER_DESCRIPTION =\n 'Deterministic procedural SVG/PNG backgrounds for websites, slides, social cards and apps: 58 generators, curated palettes and brand kits, every render reproducible from its seed.';\n\n// Output schemas: what each tool puts in structuredContent (the text content\n// carries the same JSON, so clients without structured-output support lose\n// nothing).\nconst sizeShape = z.object({\n width: z.number().describe('Native frame width in px.'),\n height: z.number().describe('Native frame height in px.'),\n});\n\nconst catalogEntryShape = z.looseObject({\n name: z\n .string()\n .describe('Structure id for describe_background / generate_background.'),\n title: z.string().describe('Human-readable name.'),\n summary: z.string().describe('One-line description of the look.'),\n tags: z.array(z.string()).describe('Style tags, e.g. geometric, organic.'),\n mood: z.array(z.string()).describe('Mood words, e.g. calm, playful, dark.'),\n useCases: z.array(z.string()).describe('Where it works well.'),\n previewUrl: z.string().describe('Preview image of the default render.'),\n defaultSize: sizeShape,\n});\n\nconst suggestionShape = z.looseObject({\n name: z.string().describe('Structure id.'),\n title: z.string(),\n summary: z.string(),\n score: z.number().describe('Relevance to the brief; higher is better.'),\n matched: z.array(z.string()).describe('Why it matched, for explaining.'),\n example: z\n .looseObject({ structure: z.string() })\n .describe('A ready-to-run generate_background request for this brief.'),\n palettes: z\n .array(z.string())\n .describe('Built-in palette ids whose mood fits the brief, best first.'),\n});\n\nconst paletteDescriptionShape = z.looseObject({\n id: z.string().describe('Value to pass as palette.palette.'),\n name: z.string(),\n colors: z.array(z.string()).describe('Hex colours.'),\n mood: z.array(z.string()).describe('Derived mood tags.'),\n lightness: z.number().describe('Average perceived lightness 0-1.'),\n saturation: z.number().describe('Average saturation 0-1.'),\n});\n\nconst paramDocShape = z.looseObject({\n key: z.string().describe('Option key to pass under shape/palette.'),\n group: z.enum(['shape', 'palette', 'frame']),\n title: z.string(),\n type: z.string(),\n description: z.string(),\n default: z.unknown().optional(),\n min: z.number().optional(),\n max: z.number().optional(),\n step: z.number().optional(),\n enum: z.array(z.string()).optional(),\n});\n\nconst structureDescriptionShape = z.looseObject({\n name: z.string(),\n title: z.string(),\n summary: z.string(),\n description: z.string(),\n tags: z.array(z.string()),\n mood: z.array(z.string()),\n useCases: z.array(z.string()),\n tips: z.array(z.string()),\n defaultSize: sizeShape,\n previewUrl: z.string(),\n params: z\n .array(paramDocShape)\n .describe('Every option this structure honours.'),\n});\n\nconst brandKitShape = z.looseObject({\n slug: z.string().describe('Value to pass as brand to generate_background.'),\n name: z.string(),\n colors: z.array(z.string()).describe('Hex colours.'),\n backgroundColor: z.string().optional(),\n defaultStructure: z.string().optional(),\n});\n\nconst generateOutputShape = {\n structure: z.string().describe('Structure that was rendered.'),\n seed: z\n .union([z.string(), z.number()])\n .describe('Seed used; reuse it to reproduce the exact image.'),\n width: z.number().describe('Render width in px.'),\n height: z.number().describe('Render height in px.'),\n format: z.enum(['svg', 'png']).describe('Delivered format.'),\n svgBytes: z.number().describe('Size of the SVG source in bytes.'),\n renderMs: z.number().describe('Render time in milliseconds.'),\n request: z\n .looseObject({ structure: z.string() })\n .describe('Resolved request incl. seed; replay it to reproduce or tweak.'),\n url: z\n .string()\n .optional()\n .describe(\n 'Hosted only: permanent, cacheable image URL in the requested format.',\n ),\n svgUrl: z\n .string()\n .optional()\n .describe('Hosted only: permanent URL of the SVG source.'),\n savedTo: z\n .string()\n .optional()\n .describe('Local only: absolute path the file was written to.'),\n bytes: z.number().optional().describe('Local only: bytes written to disk.'),\n warnings: z\n .array(z.string())\n .optional()\n .describe('Options that were ignored or clamped, and why.'),\n note: z.string().optional().describe('Anything else worth knowing.'),\n};\n\nexport function createMcpServer(options: McpServerOptions = {}): McpServer {\n const { hosted } = options;\n const maxInline = options.maxInlineBytes ?? 600_000;\n\n const server = new McpServer(\n {\n name: 'creatica-backgrounds',\n title: 'Creatica Backgrounds',\n version: ENGINE_VERSION,\n description: SERVER_DESCRIPTION,\n websiteUrl: 'https://creatica.app',\n icons: [\n {\n src: 'https://creatica.app/site/android-chrome-512x512.png',\n mimeType: 'image/png',\n sizes: ['512x512'],\n },\n {\n src: 'https://creatica.app/site/android-chrome-192x192.png',\n mimeType: 'image/png',\n sizes: ['192x192'],\n },\n ],\n },\n {\n instructions: [\n 'Creatica generates abstract, procedural SVG/PNG backgrounds (waves, blobs, bauhaus grids, topo lines, aurora glows…) for websites, slides, social cards and apps.',\n 'Workflow: suggest_backgrounds (or list_backgrounds) with the brief → describe_background for the chosen one → generate_background with a seed. Every render is deterministic: same structure + params + seed = identical image, so keep the seed to reproduce or make on-brand variants.',\n 'For brand colours pass palette.colors as hex. For a curated look pass palette.palette from list_palettes. Prefer PNG when you need a preview; SVG for the final asset.',\n ].join('\\n'),\n },\n );\n\n server.registerTool(\n 'list_backgrounds',\n {\n title: 'List backgrounds',\n description:\n 'Browse the catalog of background structures. Optionally filter by a free-text query, tag or mood word. Returns name, one-line summary, mood, use cases and a preview URL for each.',\n inputSchema: {\n query: z\n .string()\n .optional()\n .describe('Free text, e.g. \"calm waves\" or \"geometric poster\".'),\n mood: z\n .string()\n .optional()\n .describe('A mood word, e.g. dark, playful, minimal, retro.'),\n tag: z\n .string()\n .optional()\n .describe('A style tag, e.g. geometric, organic, grid, gradient.'),\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .describe('Maximum number of results (default 100).'),\n },\n outputSchema: {\n count: z.number().describe('Number of backgrounds returned.'),\n backgrounds: z.array(catalogEntryShape),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ query, mood, tag, limit }) => {\n let items = catalog();\n if (mood)\n items = items.filter((c) =>\n c.mood.some((m) => m.toLowerCase().includes(mood.toLowerCase())),\n );\n if (tag)\n items = items.filter((c) =>\n c.tags.some((t) => t.toLowerCase().includes(tag.toLowerCase())),\n );\n if (query) {\n const ranked = suggest(query, { limit: 100 }).map((s) => s.name);\n items = items\n .filter((c) => ranked.includes(c.name))\n .sort((a, b) => ranked.indexOf(a.name) - ranked.indexOf(b.name));\n }\n items = items.slice(0, limit ?? 100);\n return json({ count: items.length, backgrounds: items });\n },\n );\n\n server.registerTool(\n 'suggest_backgrounds',\n {\n title: 'Suggest backgrounds for a brief',\n description:\n 'Rank structures for a natural-language brief (\"dark aurora glow for an AI landing page\"). Returns why each matched, matching built-in palettes, and a ready-to-run example request for generate_background.',\n inputSchema: {\n brief: z\n .string()\n .min(2)\n .describe(\n 'What the background is for, in plain words: subject, mood, colours, where it goes.',\n ),\n limit: z\n .number()\n .int()\n .min(1)\n .max(20)\n .optional()\n .describe('How many suggestions to return (default 5).'),\n },\n outputSchema: {\n suggestions: z.array(suggestionShape).describe('Best match first.'),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ brief, limit }) =>\n json({ suggestions: suggest(brief, { limit: limit ?? 5 }) }),\n );\n\n server.registerTool(\n 'describe_background',\n {\n title: 'Describe a background',\n description:\n 'Full style card for one structure: what it looks like, mood, where text can go, tips, and every parameter it honours with ranges, defaults and the visual effect of low/high values. Also returns the JSON Schema for a generate request.',\n inputSchema: {\n name: z\n .string()\n .describe('Structure name from list_backgrounds, e.g. \"wave\".'),\n format: z\n .enum(['markdown', 'json'])\n .optional()\n .describe(\n 'markdown (default) is best for reading; json includes the JSON Schema.',\n ),\n },\n outputSchema: {\n name: z.string().describe('Structure id.'),\n format: z\n .enum(['markdown', 'json'])\n .describe('Which form was returned.'),\n card: z\n .string()\n .optional()\n .describe('markdown format: the style card as Markdown.'),\n description: structureDescriptionShape\n .optional()\n .describe('json format: the structured description.'),\n jsonSchema: z\n .looseObject({})\n .optional()\n .describe('json format: JSON Schema for a generate request.'),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ name, format }) => {\n try {\n if (format === 'json')\n return json({\n name,\n format: 'json',\n description: describe(name),\n jsonSchema: jsonSchemaFor(name),\n });\n const card = styleCard(name);\n return {\n content: [{ type: 'text', text: card }],\n structuredContent: { name, format: 'markdown', card },\n };\n } catch (e) {\n return error((e as Error).message);\n }\n },\n );\n\n server.registerTool(\n 'list_palettes',\n {\n title: 'List palettes',\n description:\n 'Built-in curated colour palettes with their hex colours and derived mood tags (dark, pastel, vivid, warm, cool…). Pass the id as palette.palette to generate_background.',\n inputSchema: {\n mood: z\n .string()\n .optional()\n .describe('Filter by a mood tag, e.g. \"dark\" or \"pastel\".'),\n },\n outputSchema: {\n count: z.number().describe('Number of palettes returned.'),\n palettes: z.array(paletteDescriptionShape),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ mood }) => {\n let items = listPalettes();\n if (mood)\n items = items.filter((p) => p.mood.includes(mood.toLowerCase()));\n return json({ count: items.length, palettes: items });\n },\n );\n\n if (hosted?.listBrandKits) {\n server.registerTool(\n 'list_brand_kits',\n {\n title: 'List brand kits',\n description:\n \"Saved brand palettes on this account. Pass a kit's slug as `brand` to generate_background to render on-brand without repeating hex colours.\",\n inputSchema: {},\n outputSchema: {\n brandKits: z\n .array(brandKitShape)\n .describe('Saved kits, may be empty.'),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async () => json({ brandKits: await hosted.listBrandKits!() }),\n );\n }\n\n server.registerTool(\n 'generate_background',\n {\n title: 'Generate a background',\n description: [\n 'Render a background as SVG or PNG. Deterministic: the same structure, options and seed always give the same image, so store the returned seed.',\n hosted\n ? 'Returns a permanent, cacheable image URL you can use directly in <img>/CSS, plus an inline PNG preview.'\n : 'Returns the image inline (PNG previews are visible to you); pass saveTo to also write the file to disk.',\n 'Call describe_background first to learn which shape options the structure honours.',\n ].join(' '),\n inputSchema: {\n structure: z.string().describe('Structure name, e.g. \"wave\".'),\n seed: z\n .string()\n .optional()\n .describe(\n 'Any string. Omit for a fresh random seed (returned in the result).',\n ),\n width: z\n .number()\n .int()\n .min(1)\n .max(8192)\n .optional()\n .describe(\n \"Frame width in px. Defaults to the structure's native size (see describe_background).\",\n ),\n height: z\n .number()\n .int()\n .min(1)\n .max(8192)\n .optional()\n .describe('Frame height in px. Defaults to the native size.'),\n palette: paletteShape\n .optional()\n .describe(\n 'Colour choices: explicit hex colours, a built-in palette id, or a primary colour to derive from.',\n ),\n shape: shapeShape.optional(),\n format: z\n .enum(['svg', 'png'])\n .optional()\n .describe(\n 'png (default) returns a viewable image; svg returns the vector source.',\n ),\n pngWidth: z\n .number()\n .int()\n .min(16)\n .max(8192)\n .optional()\n .describe(\n 'Raster width for PNG output/preview. Defaults to the render width, capped for inline previews.',\n ),\n ...(hosted?.listBrandKits\n ? {\n brand: z\n .string()\n .optional()\n .describe(\n 'Slug of a saved brand kit (see list_brand_kits); its colours become the palette baseline.',\n ),\n }\n : {}),\n ...(hosted\n ? {}\n : {\n saveTo: z\n .string()\n .optional()\n .describe(\n 'Local file path to write the result to (extension decides svg/png if format is omitted).',\n ),\n }),\n },\n outputSchema: generateOutputShape,\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (args) => {\n const input = { ...(args as Record<string, unknown>) };\n const brandSlug =\n typeof input.brand === 'string' ? input.brand : undefined;\n delete input.brand;\n if (brandSlug) {\n const kit = (await hosted?.listBrandKits?.())?.find(\n (k) => k.slug === brandSlug,\n );\n if (!kit)\n return error(\n `Unknown brand kit \"${brandSlug}\". Call list_brand_kits to see the available ones.`,\n );\n const basePalette: Record<string, unknown> = { colors: kit.colors };\n if (kit.backgroundColor)\n basePalette.backgroundColor = kit.backgroundColor;\n input.palette = {\n ...basePalette,\n ...((input.palette as Record<string, unknown>) ?? {}),\n };\n if (!input.structure && kit.defaultStructure)\n input.structure = kit.defaultStructure;\n }\n let normalized;\n try {\n normalized = normalizeRequest(input);\n } catch (e) {\n return error((e as Error).message);\n }\n const { request, warnings } = normalized;\n const saveTo = hosted ? undefined : (args as { saveTo?: string }).saveTo;\n const format: 'svg' | 'png' =\n (args.format as 'svg' | 'png' | undefined) ??\n (saveTo?.toLowerCase().endsWith('.svg') ? 'svg' : 'png');\n\n try {\n await hosted?.beforeRender?.(request);\n } catch (e) {\n return error((e as Error).message);\n }\n const result = await renderSvg(request);\n await hosted?.onRender?.(result, format);\n\n const content: CallToolResult['content'] = [];\n const meta: Record<string, unknown> = {\n structure: result.structure,\n seed: result.seed,\n width: result.width,\n height: result.height,\n format,\n svgBytes: result.svg.length,\n renderMs: result.durationMs,\n // Echo the resolved options so the caller can reproduce or tweak.\n request: { ...request, seed: result.seed },\n ...(warnings.length ? { warnings } : {}),\n };\n\n if (hosted) {\n meta.url = renderUrl(\n hosted.publicBaseUrl,\n { ...request, seed: result.seed },\n format,\n );\n meta.svgUrl = renderUrl(\n hosted.publicBaseUrl,\n { ...request, seed: result.seed },\n 'svg',\n );\n }\n\n if (saveTo) {\n const path = resolve(saveTo);\n await mkdir(dirname(path), { recursive: true });\n const bytes =\n format === 'png'\n ? await renderPng(result.svg, {\n width: args.pngWidth ?? result.width,\n })\n : Buffer.from(result.svg, 'utf8');\n await writeFile(path, bytes);\n meta.savedTo = path;\n meta.bytes = bytes.length;\n }\n\n if (format === 'svg') {\n if (result.svg.length <= maxInline && !saveTo) {\n content.push({\n type: 'resource',\n resource: {\n uri: `creatica://render/${result.structure}/${result.seed}.svg`,\n mimeType: 'image/svg+xml',\n text: result.svg,\n },\n });\n } else if (!saveTo && !hosted) {\n meta.note = `SVG is ${result.svg.length} bytes; pass saveTo to write it to disk instead of returning it inline.`;\n }\n }\n\n // Always attach a PNG preview so the model can see what it made. Keep\n // it modest: previews are for judging composition, not final delivery.\n const previewWidth = Math.min(args.pngWidth ?? 800, 1200);\n const png = await renderPng(result.svg, { width: previewWidth });\n if (png.length <= maxInline) {\n content.push({\n type: 'image',\n data: png.toString('base64'),\n mimeType: 'image/png',\n });\n } else {\n const small = await renderPng(result.svg, { width: 480 });\n content.push({\n type: 'image',\n data: small.toString('base64'),\n mimeType: 'image/png',\n });\n meta.note = `Preview downscaled to 480px (full PNG would be ${png.length} bytes).`;\n }\n\n content.unshift({ type: 'text', text: JSON.stringify(meta, null, 2) });\n return { content, structuredContent: meta };\n },\n );\n\n return server;\n}\n\nexport function renderUrl(\n baseUrl: string,\n req: RenderRequest,\n format: 'svg' | 'png',\n): string {\n const u = new URL(\n `/v1/render/${encodeURIComponent(req.structure)}.${format}`,\n baseUrl,\n );\n if (req.seed !== undefined) u.searchParams.set('seed', String(req.seed));\n if (req.width) u.searchParams.set('width', String(req.width));\n if (req.height) u.searchParams.set('height', String(req.height));\n for (const [k, v] of Object.entries(req.palette ?? {})) {\n if (v === undefined) continue;\n u.searchParams.set(k, Array.isArray(v) ? v.join(',') : String(v));\n }\n for (const [k, v] of Object.entries(req.shape ?? {})) {\n if (v !== undefined) u.searchParams.set(k, String(v));\n }\n return u.toString();\n}\n\nfunction json(value: Record<string, unknown>): CallToolResult {\n return {\n content: [{ type: 'text', text: JSON.stringify(value, null, 2) }],\n structuredContent: value,\n };\n}\nfunction error(message: string): CallToolResult {\n return { isError: true, content: [{ type: 'text', text: message }] };\n}\n"],"mappings":"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","names":["server"]}
|
|
1
|
+
{"version":3,"sources":["../src/stdio.ts","../src/server.ts"],"sourcesContent":["#!/usr/bin/env node\n// Local MCP server over stdio. Runs the whole engine on this machine; no\n// network, no account. Add to Claude Desktop / Claude Code / Cursor as:\n// { \"command\": \"npx\", \"args\": [\"-y\", \"@creatica/mcp\"] }\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { createMcpServer } from './server.js';\n\nif (process.argv.includes('--help') || process.argv.includes('-h')) {\n process.stdout.write(\n [\n 'creatica-mcp — Model Context Protocol server for Creatica backgrounds (stdio).',\n '',\n 'Tools: list_backgrounds, suggest_backgrounds, describe_background, list_palettes, generate_background',\n '',\n 'Claude Code: claude mcp add creatica -- npx -y @creatica/mcp',\n 'Claude Desktop: add {\"mcpServers\":{\"creatica\":{\"command\":\"npx\",\"args\":[\"-y\",\"@creatica/mcp\"]}}}',\n '',\n ].join('\\n'),\n );\n process.exit(0);\n}\n\nconst server = createMcpServer();\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n","import {\n ENGINE_VERSION,\n renderPng,\n renderSvg,\n type RenderRequest,\n type RenderResult,\n} from '@creatica/engine';\nimport {\n catalog,\n describe,\n jsonSchemaFor,\n listPalettes,\n normalizeRequest,\n styleCard,\n suggest,\n} from '@creatica/schema';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, resolve } from 'node:path';\nimport { z } from 'zod';\n\nexport interface BrandKitSummary {\n slug: string;\n name: string;\n colors: string[];\n backgroundColor?: string;\n defaultStructure?: string;\n}\n\nexport interface HostedOptions {\n /** Public origin of the API, e.g. https://api.creatica.app */\n publicBaseUrl: string;\n /** Return permanent hosted URLs (default true). Hosts set false for anonymous callers. */\n hostedUrls?: boolean;\n /** Where to get a free key; mentioned when hostedUrls is false. */\n keysUrl?: string;\n /** Brand kits of the calling account; enables `brand` on generate and list_brand_kits. */\n listBrandKits?: () => Promise<BrandKitSummary[]>;\n /**\n * Called before rendering. Throw to refuse (e.g. quota exhausted); the\n * message is returned to the model as a tool error, so discovery tools keep\n * working and the model can explain what to do next.\n */\n beforeRender?: (request: RenderRequest) => void | Promise<void>;\n /** Called after a successful render so the host can meter usage. */\n onRender?: (\n result: RenderResult,\n format: 'svg' | 'png',\n ) => void | Promise<void>;\n}\n\nexport interface McpServerOptions {\n /**\n * Local mode (default) renders in-process and can write files to disk.\n * Hosted mode additionally returns permanent, cacheable image URLs and\n * never touches the filesystem.\n */\n hosted?: HostedOptions;\n /** Inline PNG previews above this many bytes are downscaled. */\n maxInlineBytes?: number;\n}\n\nconst hexColor = z\n .string()\n .regex(\n /^#?([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,\n 'hex colour like #1e90ff',\n );\n\nconst paletteShape = z\n .object({\n colors: z\n .array(hexColor)\n .min(1)\n .max(12)\n .optional()\n .describe(\n 'Explicit hex colours to draw from (best for brand matching). Overrides palette/scheme.',\n ),\n palette: z\n .string()\n .optional()\n .describe(\n 'Id of a built-in palette from list_palettes, e.g. \"underTheSea\".',\n ),\n primaryColor: hexColor\n .optional()\n .describe('Main hex colour when not passing colors/palette.'),\n secondaryColor: hexColor\n .optional()\n .describe('Second hex colour for two-tone structures.'),\n backgroundColor: hexColor\n .optional()\n .describe('Hex colour of the canvas behind the shapes.'),\n gradientColor: z\n .boolean()\n .optional()\n .describe('Gradient fills instead of flat colour.'),\n useMultiColor: z\n .boolean()\n .optional()\n .describe('false = everything in primaryColor.'),\n colorSchemeType: z\n .enum(['Mono', 'Tetrade', 'Analogic'])\n .optional()\n .describe('Derive a palette from primaryColor.'),\n opaqueColors: z\n .boolean()\n .optional()\n .describe('true = no transparency in the shape fills.'),\n })\n .strict();\n\n// Shape options are a loose record: which keys apply depends on the structure\n// (see describe_background). normalizeRequest() validates against that.\nconst shapeShape = z\n .record(z.string(), z.union([z.number(), z.boolean(), z.string()]))\n .describe(\n 'Structure-specific options; call describe_background for the exact keys, ranges and what they do.',\n );\n\nconst SERVER_DESCRIPTION =\n 'Deterministic procedural SVG/PNG backgrounds for websites, slides, social cards and apps: 58 generators, curated palettes and brand kits, every render reproducible from its seed.';\n\n// Output schemas: what each tool puts in structuredContent (the text content\n// carries the same JSON, so clients without structured-output support lose\n// nothing).\nconst sizeShape = z.object({\n width: z.number().describe('Native frame width in px.'),\n height: z.number().describe('Native frame height in px.'),\n});\n\nconst catalogEntryShape = z.looseObject({\n name: z\n .string()\n .describe('Structure id for describe_background / generate_background.'),\n title: z.string().describe('Human-readable name.'),\n summary: z.string().describe('One-line description of the look.'),\n tags: z.array(z.string()).describe('Style tags, e.g. geometric, organic.'),\n mood: z.array(z.string()).describe('Mood words, e.g. calm, playful, dark.'),\n useCases: z.array(z.string()).describe('Where it works well.'),\n previewUrl: z.string().describe('Preview image of the default render.'),\n defaultSize: sizeShape,\n});\n\nconst suggestionShape = z.looseObject({\n name: z.string().describe('Structure id.'),\n title: z.string(),\n summary: z.string(),\n score: z.number().describe('Relevance to the brief; higher is better.'),\n matched: z.array(z.string()).describe('Why it matched, for explaining.'),\n example: z\n .looseObject({ structure: z.string() })\n .describe('A ready-to-run generate_background request for this brief.'),\n palettes: z\n .array(z.string())\n .describe('Built-in palette ids whose mood fits the brief, best first.'),\n});\n\nconst paletteDescriptionShape = z.looseObject({\n id: z.string().describe('Value to pass as palette.palette.'),\n name: z.string(),\n colors: z.array(z.string()).describe('Hex colours.'),\n mood: z.array(z.string()).describe('Derived mood tags.'),\n lightness: z.number().describe('Average perceived lightness 0-1.'),\n saturation: z.number().describe('Average saturation 0-1.'),\n});\n\nconst paramDocShape = z.looseObject({\n key: z.string().describe('Option key to pass under shape/palette.'),\n group: z.enum(['shape', 'palette', 'frame']),\n title: z.string(),\n type: z.string(),\n description: z.string(),\n default: z.unknown().optional(),\n min: z.number().optional(),\n max: z.number().optional(),\n step: z.number().optional(),\n enum: z.array(z.string()).optional(),\n});\n\nconst structureDescriptionShape = z.looseObject({\n name: z.string(),\n title: z.string(),\n summary: z.string(),\n description: z.string(),\n tags: z.array(z.string()),\n mood: z.array(z.string()),\n useCases: z.array(z.string()),\n tips: z.array(z.string()),\n defaultSize: sizeShape,\n previewUrl: z.string(),\n params: z\n .array(paramDocShape)\n .describe('Every option this structure honours.'),\n});\n\nconst brandKitShape = z.looseObject({\n slug: z.string().describe('Value to pass as brand to generate_background.'),\n name: z.string(),\n colors: z.array(z.string()).describe('Hex colours.'),\n backgroundColor: z.string().optional(),\n defaultStructure: z.string().optional(),\n});\n\nconst generateOutputShape = {\n structure: z.string().describe('Structure that was rendered.'),\n seed: z\n .union([z.string(), z.number()])\n .describe('Seed used; reuse it to reproduce the exact image.'),\n width: z.number().describe('Render width in px.'),\n height: z.number().describe('Render height in px.'),\n format: z.enum(['svg', 'png']).describe('Delivered format.'),\n svgBytes: z.number().describe('Size of the SVG source in bytes.'),\n renderMs: z.number().describe('Render time in milliseconds.'),\n request: z\n .looseObject({ structure: z.string() })\n .describe('Resolved request incl. seed; replay it to reproduce or tweak.'),\n url: z\n .string()\n .optional()\n .describe(\n 'Hosted only: permanent, cacheable image URL in the requested format.',\n ),\n svgUrl: z\n .string()\n .optional()\n .describe('Hosted only: permanent URL of the SVG source.'),\n savedTo: z\n .string()\n .optional()\n .describe('Local only: absolute path the file was written to.'),\n bytes: z.number().optional().describe('Local only: bytes written to disk.'),\n warnings: z\n .array(z.string())\n .optional()\n .describe('Options that were ignored or clamped, and why.'),\n note: z.string().optional().describe('Anything else worth knowing.'),\n hint: z\n .string()\n .optional()\n .describe('Hosted, no API key: how to get permanent URLs.'),\n};\n\nexport function createMcpServer(options: McpServerOptions = {}): McpServer {\n const { hosted } = options;\n const maxInline = options.maxInlineBytes ?? 600_000;\n\n const server = new McpServer(\n {\n name: 'creatica-backgrounds',\n title: 'Creatica Backgrounds',\n version: ENGINE_VERSION,\n description: SERVER_DESCRIPTION,\n websiteUrl: 'https://creatica.app',\n icons: [\n {\n src: 'https://creatica.app/site/android-chrome-512x512.png',\n mimeType: 'image/png',\n sizes: ['512x512'],\n },\n {\n src: 'https://creatica.app/site/android-chrome-192x192.png',\n mimeType: 'image/png',\n sizes: ['192x192'],\n },\n ],\n },\n {\n instructions: [\n 'Creatica generates abstract, procedural SVG/PNG backgrounds (waves, blobs, bauhaus grids, topo lines, aurora glows…) for websites, slides, social cards and apps.',\n 'Workflow: suggest_backgrounds (or list_backgrounds) with the brief → describe_background for the chosen one → generate_background with a seed. Every render is deterministic: same structure + params + seed = identical image, so keep the seed to reproduce or make on-brand variants.',\n 'For brand colours pass palette.colors as hex. For a curated look pass palette.palette from list_palettes. Prefer PNG when you need a preview; SVG for the final asset.',\n ].join('\\n'),\n },\n );\n\n server.registerTool(\n 'list_backgrounds',\n {\n title: 'List backgrounds',\n description:\n 'Browse the catalog of background structures. Optionally filter by a free-text query, tag or mood word. Returns name, one-line summary, mood, use cases and a preview URL for each.',\n inputSchema: {\n query: z\n .string()\n .optional()\n .describe('Free text, e.g. \"calm waves\" or \"geometric poster\".'),\n mood: z\n .string()\n .optional()\n .describe('A mood word, e.g. dark, playful, minimal, retro.'),\n tag: z\n .string()\n .optional()\n .describe('A style tag, e.g. geometric, organic, grid, gradient.'),\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .describe('Maximum number of results (default 100).'),\n },\n outputSchema: {\n count: z.number().describe('Number of backgrounds returned.'),\n backgrounds: z.array(catalogEntryShape),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ query, mood, tag, limit }) => {\n let items = catalog();\n if (mood)\n items = items.filter((c) =>\n c.mood.some((m) => m.toLowerCase().includes(mood.toLowerCase())),\n );\n if (tag)\n items = items.filter((c) =>\n c.tags.some((t) => t.toLowerCase().includes(tag.toLowerCase())),\n );\n if (query) {\n const ranked = suggest(query, { limit: 100 }).map((s) => s.name);\n items = items\n .filter((c) => ranked.includes(c.name))\n .sort((a, b) => ranked.indexOf(a.name) - ranked.indexOf(b.name));\n }\n items = items.slice(0, limit ?? 100);\n return json({ count: items.length, backgrounds: items });\n },\n );\n\n server.registerTool(\n 'suggest_backgrounds',\n {\n title: 'Suggest backgrounds for a brief',\n description:\n 'Rank structures for a natural-language brief (\"dark aurora glow for an AI landing page\"). Returns why each matched, matching built-in palettes, and a ready-to-run example request for generate_background.',\n inputSchema: {\n brief: z\n .string()\n .min(2)\n .describe(\n 'What the background is for, in plain words: subject, mood, colours, where it goes.',\n ),\n limit: z\n .number()\n .int()\n .min(1)\n .max(20)\n .optional()\n .describe('How many suggestions to return (default 5).'),\n },\n outputSchema: {\n suggestions: z.array(suggestionShape).describe('Best match first.'),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ brief, limit }) =>\n json({ suggestions: suggest(brief, { limit: limit ?? 5 }) }),\n );\n\n server.registerTool(\n 'describe_background',\n {\n title: 'Describe a background',\n description:\n 'Full style card for one structure: what it looks like, mood, where text can go, tips, and every parameter it honours with ranges, defaults and the visual effect of low/high values. Also returns the JSON Schema for a generate request.',\n inputSchema: {\n name: z\n .string()\n .describe('Structure name from list_backgrounds, e.g. \"wave\".'),\n format: z\n .enum(['markdown', 'json'])\n .optional()\n .describe(\n 'markdown (default) is best for reading; json includes the JSON Schema.',\n ),\n },\n outputSchema: {\n name: z.string().describe('Structure id.'),\n format: z\n .enum(['markdown', 'json'])\n .describe('Which form was returned.'),\n card: z\n .string()\n .optional()\n .describe('markdown format: the style card as Markdown.'),\n description: structureDescriptionShape\n .optional()\n .describe('json format: the structured description.'),\n jsonSchema: z\n .looseObject({})\n .optional()\n .describe('json format: JSON Schema for a generate request.'),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ name, format }) => {\n try {\n if (format === 'json')\n return json({\n name,\n format: 'json',\n description: describe(name),\n jsonSchema: jsonSchemaFor(name),\n });\n const card = styleCard(name);\n return {\n content: [{ type: 'text', text: card }],\n structuredContent: { name, format: 'markdown', card },\n };\n } catch (e) {\n return error((e as Error).message);\n }\n },\n );\n\n server.registerTool(\n 'list_palettes',\n {\n title: 'List palettes',\n description:\n 'Built-in curated colour palettes with their hex colours and derived mood tags (dark, pastel, vivid, warm, cool…). Pass the id as palette.palette to generate_background.',\n inputSchema: {\n mood: z\n .string()\n .optional()\n .describe('Filter by a mood tag, e.g. \"dark\" or \"pastel\".'),\n },\n outputSchema: {\n count: z.number().describe('Number of palettes returned.'),\n palettes: z.array(paletteDescriptionShape),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ mood }) => {\n let items = listPalettes();\n if (mood)\n items = items.filter((p) => p.mood.includes(mood.toLowerCase()));\n return json({ count: items.length, palettes: items });\n },\n );\n\n if (hosted?.listBrandKits) {\n server.registerTool(\n 'list_brand_kits',\n {\n title: 'List brand kits',\n description:\n \"Saved brand palettes on this account. Pass a kit's slug as `brand` to generate_background to render on-brand without repeating hex colours.\",\n inputSchema: {},\n outputSchema: {\n brandKits: z\n .array(brandKitShape)\n .describe('Saved kits, may be empty.'),\n },\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async () => json({ brandKits: await hosted.listBrandKits!() }),\n );\n }\n\n server.registerTool(\n 'generate_background',\n {\n title: 'Generate a background',\n description: [\n 'Render a background as SVG or PNG. Deterministic: the same structure, options and seed always give the same image, so store the returned seed.',\n hosted\n ? 'With an API key, returns a permanent, cacheable image URL you can use directly in <img>/CSS, plus an inline PNG preview.'\n : 'Returns the image inline (PNG previews are visible to you); pass saveTo to also write the file to disk.',\n 'Call describe_background first to learn which shape options the structure honours.',\n ].join(' '),\n inputSchema: {\n structure: z.string().describe('Structure name, e.g. \"wave\".'),\n seed: z\n .string()\n .optional()\n .describe(\n 'Any string. Omit for a fresh random seed (returned in the result).',\n ),\n width: z\n .number()\n .int()\n .min(1)\n .max(8192)\n .optional()\n .describe(\n \"Frame width in px. Defaults to the structure's native size (see describe_background).\",\n ),\n height: z\n .number()\n .int()\n .min(1)\n .max(8192)\n .optional()\n .describe('Frame height in px. Defaults to the native size.'),\n palette: paletteShape\n .optional()\n .describe(\n 'Colour choices: explicit hex colours, a built-in palette id, or a primary colour to derive from.',\n ),\n shape: shapeShape.optional(),\n format: z\n .enum(['svg', 'png'])\n .optional()\n .describe(\n 'png (default) returns a viewable image; svg returns the vector source.',\n ),\n pngWidth: z\n .number()\n .int()\n .min(16)\n .max(8192)\n .optional()\n .describe(\n 'Raster width for PNG output/preview. Defaults to the render width, capped for inline previews.',\n ),\n ...(hosted?.listBrandKits\n ? {\n brand: z\n .string()\n .optional()\n .describe(\n 'Slug of a saved brand kit (see list_brand_kits); its colours become the palette baseline.',\n ),\n }\n : {}),\n ...(hosted\n ? {}\n : {\n saveTo: z\n .string()\n .optional()\n .describe(\n 'Local file path to write the result to (extension decides svg/png if format is omitted).',\n ),\n }),\n },\n outputSchema: generateOutputShape,\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (args) => {\n const input = { ...(args as Record<string, unknown>) };\n const brandSlug =\n typeof input.brand === 'string' ? input.brand : undefined;\n delete input.brand;\n if (brandSlug) {\n const kit = (await hosted?.listBrandKits?.())?.find(\n (k) => k.slug === brandSlug,\n );\n if (!kit)\n return error(\n `Unknown brand kit \"${brandSlug}\". Call list_brand_kits to see the available ones.`,\n );\n const basePalette: Record<string, unknown> = { colors: kit.colors };\n if (kit.backgroundColor)\n basePalette.backgroundColor = kit.backgroundColor;\n input.palette = {\n ...basePalette,\n ...((input.palette as Record<string, unknown>) ?? {}),\n };\n if (!input.structure && kit.defaultStructure)\n input.structure = kit.defaultStructure;\n }\n let normalized;\n try {\n normalized = normalizeRequest(input);\n } catch (e) {\n return error((e as Error).message);\n }\n const { request, warnings } = normalized;\n const saveTo = hosted ? undefined : (args as { saveTo?: string }).saveTo;\n const format: 'svg' | 'png' =\n (args.format as 'svg' | 'png' | undefined) ??\n (saveTo?.toLowerCase().endsWith('.svg') ? 'svg' : 'png');\n\n try {\n await hosted?.beforeRender?.(request);\n } catch (e) {\n return error((e as Error).message);\n }\n const result = await renderSvg(request);\n await hosted?.onRender?.(result, format);\n\n const content: CallToolResult['content'] = [];\n const meta: Record<string, unknown> = {\n structure: result.structure,\n seed: result.seed,\n width: result.width,\n height: result.height,\n format,\n svgBytes: result.svg.length,\n renderMs: result.durationMs,\n // Echo the resolved options so the caller can reproduce or tweak.\n request: { ...request, seed: result.seed },\n ...(warnings.length ? { warnings } : {}),\n };\n\n if (hosted && hosted.hostedUrls === false) {\n meta.hint = `Permanent hosted URLs need an API key (free keys include 200 renders a month and brand kits)${hosted.keysUrl ? ': ' + hosted.keysUrl : ''}.`;\n } else if (hosted) {\n meta.url = renderUrl(\n hosted.publicBaseUrl,\n { ...request, seed: result.seed },\n format,\n );\n meta.svgUrl = renderUrl(\n hosted.publicBaseUrl,\n { ...request, seed: result.seed },\n 'svg',\n );\n }\n\n if (saveTo) {\n const path = resolve(saveTo);\n await mkdir(dirname(path), { recursive: true });\n const bytes =\n format === 'png'\n ? await renderPng(result.svg, {\n width: args.pngWidth ?? result.width,\n })\n : Buffer.from(result.svg, 'utf8');\n await writeFile(path, bytes);\n meta.savedTo = path;\n meta.bytes = bytes.length;\n }\n\n if (format === 'svg') {\n if (result.svg.length <= maxInline && !saveTo) {\n content.push({\n type: 'resource',\n resource: {\n uri: `creatica://render/${result.structure}/${result.seed}.svg`,\n mimeType: 'image/svg+xml',\n text: result.svg,\n },\n });\n } else if (!saveTo && !hosted) {\n meta.note = `SVG is ${result.svg.length} bytes; pass saveTo to write it to disk instead of returning it inline.`;\n }\n }\n\n // Always attach a PNG preview so the model can see what it made. Keep\n // it modest: previews are for judging composition, not final delivery.\n const previewWidth = Math.min(args.pngWidth ?? 800, 1200);\n const png = await renderPng(result.svg, { width: previewWidth });\n if (png.length <= maxInline) {\n content.push({\n type: 'image',\n data: png.toString('base64'),\n mimeType: 'image/png',\n });\n } else {\n const small = await renderPng(result.svg, { width: 480 });\n content.push({\n type: 'image',\n data: small.toString('base64'),\n mimeType: 'image/png',\n });\n meta.note = `Preview downscaled to 480px (full PNG would be ${png.length} bytes).`;\n }\n\n content.unshift({ type: 'text', text: JSON.stringify(meta, null, 2) });\n return { content, structuredContent: meta };\n },\n );\n\n return server;\n}\n\nexport function renderUrl(\n baseUrl: string,\n req: RenderRequest,\n format: 'svg' | 'png',\n): string {\n const u = new URL(\n `/v1/render/${encodeURIComponent(req.structure)}.${format}`,\n baseUrl,\n );\n if (req.seed !== undefined) u.searchParams.set('seed', String(req.seed));\n if (req.width) u.searchParams.set('width', String(req.width));\n if (req.height) u.searchParams.set('height', String(req.height));\n for (const [k, v] of Object.entries(req.palette ?? {})) {\n if (v === undefined) continue;\n u.searchParams.set(k, Array.isArray(v) ? v.join(',') : String(v));\n }\n for (const [k, v] of Object.entries(req.shape ?? {})) {\n if (v !== undefined) u.searchParams.set(k, String(v));\n }\n return u.toString();\n}\n\nfunction json(value: Record<string, unknown>): CallToolResult {\n return {\n content: [{ type: 'text', text: JSON.stringify(value, null, 2) }],\n structuredContent: value,\n };\n}\nfunction error(message: string): CallToolResult {\n return { isError: true, content: [{ type: 'text', text: message }] };\n}\n"],"mappings":"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","names":["server"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@creatica/mcp",
|
|
3
3
|
"mcpName": "app.creatica/backgrounds",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3",
|
|
5
5
|
"description": "MCP server for Creatica: let AI agents browse, describe and generate procedural SVG/PNG backgrounds on demand.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|