@icogenie/mcp 0.1.1 → 0.3.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.
- package/README.md +10 -7
- package/dist/index.js +98 -69
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -64,7 +64,7 @@ generate_icon({
|
|
|
64
64
|
})
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
**Returns:** `{
|
|
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
|
-
|
|
77
|
-
|
|
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 }],
|
|
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
|
-
→ {
|
|
151
|
+
→ { sessionId: "abc123", preview: "...", creditsRemaining: 49 }
|
|
149
152
|
```
|
|
150
153
|
|
|
151
154
|
3. **Refine if needed:**
|
|
152
155
|
```
|
|
153
|
-
regenerate_icon({
|
|
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"
|
|
163
|
+
→ { savedTo: "./bell-icon.zip" }
|
|
161
164
|
```
|
|
162
165
|
|
|
163
166
|
## Bundle Workflow
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
5
5
|
|
|
6
6
|
// src/server.ts
|
|
7
7
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
|
+
import { CREDIT_CONFIG } from "@icogenie/core";
|
|
8
9
|
|
|
9
10
|
// src/tools/generate.ts
|
|
10
11
|
import { z } from "zod";
|
|
@@ -162,15 +163,32 @@ function readReferenceImage(filePath) {
|
|
|
162
163
|
const mimeType = ext === ".png" ? "image/png" : ext === ".webp" ? "image/webp" : "image/jpeg";
|
|
163
164
|
return { data: buffer.toString("base64"), mimeType };
|
|
164
165
|
}
|
|
165
|
-
async function request2(endpoint,
|
|
166
|
-
const
|
|
166
|
+
async function request2(endpoint, options = {}, requireAuth = true) {
|
|
167
|
+
const { method = "POST", body, params } = options;
|
|
168
|
+
let url = `${getApiUrl()}/api${endpoint}`;
|
|
169
|
+
if (params && Object.keys(params).length > 0) {
|
|
170
|
+
url += `?${new URLSearchParams(params).toString()}`;
|
|
171
|
+
}
|
|
167
172
|
const makeRequest = async (sessionToken) => {
|
|
168
|
-
const
|
|
173
|
+
const headers = {};
|
|
174
|
+
if (sessionToken) {
|
|
175
|
+
headers["Authorization"] = `Bearer ${sessionToken}`;
|
|
176
|
+
}
|
|
177
|
+
if (body) {
|
|
178
|
+
headers["Content-Type"] = "application/json";
|
|
179
|
+
}
|
|
169
180
|
const response = await fetch(url, {
|
|
170
|
-
method
|
|
171
|
-
headers
|
|
172
|
-
body: JSON.stringify(
|
|
181
|
+
method,
|
|
182
|
+
headers,
|
|
183
|
+
...body && { body: JSON.stringify(body) }
|
|
173
184
|
});
|
|
185
|
+
const contentType = response.headers.get("content-type");
|
|
186
|
+
if (contentType?.includes("application/zip")) {
|
|
187
|
+
if (!response.ok) {
|
|
188
|
+
throw new ApiError("Download failed", response.status);
|
|
189
|
+
}
|
|
190
|
+
return response;
|
|
191
|
+
}
|
|
174
192
|
const data = await response.json();
|
|
175
193
|
if (response.status === 401 && requireAuth) {
|
|
176
194
|
const newCreds = await handleAuthError();
|
|
@@ -192,51 +210,66 @@ async function request2(endpoint, body, requireAuth = true) {
|
|
|
192
210
|
return makeRequest();
|
|
193
211
|
}
|
|
194
212
|
async function generate(options) {
|
|
195
|
-
return request2("/generate", {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
213
|
+
return request2("/generate-preview", {
|
|
214
|
+
body: {
|
|
215
|
+
prompt: options.prompt,
|
|
216
|
+
variations: options.variations || 1,
|
|
217
|
+
style: options.style || "solid",
|
|
218
|
+
...options.referenceImage && { referenceImage: options.referenceImage }
|
|
219
|
+
}
|
|
200
220
|
});
|
|
201
221
|
}
|
|
202
222
|
async function regenerate(options) {
|
|
203
|
-
return request2("/regenerate", {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
223
|
+
return request2("/regenerate-icon", {
|
|
224
|
+
body: {
|
|
225
|
+
sessionId: options.sessionId,
|
|
226
|
+
bundleId: options.bundleId,
|
|
227
|
+
index: options.index,
|
|
228
|
+
prompt: options.prompt
|
|
229
|
+
}
|
|
208
230
|
});
|
|
209
231
|
}
|
|
210
232
|
async function getCredits() {
|
|
211
|
-
return request2("/
|
|
233
|
+
return request2("/auth/session", { method: "GET" });
|
|
212
234
|
}
|
|
213
235
|
async function download(options) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
236
|
+
const params = {};
|
|
237
|
+
if (options.generationId) params.generation_id = options.generationId;
|
|
238
|
+
if (options.bundleId) params.bundle_id = options.bundleId;
|
|
239
|
+
const response = await request2("/download", {
|
|
240
|
+
method: "GET",
|
|
241
|
+
params
|
|
217
242
|
});
|
|
243
|
+
const contentDisposition = response.headers.get("content-disposition");
|
|
244
|
+
const filenameMatch = contentDisposition?.match(/filename="?([^";\n]+)"?/);
|
|
245
|
+
const filename = filenameMatch?.[1] || `icogenie-${(options.generationId || options.bundleId || "export").slice(0, 8)}.zip`;
|
|
246
|
+
return { response, filename };
|
|
218
247
|
}
|
|
219
248
|
async function normalizeBundle(options) {
|
|
220
|
-
return request2("/normalize", {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
249
|
+
return request2("/normalize-bundle", {
|
|
250
|
+
body: {
|
|
251
|
+
description: options.description,
|
|
252
|
+
targetCount: options.targetCount,
|
|
253
|
+
style: options.style
|
|
254
|
+
}
|
|
224
255
|
});
|
|
225
256
|
}
|
|
226
257
|
async function generateBundle(options) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
258
|
+
const bundleId = options.bundleId || crypto.randomUUID();
|
|
259
|
+
return request2("/generate-bundle-preview", {
|
|
260
|
+
body: {
|
|
261
|
+
bundleId,
|
|
262
|
+
icons: options.icons,
|
|
263
|
+
style: options.style || "solid",
|
|
264
|
+
...options.referenceImage && { referenceImage: options.referenceImage }
|
|
265
|
+
}
|
|
233
266
|
});
|
|
234
267
|
}
|
|
235
268
|
|
|
236
269
|
// src/tools/generate.ts
|
|
237
270
|
var generateIconSchema = {
|
|
238
271
|
prompt: z.string().describe("Description of the icon to generate"),
|
|
239
|
-
style: z.enum(["solid", "outline"]).default("solid").describe("Icon style"),
|
|
272
|
+
style: z.enum(["solid", "outline", "illustration"]).default("solid").describe("Icon style: solid (filled shapes), outline (stroked lines), or illustration (colorful, detailed)"),
|
|
240
273
|
variations: z.union([z.literal(1), z.literal(2), z.literal(4)]).default(1).describe("Number of variations (1, 2, or 4)"),
|
|
241
274
|
referenceImagePath: z.string().optional().describe("Local file path to reference image for style extraction"),
|
|
242
275
|
referenceImage: z.object({
|
|
@@ -258,37 +291,38 @@ async function generateIcon(args) {
|
|
|
258
291
|
referenceImage: refImage
|
|
259
292
|
});
|
|
260
293
|
return {
|
|
261
|
-
|
|
294
|
+
sessionId: result.sessionId,
|
|
262
295
|
preview: result.preview,
|
|
263
|
-
|
|
264
|
-
creditsRemaining: result.
|
|
265
|
-
|
|
296
|
+
previews: result.previews,
|
|
297
|
+
creditsRemaining: result.credits,
|
|
298
|
+
sessionData: result.sessionData,
|
|
299
|
+
suggestions: result.suggestions
|
|
266
300
|
};
|
|
267
301
|
}
|
|
268
302
|
|
|
269
303
|
// src/tools/regenerate.ts
|
|
270
304
|
import { z as z2 } from "zod";
|
|
271
305
|
var regenerateIconSchema = {
|
|
272
|
-
|
|
306
|
+
sessionId: z2.string().optional().describe("For single icon variations"),
|
|
273
307
|
bundleId: z2.string().optional().describe("For bundle icons"),
|
|
274
308
|
index: z2.number().describe("Which variation/icon to regenerate (0-based)"),
|
|
275
309
|
prompt: z2.string().optional().describe("Custom refinement prompt")
|
|
276
310
|
};
|
|
277
311
|
async function regenerateIcon(args) {
|
|
278
|
-
if (!args.
|
|
279
|
-
throw new Error("Must provide either
|
|
312
|
+
if (!args.sessionId && !args.bundleId) {
|
|
313
|
+
throw new Error("Must provide either sessionId or bundleId");
|
|
280
314
|
}
|
|
281
315
|
const result = await regenerate({
|
|
282
|
-
|
|
316
|
+
sessionId: args.sessionId,
|
|
283
317
|
bundleId: args.bundleId,
|
|
284
318
|
index: args.index,
|
|
285
319
|
prompt: args.prompt
|
|
286
320
|
});
|
|
287
321
|
return {
|
|
288
322
|
success: result.success,
|
|
323
|
+
index: result.index,
|
|
289
324
|
preview: result.preview,
|
|
290
|
-
|
|
291
|
-
creditsRemaining: result.creditsRemaining
|
|
325
|
+
creditsRemaining: result.credits
|
|
292
326
|
};
|
|
293
327
|
}
|
|
294
328
|
|
|
@@ -315,27 +349,23 @@ async function downloadIcon(args) {
|
|
|
315
349
|
if (!args.generationId && !args.bundleId) {
|
|
316
350
|
throw new Error("Must provide either generationId or bundleId");
|
|
317
351
|
}
|
|
318
|
-
const
|
|
352
|
+
const { response, filename } = await download({
|
|
319
353
|
generationId: args.generationId,
|
|
320
354
|
bundleId: args.bundleId
|
|
321
355
|
});
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
356
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
357
|
+
const zipBuffer = Buffer.from(arrayBuffer);
|
|
358
|
+
const result = {
|
|
359
|
+
success: true,
|
|
360
|
+
filename
|
|
327
361
|
};
|
|
328
362
|
if (args.outputPath) {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
response.savedTo = args.outputPath;
|
|
363
|
+
writeFileSync(args.outputPath, zipBuffer);
|
|
364
|
+
result.savedTo = args.outputPath;
|
|
332
365
|
} else {
|
|
333
|
-
|
|
334
|
-
data: result.bundle.data,
|
|
335
|
-
filename: result.bundle.filename
|
|
336
|
-
};
|
|
366
|
+
result.bundleData = zipBuffer.toString("base64");
|
|
337
367
|
}
|
|
338
|
-
return
|
|
368
|
+
return result;
|
|
339
369
|
}
|
|
340
370
|
|
|
341
371
|
// src/tools/normalize-bundle.ts
|
|
@@ -343,7 +373,7 @@ import { z as z4 } from "zod";
|
|
|
343
373
|
var normalizeBundleSchema = {
|
|
344
374
|
description: z4.string().describe("Description of the icon bundle to create"),
|
|
345
375
|
targetCount: z4.number().optional().describe("Target number of icons (2-20)"),
|
|
346
|
-
style: z4.enum(["solid", "outline"]).optional().describe("Preferred icon style")
|
|
376
|
+
style: z4.enum(["solid", "outline", "illustration"]).optional().describe("Preferred icon style")
|
|
347
377
|
};
|
|
348
378
|
async function normalizeBundleTool(args) {
|
|
349
379
|
const result = await normalizeBundle({
|
|
@@ -371,7 +401,7 @@ var generateBundleSchema = {
|
|
|
371
401
|
).optional().describe("Icon list from normalize_bundle or custom"),
|
|
372
402
|
description: z5.string().optional().describe("Alternative: describe the bundle to auto-generate icon list"),
|
|
373
403
|
targetCount: z5.number().optional().describe("Target icon count when using description"),
|
|
374
|
-
style: z5.enum(["solid", "outline"]).default("solid").describe("Icon style"),
|
|
404
|
+
style: z5.enum(["solid", "outline", "illustration"]).default("solid").describe("Icon style: solid (filled shapes), outline (stroked lines), or illustration (colorful, detailed)"),
|
|
375
405
|
referenceImagePath: z5.string().optional().describe("Local file path to reference image"),
|
|
376
406
|
referenceImage: z5.object({
|
|
377
407
|
data: z5.string(),
|
|
@@ -379,8 +409,8 @@ var generateBundleSchema = {
|
|
|
379
409
|
}).optional().describe("Base64-encoded reference image")
|
|
380
410
|
};
|
|
381
411
|
async function generateBundleTool(args) {
|
|
382
|
-
if (!args.icons
|
|
383
|
-
throw new Error("Must provide
|
|
412
|
+
if (!args.icons) {
|
|
413
|
+
throw new Error("Must provide icons array (use normalize_bundle first to get icon list)");
|
|
384
414
|
}
|
|
385
415
|
let refImage;
|
|
386
416
|
if (args.referenceImagePath) {
|
|
@@ -390,21 +420,20 @@ async function generateBundleTool(args) {
|
|
|
390
420
|
}
|
|
391
421
|
const result = await generateBundle({
|
|
392
422
|
icons: args.icons,
|
|
393
|
-
description: args.description,
|
|
394
|
-
targetCount: args.targetCount,
|
|
395
423
|
style: args.style || "solid",
|
|
396
424
|
referenceImage: refImage
|
|
397
425
|
});
|
|
398
426
|
return {
|
|
399
427
|
bundleId: result.bundleId,
|
|
400
|
-
iconCount: result.
|
|
401
|
-
icons: result.
|
|
428
|
+
iconCount: result.previews.length,
|
|
429
|
+
icons: result.previews.map((icon) => ({
|
|
402
430
|
name: icon.name,
|
|
403
431
|
description: icon.description,
|
|
404
432
|
preview: icon.preview
|
|
405
433
|
})),
|
|
406
|
-
|
|
407
|
-
|
|
434
|
+
pricing: result.pricing,
|
|
435
|
+
creditsUsed: result.creditsUsed,
|
|
436
|
+
creditsRemaining: result.credits
|
|
408
437
|
};
|
|
409
438
|
}
|
|
410
439
|
|
|
@@ -418,7 +447,7 @@ function createServer() {
|
|
|
418
447
|
"generate_icon",
|
|
419
448
|
{
|
|
420
449
|
title: "Generate Icon",
|
|
421
|
-
description:
|
|
450
|
+
description: `Generate an AI-powered icon preview from a text description. Costs ${CREDIT_CONFIG.costs.preview} credit. Returns a generationId for download. After generation, save the preview image to the user's working directory and display it.`,
|
|
422
451
|
inputSchema: generateIconSchema
|
|
423
452
|
},
|
|
424
453
|
async (args) => {
|
|
@@ -433,7 +462,7 @@ function createServer() {
|
|
|
433
462
|
"regenerate_icon",
|
|
434
463
|
{
|
|
435
464
|
title: "Regenerate Icon",
|
|
436
|
-
description:
|
|
465
|
+
description: `Regenerate a specific icon variation with an optional custom prompt. Costs ${CREDIT_CONFIG.costs.preview} credit. Use with generationId (single) or bundleId (bundle). After regeneration, save and display the new preview.`,
|
|
437
466
|
inputSchema: regenerateIconSchema
|
|
438
467
|
},
|
|
439
468
|
async (args) => {
|
|
@@ -463,7 +492,7 @@ function createServer() {
|
|
|
463
492
|
"download_icon",
|
|
464
493
|
{
|
|
465
494
|
title: "Download Icon",
|
|
466
|
-
description:
|
|
495
|
+
description: `Download the final SVG + PNG package for an icon. Costs ${CREDIT_CONFIG.costs.vectorDownload} credits (single) or ${CREDIT_CONFIG.costs.bundleDownload} credits/icon (bundle). Provide outputPath to save to file. Always save to the user's working directory with a descriptive filename.`,
|
|
467
496
|
inputSchema: downloadIconSchema
|
|
468
497
|
},
|
|
469
498
|
async (args) => {
|
|
@@ -493,7 +522,7 @@ function createServer() {
|
|
|
493
522
|
"generate_bundle",
|
|
494
523
|
{
|
|
495
524
|
title: "Generate Bundle",
|
|
496
|
-
description:
|
|
525
|
+
description: `Generate a bundle of icons from an icon list. Costs ${CREDIT_CONFIG.costs.bundlePreview} 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
526
|
inputSchema: generateBundleSchema
|
|
498
527
|
},
|
|
499
528
|
async (args) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@icogenie/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "MCP server for IcoGenie - Enable AI agents to generate icons programmatically",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
19
19
|
"conf": "^12.0.0",
|
|
20
20
|
"open": "^10.0.0",
|
|
21
|
-
"zod": "^3.23.0"
|
|
21
|
+
"zod": "^3.23.0",
|
|
22
|
+
"@icogenie/core": "0.1.0"
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
24
25
|
"@types/node": "^20.0.0",
|