@codingmantra/mcp-server 0.1.4 → 0.2.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/README.md +151 -38
- package/build/api-client.js +45 -15
- package/build/image-utils.js +145 -0
- package/build/index.js +1076 -128
- package/package.json +17 -7
- package/src/api-client.ts +0 -47
- package/src/index.ts +0 -440
- package/tsconfig.json +0 -14
package/build/index.js
CHANGED
|
@@ -3,35 +3,74 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
5
5
|
import { apiClient } from './api-client.js';
|
|
6
|
+
import { formatImageToolResult, resolveImageInput, resolveImagesArray } from './image-utils.js';
|
|
6
7
|
const server = new Server({
|
|
7
8
|
name: "codingmantra-mcp",
|
|
8
|
-
version: "0.
|
|
9
|
+
version: "0.2.2",
|
|
9
10
|
}, {
|
|
10
11
|
capabilities: {
|
|
11
12
|
tools: {},
|
|
12
13
|
},
|
|
13
14
|
});
|
|
15
|
+
// ─── Reusable Parameter Definitions ──────────────────────────────────────────
|
|
16
|
+
const IMAGE_SOURCE_SCHEMA = {
|
|
17
|
+
type: "object",
|
|
18
|
+
properties: {
|
|
19
|
+
url: { type: "string", description: "Public URL of the image." },
|
|
20
|
+
dataUrl: { type: "string", description: "Base64 data URI of the image." },
|
|
21
|
+
path: { type: "string", description: "Local file path on disk (will be automatically resolved to base64)." }
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const COMMON_VIDEO_PROPERTIES = {
|
|
25
|
+
prompt: { type: "string", minLength: 10, maxLength: 5000, description: "Required video description or creative prompt (10-5000 characters)." },
|
|
26
|
+
mainImage: { type: "string", description: "Base64 data URI, local file path, or public URL for the main subject image (Image-to-Video mode)." },
|
|
27
|
+
startImage: { type: "string", description: "Base64 data URI, local file path, or public URL for the first frame." },
|
|
28
|
+
endImage: { type: "string", description: "Base64 data URI, local file path, or public URL for the last frame." },
|
|
29
|
+
referenceImages: {
|
|
30
|
+
type: "array",
|
|
31
|
+
maxItems: 4,
|
|
32
|
+
items: { type: "object", properties: { image: { type: "string", description: "Public image URL, data URI, or local file path." }, label: { type: "string", description: "Optional reference label." } }, required: ["image"] },
|
|
33
|
+
description: "Reference images for style matching. Choose only one image mode: main image, frames, or references. Veo supports up to 3 references and requires 8 seconds for references or an end frame."
|
|
34
|
+
},
|
|
35
|
+
negativePrompt: { type: "string", description: "Elements to exclude from the video." },
|
|
36
|
+
dialogue: { type: "string", maxLength: 200, description: "Optional voiceover or dialogue script (up to 200 characters)." },
|
|
37
|
+
soundSuggestion: { type: "string", description: "Background music or sound effects direction." },
|
|
38
|
+
cameraMotion: { type: "string", description: "Camera motion instructions (e.g., 'orbit right', 'slow push-in')." },
|
|
39
|
+
ambientNoise: { type: "string", description: "Ambient sound description." },
|
|
40
|
+
language: { type: "string", description: "Voiceover language." },
|
|
41
|
+
timeDuration: { type: "string", description: "Required duration in seconds supported by the selected model. Veo supports 4, 6, or 8; use 8 for 1080p, references, or an end frame." },
|
|
42
|
+
resolution: { type: "string", description: "Required resolution supported by the selected model (480p, 720p, 768p, or 1080p)." },
|
|
43
|
+
model: { type: "string", description: "Model slug (e.g., 'google/veo-3.1-fast', 'alibaba/wan-3.0')." },
|
|
44
|
+
aspectRatio: { type: "string", description: "Required aspect ratio supported by the selected model (e.g., 9:16 or 16:9)." },
|
|
45
|
+
generateAudio: { type: "boolean", description: "Whether to generate synchronized audio. Default is false." },
|
|
46
|
+
seed: { type: "integer", minimum: 0, maximum: Number.MAX_SAFE_INTEGER, description: "Optional nonnegative random seed for models that support it." },
|
|
47
|
+
guidanceScale: { type: "number", description: "Optional guidance strength for models that support it." },
|
|
48
|
+
soundEffects: { type: "string", description: "Sound effects direction for Story Teller." },
|
|
49
|
+
styleAmbiance: { type: "string", description: "Visual style and atmosphere for Story Teller." },
|
|
50
|
+
characters: { type: "array", description: "Optional named characters for consistent storytelling.", items: {
|
|
51
|
+
type: "object", properties: {
|
|
52
|
+
id: { type: "string", description: "Unique character ID." },
|
|
53
|
+
name: { type: "string", description: "Character name." },
|
|
54
|
+
description: { type: "string", description: "Character appearance and role." }
|
|
55
|
+
}, required: ["id", "name", "description"]
|
|
56
|
+
} }
|
|
57
|
+
};
|
|
14
58
|
// ─── Tool Definitions ──────────────────────────────────────────────────────────
|
|
59
|
+
// 1. Product Photography
|
|
15
60
|
const GENERATE_PRODUCT_PHOTO_TOOL = {
|
|
16
61
|
name: "generate_product_photo",
|
|
17
|
-
description: "Generates
|
|
62
|
+
description: "Generates studio-grade commercial product photography with customizable background scenes, ambient occlusion contact shadows, camera optics, resolutions (1K, 2K, 4K), aspect ratios, and dynamic logo/text overlays. Returns the image directly for inline display (synchronous).",
|
|
18
63
|
inputSchema: {
|
|
19
64
|
type: "object",
|
|
20
65
|
properties: {
|
|
21
66
|
productImages: {
|
|
22
67
|
type: "array",
|
|
23
|
-
items:
|
|
24
|
-
|
|
25
|
-
properties: {
|
|
26
|
-
url: { type: "string", description: "Public URL of the product image." },
|
|
27
|
-
dataUrl: { type: "string", description: "Base64 data URI of the product image." }
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
description: "Array of product images. Each must have either a 'url' or 'dataUrl'. At least one required."
|
|
68
|
+
items: IMAGE_SOURCE_SCHEMA,
|
|
69
|
+
description: "Array of product images. Each item can have 'url', 'dataUrl', or local 'path'. At least one required."
|
|
31
70
|
},
|
|
32
71
|
scenePrompt: {
|
|
33
72
|
type: "string",
|
|
34
|
-
description: "A detailed description of the background scene and
|
|
73
|
+
description: "A detailed description of the background scene, surface, and environment for the product photo."
|
|
35
74
|
},
|
|
36
75
|
model: {
|
|
37
76
|
type: "string",
|
|
@@ -39,23 +78,23 @@ const GENERATE_PRODUCT_PHOTO_TOOL = {
|
|
|
39
78
|
},
|
|
40
79
|
resolution: {
|
|
41
80
|
type: "string",
|
|
42
|
-
description: "Output resolution (
|
|
81
|
+
description: "Output resolution ('1K', '2K', '4K'). Default is '1K'.",
|
|
43
82
|
},
|
|
44
83
|
aspectRatio: {
|
|
45
84
|
type: "string",
|
|
46
|
-
description: "Output aspect ratio (
|
|
85
|
+
description: "Output aspect ratio ('1:1', '16:9', '9:16', '4:5'). Default is '1:1'.",
|
|
47
86
|
},
|
|
48
87
|
referenceImage: {
|
|
49
88
|
type: "string",
|
|
50
|
-
description: "
|
|
89
|
+
description: "Optional URL, data URI, or local file path of a style reference image."
|
|
51
90
|
},
|
|
52
91
|
promptId: {
|
|
53
92
|
type: "string",
|
|
54
|
-
description: "Optional ID of a pre-defined
|
|
93
|
+
description: "Optional ID of a pre-defined background template."
|
|
55
94
|
},
|
|
56
95
|
logoImage: {
|
|
57
96
|
type: "string",
|
|
58
|
-
description: "Optional URL or
|
|
97
|
+
description: "Optional URL, data URI, or local file path of a brand logo to place on the image."
|
|
59
98
|
},
|
|
60
99
|
logoPlacement: {
|
|
61
100
|
type: "string",
|
|
@@ -63,7 +102,7 @@ const GENERATE_PRODUCT_PHOTO_TOOL = {
|
|
|
63
102
|
},
|
|
64
103
|
logoSize: {
|
|
65
104
|
type: "number",
|
|
66
|
-
description: "Scale of the logo overlay (0.
|
|
105
|
+
description: "Scale of the logo overlay (0.05 to 0.5). Default is 0.15."
|
|
67
106
|
},
|
|
68
107
|
overlayText: {
|
|
69
108
|
type: "string",
|
|
@@ -71,15 +110,16 @@ const GENERATE_PRODUCT_PHOTO_TOOL = {
|
|
|
71
110
|
},
|
|
72
111
|
marketingText: {
|
|
73
112
|
type: "string",
|
|
74
|
-
description: "Optional marketing text to overlay."
|
|
113
|
+
description: "Optional marketing text or slogan to overlay."
|
|
75
114
|
}
|
|
76
115
|
},
|
|
77
116
|
required: ["productImages", "scenePrompt"]
|
|
78
117
|
}
|
|
79
118
|
};
|
|
119
|
+
// 2. Logo Creator
|
|
80
120
|
const GENERATE_LOGO_TOOL = {
|
|
81
121
|
name: "generate_logo",
|
|
82
|
-
description: "Generates
|
|
122
|
+
description: "Generates bespoke vector-style brand logos, monograms, emblems, and modern wordmarks with character-perfect typography, color palettes, and reference image guidance. Default model is Flash. Returns the generated logo directly for inline display (synchronous).",
|
|
83
123
|
inputSchema: {
|
|
84
124
|
type: "object",
|
|
85
125
|
properties: {
|
|
@@ -89,7 +129,7 @@ const GENERATE_LOGO_TOOL = {
|
|
|
89
129
|
},
|
|
90
130
|
stylePrompt: {
|
|
91
131
|
type: "string",
|
|
92
|
-
description: "A detailed style description for the logo (e.g., 'minimalist flat vector logo,
|
|
132
|
+
description: "A detailed style description for the logo (e.g., 'minimalist flat vector logo, navy blue and gold, clean tech aesthetic')."
|
|
93
133
|
},
|
|
94
134
|
subtitle: {
|
|
95
135
|
type: "string",
|
|
@@ -97,43 +137,646 @@ const GENERATE_LOGO_TOOL = {
|
|
|
97
137
|
},
|
|
98
138
|
industry: {
|
|
99
139
|
type: "string",
|
|
100
|
-
description: "The industry the company operates in (e.g., 'Technology', '
|
|
140
|
+
description: "The industry the company operates in (e.g., 'Technology', 'Luxury Jewelry', 'Fashion')."
|
|
101
141
|
},
|
|
102
142
|
ideas: {
|
|
103
143
|
type: "string",
|
|
104
|
-
description: "
|
|
144
|
+
description: "Core keywords, symbols, or concepts for the logo."
|
|
105
145
|
},
|
|
106
146
|
colors: {
|
|
107
147
|
type: "string",
|
|
108
|
-
description: "Preferred color palette description (e.g., '
|
|
148
|
+
description: "Preferred color palette description (e.g., 'emerald green and brushed gold')."
|
|
149
|
+
},
|
|
150
|
+
aspectRatio: {
|
|
151
|
+
type: "string",
|
|
152
|
+
description: "Output aspect ratio ('1:1', '16:9', '4:3'). Default is '1:1'.",
|
|
153
|
+
},
|
|
154
|
+
model: {
|
|
155
|
+
type: "string",
|
|
156
|
+
description: "Model tier to use ('flash' or 'pro'). Default is 'flash' (google/gemini-3.1-flash-image)."
|
|
157
|
+
},
|
|
158
|
+
modelId: {
|
|
159
|
+
type: "string",
|
|
160
|
+
description: "Full image model ID if specific model desired (e.g. google/gemini-3.1-flash-image).",
|
|
161
|
+
},
|
|
162
|
+
resolution: {
|
|
163
|
+
type: "string",
|
|
164
|
+
description: "Output resolution ('1K', '2K', '4K'). Default is '1K'.",
|
|
165
|
+
},
|
|
166
|
+
referenceImage: {
|
|
167
|
+
type: "string",
|
|
168
|
+
description: "Optional style reference image URL, data URI, or local file path."
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
required: ["companyName", "stylePrompt"]
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
// 3. Jewelry Try-On
|
|
175
|
+
const TRY_ON_JEWELRY_TOOL = {
|
|
176
|
+
name: "try_on_jewelry",
|
|
177
|
+
description: "Luxury jewelry virtual try-on. Places necklaces, rings, earrings, and bracelets naturally on human models with prongs/gemstone preservation, authentic optical dispersion, and anatomical contact shadows. Returns generated image directly (synchronous).",
|
|
178
|
+
inputSchema: {
|
|
179
|
+
type: "object",
|
|
180
|
+
properties: {
|
|
181
|
+
jewelryImages: {
|
|
182
|
+
type: "array",
|
|
183
|
+
items: IMAGE_SOURCE_SCHEMA,
|
|
184
|
+
description: "Array of jewelry product images. Each can have 'url', 'dataUrl', or local 'path'. At least one required."
|
|
185
|
+
},
|
|
186
|
+
personImage: {
|
|
187
|
+
type: "string",
|
|
188
|
+
description: "Optional photo of a person to model the jewelry (URL, data URI, or local file path). If omitted, an elegant editorial model is generated."
|
|
189
|
+
},
|
|
190
|
+
prompt: {
|
|
191
|
+
type: "string",
|
|
192
|
+
description: "Creative styling directions (e.g., 'wearing black velvet evening gown, soft studio rim lighting, Parisian luxury ambiance')."
|
|
193
|
+
},
|
|
194
|
+
sizeMeasurement: {
|
|
195
|
+
type: "string",
|
|
196
|
+
description: "Physical dimensions (e.g., '2 cm pendant', 'ring size 7') to maintain accurate scale."
|
|
197
|
+
},
|
|
198
|
+
aspectRatio: {
|
|
199
|
+
type: "string",
|
|
200
|
+
description: "Output aspect ratio ('1:1', '9:16', '16:9'). Default is '1:1'."
|
|
201
|
+
},
|
|
202
|
+
resolution: {
|
|
203
|
+
type: "string",
|
|
204
|
+
description: "Output resolution ('1K', '2K', '4K'). Default is '1K'."
|
|
205
|
+
},
|
|
206
|
+
model: {
|
|
207
|
+
type: "string",
|
|
208
|
+
description: "Model tier slug ('standard', 'pro', 'flash'). Default is 'flash'."
|
|
209
|
+
},
|
|
210
|
+
referenceImage: {
|
|
211
|
+
type: "string",
|
|
212
|
+
description: "Optional campaign reference image (URL, data URI, or local path) to copy lighting and mood from."
|
|
213
|
+
},
|
|
214
|
+
logoImage: {
|
|
215
|
+
type: "string",
|
|
216
|
+
description: "Optional brand logo overlay."
|
|
217
|
+
},
|
|
218
|
+
logoPlacement: {
|
|
219
|
+
type: "string",
|
|
220
|
+
description: "Logo placement ('top-left', 'bottom-right', etc.)."
|
|
221
|
+
},
|
|
222
|
+
overlayText: {
|
|
223
|
+
type: "string",
|
|
224
|
+
description: "Optional text to overlay on the image."
|
|
225
|
+
},
|
|
226
|
+
marketingText: {
|
|
227
|
+
type: "string",
|
|
228
|
+
description: "Optional marketing text or slogan."
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
required: ["jewelryImages"]
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
// 4. Apparel Try-On
|
|
235
|
+
const TRY_ON_APPAREL_TOOL = {
|
|
236
|
+
name: "try_on_apparel",
|
|
237
|
+
description: "Virtual fashion apparel try-on. Drapes garments realistically along model anatomy with natural gravitational folds, realistic tension, ambient occlusion contact shadows, and editorial lighting. Default model tier is Flash. Returns generated image directly (synchronous).",
|
|
238
|
+
inputSchema: {
|
|
239
|
+
type: "object",
|
|
240
|
+
properties: {
|
|
241
|
+
apparelImages: {
|
|
242
|
+
type: "array",
|
|
243
|
+
items: IMAGE_SOURCE_SCHEMA,
|
|
244
|
+
description: "Array of clothing/apparel images. Each can have 'url', 'dataUrl', or local 'path'. At least one required."
|
|
245
|
+
},
|
|
246
|
+
modelImage: {
|
|
247
|
+
type: "string",
|
|
248
|
+
description: "Optional photo of a person/model (URL, data URI, or local path). If omitted, a professional fashion model is generated."
|
|
249
|
+
},
|
|
250
|
+
prompt: {
|
|
251
|
+
type: "string",
|
|
252
|
+
description: "Styling and scene creative direction (e.g., 'standing on Milan street, golden hour sunlight, editorial fashion magazine style')."
|
|
253
|
+
},
|
|
254
|
+
aspectRatio: {
|
|
255
|
+
type: "string",
|
|
256
|
+
description: "Output aspect ratio ('9:16', '1:1', '16:9', '4:5'). Default is '9:16'."
|
|
257
|
+
},
|
|
258
|
+
resolution: {
|
|
259
|
+
type: "string",
|
|
260
|
+
description: "Output resolution ('1K', '2K', '4K'). Default is '1K'."
|
|
261
|
+
},
|
|
262
|
+
model: {
|
|
263
|
+
type: "string",
|
|
264
|
+
description: "The model tier ('flash', 'pro', 'standard'). Default is 'flash'."
|
|
265
|
+
},
|
|
266
|
+
referenceImage: {
|
|
267
|
+
type: "string",
|
|
268
|
+
description: "Optional style reference image URL, data URI, or local path."
|
|
269
|
+
},
|
|
270
|
+
logoImage: {
|
|
271
|
+
type: "string",
|
|
272
|
+
description: "Optional brand logo overlay."
|
|
273
|
+
},
|
|
274
|
+
overlayText: {
|
|
275
|
+
type: "string",
|
|
276
|
+
description: "Optional text overlay."
|
|
277
|
+
},
|
|
278
|
+
marketingText: {
|
|
279
|
+
type: "string",
|
|
280
|
+
description: "Optional marketing copy."
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
required: ["apparelImages"]
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
// 5. Product Try-On
|
|
287
|
+
const TRY_ON_PRODUCT_TOOL = {
|
|
288
|
+
name: "try_on_product",
|
|
289
|
+
description: "Universal commercial product staging and try-on across footwear, accessories, watches, eyewear, cosmetics, and furniture with 3-point studio lighting and ambient occlusion contact shadows. Default model tier is Flash. Returns generated image directly (synchronous).",
|
|
290
|
+
inputSchema: {
|
|
291
|
+
type: "object",
|
|
292
|
+
properties: {
|
|
293
|
+
productImages: {
|
|
294
|
+
type: "array",
|
|
295
|
+
items: IMAGE_SOURCE_SCHEMA,
|
|
296
|
+
description: "Array of product images. At least one required."
|
|
297
|
+
},
|
|
298
|
+
mainImage: {
|
|
299
|
+
type: "string",
|
|
300
|
+
description: "Optional base image (model portrait, empty room, or tabletop) to place the product into."
|
|
301
|
+
},
|
|
302
|
+
prompt: {
|
|
303
|
+
type: "string",
|
|
304
|
+
description: "Creative styling and environment directions."
|
|
305
|
+
},
|
|
306
|
+
sizeMeasurement: {
|
|
307
|
+
type: "string",
|
|
308
|
+
description: "Physical dimensions (e.g., '10 inches', '30 cm') to maintain exact scale."
|
|
309
|
+
},
|
|
310
|
+
aspectRatio: {
|
|
311
|
+
type: "string",
|
|
312
|
+
description: "Output aspect ratio ('1:1', '16:9', '9:16'). Default is '1:1'."
|
|
313
|
+
},
|
|
314
|
+
resolution: {
|
|
315
|
+
type: "string",
|
|
316
|
+
description: "Output resolution ('1K', '2K', '4K'). Default is '1K'."
|
|
317
|
+
},
|
|
318
|
+
model: {
|
|
319
|
+
type: "string",
|
|
320
|
+
description: "The model tier ('flash', 'pro', 'standard'). Default is 'flash'."
|
|
321
|
+
},
|
|
322
|
+
referenceImage: {
|
|
323
|
+
type: "string",
|
|
324
|
+
description: "Optional style reference image."
|
|
325
|
+
},
|
|
326
|
+
logoImage: {
|
|
327
|
+
type: "string",
|
|
328
|
+
description: "Optional brand logo overlay."
|
|
329
|
+
},
|
|
330
|
+
overlayText: {
|
|
331
|
+
type: "string",
|
|
332
|
+
description: "Optional text overlay."
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
required: ["productImages"]
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
// 6. Festival Post Generator
|
|
339
|
+
const GENERATE_FESTIVAL_POST_TOOL = {
|
|
340
|
+
name: "generate_festival_post",
|
|
341
|
+
description: "Generates high-conversion festival marketing graphics, holiday greetings (Diwali, Eid, Christmas, New Year, Valentine's), and promotional event banners with product and brand logo integration. Default model is Flash. Returns generated image directly (synchronous).",
|
|
342
|
+
inputSchema: {
|
|
343
|
+
type: "object",
|
|
344
|
+
properties: {
|
|
345
|
+
festivalPrompt: {
|
|
346
|
+
type: "string",
|
|
347
|
+
description: "Festival theme or campaign message (e.g., 'Diwali luxury jewelry promotion with warm golden diyas and floral rangoli')."
|
|
348
|
+
},
|
|
349
|
+
productImage: {
|
|
350
|
+
type: "string",
|
|
351
|
+
description: "Optional hero product image (URL, data URI, or local file path) to place centrally in the festive composition."
|
|
352
|
+
},
|
|
353
|
+
logoImage: {
|
|
354
|
+
type: "string",
|
|
355
|
+
description: "Optional brand logo image."
|
|
356
|
+
},
|
|
357
|
+
overlayText: {
|
|
358
|
+
type: "string",
|
|
359
|
+
description: "Main headline or festive greeting text (e.g., 'Happy Diwali - 20% Off')."
|
|
360
|
+
},
|
|
361
|
+
marketingText: {
|
|
362
|
+
type: "string",
|
|
363
|
+
description: "Supporting promotional message or contact details."
|
|
364
|
+
},
|
|
365
|
+
model: {
|
|
366
|
+
type: "string",
|
|
367
|
+
description: "The model tier ('flash', 'pro', 'standard'). Default is 'flash' (Gemini 3.1 Flash)."
|
|
109
368
|
},
|
|
110
369
|
aspectRatio: {
|
|
111
370
|
type: "string",
|
|
112
|
-
description: "Output aspect ratio. Default is '1:1'."
|
|
371
|
+
description: "Output aspect ratio ('1:1', '9:16', '16:9'). Default is '1:1'."
|
|
372
|
+
},
|
|
373
|
+
resolution: {
|
|
374
|
+
type: "string",
|
|
375
|
+
description: "Output resolution ('1K', '2K'). Default is '1K'."
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
required: ["festivalPrompt"]
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
// 7. Human Builder / Virtual Model Generator
|
|
382
|
+
const BUILD_HUMAN_TOOL = {
|
|
383
|
+
name: "build_human",
|
|
384
|
+
description: "Creates photorealistic AI human models tailored for brand photography, fashion, ecommerce, and marketing campaigns with complete demographic, facial, hair, and body customization, plus multi-view character sheets (2x2 grid). Default model tier is Flash. Returns generated image directly (synchronous).",
|
|
385
|
+
inputSchema: {
|
|
386
|
+
type: "object",
|
|
387
|
+
properties: {
|
|
388
|
+
name: { type: "string", description: "Optional name or character identifier for the model." },
|
|
389
|
+
age: { type: "string", description: "Age category or specific age (e.g., 'Young Adult', '25 years old', 'Middle-aged')." },
|
|
390
|
+
gender: { type: "string", description: "Gender identity (e.g., 'Female', 'Male', 'Non-binary')." },
|
|
391
|
+
culturalTraits: { type: "string", description: "Ethnicity or cultural heritage (e.g., 'South Asian', 'East Asian', 'Caucasian', 'African')." },
|
|
392
|
+
country: { type: "string", description: "Country of origin (e.g., 'India', 'Japan', 'France', 'Brazil')." },
|
|
393
|
+
skinTone: { type: "string", description: "Complexion and skin tone (e.g., 'Medium Warm', 'Fair Porcelain', 'Rich Deep Bronze')." },
|
|
394
|
+
eyeColor: { type: "string", description: "Eye color (e.g., 'Dark Brown', 'Hazel Green', 'Deep Blue')." },
|
|
395
|
+
eyeShape: { type: "string", description: "Eye shape (e.g., 'Almond', 'Round', 'Monolid', 'Hooded')." },
|
|
396
|
+
noseShape: { type: "string", description: "Nose shape (e.g., 'Natural Straight', 'Aquiline', 'Button', 'Broad')." },
|
|
397
|
+
faceShape: { type: "string", description: "Face shape (e.g., 'Oval', 'Square', 'Heart', 'Round')." },
|
|
398
|
+
hairStyle: { type: "string", description: "Hairstyle (e.g., 'Long Waves', 'Buzz Cut', 'Sleek Bob', 'Afro', 'Layered Cut')." },
|
|
399
|
+
hairColor: { type: "string", description: "Hair color (e.g., 'Natural Black', 'Chestnut Brown', 'Honey Blonde')." },
|
|
400
|
+
hairThickness: { type: "string", description: "Hair density (e.g., 'Thick', 'Medium', 'Fine')." },
|
|
401
|
+
hairType: { type: "string", description: "Hair texture (e.g., 'Straight', 'Wavy', 'Curly', 'Coily')." },
|
|
402
|
+
bodySize: { type: "string", description: "Body build (e.g., 'Petite', 'Slim Athletic', 'Medium', 'Curvy', 'Plus Size')." },
|
|
403
|
+
bodyHeight: { type: "string", description: "Height description (e.g., 'Petite', 'Average', 'Tall Fashion Model')." },
|
|
404
|
+
bodyShape: { type: "string", description: "Body shape (e.g., 'Hourglass', 'Athletic Rectangular', 'Pear', 'Inverted Triangle')." },
|
|
405
|
+
muscleDefinition: { type: "string", description: "Muscle definition (e.g., 'Soft Natural', 'Toned Athletic', 'Defined Muscular')." },
|
|
406
|
+
cupSize: { type: "string", description: "Bust proportion if female (e.g., 'Small', 'Medium', 'Full')." },
|
|
407
|
+
extraDescription: { type: "string", description: "Extra unique physical traits (e.g., 'light freckles across nose bridge, subtle smile')." },
|
|
408
|
+
customTweakPrompt: { type: "string", description: "Custom refinement or scene styling prompt (e.g., 'wearing an ivory cashmere turtleneck against a warm minimalist studio backdrop')." },
|
|
409
|
+
generateMultiView: { type: "boolean", description: "Generate a 4-panel consistent character sheet in a 2x2 grid (Front, Side, 3/4, Close-up detail). Default is false." },
|
|
410
|
+
referenceImages: {
|
|
411
|
+
type: "array",
|
|
412
|
+
items: { type: "string" },
|
|
413
|
+
description: "Optional array of reference face or body images (URLs, data URIs, or local file paths) to guide identity."
|
|
414
|
+
},
|
|
415
|
+
aspectRatio: { type: "string", description: "Output aspect ratio ('1:1', '9:16', '4:5', '16:9'). Default is '1:1'." },
|
|
416
|
+
resolution: { type: "string", description: "Output resolution ('1K', '2K', '4K'). Default is '1K'." },
|
|
417
|
+
model: { type: "string", description: "Model tier ('flash', 'pro', 'standard'). Default is 'flash'." }
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
// 8. YouTube Thumbnail Generator
|
|
422
|
+
const GENERATE_YOUTUBE_THUMBNAIL_TOOL = {
|
|
423
|
+
name: "generate_youtube_thumbnail",
|
|
424
|
+
description: "Generates high-CTR YouTube thumbnails with rule-of-thirds composition, emotional human expressions, vibrant contrast separation, and legible bold text overlays. Returns generated image directly (synchronous).",
|
|
425
|
+
inputSchema: {
|
|
426
|
+
type: "object",
|
|
427
|
+
properties: {
|
|
428
|
+
prompt: {
|
|
429
|
+
type: "string",
|
|
430
|
+
description: "Core video concept or thumbnail description (e.g., 'Shocked tech reviewer holding futuristic glowing AI smartphone, neon studio background')."
|
|
431
|
+
},
|
|
432
|
+
overlayText: {
|
|
433
|
+
type: "string",
|
|
434
|
+
description: "Short, punchy thumbnail headline text (e.g., 'DON\\'T BUY THIS!')."
|
|
435
|
+
},
|
|
436
|
+
personImage: {
|
|
437
|
+
type: "string",
|
|
438
|
+
description: "Optional photo of the YouTube creator/subject (URL, data URI, or local path) to feature prominently."
|
|
439
|
+
},
|
|
440
|
+
backgroundImage: {
|
|
441
|
+
type: "string",
|
|
442
|
+
description: "Optional custom background image."
|
|
443
|
+
},
|
|
444
|
+
logoImage: {
|
|
445
|
+
type: "string",
|
|
446
|
+
description: "Optional channel/brand logo to place in corner."
|
|
447
|
+
},
|
|
448
|
+
referenceImage: {
|
|
449
|
+
type: "string",
|
|
450
|
+
description: "Optional style or concept reference image (URL, data URI, or local file path)."
|
|
451
|
+
},
|
|
452
|
+
promptId: {
|
|
453
|
+
type: "string",
|
|
454
|
+
description: "Optional ID or title of a pre-defined layout style template from youtubeThumbnailPrompts."
|
|
455
|
+
},
|
|
456
|
+
model: {
|
|
457
|
+
type: "string",
|
|
458
|
+
description: "Model tier ('flash', 'pro', 'standard'). Default is 'flash' (google/gemini-3.1-flash-image)."
|
|
113
459
|
},
|
|
114
460
|
modelId: {
|
|
115
461
|
type: "string",
|
|
116
|
-
description: "The image model ID.
|
|
462
|
+
description: "The image model ID."
|
|
463
|
+
},
|
|
464
|
+
aspectRatio: {
|
|
465
|
+
type: "string",
|
|
466
|
+
description: "Thumbnail aspect ratio. Default is '16:9'."
|
|
117
467
|
},
|
|
118
468
|
resolution: {
|
|
119
469
|
type: "string",
|
|
120
|
-
description: "Output resolution (
|
|
470
|
+
description: "Output resolution ('1K', '2K', '4K'). Default is '1K'."
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
required: ["prompt"]
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
// 8. Passport Photo Creator
|
|
477
|
+
const GENERATE_PASSPORT_PHOTO_TOOL = {
|
|
478
|
+
name: "generate_passport_photo",
|
|
479
|
+
description: "Converts any portrait into an official, compliant passport or visa identity photo with pixel-level facial identity preservation, neutral lighting, and plain white/off-white background. Default model tier is Flash. Default aspect ratio is '1:1'. Returns generated image directly (synchronous).",
|
|
480
|
+
inputSchema: {
|
|
481
|
+
type: "object",
|
|
482
|
+
properties: {
|
|
483
|
+
photoDataUri: {
|
|
484
|
+
type: "string",
|
|
485
|
+
description: "Source portrait photo (URL, data URI, or local file path) to convert."
|
|
486
|
+
},
|
|
487
|
+
prompt: {
|
|
488
|
+
type: "string",
|
|
489
|
+
description: "Adjustments (e.g., 'white background, formal dark navy business suit, centered frontal view')."
|
|
121
490
|
},
|
|
122
491
|
promptId: {
|
|
123
492
|
type: "string",
|
|
124
|
-
description: "Optional ID or
|
|
493
|
+
description: "Optional ID or title of a pre-defined style template from passportPhotoPrompts."
|
|
125
494
|
},
|
|
126
495
|
referenceImage: {
|
|
127
496
|
type: "string",
|
|
128
|
-
description: "
|
|
497
|
+
description: "Optional style reference image (URL, data URI, or local file path) to guide attire or lighting."
|
|
498
|
+
},
|
|
499
|
+
model: {
|
|
500
|
+
type: "string",
|
|
501
|
+
description: "Model tier ('flash', 'pro', 'standard'). Default is 'flash' (google/gemini-3.1-flash-image)."
|
|
502
|
+
},
|
|
503
|
+
modelId: {
|
|
504
|
+
type: "string",
|
|
505
|
+
description: "The image model ID."
|
|
506
|
+
},
|
|
507
|
+
aspectRatio: {
|
|
508
|
+
type: "string",
|
|
509
|
+
description: "Passport aspect ratio ('1:1', '4:5', '3:4'). Default is '1:1'."
|
|
510
|
+
},
|
|
511
|
+
resolution: {
|
|
512
|
+
type: "string",
|
|
513
|
+
description: "Output resolution ('1K', '2K', '4K'). Default is '1K'."
|
|
129
514
|
}
|
|
130
515
|
},
|
|
131
|
-
required: ["
|
|
516
|
+
required: ["photoDataUri"]
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
// 10. Sketch to Real
|
|
520
|
+
const SKETCH_TO_REAL_TOOL = {
|
|
521
|
+
name: "sketch_to_real",
|
|
522
|
+
description: "Transforms hand-drawn sketches, line drawings, or product drafts into photorealistic commercial images while strictly preserving the sketched silhouette, proportions, and outlines. Default model tier is Flash. Returns generated image directly (synchronous).",
|
|
523
|
+
inputSchema: {
|
|
524
|
+
type: "object",
|
|
525
|
+
properties: {
|
|
526
|
+
sketchImage: {
|
|
527
|
+
type: "string",
|
|
528
|
+
description: "The source sketch/drawing image (URL, data URI, or local file path)."
|
|
529
|
+
},
|
|
530
|
+
prompt: {
|
|
531
|
+
type: "string",
|
|
532
|
+
description: "Description of materials, textures, colors, and lighting (e.g., 'matte black carbon fiber body, polished titanium accents, studio lighting')."
|
|
533
|
+
},
|
|
534
|
+
style: {
|
|
535
|
+
type: "string",
|
|
536
|
+
description: "Target render style ('Photorealistic', 'Cinematic', '3D Render'). Default is 'Photorealistic'."
|
|
537
|
+
},
|
|
538
|
+
model: {
|
|
539
|
+
type: "string",
|
|
540
|
+
description: "Model tier ('flash', 'pro', 'standard'). Default is 'flash'."
|
|
541
|
+
},
|
|
542
|
+
referenceImage: {
|
|
543
|
+
type: "string",
|
|
544
|
+
description: "Optional style/concept reference image (URL, data URI, or local file path)."
|
|
545
|
+
},
|
|
546
|
+
logoImage: {
|
|
547
|
+
type: "string",
|
|
548
|
+
description: "Optional brand logo overlay (URL, data URI, or local file path)."
|
|
549
|
+
},
|
|
550
|
+
overlayText: {
|
|
551
|
+
type: "string",
|
|
552
|
+
description: "Optional headline text overlay."
|
|
553
|
+
},
|
|
554
|
+
marketingText: {
|
|
555
|
+
type: "string",
|
|
556
|
+
description: "Optional marketing copy overlay."
|
|
557
|
+
},
|
|
558
|
+
aspectRatio: {
|
|
559
|
+
type: "string",
|
|
560
|
+
description: "Output aspect ratio ('1:1', '16:9', '9:16', '4:5'). Default is '1:1'."
|
|
561
|
+
},
|
|
562
|
+
resolution: {
|
|
563
|
+
type: "string",
|
|
564
|
+
description: "Output resolution ('1K', '2K', '4K'). Default is '1K'."
|
|
565
|
+
}
|
|
566
|
+
},
|
|
567
|
+
required: ["sketchImage"]
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
// 11. Professional Photography Editor
|
|
571
|
+
const EDIT_PROFESSIONAL_PHOTO_TOOL = {
|
|
572
|
+
name: "edit_professional_photo",
|
|
573
|
+
description: "Transforms, grades, and enhances portraits and lifestyle photos into magazine-grade studio or commercial editorial photography. Enforces natural dermal micro-pores, authentic iris catchlights, directional studio lighting, and realistic depth of field. Default model tier is Flash. Returns generated image directly (synchronous).",
|
|
574
|
+
inputSchema: {
|
|
575
|
+
type: "object",
|
|
576
|
+
properties: {
|
|
577
|
+
images: {
|
|
578
|
+
type: "array",
|
|
579
|
+
items: IMAGE_SOURCE_SCHEMA,
|
|
580
|
+
description: "Array of subject reference photos (URL, data URI, or local file path). Each item can have 'url', 'dataUrl', or local 'path'. At least one required."
|
|
581
|
+
},
|
|
582
|
+
prompt: {
|
|
583
|
+
type: "string",
|
|
584
|
+
description: "Enhancement instruction or desired photo transformation (e.g., 'warm dusk cinematic lighting, shallow depth of field, natural skin texture, magazine editorial portrait')."
|
|
585
|
+
},
|
|
586
|
+
image: {
|
|
587
|
+
type: "string",
|
|
588
|
+
description: "Convenience single subject photo (URL, data URI, or local file path) if only providing one image."
|
|
589
|
+
},
|
|
590
|
+
referenceImage: {
|
|
591
|
+
type: "string",
|
|
592
|
+
description: "Optional style or concept reference image (URL, data URI, or local file path)."
|
|
593
|
+
},
|
|
594
|
+
promptId: {
|
|
595
|
+
type: "string",
|
|
596
|
+
description: "Optional ID or title of a pre-defined photography scene template."
|
|
597
|
+
},
|
|
598
|
+
model: {
|
|
599
|
+
type: "string",
|
|
600
|
+
description: "Model tier ('flash', 'pro', 'standard'). Default is 'flash' (google/gemini-3.1-flash-image)."
|
|
601
|
+
},
|
|
602
|
+
modelId: {
|
|
603
|
+
type: "string",
|
|
604
|
+
description: "The image model ID."
|
|
605
|
+
},
|
|
606
|
+
resolution: {
|
|
607
|
+
type: "string",
|
|
608
|
+
description: "Output resolution ('1K', '2K', '4K'). Default is '1K'."
|
|
609
|
+
},
|
|
610
|
+
aspectRatio: {
|
|
611
|
+
type: "string",
|
|
612
|
+
description: "Output aspect ratio ('1:1', '4:5', '9:16', '16:9'). Default is '1:1'."
|
|
613
|
+
}
|
|
614
|
+
},
|
|
615
|
+
required: ["prompt"]
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
// 12. Nano Banana Image Editor (AI)
|
|
619
|
+
const EDIT_NANO_BANANA_TOOL = {
|
|
620
|
+
name: "edit_nano_banana",
|
|
621
|
+
description: "Creative multi-reference AI image editor and compositor. Generates, modifies, or restyles images from multiple reference photos and text instructions with multi-subject composition, perspective alignment, ground contact shadows, and versatile artistic styles (photorealistic, action figurine, chibi/Funko Pop, anime/Ghibli, 3D render). Default model tier is Flash. Returns generated image directly (synchronous).",
|
|
622
|
+
inputSchema: {
|
|
623
|
+
type: "object",
|
|
624
|
+
properties: {
|
|
625
|
+
images: {
|
|
626
|
+
type: "array",
|
|
627
|
+
items: IMAGE_SOURCE_SCHEMA,
|
|
628
|
+
description: "Array of reference images (URL, data URI, or local file path). Each item can have 'url', 'dataUrl', or local 'path'. At least one required."
|
|
629
|
+
},
|
|
630
|
+
prompt: {
|
|
631
|
+
type: "string",
|
|
632
|
+
description: "The creative editing or generation prompt describing desired composition, style, or changes."
|
|
633
|
+
},
|
|
634
|
+
image: {
|
|
635
|
+
type: "string",
|
|
636
|
+
description: "Convenience single reference photo (URL, data URI, or local file path) if only providing one image."
|
|
637
|
+
},
|
|
638
|
+
referenceImage: {
|
|
639
|
+
type: "string",
|
|
640
|
+
description: "Optional style or concept reference image (URL, data URI, or local file path)."
|
|
641
|
+
},
|
|
642
|
+
promptId: {
|
|
643
|
+
type: "string",
|
|
644
|
+
description: "Optional ID or title of a pre-defined style template (e.g., 'action-figure', 'funko-pop', 'studio-ghibli', '16bit-game-character')."
|
|
645
|
+
},
|
|
646
|
+
model: {
|
|
647
|
+
type: "string",
|
|
648
|
+
description: "Model tier ('flash', 'pro', 'standard'). Default is 'flash' (google/gemini-3.1-flash-image)."
|
|
649
|
+
},
|
|
650
|
+
modelId: {
|
|
651
|
+
type: "string",
|
|
652
|
+
description: "The image model ID."
|
|
653
|
+
},
|
|
654
|
+
resolution: {
|
|
655
|
+
type: "string",
|
|
656
|
+
description: "Output resolution ('1K', '2K', '4K'). Default is '1K'."
|
|
657
|
+
},
|
|
658
|
+
aspectRatio: {
|
|
659
|
+
type: "string",
|
|
660
|
+
description: "Output aspect ratio ('1:1', '4:5', '9:16', '16:9'). Default is '1:1'."
|
|
661
|
+
}
|
|
662
|
+
},
|
|
663
|
+
required: ["prompt"]
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
// 13. Blog Image Generator (AI)
|
|
667
|
+
const GENERATE_BLOG_IMAGE_TOOL = {
|
|
668
|
+
name: "generate_blog_image",
|
|
669
|
+
description: "Generates high-impact, editorial blog hero images, article thumbnails, and banners with clean composition, visual hierarchy, intentional negative space, and exact text overlays. Default aspect ratio is 16:9. Default model tier is Flash. Returns generated image directly (synchronous).",
|
|
670
|
+
inputSchema: {
|
|
671
|
+
type: "object",
|
|
672
|
+
properties: {
|
|
673
|
+
prompt: {
|
|
674
|
+
type: "string",
|
|
675
|
+
description: "Description of the desired blog hero image, article concept, or editorial illustration."
|
|
676
|
+
},
|
|
677
|
+
overlayText: {
|
|
678
|
+
type: "string",
|
|
679
|
+
description: "Optional short text, title, or headline to overlay legibly on the image."
|
|
680
|
+
},
|
|
681
|
+
referenceImage: {
|
|
682
|
+
type: "string",
|
|
683
|
+
description: "Optional style or aesthetic reference image (URL, data URI, or local file path)."
|
|
684
|
+
},
|
|
685
|
+
promptId: {
|
|
686
|
+
type: "string",
|
|
687
|
+
description: "Optional ID or title of a pre-defined style template from blogImagePrompts (e.g., 'neon-cyber-circuit', 'balancing-stones')."
|
|
688
|
+
},
|
|
689
|
+
model: {
|
|
690
|
+
type: "string",
|
|
691
|
+
description: "Model tier ('flash', 'pro', 'standard'). Default is 'flash' (google/gemini-3.1-flash-image)."
|
|
692
|
+
},
|
|
693
|
+
modelId: {
|
|
694
|
+
type: "string",
|
|
695
|
+
description: "The image model ID."
|
|
696
|
+
},
|
|
697
|
+
resolution: {
|
|
698
|
+
type: "string",
|
|
699
|
+
description: "Output resolution ('1K', '2K', '4K'). Default is '1K'."
|
|
700
|
+
},
|
|
701
|
+
aspectRatio: {
|
|
702
|
+
type: "string",
|
|
703
|
+
description: "Output aspect ratio ('16:9', '1:1', '4:3', '3:4', '9:16', '4:5'). Default is '16:9'."
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
required: ["prompt"]
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
// 14. Baby Milestone Generator
|
|
710
|
+
const GENERATE_BABY_MILESTONE_TOOL = {
|
|
711
|
+
name: "generate_baby_milestone",
|
|
712
|
+
description: "Creates magical baby milestone keepsake portraits by isolating the baby and generating enchanting themed backgrounds with organic milestone text integration, while preserving the baby's exact face, expression, skin tone, clothing, and posture. Default model tier is Flash. Default aspect ratio is '1:1'. Returns generated image directly (synchronous).",
|
|
713
|
+
inputSchema: {
|
|
714
|
+
type: "object",
|
|
715
|
+
properties: {
|
|
716
|
+
photoDataUri: {
|
|
717
|
+
type: "string",
|
|
718
|
+
description: "The baby photo (URL, data URI, or local file path) to isolate and preserve as the main subject."
|
|
719
|
+
},
|
|
720
|
+
milestoneValue: {
|
|
721
|
+
type: "number",
|
|
722
|
+
description: "Milestone number (e.g., 1, 3, 6, 12)."
|
|
723
|
+
},
|
|
724
|
+
milestoneUnit: {
|
|
725
|
+
type: "string",
|
|
726
|
+
enum: ["month", "year"],
|
|
727
|
+
description: "Unit for milestone ('month' or 'year')."
|
|
728
|
+
},
|
|
729
|
+
customPrompt: {
|
|
730
|
+
type: "string",
|
|
731
|
+
description: "Creative theme or environment instructions (e.g., 'Enchanted woodland forest with soft morning sunbeams and wildflowers')."
|
|
732
|
+
},
|
|
733
|
+
promptId: {
|
|
734
|
+
type: "string",
|
|
735
|
+
description: "Optional ID or title of a pre-defined style preset from babyMilestonePrompts."
|
|
736
|
+
},
|
|
737
|
+
referenceImage: {
|
|
738
|
+
type: "string",
|
|
739
|
+
description: "Optional environmental style reference image (URL, data URI, or local file path)."
|
|
740
|
+
},
|
|
741
|
+
model: {
|
|
742
|
+
type: "string",
|
|
743
|
+
description: "Model tier ('flash', 'pro', 'standard'). Default is 'flash' (google/gemini-3.1-flash-image)."
|
|
744
|
+
},
|
|
745
|
+
modelId: {
|
|
746
|
+
type: "string",
|
|
747
|
+
description: "The image model ID."
|
|
748
|
+
},
|
|
749
|
+
resolution: {
|
|
750
|
+
type: "string",
|
|
751
|
+
description: "Output resolution ('1K', '2K', '4K'). Default is '1K'."
|
|
752
|
+
},
|
|
753
|
+
aspectRatio: {
|
|
754
|
+
type: "string",
|
|
755
|
+
description: "Output aspect ratio ('1:1', '4:5', '3:4', '16:9', '9:16'). Default is '1:1'."
|
|
756
|
+
}
|
|
757
|
+
},
|
|
758
|
+
required: ["photoDataUri"]
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
// 13. Upscale Image
|
|
762
|
+
const UPSCALE_IMAGE_TOOL = {
|
|
763
|
+
name: "upscale_image",
|
|
764
|
+
description: "Enhances a reference image with the Pro AI model at 4K. Preserves composition through instructions and validates larger dimensions and matching proportions. AI may alter fine details. Uses 60 credits; returns the upscaled image synchronously.",
|
|
765
|
+
inputSchema: {
|
|
766
|
+
type: "object",
|
|
767
|
+
properties: {
|
|
768
|
+
imageDataUri: {
|
|
769
|
+
type: "string",
|
|
770
|
+
description: "The image to upscale (URL, data URI, or local file path)."
|
|
771
|
+
}
|
|
772
|
+
},
|
|
773
|
+
required: ["imageDataUri"]
|
|
132
774
|
}
|
|
133
775
|
};
|
|
776
|
+
// 11. QR Code Generator (Full-featured)
|
|
134
777
|
const GENERATE_QR_CODE_TOOL = {
|
|
135
778
|
name: "generate_qr_code",
|
|
136
|
-
description: "Generates
|
|
779
|
+
description: "Generates custom QR codes for URLs, plain text, Wi-Fi credentials, vCards, emails, and UPI payment strings with customizable colors, sizing, and error correction. Returns QR image directly (synchronous).",
|
|
137
780
|
inputSchema: {
|
|
138
781
|
type: "object",
|
|
139
782
|
properties: {
|
|
@@ -144,7 +787,7 @@ const GENERATE_QR_CODE_TOOL = {
|
|
|
144
787
|
},
|
|
145
788
|
value: {
|
|
146
789
|
type: "string",
|
|
147
|
-
description: "The text or
|
|
790
|
+
description: "The text, URL, or data payload to encode."
|
|
148
791
|
},
|
|
149
792
|
size: {
|
|
150
793
|
type: "number",
|
|
@@ -167,9 +810,10 @@ const GENERATE_QR_CODE_TOOL = {
|
|
|
167
810
|
required: ["type", "value"]
|
|
168
811
|
}
|
|
169
812
|
};
|
|
813
|
+
// 12. QR Code Simple
|
|
170
814
|
const GENERATE_QR_CODE_SIMPLE_TOOL = {
|
|
171
815
|
name: "generate_qr_code_simple",
|
|
172
|
-
description: "Quick QR code generation from plain text or URL.
|
|
816
|
+
description: "Quick single-parameter QR code generation from plain text or URL. Returns QR image directly (synchronous).",
|
|
173
817
|
inputSchema: {
|
|
174
818
|
type: "object",
|
|
175
819
|
properties: {
|
|
@@ -181,60 +825,119 @@ const GENERATE_QR_CODE_SIMPLE_TOOL = {
|
|
|
181
825
|
required: ["text"]
|
|
182
826
|
}
|
|
183
827
|
};
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
resolution: { type: "string", description: "Resolution (e.g., '720p', '1080p'). Default is '720p'." },
|
|
202
|
-
model: { type: "string", description: "Model slug (e.g., 'google/veo-3.1-fast', 'openrouter/wan-2.7')." },
|
|
203
|
-
aspectRatio: { type: "string", description: "Aspect ratio (e.g., '9:16', '16:9'). Default is '9:16'." },
|
|
204
|
-
generateAudio: { type: "boolean", description: "Whether to generate audio. Default is false." }
|
|
828
|
+
// 13. Get User Credits
|
|
829
|
+
const GET_USER_CREDITS_TOOL = {
|
|
830
|
+
name: "get_user_credits",
|
|
831
|
+
description: "Checks your current CodingMantra AI wallet credit balance. Useful before launching batches or large video/image tasks.",
|
|
832
|
+
inputSchema: {
|
|
833
|
+
type: "object",
|
|
834
|
+
properties: {}
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
// 14. List Image Models
|
|
838
|
+
const LIST_IMAGE_MODELS_TOOL = {
|
|
839
|
+
name: "list_image_models",
|
|
840
|
+
description: "Lists all available CodingMantra AI image generation models (e.g., Gemini Flash, Gemini Pro, Grok Imagine 2.0, GPT Image 2.5 Flare), including supported resolutions, aspect ratios, and credit costs.",
|
|
841
|
+
inputSchema: {
|
|
842
|
+
type: "object",
|
|
843
|
+
properties: {}
|
|
844
|
+
}
|
|
205
845
|
};
|
|
846
|
+
// 15. Product Video Generation (Async)
|
|
206
847
|
const GENERATE_PRODUCT_VIDEO_TOOL = {
|
|
207
848
|
name: "generate_product_video",
|
|
208
|
-
description: "Generates
|
|
209
|
-
inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES }
|
|
849
|
+
description: "Generates commercial product videography. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion.",
|
|
850
|
+
inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES, required: ["prompt", "model", "resolution", "aspectRatio", "timeDuration"] }
|
|
210
851
|
};
|
|
852
|
+
// 16. Apparel Video Generation (Async)
|
|
211
853
|
const GENERATE_APPAREL_VIDEO_TOOL = {
|
|
212
854
|
name: "generate_apparel_video",
|
|
213
|
-
description: "Generates
|
|
214
|
-
inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES }
|
|
855
|
+
description: "Generates runway fashion and apparel motion showcase videos. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion.",
|
|
856
|
+
inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES, required: ["prompt", "model", "resolution", "aspectRatio", "timeDuration"] }
|
|
215
857
|
};
|
|
858
|
+
// 17. Festival Video Generation (Async)
|
|
216
859
|
const GENERATE_FESTIVAL_VIDEO_TOOL = {
|
|
217
860
|
name: "generate_festival_video",
|
|
218
|
-
description: "Generates
|
|
219
|
-
inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES }
|
|
861
|
+
description: "Generates celebratory festival greetings and motion graphics. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion.",
|
|
862
|
+
inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES, required: ["prompt", "model", "resolution", "aspectRatio", "timeDuration"] }
|
|
220
863
|
};
|
|
864
|
+
// 18. Jewelry Video Generation (Async)
|
|
221
865
|
const GENERATE_JEWELRY_VIDEO_TOOL = {
|
|
222
866
|
name: "generate_jewelry_video",
|
|
223
|
-
description: "Generates
|
|
224
|
-
inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES }
|
|
867
|
+
description: "Generates luxury jewelry videography with optical brilliance and rotating display. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion.",
|
|
868
|
+
inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES, required: ["prompt", "model", "resolution", "aspectRatio", "timeDuration"] }
|
|
225
869
|
};
|
|
870
|
+
// 19. Logo Video Generation (Async)
|
|
226
871
|
const GENERATE_LOGO_VIDEO_TOOL = {
|
|
227
872
|
name: "generate_logo_video",
|
|
228
|
-
description: "Generates
|
|
229
|
-
inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES }
|
|
873
|
+
description: "Generates 3D logo reveal and motion graphic video intros. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion.",
|
|
874
|
+
inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES, required: ["prompt", "model", "resolution", "aspectRatio", "timeDuration"] }
|
|
875
|
+
};
|
|
876
|
+
const GENERATE_STORY_VIDEO_TOOL = {
|
|
877
|
+
name: "generate_story_video",
|
|
878
|
+
description: "Generates cinematic story videos with character descriptions, reference images, sound effects, and atmosphere. Asynchronous: returns a jobId; poll check_video_job_status until completed, failed, or cancelled.",
|
|
879
|
+
inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES, required: ["prompt", "model", "resolution", "aspectRatio", "timeDuration"] }
|
|
880
|
+
};
|
|
881
|
+
const GENERATE_TALKING_AVATAR_TOOL = {
|
|
882
|
+
name: "generate_talking_avatar",
|
|
883
|
+
description: "Animates a portrait with HeyGen Avatar IV lip sync from a script and HeyGen voice ID. Asynchronous: returns a jobId; poll check_video_job_status until completed, failed, or cancelled. Credits are calculated by the server from the script budget and resolution.",
|
|
884
|
+
inputSchema: {
|
|
885
|
+
type: "object",
|
|
886
|
+
properties: {
|
|
887
|
+
image: { type: "string", description: "PNG, JPEG, or WebP portrait as a base64 data URI or local file path. Public URLs are not accepted." },
|
|
888
|
+
speechMode: { type: "string", enum: ["text"], default: "text", description: "Speech source; currently only text is supported." },
|
|
889
|
+
script: { type: "string", minLength: 3, maxLength: 2000, description: "Spoken script. Must fit the selected duration budget and speech speed." },
|
|
890
|
+
voiceId: { type: "string", minLength: 1, maxLength: 150, pattern: "^[A-Za-z0-9_-]+$", description: "HeyGen voice ID for the narration." },
|
|
891
|
+
speed: { type: "number", minimum: 0.5, maximum: 1.5, default: 1, description: "Speech speed multiplier." },
|
|
892
|
+
targetDuration: { type: "integer", minimum: 5, maximum: 120, default: 15, description: "Maximum script duration budget in seconds." },
|
|
893
|
+
performancePreset: { type: "string", enum: ["natural", "professional", "energetic", "friendly", "presenter", "storyteller"], default: "professional", description: "Avatar performance style." },
|
|
894
|
+
expressiveness: { type: "string", enum: ["low", "medium", "high"], description: "Optional expression intensity override." },
|
|
895
|
+
motionPrompt: { type: "string", maxLength: 500, description: "Optional motion instructions overriding the preset." },
|
|
896
|
+
backgroundMode: { type: "string", enum: ["original", "color"], default: "original", description: "Preserve the portrait background or use a solid color." },
|
|
897
|
+
backgroundColor: { type: "string", pattern: "^#[0-9a-fA-F]{6}$", default: "#111827", description: "Solid background color when backgroundMode is color." },
|
|
898
|
+
captions: { type: "boolean", default: false, description: "Whether to add captions." },
|
|
899
|
+
title: { type: "string", maxLength: 100, description: "Optional video title." },
|
|
900
|
+
resolution: { type: "string", enum: ["720p", "1080p"], default: "1080p", description: "Output resolution." },
|
|
901
|
+
aspectRatio: { type: "string", enum: ["9:16", "1:1", "16:9"], default: "9:16", description: "Output aspect ratio." }
|
|
902
|
+
},
|
|
903
|
+
required: ["image", "script", "voiceId"]
|
|
904
|
+
}
|
|
230
905
|
};
|
|
906
|
+
const GENERATE_JEWELLERY_RATE_POSTER_TOOL = {
|
|
907
|
+
name: "generate_jewellery_rate_poster",
|
|
908
|
+
description: "Generates a branded gold and silver rate poster. Synchronous: returns the generated image for inline display. Rates are supplied by the caller, not fetched from a market feed.",
|
|
909
|
+
inputSchema: {
|
|
910
|
+
type: "object",
|
|
911
|
+
properties: {
|
|
912
|
+
scenePrompt: { type: "string", description: "Poster scene, background, and visual style." },
|
|
913
|
+
productImage: { type: "string", description: "Optional jewelry image URL, data URI, or local file path." },
|
|
914
|
+
logoImage: { type: "string", description: "Optional brand logo URL, data URI, or local file path." },
|
|
915
|
+
goldRate24k: { type: "string", description: "24K gold rate text, including currency and units." },
|
|
916
|
+
goldRate22k: { type: "string", description: "22K gold rate text, including currency and units." },
|
|
917
|
+
goldRate18k: { type: "string", description: "18K gold rate text, including currency and units." },
|
|
918
|
+
goldRate14k: { type: "string", description: "14K gold rate text, including currency and units." },
|
|
919
|
+
silverRate: { type: "string", description: "Silver rate text, including currency and units." },
|
|
920
|
+
date: { type: "string", description: "Date to display on the poster." },
|
|
921
|
+
brandName: { type: "string", description: "Jewelry business name." },
|
|
922
|
+
tagLine: { type: "string", description: "Optional brand tagline." },
|
|
923
|
+
footerText: { type: "string", description: "Optional footer or disclaimer." },
|
|
924
|
+
address: { type: "string", description: "Business address." },
|
|
925
|
+
phoneNumber: { type: "string", description: "Business contact number." },
|
|
926
|
+
model: { type: "string", description: "Image model slug; use list_image_models to discover models." },
|
|
927
|
+
resolution: { type: "string", description: "Resolution supported by the selected model (1K, 2K, or 4K)." },
|
|
928
|
+
aspectRatio: { type: "string", default: "1:1", description: "Aspect ratio supported by the selected model." }
|
|
929
|
+
},
|
|
930
|
+
required: ["scenePrompt"]
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
// 20. Check Video Job Status (Polling)
|
|
231
934
|
const CHECK_JOB_STATUS_TOOL = {
|
|
232
935
|
name: "check_video_job_status",
|
|
233
|
-
description: "Checks the status of an asynchronous video generation job. Call this repeatedly (
|
|
936
|
+
description: "Checks the real-time status of an asynchronous video generation job. Call this repeatedly (every 10-30 seconds) until the job status is 'completed', 'failed', or 'cancelled'.",
|
|
234
937
|
inputSchema: {
|
|
235
938
|
type: "object",
|
|
236
939
|
properties: {
|
|
237
|
-
jobId: { type: "string", description: "The ID of the job to
|
|
940
|
+
jobId: { type: "string", description: "The ID of the video job to track." }
|
|
238
941
|
},
|
|
239
942
|
required: ["jobId"]
|
|
240
943
|
}
|
|
@@ -243,15 +946,33 @@ const CHECK_JOB_STATUS_TOOL = {
|
|
|
243
946
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
244
947
|
return {
|
|
245
948
|
tools: [
|
|
949
|
+
GENERATE_JEWELLERY_RATE_POSTER_TOOL,
|
|
246
950
|
GENERATE_PRODUCT_PHOTO_TOOL,
|
|
247
951
|
GENERATE_LOGO_TOOL,
|
|
952
|
+
TRY_ON_JEWELRY_TOOL,
|
|
953
|
+
TRY_ON_APPAREL_TOOL,
|
|
954
|
+
TRY_ON_PRODUCT_TOOL,
|
|
955
|
+
GENERATE_FESTIVAL_POST_TOOL,
|
|
956
|
+
BUILD_HUMAN_TOOL,
|
|
957
|
+
GENERATE_YOUTUBE_THUMBNAIL_TOOL,
|
|
958
|
+
GENERATE_PASSPORT_PHOTO_TOOL,
|
|
959
|
+
SKETCH_TO_REAL_TOOL,
|
|
960
|
+
EDIT_PROFESSIONAL_PHOTO_TOOL,
|
|
961
|
+
EDIT_NANO_BANANA_TOOL,
|
|
962
|
+
GENERATE_BLOG_IMAGE_TOOL,
|
|
963
|
+
GENERATE_BABY_MILESTONE_TOOL,
|
|
964
|
+
UPSCALE_IMAGE_TOOL,
|
|
248
965
|
GENERATE_QR_CODE_TOOL,
|
|
249
966
|
GENERATE_QR_CODE_SIMPLE_TOOL,
|
|
967
|
+
GET_USER_CREDITS_TOOL,
|
|
968
|
+
LIST_IMAGE_MODELS_TOOL,
|
|
250
969
|
GENERATE_PRODUCT_VIDEO_TOOL,
|
|
251
970
|
GENERATE_APPAREL_VIDEO_TOOL,
|
|
252
971
|
GENERATE_FESTIVAL_VIDEO_TOOL,
|
|
253
972
|
GENERATE_JEWELRY_VIDEO_TOOL,
|
|
254
973
|
GENERATE_LOGO_VIDEO_TOOL,
|
|
974
|
+
GENERATE_STORY_VIDEO_TOOL,
|
|
975
|
+
GENERATE_TALKING_AVATAR_TOOL,
|
|
255
976
|
CHECK_JOB_STATUS_TOOL,
|
|
256
977
|
],
|
|
257
978
|
};
|
|
@@ -259,110 +980,330 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
259
980
|
// ─── Tool Execution ─────────────────────────────────────────────────────────────
|
|
260
981
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
261
982
|
try {
|
|
262
|
-
const { name, arguments:
|
|
263
|
-
|
|
983
|
+
const { name, arguments: rawArgs } = request.params;
|
|
984
|
+
const args = rawArgs || {};
|
|
985
|
+
if (name === 'generate_jewellery_rate_poster') {
|
|
986
|
+
const response = await apiClient('/image/jewellery-rate-poster', {
|
|
987
|
+
method: 'POST',
|
|
988
|
+
body: JSON.stringify({ ...args, productImage: resolveImageInput(args.productImage),
|
|
989
|
+
logoImage: resolveImageInput(args.logoImage), outputResult: 'base64' }),
|
|
990
|
+
});
|
|
991
|
+
return formatImageToolResult(response, 'Jewellery Rate Poster Generated');
|
|
992
|
+
}
|
|
993
|
+
// ── 1. Product Photography (synchronous) ──────────────────────────────────
|
|
264
994
|
if (name === 'generate_product_photo') {
|
|
995
|
+
const payload = {
|
|
996
|
+
...args,
|
|
997
|
+
productImages: resolveImagesArray(args.productImages),
|
|
998
|
+
referenceImage: resolveImageInput(args.referenceImage),
|
|
999
|
+
logoImage: resolveImageInput(args.logoImage),
|
|
1000
|
+
};
|
|
265
1001
|
const response = await apiClient('/image/product-photography', {
|
|
266
1002
|
method: 'POST',
|
|
267
|
-
body: JSON.stringify(
|
|
1003
|
+
body: JSON.stringify(payload),
|
|
268
1004
|
});
|
|
269
|
-
|
|
270
|
-
let text = '✅ Product photo generated successfully!\n\n';
|
|
271
|
-
if (result?.imageUrl) {
|
|
272
|
-
text += `Image URL: ${result.imageUrl}`;
|
|
273
|
-
}
|
|
274
|
-
else if (result?.photoDataUri) {
|
|
275
|
-
text += `Image data returned (base64). Length: ${String(result.photoDataUri).length} characters.\nData URI: ${String(result.photoDataUri).substring(0, 100)}...`;
|
|
276
|
-
}
|
|
277
|
-
else if (result?.output) {
|
|
278
|
-
text += `Image data returned (base64). Length: ${String(result.output).length} characters.`;
|
|
279
|
-
}
|
|
280
|
-
else {
|
|
281
|
-
text += `Result: ${JSON.stringify(result).substring(0, 500)}`;
|
|
282
|
-
}
|
|
283
|
-
return { content: [{ type: "text", text }] };
|
|
1005
|
+
return formatImageToolResult(response, 'Product Photo Generated');
|
|
284
1006
|
}
|
|
285
|
-
// ── Logo Creator (synchronous)
|
|
1007
|
+
// ── 2. Logo Creator (synchronous) ─────────────────────────────────────────
|
|
286
1008
|
if (name === 'generate_logo') {
|
|
1009
|
+
const payload = {
|
|
1010
|
+
...args,
|
|
1011
|
+
referenceImage: resolveImageInput(args.referenceImage),
|
|
1012
|
+
};
|
|
287
1013
|
const response = await apiClient('/image/logo-creator', {
|
|
288
1014
|
method: 'POST',
|
|
289
|
-
body: JSON.stringify(
|
|
1015
|
+
body: JSON.stringify(payload),
|
|
290
1016
|
});
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
1017
|
+
return formatImageToolResult(response, 'Brand Logo Generated');
|
|
1018
|
+
}
|
|
1019
|
+
// ── 3. Jewelry Try-On (synchronous) ───────────────────────────────────────
|
|
1020
|
+
if (name === 'try_on_jewelry') {
|
|
1021
|
+
const payload = {
|
|
1022
|
+
...args,
|
|
1023
|
+
jewelryImages: resolveImagesArray(args.jewelryImages),
|
|
1024
|
+
personImage: resolveImageInput(args.personImage),
|
|
1025
|
+
referenceImage: resolveImageInput(args.referenceImage),
|
|
1026
|
+
logoImage: resolveImageInput(args.logoImage),
|
|
1027
|
+
};
|
|
1028
|
+
const response = await apiClient('/image/jewelry-try-on', {
|
|
1029
|
+
method: 'POST',
|
|
1030
|
+
body: JSON.stringify(payload),
|
|
1031
|
+
});
|
|
1032
|
+
return formatImageToolResult(response, 'Jewelry Try-On Image Generated');
|
|
1033
|
+
}
|
|
1034
|
+
// ── 4. Apparel Try-On (synchronous) ───────────────────────────────────────
|
|
1035
|
+
if (name === 'try_on_apparel') {
|
|
1036
|
+
const payload = {
|
|
1037
|
+
...args,
|
|
1038
|
+
apparelImages: resolveImagesArray(args.apparelImages),
|
|
1039
|
+
modelImage: resolveImageInput(args.modelImage),
|
|
1040
|
+
referenceImage: resolveImageInput(args.referenceImage),
|
|
1041
|
+
logoImage: resolveImageInput(args.logoImage),
|
|
1042
|
+
};
|
|
1043
|
+
const response = await apiClient('/image/apparel-try-on', {
|
|
1044
|
+
method: 'POST',
|
|
1045
|
+
body: JSON.stringify(payload),
|
|
1046
|
+
});
|
|
1047
|
+
return formatImageToolResult(response, 'Apparel Try-On Image Generated');
|
|
1048
|
+
}
|
|
1049
|
+
// ── 5. Product Try-On (synchronous) ───────────────────────────────────────
|
|
1050
|
+
if (name === 'try_on_product') {
|
|
1051
|
+
const payload = {
|
|
1052
|
+
...args,
|
|
1053
|
+
productImages: resolveImagesArray(args.productImages),
|
|
1054
|
+
mainImage: resolveImageInput(args.mainImage),
|
|
1055
|
+
referenceImage: resolveImageInput(args.referenceImage),
|
|
1056
|
+
logoImage: resolveImageInput(args.logoImage),
|
|
1057
|
+
};
|
|
1058
|
+
const response = await apiClient('/image/product-try-on', {
|
|
1059
|
+
method: 'POST',
|
|
1060
|
+
body: JSON.stringify(payload),
|
|
1061
|
+
});
|
|
1062
|
+
return formatImageToolResult(response, 'Product Try-On Image Generated');
|
|
1063
|
+
}
|
|
1064
|
+
// ── 6. Festival Post (synchronous) ────────────────────────────────────────
|
|
1065
|
+
if (name === 'generate_festival_post') {
|
|
1066
|
+
const payload = {
|
|
1067
|
+
...args,
|
|
1068
|
+
productImage: resolveImageInput(args.productImage),
|
|
1069
|
+
logoImage: resolveImageInput(args.logoImage),
|
|
1070
|
+
};
|
|
1071
|
+
const response = await apiClient('/image/festival-post-generator', {
|
|
1072
|
+
method: 'POST',
|
|
1073
|
+
body: JSON.stringify(payload),
|
|
1074
|
+
});
|
|
1075
|
+
return formatImageToolResult(response, 'Festival Post Generated');
|
|
1076
|
+
}
|
|
1077
|
+
// ── 7. Human Builder (synchronous) ────────────────────────────────────────
|
|
1078
|
+
if (name === 'build_human') {
|
|
1079
|
+
const payload = {
|
|
1080
|
+
...args,
|
|
1081
|
+
referenceImages: Array.isArray(args.referenceImages)
|
|
1082
|
+
? args.referenceImages.map((img) => typeof img === 'string'
|
|
1083
|
+
? resolveImageInput(img)
|
|
1084
|
+
: resolveImageInput(img?.dataUrl || img?.path || img?.url))
|
|
1085
|
+
: undefined,
|
|
1086
|
+
};
|
|
1087
|
+
const response = await apiClient('/image/human-builder', {
|
|
1088
|
+
method: 'POST',
|
|
1089
|
+
body: JSON.stringify(payload),
|
|
1090
|
+
});
|
|
1091
|
+
return formatImageToolResult(response, 'AI Human Model Generated');
|
|
1092
|
+
}
|
|
1093
|
+
// ── 8. YouTube Thumbnail (synchronous) ────────────────────────────────────
|
|
1094
|
+
if (name === 'generate_youtube_thumbnail') {
|
|
1095
|
+
const payload = {
|
|
1096
|
+
...args,
|
|
1097
|
+
personImage: resolveImageInput(args.personImage),
|
|
1098
|
+
backgroundImage: resolveImageInput(args.backgroundImage),
|
|
1099
|
+
logoImage: resolveImageInput(args.logoImage),
|
|
1100
|
+
referenceImage: resolveImageInput(args.referenceImage),
|
|
1101
|
+
};
|
|
1102
|
+
const response = await apiClient('/image/youtube-thumbnail-generator', {
|
|
1103
|
+
method: 'POST',
|
|
1104
|
+
body: JSON.stringify(payload),
|
|
1105
|
+
});
|
|
1106
|
+
return formatImageToolResult(response, 'YouTube Thumbnail Generated');
|
|
1107
|
+
}
|
|
1108
|
+
// ── 8. Passport Photo (synchronous) ───────────────────────────────────────
|
|
1109
|
+
if (name === 'generate_passport_photo') {
|
|
1110
|
+
const payload = {
|
|
1111
|
+
...args,
|
|
1112
|
+
photoDataUri: resolveImageInput(args.photoDataUri),
|
|
1113
|
+
referenceImage: resolveImageInput(args.referenceImage),
|
|
1114
|
+
};
|
|
1115
|
+
const response = await apiClient('/image/passport-photo', {
|
|
1116
|
+
method: 'POST',
|
|
1117
|
+
body: JSON.stringify(payload),
|
|
1118
|
+
});
|
|
1119
|
+
return formatImageToolResult(response, 'Passport Photo Generated');
|
|
1120
|
+
}
|
|
1121
|
+
// ── 9. Sketch to Real (synchronous) ───────────────────────────────────────
|
|
1122
|
+
if (name === 'sketch_to_real') {
|
|
1123
|
+
const payload = {
|
|
1124
|
+
...args,
|
|
1125
|
+
sketchImage: resolveImageInput(args.sketchImage),
|
|
1126
|
+
referenceImage: resolveImageInput(args.referenceImage),
|
|
1127
|
+
logoImage: resolveImageInput(args.logoImage),
|
|
1128
|
+
};
|
|
1129
|
+
const response = await apiClient('/image/sketch-to-real', {
|
|
1130
|
+
method: 'POST',
|
|
1131
|
+
body: JSON.stringify(payload),
|
|
1132
|
+
});
|
|
1133
|
+
return formatImageToolResult(response, 'Sketch-to-Real Image Generated');
|
|
1134
|
+
}
|
|
1135
|
+
// ── 10. Professional Photography Editor (synchronous) ─────────────────────
|
|
1136
|
+
if (name === 'edit_professional_photo') {
|
|
1137
|
+
let resolvedImages = args.images ? resolveImagesArray(args.images) : [];
|
|
1138
|
+
if (resolvedImages.length === 0 && args.image) {
|
|
1139
|
+
const single = resolveImageInput(args.image);
|
|
1140
|
+
if (single) {
|
|
1141
|
+
resolvedImages = [{ dataUrl: single }];
|
|
1142
|
+
}
|
|
301
1143
|
}
|
|
302
|
-
|
|
303
|
-
|
|
1144
|
+
const payload = {
|
|
1145
|
+
...args,
|
|
1146
|
+
images: resolvedImages,
|
|
1147
|
+
referenceImage: resolveImageInput(args.referenceImage),
|
|
1148
|
+
};
|
|
1149
|
+
const response = await apiClient('/image/professional-photography-editor', {
|
|
1150
|
+
method: 'POST',
|
|
1151
|
+
body: JSON.stringify(payload),
|
|
1152
|
+
});
|
|
1153
|
+
return formatImageToolResult(response, 'Professional Photo Generated');
|
|
1154
|
+
}
|
|
1155
|
+
// ── 11. Nano Banana Image Editor (synchronous) ────────────────────────────
|
|
1156
|
+
if (name === 'edit_nano_banana') {
|
|
1157
|
+
let resolvedImages = args.images ? resolveImagesArray(args.images) : [];
|
|
1158
|
+
if (resolvedImages.length === 0 && args.image) {
|
|
1159
|
+
const single = resolveImageInput(args.image);
|
|
1160
|
+
if (single) {
|
|
1161
|
+
resolvedImages = [{ dataUrl: single }];
|
|
1162
|
+
}
|
|
304
1163
|
}
|
|
305
|
-
|
|
1164
|
+
const payload = {
|
|
1165
|
+
...args,
|
|
1166
|
+
images: resolvedImages,
|
|
1167
|
+
referenceImage: resolveImageInput(args.referenceImage),
|
|
1168
|
+
};
|
|
1169
|
+
const response = await apiClient('/image/nano-banana-editor', {
|
|
1170
|
+
method: 'POST',
|
|
1171
|
+
body: JSON.stringify(payload),
|
|
1172
|
+
});
|
|
1173
|
+
return formatImageToolResult(response, 'Nano Banana Image Generated');
|
|
306
1174
|
}
|
|
307
|
-
// ──
|
|
1175
|
+
// ── 12. Blog Image Generator (synchronous) ────────────────────────────────
|
|
1176
|
+
if (name === 'generate_blog_image') {
|
|
1177
|
+
const payload = {
|
|
1178
|
+
...args,
|
|
1179
|
+
referenceImage: resolveImageInput(args.referenceImage),
|
|
1180
|
+
};
|
|
1181
|
+
const response = await apiClient('/image/blog-image-generator', {
|
|
1182
|
+
method: 'POST',
|
|
1183
|
+
body: JSON.stringify(payload),
|
|
1184
|
+
});
|
|
1185
|
+
return formatImageToolResult(response, 'Blog Image Generated');
|
|
1186
|
+
}
|
|
1187
|
+
// ── 13. Baby Milestone Generator (synchronous) ───────────────────────────
|
|
1188
|
+
if (name === 'generate_baby_milestone') {
|
|
1189
|
+
const payload = {
|
|
1190
|
+
...args,
|
|
1191
|
+
photoDataUri: resolveImageInput(args.photoDataUri),
|
|
1192
|
+
referenceImage: resolveImageInput(args.referenceImage),
|
|
1193
|
+
};
|
|
1194
|
+
const response = await apiClient('/image/baby-milestone-generator', {
|
|
1195
|
+
method: 'POST',
|
|
1196
|
+
body: JSON.stringify(payload),
|
|
1197
|
+
});
|
|
1198
|
+
return formatImageToolResult(response, 'Baby Milestone Photo Generated');
|
|
1199
|
+
}
|
|
1200
|
+
// ── 12. Upscale Image (synchronous) ───────────────────────────────────────
|
|
1201
|
+
if (name === 'upscale_image') {
|
|
1202
|
+
const payload = {
|
|
1203
|
+
...args,
|
|
1204
|
+
imageDataUri: resolveImageInput(args.imageDataUri),
|
|
1205
|
+
};
|
|
1206
|
+
const response = await apiClient('/image/upscale-image', {
|
|
1207
|
+
method: 'POST',
|
|
1208
|
+
body: JSON.stringify(payload),
|
|
1209
|
+
signal: AbortSignal.timeout(12 * 60 * 1000),
|
|
1210
|
+
});
|
|
1211
|
+
return formatImageToolResult(response, 'Image Upscaled Successfully');
|
|
1212
|
+
}
|
|
1213
|
+
// ── 11. QR Code (POST, full-featured) ─────────────────────────────────────
|
|
308
1214
|
if (name === 'generate_qr_code') {
|
|
309
1215
|
const response = await apiClient('/qr-code/generate', {
|
|
310
1216
|
method: 'POST',
|
|
311
1217
|
body: JSON.stringify(args),
|
|
312
1218
|
});
|
|
313
|
-
|
|
314
|
-
if (qrDataUrl) {
|
|
315
|
-
return {
|
|
316
|
-
content: [{ type: "text", text: `✅ QR Code generated successfully!\n\nData URI: ${qrDataUrl}` }],
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
return {
|
|
320
|
-
content: [{ type: "text", text: `✅ QR Code generated. Result: ${JSON.stringify(response.data).substring(0, 500)}` }],
|
|
321
|
-
};
|
|
1219
|
+
return formatImageToolResult(response, 'QR Code Generated');
|
|
322
1220
|
}
|
|
323
|
-
// ── QR Code Simple (GET,
|
|
1221
|
+
// ── 12. QR Code Simple (GET, legacy) ──────────────────────────────────────
|
|
324
1222
|
if (name === 'generate_qr_code_simple') {
|
|
325
1223
|
const { text } = args;
|
|
326
1224
|
const encodedText = encodeURIComponent(text);
|
|
327
|
-
const apiKey = process.env.CODINGMANTRA_API_KEY;
|
|
1225
|
+
const apiKey = process.env.CODINGMANTRA_API_KEY || '';
|
|
328
1226
|
const response = await apiClient(`/qr-code/generate-base64/${apiKey}/${encodedText}`, {
|
|
329
1227
|
method: 'GET',
|
|
330
1228
|
});
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
1229
|
+
return formatImageToolResult(response, 'QR Code Generated');
|
|
1230
|
+
}
|
|
1231
|
+
// ── 13. Get User Credits ──────────────────────────────────────────────────
|
|
1232
|
+
if (name === 'get_user_credits') {
|
|
1233
|
+
const response = await apiClient('/user/credits', {
|
|
1234
|
+
method: 'GET',
|
|
1235
|
+
});
|
|
1236
|
+
const credits = response.data?.credits ?? 0;
|
|
1237
|
+
return {
|
|
1238
|
+
content: [{
|
|
1239
|
+
type: "text",
|
|
1240
|
+
text: `💳 **CodingMantra Wallet Balance**\n\n- Available Credits: **${credits}**\n- Need more credits? Top up at [CodingMantra Pricing](https://codingmantra.com/pricing)\n- View full usage history in your [Account Dashboard](https://codingmantra.com/dashboard)`
|
|
1241
|
+
}]
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
// ── 14. List Image Models ─────────────────────────────────────────────────
|
|
1245
|
+
if (name === 'list_image_models') {
|
|
1246
|
+
const response = await apiClient('/image/image-model-options', {
|
|
1247
|
+
method: 'GET',
|
|
1248
|
+
});
|
|
1249
|
+
const models = response.data || [];
|
|
1250
|
+
let text = `🤖 **Available CodingMantra Image Models**\n\n`;
|
|
1251
|
+
for (const m of models) {
|
|
1252
|
+
text += `#### ${m.name} (\`${m.model}\`)\n`;
|
|
1253
|
+
text += `- **Provider:** ${m.provider}\n`;
|
|
1254
|
+
text += `- **Description:** ${m.description || 'High-performance generative model'}\n`;
|
|
1255
|
+
text += `- **Supported Resolutions:** ${m.supportedResolutions?.join(', ') || '1K'}\n`;
|
|
1256
|
+
text += `- **Supported Aspect Ratios:** ${m.supportedAspectRatios?.join(', ') || '1:1'}\n`;
|
|
1257
|
+
text += `- **Credit Cost:** ${m.estimatedCost?.credits ?? 10} credits\n\n`;
|
|
336
1258
|
}
|
|
337
1259
|
return {
|
|
338
|
-
content: [{ type: "text", text:
|
|
1260
|
+
content: [{ type: "text", text: text.trim() }]
|
|
339
1261
|
};
|
|
340
1262
|
}
|
|
341
|
-
// ── Video Generation (Asynchronous)
|
|
1263
|
+
// ── 15-19. Video Generation (Asynchronous) ────────────────────────────────
|
|
342
1264
|
const videoEndpoints = {
|
|
343
1265
|
generate_product_video: '/product-video-generation',
|
|
344
1266
|
generate_apparel_video: '/apparel-video-generation',
|
|
345
1267
|
generate_festival_video: '/festival-video-generation',
|
|
346
1268
|
generate_jewelry_video: '/jewelry-video-generation',
|
|
347
|
-
generate_logo_video: '/logo-video-generation'
|
|
1269
|
+
generate_logo_video: '/logo-video-generation',
|
|
1270
|
+
generate_story_video: '/story-teller-generation',
|
|
1271
|
+
generate_talking_avatar: '/ai/talking-avatar/generate'
|
|
348
1272
|
};
|
|
349
1273
|
if (videoEndpoints[name]) {
|
|
1274
|
+
const optionalImage = (input) => typeof input === 'string' && input.trim()
|
|
1275
|
+
? resolveImageInput(input) : undefined;
|
|
1276
|
+
const references = Array.isArray(args.referenceImages)
|
|
1277
|
+
? args.referenceImages.map((reference) => ({
|
|
1278
|
+
...reference, image: resolveImageInput(reference.image)
|
|
1279
|
+
})) : undefined;
|
|
1280
|
+
const avatarImage = name === 'generate_talking_avatar' ? optionalImage(args.image) : undefined;
|
|
1281
|
+
if (name === 'generate_talking_avatar' && !/^data:image\/(png|jpeg|webp);base64,/.test(avatarImage || '')) {
|
|
1282
|
+
throw new Error('Talking Avatar requires a PNG, JPEG, or WebP portrait as a local file path or base64 data URI.');
|
|
1283
|
+
}
|
|
1284
|
+
const payload = name === 'generate_talking_avatar' ? { ...args, image: avatarImage } : {
|
|
1285
|
+
...args,
|
|
1286
|
+
mainImage: optionalImage(args.mainImage),
|
|
1287
|
+
startImage: optionalImage(args.startImage),
|
|
1288
|
+
endImage: optionalImage(args.endImage),
|
|
1289
|
+
referenceImages: references,
|
|
1290
|
+
};
|
|
350
1291
|
const response = await apiClient(videoEndpoints[name], {
|
|
351
1292
|
method: 'POST',
|
|
352
|
-
body: JSON.stringify(
|
|
1293
|
+
body: JSON.stringify(payload),
|
|
353
1294
|
});
|
|
354
1295
|
const result = response.data || response;
|
|
355
1296
|
if (result?.jobId) {
|
|
356
1297
|
return {
|
|
357
1298
|
content: [{
|
|
358
1299
|
type: "text",
|
|
359
|
-
text:
|
|
1300
|
+
text: `🎬 **Video Generation Job Queued Successfully!**\n\n- **Job ID:** \`${result.jobId}\`\n- **Status:** Queued\n- **Message:** ${result.message || 'Video job dispatched to rendering pipeline.'}\n\n👉 **Next Step:** Call the \`check_video_job_status\` tool with \`jobId: "${result.jobId}"\` every 15-30 seconds until completed. Rendering typically takes 1-3 minutes.`
|
|
360
1301
|
}]
|
|
361
1302
|
};
|
|
362
1303
|
}
|
|
363
1304
|
return { content: [{ type: "text", text: `Job started. Result: ${JSON.stringify(result).substring(0, 500)}` }] };
|
|
364
1305
|
}
|
|
365
|
-
// ── Check Job Status
|
|
1306
|
+
// ── 20. Check Video Job Status ────────────────────────────────────────────
|
|
366
1307
|
if (name === 'check_video_job_status') {
|
|
367
1308
|
const { jobId } = args;
|
|
368
1309
|
const response = await apiClient(`/jobs/status?jobId=${encodeURIComponent(jobId)}`, {
|
|
@@ -371,15 +1312,22 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
371
1312
|
const result = response.data || response;
|
|
372
1313
|
if (result?.job) {
|
|
373
1314
|
const job = result.job;
|
|
374
|
-
let text =
|
|
1315
|
+
let text = `### 🎬 Video Job Status: **${job.status.toUpperCase()}**\n\n`;
|
|
1316
|
+
text += `- **Progress:** ${job.progress}%\n`;
|
|
1317
|
+
text += `- **Stage:** ${job.stage || 'Processing'}\n`;
|
|
375
1318
|
if (job.status === 'completed' && job.result?.videoUrl) {
|
|
376
|
-
text += `\n
|
|
1319
|
+
text += `\n✅ **Video Ready:** [Watch / Download Video](${job.result.videoUrl})\n`;
|
|
1320
|
+
text += `\n📁 **Gallery:** View in your [CodingMantra Gallery](https://codingmantra.com/my-gallery)`;
|
|
1321
|
+
}
|
|
1322
|
+
else if (job.status === 'cancelled') {
|
|
1323
|
+
text += `\nJob cancelled. No further polling is needed.`;
|
|
377
1324
|
}
|
|
378
1325
|
else if (job.status === 'failed') {
|
|
379
|
-
text += `\n
|
|
1326
|
+
text += `\n❌ **Job Failed:** ${job.error || 'Unknown error occurred during generation.'}\n`;
|
|
1327
|
+
text += `Your credits have been refunded automatically.`;
|
|
380
1328
|
}
|
|
381
1329
|
else {
|
|
382
|
-
text += `\n
|
|
1330
|
+
text += `\n⏳ **Job is actively rendering.** Please poll again in 15-20 seconds.`;
|
|
383
1331
|
}
|
|
384
1332
|
return { content: [{ type: "text", text }] };
|
|
385
1333
|
}
|
|
@@ -389,7 +1337,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
389
1337
|
}
|
|
390
1338
|
catch (error) {
|
|
391
1339
|
return {
|
|
392
|
-
content: [{ type: "text", text: `❌ Error
|
|
1340
|
+
content: [{ type: "text", text: `❌ **Error:** ${error.message || error}` }],
|
|
393
1341
|
isError: true,
|
|
394
1342
|
};
|
|
395
1343
|
}
|
|
@@ -398,9 +1346,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
398
1346
|
async function run() {
|
|
399
1347
|
const transport = new StdioServerTransport();
|
|
400
1348
|
await server.connect(transport);
|
|
401
|
-
console.error("CodingMantra MCP Server running on stdio");
|
|
1349
|
+
console.error("[CodingMantra MCP] Server v0.2.2 initialized and running on stdio (28 tools active)");
|
|
402
1350
|
}
|
|
403
1351
|
run().catch((error) => {
|
|
404
|
-
console.error("Fatal error running server:", error);
|
|
1352
|
+
console.error("Fatal error running CodingMantra MCP server:", error);
|
|
405
1353
|
process.exit(1);
|
|
406
1354
|
});
|