@creatica/mcp 0.1.0 → 0.1.2

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 CHANGED
@@ -28,22 +28,122 @@ var paletteShape = z.object({
28
28
  palette: z.string().optional().describe(
29
29
  'Id of a built-in palette from list_palettes, e.g. "underTheSea".'
30
30
  ),
31
- primaryColor: hexColor.optional(),
32
- secondaryColor: hexColor.optional(),
33
- backgroundColor: hexColor.optional(),
31
+ primaryColor: hexColor.optional().describe("Main hex colour when not passing colors/palette."),
32
+ secondaryColor: hexColor.optional().describe("Second hex colour for two-tone structures."),
33
+ backgroundColor: hexColor.optional().describe("Hex colour of the canvas behind the shapes."),
34
34
  gradientColor: z.boolean().optional().describe("Gradient fills instead of flat colour."),
35
35
  useMultiColor: z.boolean().optional().describe("false = everything in primaryColor."),
36
36
  colorSchemeType: z.enum(["Mono", "Tetrade", "Analogic"]).optional().describe("Derive a palette from primaryColor."),
37
- opaqueColors: z.boolean().optional()
37
+ opaqueColors: z.boolean().optional().describe("true = no transparency in the shape fills.")
38
38
  }).strict();
39
39
  var shapeShape = z.record(z.string(), z.union([z.number(), z.boolean(), z.string()])).describe(
40
40
  "Structure-specific options; call describe_background for the exact keys, ranges and what they do."
41
41
  );
42
+ var SERVER_DESCRIPTION = "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.";
43
+ var sizeShape = z.object({
44
+ width: z.number().describe("Native frame width in px."),
45
+ height: z.number().describe("Native frame height in px.")
46
+ });
47
+ var catalogEntryShape = z.looseObject({
48
+ name: z.string().describe("Structure id for describe_background / generate_background."),
49
+ title: z.string().describe("Human-readable name."),
50
+ summary: z.string().describe("One-line description of the look."),
51
+ tags: z.array(z.string()).describe("Style tags, e.g. geometric, organic."),
52
+ mood: z.array(z.string()).describe("Mood words, e.g. calm, playful, dark."),
53
+ useCases: z.array(z.string()).describe("Where it works well."),
54
+ previewUrl: z.string().describe("Preview image of the default render."),
55
+ defaultSize: sizeShape
56
+ });
57
+ var suggestionShape = z.looseObject({
58
+ name: z.string().describe("Structure id."),
59
+ title: z.string(),
60
+ summary: z.string(),
61
+ score: z.number().describe("Relevance to the brief; higher is better."),
62
+ matched: z.array(z.string()).describe("Why it matched, for explaining."),
63
+ example: z.looseObject({ structure: z.string() }).describe("A ready-to-run generate_background request for this brief."),
64
+ palettes: z.array(z.string()).describe("Built-in palette ids whose mood fits the brief, best first.")
65
+ });
66
+ var paletteDescriptionShape = z.looseObject({
67
+ id: z.string().describe("Value to pass as palette.palette."),
68
+ name: z.string(),
69
+ colors: z.array(z.string()).describe("Hex colours."),
70
+ mood: z.array(z.string()).describe("Derived mood tags."),
71
+ lightness: z.number().describe("Average perceived lightness 0-1."),
72
+ saturation: z.number().describe("Average saturation 0-1.")
73
+ });
74
+ var paramDocShape = z.looseObject({
75
+ key: z.string().describe("Option key to pass under shape/palette."),
76
+ group: z.enum(["shape", "palette", "frame"]),
77
+ title: z.string(),
78
+ type: z.string(),
79
+ description: z.string(),
80
+ default: z.unknown().optional(),
81
+ min: z.number().optional(),
82
+ max: z.number().optional(),
83
+ step: z.number().optional(),
84
+ enum: z.array(z.string()).optional()
85
+ });
86
+ var structureDescriptionShape = z.looseObject({
87
+ name: z.string(),
88
+ title: z.string(),
89
+ summary: z.string(),
90
+ description: z.string(),
91
+ tags: z.array(z.string()),
92
+ mood: z.array(z.string()),
93
+ useCases: z.array(z.string()),
94
+ tips: z.array(z.string()),
95
+ defaultSize: sizeShape,
96
+ previewUrl: z.string(),
97
+ params: z.array(paramDocShape).describe("Every option this structure honours.")
98
+ });
99
+ var brandKitShape = z.looseObject({
100
+ slug: z.string().describe("Value to pass as brand to generate_background."),
101
+ name: z.string(),
102
+ colors: z.array(z.string()).describe("Hex colours."),
103
+ backgroundColor: z.string().optional(),
104
+ defaultStructure: z.string().optional()
105
+ });
106
+ var generateOutputShape = {
107
+ structure: z.string().describe("Structure that was rendered."),
108
+ seed: z.union([z.string(), z.number()]).describe("Seed used; reuse it to reproduce the exact image."),
109
+ width: z.number().describe("Render width in px."),
110
+ height: z.number().describe("Render height in px."),
111
+ format: z.enum(["svg", "png"]).describe("Delivered format."),
112
+ svgBytes: z.number().describe("Size of the SVG source in bytes."),
113
+ renderMs: z.number().describe("Render time in milliseconds."),
114
+ request: z.looseObject({ structure: z.string() }).describe("Resolved request incl. seed; replay it to reproduce or tweak."),
115
+ url: z.string().optional().describe(
116
+ "Hosted only: permanent, cacheable image URL in the requested format."
117
+ ),
118
+ svgUrl: z.string().optional().describe("Hosted only: permanent URL of the SVG source."),
119
+ savedTo: z.string().optional().describe("Local only: absolute path the file was written to."),
120
+ bytes: z.number().optional().describe("Local only: bytes written to disk."),
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.")
123
+ };
42
124
  function createMcpServer(options = {}) {
43
125
  const { hosted } = options;
44
126
  const maxInline = options.maxInlineBytes ?? 6e5;
45
127
  const server = new McpServer(
46
- { name: "creatica-backgrounds", version: ENGINE_VERSION },
128
+ {
129
+ name: "creatica-backgrounds",
130
+ title: "Creatica Backgrounds",
131
+ version: ENGINE_VERSION,
132
+ description: SERVER_DESCRIPTION,
133
+ websiteUrl: "https://creatica.app",
134
+ icons: [
135
+ {
136
+ src: "https://creatica.app/site/android-chrome-512x512.png",
137
+ mimeType: "image/png",
138
+ sizes: ["512x512"]
139
+ },
140
+ {
141
+ src: "https://creatica.app/site/android-chrome-192x192.png",
142
+ mimeType: "image/png",
143
+ sizes: ["192x192"]
144
+ }
145
+ ]
146
+ },
47
147
  {
48
148
  instructions: [
49
149
  "Creatica generates abstract, procedural SVG/PNG backgrounds (waves, blobs, bauhaus grids, topo lines, aurora glows\u2026) for websites, slides, social cards and apps.",
@@ -60,8 +160,12 @@ function createMcpServer(options = {}) {
60
160
  inputSchema: {
61
161
  query: z.string().optional().describe('Free text, e.g. "calm waves" or "geometric poster".'),
62
162
  mood: z.string().optional().describe("A mood word, e.g. dark, playful, minimal, retro."),
63
- tag: z.string().optional(),
64
- limit: z.number().int().min(1).max(100).optional()
163
+ tag: z.string().optional().describe("A style tag, e.g. geometric, organic, grid, gradient."),
164
+ limit: z.number().int().min(1).max(100).optional().describe("Maximum number of results (default 100).")
165
+ },
166
+ outputSchema: {
167
+ count: z.number().describe("Number of backgrounds returned."),
168
+ backgrounds: z.array(catalogEntryShape)
65
169
  },
66
170
  annotations: {
67
171
  readOnlyHint: true,
@@ -93,8 +197,13 @@ function createMcpServer(options = {}) {
93
197
  title: "Suggest backgrounds for a brief",
94
198
  description: '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.',
95
199
  inputSchema: {
96
- brief: z.string().min(2),
97
- limit: z.number().int().min(1).max(20).optional()
200
+ brief: z.string().min(2).describe(
201
+ "What the background is for, in plain words: subject, mood, colours, where it goes."
202
+ ),
203
+ limit: z.number().int().min(1).max(20).optional().describe("How many suggestions to return (default 5).")
204
+ },
205
+ outputSchema: {
206
+ suggestions: z.array(suggestionShape).describe("Best match first.")
98
207
  },
99
208
  annotations: {
100
209
  readOnlyHint: true,
@@ -115,6 +224,13 @@ function createMcpServer(options = {}) {
115
224
  "markdown (default) is best for reading; json includes the JSON Schema."
116
225
  )
117
226
  },
227
+ outputSchema: {
228
+ name: z.string().describe("Structure id."),
229
+ format: z.enum(["markdown", "json"]).describe("Which form was returned."),
230
+ card: z.string().optional().describe("markdown format: the style card as Markdown."),
231
+ description: structureDescriptionShape.optional().describe("json format: the structured description."),
232
+ jsonSchema: z.looseObject({}).optional().describe("json format: JSON Schema for a generate request.")
233
+ },
118
234
  annotations: {
119
235
  readOnlyHint: true,
120
236
  idempotentHint: true,
@@ -124,8 +240,17 @@ function createMcpServer(options = {}) {
124
240
  async ({ name, format }) => {
125
241
  try {
126
242
  if (format === "json")
127
- return json({ ...describe(name), jsonSchema: jsonSchemaFor(name) });
128
- return text(styleCard(name));
243
+ return json({
244
+ name,
245
+ format: "json",
246
+ description: describe(name),
247
+ jsonSchema: jsonSchemaFor(name)
248
+ });
249
+ const card = styleCard(name);
250
+ return {
251
+ content: [{ type: "text", text: card }],
252
+ structuredContent: { name, format: "markdown", card }
253
+ };
129
254
  } catch (e) {
130
255
  return error(e.message);
131
256
  }
@@ -139,6 +264,10 @@ function createMcpServer(options = {}) {
139
264
  inputSchema: {
140
265
  mood: z.string().optional().describe('Filter by a mood tag, e.g. "dark" or "pastel".')
141
266
  },
267
+ outputSchema: {
268
+ count: z.number().describe("Number of palettes returned."),
269
+ palettes: z.array(paletteDescriptionShape)
270
+ },
142
271
  annotations: {
143
272
  readOnlyHint: true,
144
273
  idempotentHint: true,
@@ -159,6 +288,9 @@ function createMcpServer(options = {}) {
159
288
  title: "List brand kits",
160
289
  description: "Saved brand palettes on this account. Pass a kit's slug as `brand` to generate_background to render on-brand without repeating hex colours.",
161
290
  inputSchema: {},
291
+ outputSchema: {
292
+ brandKits: z.array(brandKitShape).describe("Saved kits, may be empty.")
293
+ },
162
294
  annotations: {
163
295
  readOnlyHint: true,
164
296
  idempotentHint: true,
@@ -182,9 +314,13 @@ function createMcpServer(options = {}) {
182
314
  seed: z.string().optional().describe(
183
315
  "Any string. Omit for a fresh random seed (returned in the result)."
184
316
  ),
185
- width: z.number().int().min(1).max(8192).optional(),
186
- height: z.number().int().min(1).max(8192).optional(),
187
- palette: paletteShape.optional(),
317
+ width: z.number().int().min(1).max(8192).optional().describe(
318
+ "Frame width in px. Defaults to the structure's native size (see describe_background)."
319
+ ),
320
+ height: z.number().int().min(1).max(8192).optional().describe("Frame height in px. Defaults to the native size."),
321
+ palette: paletteShape.optional().describe(
322
+ "Colour choices: explicit hex colours, a built-in palette id, or a primary colour to derive from."
323
+ ),
188
324
  shape: shapeShape.optional(),
189
325
  format: z.enum(["svg", "png"]).optional().describe(
190
326
  "png (default) returns a viewable image; svg returns the vector source."
@@ -203,6 +339,7 @@ function createMcpServer(options = {}) {
203
339
  )
204
340
  }
205
341
  },
342
+ outputSchema: generateOutputShape,
206
343
  annotations: {
207
344
  readOnlyHint: true,
208
345
  idempotentHint: true,
@@ -275,7 +412,9 @@ function createMcpServer(options = {}) {
275
412
  if (saveTo) {
276
413
  const path = resolve(saveTo);
277
414
  await mkdir(dirname(path), { recursive: true });
278
- const bytes = format === "png" ? await renderPng(result.svg, { width: args.pngWidth ?? result.width }) : Buffer.from(result.svg, "utf8");
415
+ const bytes = format === "png" ? await renderPng(result.svg, {
416
+ width: args.pngWidth ?? result.width
417
+ }) : Buffer.from(result.svg, "utf8");
279
418
  await writeFile(path, bytes);
280
419
  meta.savedTo = path;
281
420
  meta.bytes = bytes.length;
@@ -312,7 +451,7 @@ function createMcpServer(options = {}) {
312
451
  meta.note = `Preview downscaled to 480px (full PNG would be ${png.length} bytes).`;
313
452
  }
314
453
  content.unshift({ type: "text", text: JSON.stringify(meta, null, 2) });
315
- return { content };
454
+ return { content, structuredContent: meta };
316
455
  }
317
456
  );
318
457
  return server;
@@ -335,10 +474,10 @@ function renderUrl(baseUrl, req, format) {
335
474
  return u.toString();
336
475
  }
337
476
  function json(value) {
338
- return { content: [{ type: "text", text: JSON.stringify(value, null, 2) }] };
339
- }
340
- function text(value) {
341
- return { content: [{ type: "text", text: value }] };
477
+ return {
478
+ content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
479
+ structuredContent: value
480
+ };
342
481
  }
343
482
  function error(message) {
344
483
  return { isError: true, content: [{ type: "text", text: message }] };
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.optional(),\n secondaryColor: hexColor.optional(),\n backgroundColor: hexColor.optional(),\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.boolean().optional(),\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\nexport function createMcpServer(options: McpServerOptions = {}): McpServer {\n const { hosted } = options;\n const maxInline = options.maxInlineBytes ?? 600_000;\n\n const server = new McpServer(\n { name: 'creatica-backgrounds', version: ENGINE_VERSION },\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.string().optional(),\n limit: z.number().int().min(1).max(100).optional(),\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.string().min(2),\n limit: z.number().int().min(1).max(20).optional(),\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 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({ ...describe(name), jsonSchema: jsonSchemaFor(name) });\n return text(styleCard(name));\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 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 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.number().int().min(1).max(8192).optional(),\n height: z.number().int().min(1).max(8192).optional(),\n palette: paletteShape.optional(),\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 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, { width: args.pngWidth ?? result.width })\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 };\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: unknown): CallToolResult {\n return { content: [{ type: 'text', text: JSON.stringify(value, null, 2) }] };\n}\nfunction text(value: string): CallToolResult {\n return { content: [{ type: 'text', text: value }] };\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 /** 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":[]}
package/dist/stdio.js CHANGED
@@ -33,22 +33,122 @@ var paletteShape = z.object({
33
33
  palette: z.string().optional().describe(
34
34
  'Id of a built-in palette from list_palettes, e.g. "underTheSea".'
35
35
  ),
36
- primaryColor: hexColor.optional(),
37
- secondaryColor: hexColor.optional(),
38
- backgroundColor: hexColor.optional(),
36
+ primaryColor: hexColor.optional().describe("Main hex colour when not passing colors/palette."),
37
+ secondaryColor: hexColor.optional().describe("Second hex colour for two-tone structures."),
38
+ backgroundColor: hexColor.optional().describe("Hex colour of the canvas behind the shapes."),
39
39
  gradientColor: z.boolean().optional().describe("Gradient fills instead of flat colour."),
40
40
  useMultiColor: z.boolean().optional().describe("false = everything in primaryColor."),
41
41
  colorSchemeType: z.enum(["Mono", "Tetrade", "Analogic"]).optional().describe("Derive a palette from primaryColor."),
42
- opaqueColors: z.boolean().optional()
42
+ opaqueColors: z.boolean().optional().describe("true = no transparency in the shape fills.")
43
43
  }).strict();
44
44
  var shapeShape = z.record(z.string(), z.union([z.number(), z.boolean(), z.string()])).describe(
45
45
  "Structure-specific options; call describe_background for the exact keys, ranges and what they do."
46
46
  );
47
+ var SERVER_DESCRIPTION = "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.";
48
+ var sizeShape = z.object({
49
+ width: z.number().describe("Native frame width in px."),
50
+ height: z.number().describe("Native frame height in px.")
51
+ });
52
+ var catalogEntryShape = z.looseObject({
53
+ name: z.string().describe("Structure id for describe_background / generate_background."),
54
+ title: z.string().describe("Human-readable name."),
55
+ summary: z.string().describe("One-line description of the look."),
56
+ tags: z.array(z.string()).describe("Style tags, e.g. geometric, organic."),
57
+ mood: z.array(z.string()).describe("Mood words, e.g. calm, playful, dark."),
58
+ useCases: z.array(z.string()).describe("Where it works well."),
59
+ previewUrl: z.string().describe("Preview image of the default render."),
60
+ defaultSize: sizeShape
61
+ });
62
+ var suggestionShape = z.looseObject({
63
+ name: z.string().describe("Structure id."),
64
+ title: z.string(),
65
+ summary: z.string(),
66
+ score: z.number().describe("Relevance to the brief; higher is better."),
67
+ matched: z.array(z.string()).describe("Why it matched, for explaining."),
68
+ example: z.looseObject({ structure: z.string() }).describe("A ready-to-run generate_background request for this brief."),
69
+ palettes: z.array(z.string()).describe("Built-in palette ids whose mood fits the brief, best first.")
70
+ });
71
+ var paletteDescriptionShape = z.looseObject({
72
+ id: z.string().describe("Value to pass as palette.palette."),
73
+ name: z.string(),
74
+ colors: z.array(z.string()).describe("Hex colours."),
75
+ mood: z.array(z.string()).describe("Derived mood tags."),
76
+ lightness: z.number().describe("Average perceived lightness 0-1."),
77
+ saturation: z.number().describe("Average saturation 0-1.")
78
+ });
79
+ var paramDocShape = z.looseObject({
80
+ key: z.string().describe("Option key to pass under shape/palette."),
81
+ group: z.enum(["shape", "palette", "frame"]),
82
+ title: z.string(),
83
+ type: z.string(),
84
+ description: z.string(),
85
+ default: z.unknown().optional(),
86
+ min: z.number().optional(),
87
+ max: z.number().optional(),
88
+ step: z.number().optional(),
89
+ enum: z.array(z.string()).optional()
90
+ });
91
+ var structureDescriptionShape = z.looseObject({
92
+ name: z.string(),
93
+ title: z.string(),
94
+ summary: z.string(),
95
+ description: z.string(),
96
+ tags: z.array(z.string()),
97
+ mood: z.array(z.string()),
98
+ useCases: z.array(z.string()),
99
+ tips: z.array(z.string()),
100
+ defaultSize: sizeShape,
101
+ previewUrl: z.string(),
102
+ params: z.array(paramDocShape).describe("Every option this structure honours.")
103
+ });
104
+ var brandKitShape = z.looseObject({
105
+ slug: z.string().describe("Value to pass as brand to generate_background."),
106
+ name: z.string(),
107
+ colors: z.array(z.string()).describe("Hex colours."),
108
+ backgroundColor: z.string().optional(),
109
+ defaultStructure: z.string().optional()
110
+ });
111
+ var generateOutputShape = {
112
+ structure: z.string().describe("Structure that was rendered."),
113
+ seed: z.union([z.string(), z.number()]).describe("Seed used; reuse it to reproduce the exact image."),
114
+ width: z.number().describe("Render width in px."),
115
+ height: z.number().describe("Render height in px."),
116
+ format: z.enum(["svg", "png"]).describe("Delivered format."),
117
+ svgBytes: z.number().describe("Size of the SVG source in bytes."),
118
+ renderMs: z.number().describe("Render time in milliseconds."),
119
+ request: z.looseObject({ structure: z.string() }).describe("Resolved request incl. seed; replay it to reproduce or tweak."),
120
+ url: z.string().optional().describe(
121
+ "Hosted only: permanent, cacheable image URL in the requested format."
122
+ ),
123
+ svgUrl: z.string().optional().describe("Hosted only: permanent URL of the SVG source."),
124
+ savedTo: z.string().optional().describe("Local only: absolute path the file was written to."),
125
+ bytes: z.number().optional().describe("Local only: bytes written to disk."),
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.")
128
+ };
47
129
  function createMcpServer(options = {}) {
48
130
  const { hosted } = options;
49
131
  const maxInline = options.maxInlineBytes ?? 6e5;
50
132
  const server2 = new McpServer(
51
- { name: "creatica-backgrounds", version: ENGINE_VERSION },
133
+ {
134
+ name: "creatica-backgrounds",
135
+ title: "Creatica Backgrounds",
136
+ version: ENGINE_VERSION,
137
+ description: SERVER_DESCRIPTION,
138
+ websiteUrl: "https://creatica.app",
139
+ icons: [
140
+ {
141
+ src: "https://creatica.app/site/android-chrome-512x512.png",
142
+ mimeType: "image/png",
143
+ sizes: ["512x512"]
144
+ },
145
+ {
146
+ src: "https://creatica.app/site/android-chrome-192x192.png",
147
+ mimeType: "image/png",
148
+ sizes: ["192x192"]
149
+ }
150
+ ]
151
+ },
52
152
  {
53
153
  instructions: [
54
154
  "Creatica generates abstract, procedural SVG/PNG backgrounds (waves, blobs, bauhaus grids, topo lines, aurora glows\u2026) for websites, slides, social cards and apps.",
@@ -65,8 +165,12 @@ function createMcpServer(options = {}) {
65
165
  inputSchema: {
66
166
  query: z.string().optional().describe('Free text, e.g. "calm waves" or "geometric poster".'),
67
167
  mood: z.string().optional().describe("A mood word, e.g. dark, playful, minimal, retro."),
68
- tag: z.string().optional(),
69
- limit: z.number().int().min(1).max(100).optional()
168
+ tag: z.string().optional().describe("A style tag, e.g. geometric, organic, grid, gradient."),
169
+ limit: z.number().int().min(1).max(100).optional().describe("Maximum number of results (default 100).")
170
+ },
171
+ outputSchema: {
172
+ count: z.number().describe("Number of backgrounds returned."),
173
+ backgrounds: z.array(catalogEntryShape)
70
174
  },
71
175
  annotations: {
72
176
  readOnlyHint: true,
@@ -98,8 +202,13 @@ function createMcpServer(options = {}) {
98
202
  title: "Suggest backgrounds for a brief",
99
203
  description: '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.',
100
204
  inputSchema: {
101
- brief: z.string().min(2),
102
- limit: z.number().int().min(1).max(20).optional()
205
+ brief: z.string().min(2).describe(
206
+ "What the background is for, in plain words: subject, mood, colours, where it goes."
207
+ ),
208
+ limit: z.number().int().min(1).max(20).optional().describe("How many suggestions to return (default 5).")
209
+ },
210
+ outputSchema: {
211
+ suggestions: z.array(suggestionShape).describe("Best match first.")
103
212
  },
104
213
  annotations: {
105
214
  readOnlyHint: true,
@@ -120,6 +229,13 @@ function createMcpServer(options = {}) {
120
229
  "markdown (default) is best for reading; json includes the JSON Schema."
121
230
  )
122
231
  },
232
+ outputSchema: {
233
+ name: z.string().describe("Structure id."),
234
+ format: z.enum(["markdown", "json"]).describe("Which form was returned."),
235
+ card: z.string().optional().describe("markdown format: the style card as Markdown."),
236
+ description: structureDescriptionShape.optional().describe("json format: the structured description."),
237
+ jsonSchema: z.looseObject({}).optional().describe("json format: JSON Schema for a generate request.")
238
+ },
123
239
  annotations: {
124
240
  readOnlyHint: true,
125
241
  idempotentHint: true,
@@ -129,8 +245,17 @@ function createMcpServer(options = {}) {
129
245
  async ({ name, format }) => {
130
246
  try {
131
247
  if (format === "json")
132
- return json({ ...describe(name), jsonSchema: jsonSchemaFor(name) });
133
- return text(styleCard(name));
248
+ return json({
249
+ name,
250
+ format: "json",
251
+ description: describe(name),
252
+ jsonSchema: jsonSchemaFor(name)
253
+ });
254
+ const card = styleCard(name);
255
+ return {
256
+ content: [{ type: "text", text: card }],
257
+ structuredContent: { name, format: "markdown", card }
258
+ };
134
259
  } catch (e) {
135
260
  return error(e.message);
136
261
  }
@@ -144,6 +269,10 @@ function createMcpServer(options = {}) {
144
269
  inputSchema: {
145
270
  mood: z.string().optional().describe('Filter by a mood tag, e.g. "dark" or "pastel".')
146
271
  },
272
+ outputSchema: {
273
+ count: z.number().describe("Number of palettes returned."),
274
+ palettes: z.array(paletteDescriptionShape)
275
+ },
147
276
  annotations: {
148
277
  readOnlyHint: true,
149
278
  idempotentHint: true,
@@ -164,6 +293,9 @@ function createMcpServer(options = {}) {
164
293
  title: "List brand kits",
165
294
  description: "Saved brand palettes on this account. Pass a kit's slug as `brand` to generate_background to render on-brand without repeating hex colours.",
166
295
  inputSchema: {},
296
+ outputSchema: {
297
+ brandKits: z.array(brandKitShape).describe("Saved kits, may be empty.")
298
+ },
167
299
  annotations: {
168
300
  readOnlyHint: true,
169
301
  idempotentHint: true,
@@ -187,9 +319,13 @@ function createMcpServer(options = {}) {
187
319
  seed: z.string().optional().describe(
188
320
  "Any string. Omit for a fresh random seed (returned in the result)."
189
321
  ),
190
- width: z.number().int().min(1).max(8192).optional(),
191
- height: z.number().int().min(1).max(8192).optional(),
192
- palette: paletteShape.optional(),
322
+ width: z.number().int().min(1).max(8192).optional().describe(
323
+ "Frame width in px. Defaults to the structure's native size (see describe_background)."
324
+ ),
325
+ height: z.number().int().min(1).max(8192).optional().describe("Frame height in px. Defaults to the native size."),
326
+ palette: paletteShape.optional().describe(
327
+ "Colour choices: explicit hex colours, a built-in palette id, or a primary colour to derive from."
328
+ ),
193
329
  shape: shapeShape.optional(),
194
330
  format: z.enum(["svg", "png"]).optional().describe(
195
331
  "png (default) returns a viewable image; svg returns the vector source."
@@ -208,6 +344,7 @@ function createMcpServer(options = {}) {
208
344
  )
209
345
  }
210
346
  },
347
+ outputSchema: generateOutputShape,
211
348
  annotations: {
212
349
  readOnlyHint: true,
213
350
  idempotentHint: true,
@@ -280,7 +417,9 @@ function createMcpServer(options = {}) {
280
417
  if (saveTo) {
281
418
  const path = resolve(saveTo);
282
419
  await mkdir(dirname(path), { recursive: true });
283
- const bytes = format === "png" ? await renderPng(result.svg, { width: args.pngWidth ?? result.width }) : Buffer.from(result.svg, "utf8");
420
+ const bytes = format === "png" ? await renderPng(result.svg, {
421
+ width: args.pngWidth ?? result.width
422
+ }) : Buffer.from(result.svg, "utf8");
284
423
  await writeFile(path, bytes);
285
424
  meta.savedTo = path;
286
425
  meta.bytes = bytes.length;
@@ -317,7 +456,7 @@ function createMcpServer(options = {}) {
317
456
  meta.note = `Preview downscaled to 480px (full PNG would be ${png.length} bytes).`;
318
457
  }
319
458
  content.unshift({ type: "text", text: JSON.stringify(meta, null, 2) });
320
- return { content };
459
+ return { content, structuredContent: meta };
321
460
  }
322
461
  );
323
462
  return server2;
@@ -340,10 +479,10 @@ function renderUrl(baseUrl, req, format) {
340
479
  return u.toString();
341
480
  }
342
481
  function json(value) {
343
- return { content: [{ type: "text", text: JSON.stringify(value, null, 2) }] };
344
- }
345
- function text(value) {
346
- return { content: [{ type: "text", text: value }] };
482
+ return {
483
+ content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
484
+ structuredContent: value
485
+ };
347
486
  }
348
487
  function error(message) {
349
488
  return { isError: true, content: [{ type: "text", text: message }] };
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.optional(),\n secondaryColor: hexColor.optional(),\n backgroundColor: hexColor.optional(),\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.boolean().optional(),\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\nexport function createMcpServer(options: McpServerOptions = {}): McpServer {\n const { hosted } = options;\n const maxInline = options.maxInlineBytes ?? 600_000;\n\n const server = new McpServer(\n { name: 'creatica-backgrounds', version: ENGINE_VERSION },\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.string().optional(),\n limit: z.number().int().min(1).max(100).optional(),\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.string().min(2),\n limit: z.number().int().min(1).max(20).optional(),\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 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({ ...describe(name), jsonSchema: jsonSchemaFor(name) });\n return text(styleCard(name));\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 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 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.number().int().min(1).max(8192).optional(),\n height: z.number().int().min(1).max(8192).optional(),\n palette: paletteShape.optional(),\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 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, { width: args.pngWidth ?? result.width })\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 };\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: unknown): CallToolResult {\n return { content: [{ type: 'text', text: JSON.stringify(value, null, 2) }] };\n}\nfunction text(value: string): CallToolResult {\n return { content: [{ type: 'text', text: value }] };\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 /** 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"]}
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@creatica/mcp",
3
- "version": "0.1.0",
3
+ "mcpName": "app.creatica/backgrounds",
4
+ "version": "0.1.2",
4
5
  "description": "MCP server for Creatica: let AI agents browse, describe and generate procedural SVG/PNG backgrounds on demand.",
5
6
  "license": "MIT",
6
7
  "type": "module",