@codingmantra/mcp-server 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,9 +4,9 @@ A **Model Context Protocol (MCP)** server that connects AI agents (like Claude D
4
4
 
5
5
  ## Features
6
6
 
7
- - **Product Photography** — Generate AI studio product photos with custom scenes
8
- - **Logo Creator** — Generate AI brand logos with style and color customization
9
- - **QR Code Generator** — Create custom QR codes (URL, text, WiFi, vCard, UPI, email)
7
+ - **Product Photography** — Generate AI studio product photos with custom scenes, resolutions, templates, and dynamic logo/text overlays.
8
+ - **Logo Creator** — Generate AI brand logos with style, resolution, references, and color customization.
9
+ - **QR Code Generator** — Create custom QR codes (URL, text, WiFi, vCard, UPI, email) with branding and colors.
10
10
 
11
11
  ## Setup
12
12
 
package/build/index.js CHANGED
@@ -48,6 +48,30 @@ const GENERATE_PRODUCT_PHOTO_TOOL = {
48
48
  referenceImage: {
49
49
  type: "string",
50
50
  description: "An optional URL or data URI of a reference image to guide style."
51
+ },
52
+ promptId: {
53
+ type: "string",
54
+ description: "Optional ID of a pre-defined prompt template."
55
+ },
56
+ logoImage: {
57
+ type: "string",
58
+ description: "Optional URL or Base64 data URI of a logo to place on the image."
59
+ },
60
+ logoPlacement: {
61
+ type: "string",
62
+ description: "Where to place the logo (e.g., 'top-left', 'bottom-right')."
63
+ },
64
+ logoSize: {
65
+ type: "number",
66
+ description: "Scale of the logo overlay (0.1 to 1.0)."
67
+ },
68
+ overlayText: {
69
+ type: "string",
70
+ description: "Optional text to overlay on the image."
71
+ },
72
+ marketingText: {
73
+ type: "string",
74
+ description: "Optional marketing text to overlay."
51
75
  }
52
76
  },
53
77
  required: ["productImages", "scenePrompt"]
@@ -94,6 +118,14 @@ const GENERATE_LOGO_TOOL = {
94
118
  resolution: {
95
119
  type: "string",
96
120
  description: "Output resolution (e.g., '1K', '2K'). Default is '1K'.",
121
+ },
122
+ promptId: {
123
+ type: "string",
124
+ description: "Optional ID or value of a pre-defined style template."
125
+ },
126
+ referenceImage: {
127
+ type: "string",
128
+ description: "An optional general style reference image URL or data URI."
97
129
  }
98
130
  },
99
131
  required: ["companyName", "stylePrompt"]
@@ -149,6 +181,64 @@ const GENERATE_QR_CODE_SIMPLE_TOOL = {
149
181
  required: ["text"]
150
182
  }
151
183
  };
184
+ const COMMON_VIDEO_PROPERTIES = {
185
+ prompt: { type: "string", description: "Detailed video description or prompt." },
186
+ mainImage: { type: "string", description: "Base64 data URI or URL for the main image (Image-to-Video mode)." },
187
+ startImage: { type: "string", description: "Base64 data URI or URL for the first frame." },
188
+ endImage: { type: "string", description: "Base64 data URI or URL for the last frame." },
189
+ referenceImages: {
190
+ type: "array",
191
+ items: { type: "object", properties: { image: { type: "string" }, label: { type: "string" } } },
192
+ description: "Array of reference images for style matching."
193
+ },
194
+ negativePrompt: { type: "string", description: "Elements to exclude from the video." },
195
+ dialogue: { type: "string", description: "Optional voiceover or dialogue." },
196
+ soundSuggestion: { type: "string", description: "Background music or sound effects." },
197
+ cameraMotion: { type: "string", description: "Camera motion instructions." },
198
+ ambientNoise: { type: "string", description: "Ambient sound description." },
199
+ language: { type: "string", description: "Voiceover language." },
200
+ timeDuration: { type: "string", description: "Video duration in seconds. Default is '4'." },
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." }
205
+ };
206
+ const GENERATE_PRODUCT_VIDEO_TOOL = {
207
+ name: "generate_product_video",
208
+ description: "Generates a product video. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion. Automatically deducts credits.",
209
+ inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES }
210
+ };
211
+ const GENERATE_APPAREL_VIDEO_TOOL = {
212
+ name: "generate_apparel_video",
213
+ description: "Generates an apparel try-on video. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion. Automatically deducts credits.",
214
+ inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES }
215
+ };
216
+ const GENERATE_FESTIVAL_VIDEO_TOOL = {
217
+ name: "generate_festival_video",
218
+ description: "Generates a festival or event video. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion. Automatically deducts credits.",
219
+ inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES }
220
+ };
221
+ const GENERATE_JEWELRY_VIDEO_TOOL = {
222
+ name: "generate_jewelry_video",
223
+ description: "Generates a jewelry showcase video. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion. Automatically deducts credits.",
224
+ inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES }
225
+ };
226
+ const GENERATE_LOGO_VIDEO_TOOL = {
227
+ name: "generate_logo_video",
228
+ description: "Generates a logo animation video. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion. Automatically deducts credits.",
229
+ inputSchema: { type: "object", properties: COMMON_VIDEO_PROPERTIES }
230
+ };
231
+ const CHECK_JOB_STATUS_TOOL = {
232
+ name: "check_video_job_status",
233
+ description: "Checks the status of an asynchronous video generation job. Call this repeatedly (e.g. every 10-30 seconds) until the job status is 'completed' or 'failed'.",
234
+ inputSchema: {
235
+ type: "object",
236
+ properties: {
237
+ jobId: { type: "string", description: "The ID of the job to check." }
238
+ },
239
+ required: ["jobId"]
240
+ }
241
+ };
152
242
  // ─── Tool Registration ─────────────────────────────────────────────────────────
153
243
  server.setRequestHandler(ListToolsRequestSchema, async () => {
154
244
  return {
@@ -157,6 +247,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
157
247
  GENERATE_LOGO_TOOL,
158
248
  GENERATE_QR_CODE_TOOL,
159
249
  GENERATE_QR_CODE_SIMPLE_TOOL,
250
+ GENERATE_PRODUCT_VIDEO_TOOL,
251
+ GENERATE_APPAREL_VIDEO_TOOL,
252
+ GENERATE_FESTIVAL_VIDEO_TOOL,
253
+ GENERATE_JEWELRY_VIDEO_TOOL,
254
+ GENERATE_LOGO_VIDEO_TOOL,
255
+ CHECK_JOB_STATUS_TOOL,
160
256
  ],
161
257
  };
162
258
  });
@@ -242,6 +338,53 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
242
338
  content: [{ type: "text", text: `✅ QR Code generated. Result: ${JSON.stringify(response.data).substring(0, 500)}` }],
243
339
  };
244
340
  }
341
+ // ── Video Generation (Asynchronous) ──────────────────────────────────────
342
+ const videoEndpoints = {
343
+ generate_product_video: '/product-video-generation',
344
+ generate_apparel_video: '/apparel-video-generation',
345
+ generate_festival_video: '/festival-video-generation',
346
+ generate_jewelry_video: '/jewelry-video-generation',
347
+ generate_logo_video: '/logo-video-generation'
348
+ };
349
+ if (videoEndpoints[name]) {
350
+ const response = await apiClient(videoEndpoints[name], {
351
+ method: 'POST',
352
+ body: JSON.stringify(args),
353
+ });
354
+ const result = response.data || response;
355
+ if (result?.jobId) {
356
+ return {
357
+ content: [{
358
+ type: "text",
359
+ text: `✅ Job created successfully!\nJob ID: ${result.jobId}\nMessage: ${result.message}\n\nPlease use the check_video_job_status tool with this Job ID to poll for the result. Wait about 10-30 seconds between polls. Video generation can take several minutes.`
360
+ }]
361
+ };
362
+ }
363
+ return { content: [{ type: "text", text: `Job started. Result: ${JSON.stringify(result).substring(0, 500)}` }] };
364
+ }
365
+ // ── Check Job Status ─────────────────────────────────────────────────────
366
+ if (name === 'check_video_job_status') {
367
+ const { jobId } = args;
368
+ const response = await apiClient(`/jobs/status?jobId=${encodeURIComponent(jobId)}`, {
369
+ method: 'GET',
370
+ });
371
+ const result = response.data || response;
372
+ if (result?.job) {
373
+ const job = result.job;
374
+ let text = `Job Status: ${job.status}\nProgress: ${job.progress}%\nStage: ${job.stage || 'N/A'}`;
375
+ if (job.status === 'completed' && job.result?.videoUrl) {
376
+ text += `\n\n✅ Video generated successfully!\nVideo URL: ${job.result.videoUrl}`;
377
+ }
378
+ else if (job.status === 'failed') {
379
+ text += `\n\n❌ Job failed: ${job.error || 'Unknown error'}`;
380
+ }
381
+ else {
382
+ text += `\n\nJob is still running. Please check back again shortly.`;
383
+ }
384
+ return { content: [{ type: "text", text }] };
385
+ }
386
+ return { content: [{ type: "text", text: `Status check result: ${JSON.stringify(result).substring(0, 500)}` }] };
387
+ }
245
388
  throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
246
389
  }
247
390
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codingmantra/mcp-server",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "MCP Server for CodingMantra AI Tools",
5
5
  "type": "module",
6
6
  "bin": "build/index.js",
package/src/index.ts CHANGED
@@ -55,6 +55,30 @@ const GENERATE_PRODUCT_PHOTO_TOOL = {
55
55
  referenceImage: {
56
56
  type: "string",
57
57
  description: "An optional URL or data URI of a reference image to guide style."
58
+ },
59
+ promptId: {
60
+ type: "string",
61
+ description: "Optional ID of a pre-defined prompt template."
62
+ },
63
+ logoImage: {
64
+ type: "string",
65
+ description: "Optional URL or Base64 data URI of a logo to place on the image."
66
+ },
67
+ logoPlacement: {
68
+ type: "string",
69
+ description: "Where to place the logo (e.g., 'top-left', 'bottom-right')."
70
+ },
71
+ logoSize: {
72
+ type: "number",
73
+ description: "Scale of the logo overlay (0.1 to 1.0)."
74
+ },
75
+ overlayText: {
76
+ type: "string",
77
+ description: "Optional text to overlay on the image."
78
+ },
79
+ marketingText: {
80
+ type: "string",
81
+ description: "Optional marketing text to overlay."
58
82
  }
59
83
  },
60
84
  required: ["productImages", "scenePrompt"]
@@ -102,6 +126,14 @@ const GENERATE_LOGO_TOOL = {
102
126
  resolution: {
103
127
  type: "string",
104
128
  description: "Output resolution (e.g., '1K', '2K'). Default is '1K'.",
129
+ },
130
+ promptId: {
131
+ type: "string",
132
+ description: "Optional ID or value of a pre-defined style template."
133
+ },
134
+ referenceImage: {
135
+ type: "string",
136
+ description: "An optional general style reference image URL or data URI."
105
137
  }
106
138
  },
107
139
  required: ["companyName", "stylePrompt"]
@@ -160,6 +192,71 @@ const GENERATE_QR_CODE_SIMPLE_TOOL = {
160
192
  }
161
193
  };
162
194
 
195
+ const COMMON_VIDEO_PROPERTIES = {
196
+ prompt: { type: "string", description: "Detailed video description or prompt." },
197
+ mainImage: { type: "string", description: "Base64 data URI or URL for the main image (Image-to-Video mode)." },
198
+ startImage: { type: "string", description: "Base64 data URI or URL for the first frame." },
199
+ endImage: { type: "string", description: "Base64 data URI or URL for the last frame." },
200
+ referenceImages: {
201
+ type: "array",
202
+ items: { type: "object", properties: { image: { type: "string" }, label: { type: "string" } } },
203
+ description: "Array of reference images for style matching."
204
+ },
205
+ negativePrompt: { type: "string", description: "Elements to exclude from the video." },
206
+ dialogue: { type: "string", description: "Optional voiceover or dialogue." },
207
+ soundSuggestion: { type: "string", description: "Background music or sound effects." },
208
+ cameraMotion: { type: "string", description: "Camera motion instructions." },
209
+ ambientNoise: { type: "string", description: "Ambient sound description." },
210
+ language: { type: "string", description: "Voiceover language." },
211
+ timeDuration: { type: "string", description: "Video duration in seconds. Default is '4'." },
212
+ resolution: { type: "string", description: "Resolution (e.g., '720p', '1080p'). Default is '720p'." },
213
+ model: { type: "string", description: "Model slug (e.g., 'google/veo-3.1-fast', 'openrouter/wan-2.7')." },
214
+ aspectRatio: { type: "string", description: "Aspect ratio (e.g., '9:16', '16:9'). Default is '9:16'." },
215
+ generateAudio: { type: "boolean", description: "Whether to generate audio. Default is false." }
216
+ };
217
+
218
+ const GENERATE_PRODUCT_VIDEO_TOOL = {
219
+ name: "generate_product_video",
220
+ description: "Generates a product video. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion. Automatically deducts credits.",
221
+ inputSchema: { type: "object" as const, properties: COMMON_VIDEO_PROPERTIES }
222
+ };
223
+
224
+ const GENERATE_APPAREL_VIDEO_TOOL = {
225
+ name: "generate_apparel_video",
226
+ description: "Generates an apparel try-on video. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion. Automatically deducts credits.",
227
+ inputSchema: { type: "object" as const, properties: COMMON_VIDEO_PROPERTIES }
228
+ };
229
+
230
+ const GENERATE_FESTIVAL_VIDEO_TOOL = {
231
+ name: "generate_festival_video",
232
+ description: "Generates a festival or event video. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion. Automatically deducts credits.",
233
+ inputSchema: { type: "object" as const, properties: COMMON_VIDEO_PROPERTIES }
234
+ };
235
+
236
+ const GENERATE_JEWELRY_VIDEO_TOOL = {
237
+ name: "generate_jewelry_video",
238
+ description: "Generates a jewelry showcase video. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion. Automatically deducts credits.",
239
+ inputSchema: { type: "object" as const, properties: COMMON_VIDEO_PROPERTIES }
240
+ };
241
+
242
+ const GENERATE_LOGO_VIDEO_TOOL = {
243
+ name: "generate_logo_video",
244
+ description: "Generates a logo animation video. Asynchronous: returns a jobId. You MUST use check_video_job_status with the jobId to poll for completion. Automatically deducts credits.",
245
+ inputSchema: { type: "object" as const, properties: COMMON_VIDEO_PROPERTIES }
246
+ };
247
+
248
+ const CHECK_JOB_STATUS_TOOL = {
249
+ name: "check_video_job_status",
250
+ description: "Checks the status of an asynchronous video generation job. Call this repeatedly (e.g. every 10-30 seconds) until the job status is 'completed' or 'failed'.",
251
+ inputSchema: {
252
+ type: "object" as const,
253
+ properties: {
254
+ jobId: { type: "string", description: "The ID of the job to check." }
255
+ },
256
+ required: ["jobId"]
257
+ }
258
+ };
259
+
163
260
  // ─── Tool Registration ─────────────────────────────────────────────────────────
164
261
 
165
262
  server.setRequestHandler(ListToolsRequestSchema, async () => {
@@ -169,6 +266,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
169
266
  GENERATE_LOGO_TOOL,
170
267
  GENERATE_QR_CODE_TOOL,
171
268
  GENERATE_QR_CODE_SIMPLE_TOOL,
269
+ GENERATE_PRODUCT_VIDEO_TOOL,
270
+ GENERATE_APPAREL_VIDEO_TOOL,
271
+ GENERATE_FESTIVAL_VIDEO_TOOL,
272
+ GENERATE_JEWELRY_VIDEO_TOOL,
273
+ GENERATE_LOGO_VIDEO_TOOL,
274
+ CHECK_JOB_STATUS_TOOL,
172
275
  ],
173
276
  };
174
277
  });
@@ -263,6 +366,57 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
263
366
  };
264
367
  }
265
368
 
369
+ // ── Video Generation (Asynchronous) ──────────────────────────────────────
370
+ const videoEndpoints: Record<string, string> = {
371
+ generate_product_video: '/product-video-generation',
372
+ generate_apparel_video: '/apparel-video-generation',
373
+ generate_festival_video: '/festival-video-generation',
374
+ generate_jewelry_video: '/jewelry-video-generation',
375
+ generate_logo_video: '/logo-video-generation'
376
+ };
377
+
378
+ if (videoEndpoints[name]) {
379
+ const response = await apiClient(videoEndpoints[name], {
380
+ method: 'POST',
381
+ body: JSON.stringify(args),
382
+ });
383
+
384
+ const result = response.data || response;
385
+ if (result?.jobId) {
386
+ return {
387
+ content: [{
388
+ type: "text",
389
+ text: `✅ Job created successfully!\nJob ID: ${result.jobId}\nMessage: ${result.message}\n\nPlease use the check_video_job_status tool with this Job ID to poll for the result. Wait about 10-30 seconds between polls. Video generation can take several minutes.`
390
+ }]
391
+ };
392
+ }
393
+ return { content: [{ type: "text", text: `Job started. Result: ${JSON.stringify(result).substring(0, 500)}` }] };
394
+ }
395
+
396
+ // ── Check Job Status ─────────────────────────────────────────────────────
397
+ if (name === 'check_video_job_status') {
398
+ const { jobId } = args as { jobId: string };
399
+ const response = await apiClient(`/jobs/status?jobId=${encodeURIComponent(jobId)}`, {
400
+ method: 'GET',
401
+ });
402
+
403
+ const result = response.data || response;
404
+ if (result?.job) {
405
+ const job = result.job;
406
+ let text = `Job Status: ${job.status}\nProgress: ${job.progress}%\nStage: ${job.stage || 'N/A'}`;
407
+
408
+ if (job.status === 'completed' && job.result?.videoUrl) {
409
+ text += `\n\n✅ Video generated successfully!\nVideo URL: ${job.result.videoUrl}`;
410
+ } else if (job.status === 'failed') {
411
+ text += `\n\n❌ Job failed: ${job.error || 'Unknown error'}`;
412
+ } else {
413
+ text += `\n\nJob is still running. Please check back again shortly.`;
414
+ }
415
+ return { content: [{ type: "text", text }] };
416
+ }
417
+ return { content: [{ type: "text", text: `Status check result: ${JSON.stringify(result).substring(0, 500)}` }] };
418
+ }
419
+
266
420
  throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
267
421
  } catch (error: any) {
268
422
  return {