@icogenie/mcp 0.1.1 → 0.2.0

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.
Files changed (3) hide show
  1. package/README.md +10 -7
  2. package/dist/index.js +94 -66
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -64,7 +64,7 @@ generate_icon({
64
64
  })
65
65
  ```
66
66
 
67
- **Returns:** `{ generationId, preview, creditsUsed, creditsRemaining, metadata }`
67
+ **Returns:** `{ sessionId, preview, previews, creditsRemaining, sessionData, suggestions }`
68
68
 
69
69
  ### regenerate_icon
70
70
  Regenerate a specific icon variation with a custom refinement prompt.
@@ -73,12 +73,15 @@ Regenerate a specific icon variation with a custom refinement prompt.
73
73
 
74
74
  ```
75
75
  regenerate_icon({
76
- generationId: "abc123", // or bundleId for bundles
77
- index: 0, // which variation (0-based)
76
+ sessionId: "abc123", // for single icons
77
+ bundleId: "xyz789", // for bundles (use one or the other)
78
+ index: 0, // which variation (0-based)
78
79
  prompt: "Make it more 3D" // optional refinement
79
80
  })
80
81
  ```
81
82
 
83
+ **Returns:** `{ success, index, preview, creditsRemaining }`
84
+
82
85
  ### check_credits
83
86
  Check your current credit balance.
84
87
 
@@ -132,7 +135,7 @@ generate_bundle({
132
135
  })
133
136
  ```
134
137
 
135
- **Returns:** `{ bundleId, icons: [{ name, preview }], credits }`
138
+ **Returns:** `{ bundleId, iconCount, icons: [{ name, description, preview }], pricing, creditsUsed, creditsRemaining }`
136
139
 
137
140
  ## Example Workflow
138
141
 
@@ -145,19 +148,19 @@ generate_bundle({
145
148
  2. **Generate a single icon:**
146
149
  ```
147
150
  generate_icon({ prompt: "notification bell icon", style: "outline" })
148
- → { generationId: "abc123", preview: "...", creditsRemaining: 49 }
151
+ → { sessionId: "abc123", preview: "...", creditsRemaining: 49 }
149
152
  ```
150
153
 
151
154
  3. **Refine if needed:**
152
155
  ```
153
- regenerate_icon({ generationId: "abc123", index: 0, prompt: "Add a dot indicator" })
156
+ regenerate_icon({ sessionId: "abc123", index: 0, prompt: "Add a dot indicator" })
154
157
  → { preview: "...", creditsRemaining: 48 }
155
158
  ```
156
159
 
157
160
  4. **Download final package:**
158
161
  ```
159
162
  download_icon({ generationId: "abc123", outputPath: "./bell-icon.zip" })
160
- → { savedTo: "./bell-icon.zip", creditsRemaining: 43 }
163
+ → { savedTo: "./bell-icon.zip" }
161
164
  ```
162
165
 
163
166
  ## Bundle Workflow
package/dist/index.js CHANGED
@@ -162,15 +162,32 @@ function readReferenceImage(filePath) {
162
162
  const mimeType = ext === ".png" ? "image/png" : ext === ".webp" ? "image/webp" : "image/jpeg";
163
163
  return { data: buffer.toString("base64"), mimeType };
164
164
  }
165
- async function request2(endpoint, body, requireAuth = true) {
166
- const url = `${getApiUrl()}/api/cli${endpoint}`;
165
+ async function request2(endpoint, options = {}, requireAuth = true) {
166
+ const { method = "POST", body, params } = options;
167
+ let url = `${getApiUrl()}/api${endpoint}`;
168
+ if (params && Object.keys(params).length > 0) {
169
+ url += `?${new URLSearchParams(params).toString()}`;
170
+ }
167
171
  const makeRequest = async (sessionToken) => {
168
- const requestBody = sessionToken ? { ...body, sessionToken } : body;
172
+ const headers = {};
173
+ if (sessionToken) {
174
+ headers["Authorization"] = `Bearer ${sessionToken}`;
175
+ }
176
+ if (body) {
177
+ headers["Content-Type"] = "application/json";
178
+ }
169
179
  const response = await fetch(url, {
170
- method: "POST",
171
- headers: { "Content-Type": "application/json" },
172
- body: JSON.stringify(requestBody)
180
+ method,
181
+ headers,
182
+ ...body && { body: JSON.stringify(body) }
173
183
  });
184
+ const contentType = response.headers.get("content-type");
185
+ if (contentType?.includes("application/zip")) {
186
+ if (!response.ok) {
187
+ throw new ApiError("Download failed", response.status);
188
+ }
189
+ return response;
190
+ }
174
191
  const data = await response.json();
175
192
  if (response.status === 401 && requireAuth) {
176
193
  const newCreds = await handleAuthError();
@@ -192,44 +209,59 @@ async function request2(endpoint, body, requireAuth = true) {
192
209
  return makeRequest();
193
210
  }
194
211
  async function generate(options) {
195
- return request2("/generate", {
196
- prompt: options.prompt,
197
- variations: options.variations || 1,
198
- style: options.style || "solid",
199
- ...options.referenceImage && { referenceImage: options.referenceImage }
212
+ return request2("/generate-preview", {
213
+ body: {
214
+ prompt: options.prompt,
215
+ variations: options.variations || 1,
216
+ style: options.style || "solid",
217
+ ...options.referenceImage && { referenceImage: options.referenceImage }
218
+ }
200
219
  });
201
220
  }
202
221
  async function regenerate(options) {
203
- return request2("/regenerate", {
204
- generationId: options.generationId,
205
- bundleId: options.bundleId,
206
- index: options.index,
207
- prompt: options.prompt
222
+ return request2("/regenerate-icon", {
223
+ body: {
224
+ sessionId: options.sessionId,
225
+ bundleId: options.bundleId,
226
+ index: options.index,
227
+ prompt: options.prompt
228
+ }
208
229
  });
209
230
  }
210
231
  async function getCredits() {
211
- return request2("/credits", {});
232
+ return request2("/auth/session", { method: "GET" });
212
233
  }
213
234
  async function download(options) {
214
- return request2("/download", {
215
- generationId: options.generationId,
216
- bundleId: options.bundleId
235
+ const params = {};
236
+ if (options.generationId) params.generation_id = options.generationId;
237
+ if (options.bundleId) params.bundle_id = options.bundleId;
238
+ const response = await request2("/download", {
239
+ method: "GET",
240
+ params
217
241
  });
242
+ const contentDisposition = response.headers.get("content-disposition");
243
+ const filenameMatch = contentDisposition?.match(/filename="?([^";\n]+)"?/);
244
+ const filename = filenameMatch?.[1] || `icogenie-${(options.generationId || options.bundleId || "export").slice(0, 8)}.zip`;
245
+ return { response, filename };
218
246
  }
219
247
  async function normalizeBundle(options) {
220
- return request2("/normalize", {
221
- description: options.description,
222
- targetCount: options.targetCount,
223
- style: options.style
248
+ return request2("/normalize-bundle", {
249
+ body: {
250
+ description: options.description,
251
+ targetCount: options.targetCount,
252
+ style: options.style
253
+ }
224
254
  });
225
255
  }
226
256
  async function generateBundle(options) {
227
- return request2("/bundle", {
228
- description: options.description,
229
- targetCount: options.targetCount,
230
- icons: options.icons,
231
- style: options.style || "solid",
232
- ...options.referenceImage && { referenceImage: options.referenceImage }
257
+ const bundleId = options.bundleId || crypto.randomUUID();
258
+ return request2("/generate-bundle-preview", {
259
+ body: {
260
+ bundleId,
261
+ icons: options.icons,
262
+ style: options.style || "solid",
263
+ ...options.referenceImage && { referenceImage: options.referenceImage }
264
+ }
233
265
  });
234
266
  }
235
267
 
@@ -258,37 +290,38 @@ async function generateIcon(args) {
258
290
  referenceImage: refImage
259
291
  });
260
292
  return {
261
- generationId: result.generationId,
293
+ sessionId: result.sessionId,
262
294
  preview: result.preview,
263
- creditsUsed: result.creditsUsed,
264
- creditsRemaining: result.creditsRemaining,
265
- metadata: result.metadata
295
+ previews: result.previews,
296
+ creditsRemaining: result.credits,
297
+ sessionData: result.sessionData,
298
+ suggestions: result.suggestions
266
299
  };
267
300
  }
268
301
 
269
302
  // src/tools/regenerate.ts
270
303
  import { z as z2 } from "zod";
271
304
  var regenerateIconSchema = {
272
- generationId: z2.string().optional().describe("For single icon variations"),
305
+ sessionId: z2.string().optional().describe("For single icon variations"),
273
306
  bundleId: z2.string().optional().describe("For bundle icons"),
274
307
  index: z2.number().describe("Which variation/icon to regenerate (0-based)"),
275
308
  prompt: z2.string().optional().describe("Custom refinement prompt")
276
309
  };
277
310
  async function regenerateIcon(args) {
278
- if (!args.generationId && !args.bundleId) {
279
- throw new Error("Must provide either generationId or bundleId");
311
+ if (!args.sessionId && !args.bundleId) {
312
+ throw new Error("Must provide either sessionId or bundleId");
280
313
  }
281
314
  const result = await regenerate({
282
- generationId: args.generationId,
315
+ sessionId: args.sessionId,
283
316
  bundleId: args.bundleId,
284
317
  index: args.index,
285
318
  prompt: args.prompt
286
319
  });
287
320
  return {
288
321
  success: result.success,
322
+ index: result.index,
289
323
  preview: result.preview,
290
- creditsUsed: result.creditsUsed,
291
- creditsRemaining: result.creditsRemaining
324
+ creditsRemaining: result.credits
292
325
  };
293
326
  }
294
327
 
@@ -315,27 +348,23 @@ async function downloadIcon(args) {
315
348
  if (!args.generationId && !args.bundleId) {
316
349
  throw new Error("Must provide either generationId or bundleId");
317
350
  }
318
- const result = await download({
351
+ const { response, filename } = await download({
319
352
  generationId: args.generationId,
320
353
  bundleId: args.bundleId
321
354
  });
322
- const response = {
323
- success: result.success,
324
- creditsUsed: result.creditsUsed,
325
- creditsRemaining: result.creditsRemaining,
326
- iconCount: result.iconCount
355
+ const arrayBuffer = await response.arrayBuffer();
356
+ const zipBuffer = Buffer.from(arrayBuffer);
357
+ const result = {
358
+ success: true,
359
+ filename
327
360
  };
328
361
  if (args.outputPath) {
329
- const buffer = Buffer.from(result.bundle.data, "base64");
330
- writeFileSync(args.outputPath, buffer);
331
- response.savedTo = args.outputPath;
362
+ writeFileSync(args.outputPath, zipBuffer);
363
+ result.savedTo = args.outputPath;
332
364
  } else {
333
- response.bundle = {
334
- data: result.bundle.data,
335
- filename: result.bundle.filename
336
- };
365
+ result.bundleData = zipBuffer.toString("base64");
337
366
  }
338
- return response;
367
+ return result;
339
368
  }
340
369
 
341
370
  // src/tools/normalize-bundle.ts
@@ -379,8 +408,8 @@ var generateBundleSchema = {
379
408
  }).optional().describe("Base64-encoded reference image")
380
409
  };
381
410
  async function generateBundleTool(args) {
382
- if (!args.icons && !args.description) {
383
- throw new Error("Must provide either icons array or description");
411
+ if (!args.icons) {
412
+ throw new Error("Must provide icons array (use normalize_bundle first to get icon list)");
384
413
  }
385
414
  let refImage;
386
415
  if (args.referenceImagePath) {
@@ -390,21 +419,20 @@ async function generateBundleTool(args) {
390
419
  }
391
420
  const result = await generateBundle({
392
421
  icons: args.icons,
393
- description: args.description,
394
- targetCount: args.targetCount,
395
422
  style: args.style || "solid",
396
423
  referenceImage: refImage
397
424
  });
398
425
  return {
399
426
  bundleId: result.bundleId,
400
- iconCount: result.iconCount,
401
- icons: result.icons.map((icon) => ({
427
+ iconCount: result.previews.length,
428
+ icons: result.previews.map((icon) => ({
402
429
  name: icon.name,
403
430
  description: icon.description,
404
431
  preview: icon.preview
405
432
  })),
406
- credits: result.credits,
407
- nextStep: result.nextStep
433
+ pricing: result.pricing,
434
+ creditsUsed: result.creditsUsed,
435
+ creditsRemaining: result.credits
408
436
  };
409
437
  }
410
438
 
@@ -418,7 +446,7 @@ function createServer() {
418
446
  "generate_icon",
419
447
  {
420
448
  title: "Generate Icon",
421
- description: "Generate an AI-powered icon preview from a text description. Costs 1 credit. Returns a generationId for download.",
449
+ description: "Generate an AI-powered icon preview from a text description. Costs 1 credit. Returns a generationId for download. After generation, save the preview image to the user's working directory and display it.",
422
450
  inputSchema: generateIconSchema
423
451
  },
424
452
  async (args) => {
@@ -433,7 +461,7 @@ function createServer() {
433
461
  "regenerate_icon",
434
462
  {
435
463
  title: "Regenerate Icon",
436
- description: "Regenerate a specific icon variation with an optional custom prompt. Costs 1 credit. Use with generationId (single) or bundleId (bundle).",
464
+ description: "Regenerate a specific icon variation with an optional custom prompt. Costs 1 credit. Use with generationId (single) or bundleId (bundle). After regeneration, save and display the new preview.",
437
465
  inputSchema: regenerateIconSchema
438
466
  },
439
467
  async (args) => {
@@ -463,7 +491,7 @@ function createServer() {
463
491
  "download_icon",
464
492
  {
465
493
  title: "Download Icon",
466
- description: "Download the final SVG + PNG package for an icon. Costs 5 credits (single) or 4 credits/icon (bundle). Provide outputPath to save to file.",
494
+ description: "Download the final SVG + PNG package for an icon. Costs 5 credits (single) or 4 credits/icon (bundle). Provide outputPath to save to file. Always save to the user's working directory with a descriptive filename.",
467
495
  inputSchema: downloadIconSchema
468
496
  },
469
497
  async (args) => {
@@ -493,7 +521,7 @@ function createServer() {
493
521
  "generate_bundle",
494
522
  {
495
523
  title: "Generate Bundle",
496
- description: "Generate a bundle of icons from an icon list. Costs 1 credit per icon. Use normalize_bundle first to plan, or provide icons directly.",
524
+ description: "Generate a bundle of icons from an icon list. Costs 1 credit per icon. Use normalize_bundle first to plan, or provide icons directly. After generation, save preview images to the user's working directory and display them.",
497
525
  inputSchema: generateBundleSchema
498
526
  },
499
527
  async (args) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@icogenie/mcp",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server for IcoGenie - Enable AI agents to generate icons programmatically",
5
5
  "type": "module",
6
6
  "bin": {