@codingmantra/mcp-server 0.1.3 β†’ 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,65 +1,161 @@
1
1
  # @codingmantra/mcp-server
2
2
 
3
- A **Model Context Protocol (MCP)** server that connects AI agents (like Claude Desktop, Cursor, and Cline) to CodingMantra's AI generation tools.
3
+ The official **Model Context Protocol (MCP)** server connecting AI assistants (Claude Desktop, Cursor, Cline, and Antigravity) to CodingMantra's generative AI media engines.
4
4
 
5
- ## Features
5
+ ## What's New in v0.2.0
6
+ - πŸ–ΌοΈ **Native MCP Image Output**: Generated images (including QR codes, logos, try-on shots, and product photos) return standard MCP `ImageContent` so they render directly in your AI assistant's chat window.
7
+ - πŸ“ **Local File Path Resolution**: Pass local paths (e.g. `./shoe.png` or `/Users/.../portrait.jpg`) directly in tool argumentsβ€”the server automatically reads and encodes them as base64 data URIs.
8
+ - ⚑ **Expanded Tool Suite (20 Tools)**: Added support for Jewelry Try-On, Apparel Try-On, Product Try-On, Festival Posts, YouTube Thumbnails, Passport Photos, Sketch-to-Real, Upscaling, Wallet Credit Checking, and Model Catalog discovery.
9
+ - πŸ›‘οΈ **Graceful Error Handling & 120s Timeout**: Informative error diagnostics when API keys are missing or requests time out, with clean stdio protocol execution.
6
10
 
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.
11
+ ---
10
12
 
11
- ## Setup
13
+ ## Features & Tool Suite
12
14
 
13
- ### 1. Get an API Key
15
+ The server exposes **20 specialized generative and utility tools** over standard I/O (`stdio`):
14
16
 
17
+ ### 1. Synchronous Image Generation (Immediate Inline Image Output)
18
+ - **`generate_product_photo`** β€” Generates studio-grade commercial product photos with custom background scenes, ambient occlusion contact shadows, Hasselblad camera optics, resolutions (1K, 2K, 4K), aspect ratios, and dynamic logo/text overlays.
19
+ - **`generate_logo`** β€” Generates bespoke vector-style or 3D brand logos with customizable typography, colors, industries, and reference images.
20
+ - **`try_on_jewelry`** β€” Virtual luxury jewelry try-on with model styling, metal & gemstone preservation, Fresnel light dispersion, and anatomical contact shadows.
21
+ - **`try_on_apparel`** β€” Virtual fashion apparel try-on with natural gravitational folds, realistic fabric tension, Hasselblad medium-format camera optics, and ground contact shadows.
22
+ - **`try_on_product`** β€” Universal commercial product staging and virtual try-on across footwear, accessories, cosmetics, eyewear, and furniture with 3-point studio lighting.
23
+ - **`generate_festival_post`** β€” High-conversion festival marketing graphics, holiday greetings (Diwali, Eid, Christmas, New Year), and promotional banners with product and logo integration.
24
+ - **`generate_youtube_thumbnail`** β€” High-CTR YouTube thumbnails with rule-of-thirds composition, emotional human expressions, vibrant contrast separation, and legible bold text overlays.
25
+ - **`generate_passport_photo`** β€” Converts any portrait into an official, compliant passport or visa identity photo with pixel-level facial identity preservation.
26
+ - **`sketch_to_real`** β€” Transforms hand-drawn sketches, line drawings, or product drafts into photorealistic commercial images while preserving ground-truth silhouettes.
27
+ - **`upscale_image`** β€” Upscales and enhances any image with AI detail recovery, removing compression artifacts and increasing resolution up to 4K.
28
+
29
+ ### 2. QR Code Tools
30
+ - **`generate_qr_code`** β€” Full-featured custom QR code generator supporting URLs, plain text, Wi-Fi credentials, vCards, emails, and UPI payment strings with custom styling, colors, and error correction.
31
+ - **`generate_qr_code_simple`** β€” Lightweight single-parameter QR code generation from text or URL.
32
+
33
+ ### 3. Account & Discovery Utilities
34
+ - **`get_user_credits`** β€” Checks your current CodingMantra AI wallet credit balance in real time.
35
+ - **`list_image_models`** β€” Queries all available CodingMantra AI image generation models (Gemini Flash, Pro, Flux, etc.), supported resolutions, aspect ratios, and credit costs.
36
+
37
+ ### 4. Asynchronous Video Tools (with Job Polling)
38
+ - **`generate_product_video`** β€” Commercial product videography (Google Veo 3.1 & OpenRouter Wan 2.7).
39
+ - **`generate_apparel_video`** β€” Model runway and apparel try-on video showcase.
40
+ - **`generate_festival_video`** β€” Festive event greetings and celebratory motion graphics.
41
+ - **`generate_jewelry_video`** β€” High-end luxury jewelry videography with realistic optical brilliance dispersion.
42
+ - **`generate_logo_video`** β€” 3D logo reveal and motion graphic intros.
43
+ - **`check_video_job_status`** β€” Real-time polling tool to track background video rendering status (`queued` β†’ `processing` β†’ `generating` β†’ `uploading` β†’ `completed` / `failed`).
44
+
45
+ All generations automatically deduct credits from your CodingMantra wallet and persist outputs directly to your online media gallery at [https://codingmantra.com/my-gallery](https://codingmantra.com/my-gallery).
46
+
47
+ ---
48
+
49
+ ## Quick Setup
50
+
51
+ ### 1. Obtain Your API Key
15
52
  Generate an API key from your [CodingMantra Dashboard β†’ My API Keys](https://codingmantra.com/my-api).
16
53
 
17
- ### 2. Configure Claude Desktop
54
+ ### 2. Configure Your AI Client
18
55
 
19
- Add the following to your `claude_desktop_config.json`:
56
+ #### A. Claude Desktop
57
+ Add to your `claude_desktop_config.json`:
58
+ - **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
59
+ - **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
20
60
 
21
61
  ```json
22
62
  {
23
63
  "mcpServers": {
24
64
  "codingmantra": {
25
65
  "command": "npx",
26
- "args": ["-y", "@codingmantra/mcp-server"],
66
+ "args": ["-y", "@codingmantra/mcp-server@latest"],
27
67
  "env": {
28
- "CODINGMANTRA_API_KEY": "YOUR_API_KEY"
68
+ "CODINGMANTRA_API_KEY": "YOUR_CODINGMANTRA_API_KEY"
29
69
  }
30
70
  }
31
71
  }
32
72
  }
33
73
  ```
34
74
 
35
- ### 3. Restart Claude Desktop
75
+ #### B. Cursor
76
+ Add to `.cursor/mcp.json` in your project or global settings:
36
77
 
37
- After saving the config, restart Claude Desktop. You can now ask Claude to:
38
-
39
- - *"Generate a product photo of this watch on a marble surface"*
40
- - *"Create a minimalist logo for my company TechFlow"*
41
- - *"Generate a QR code for https://codingmantra.com"*
78
+ ```json
79
+ {
80
+ "mcpServers": {
81
+ "codingmantra": {
82
+ "command": "npx",
83
+ "args": ["-y", "@codingmantra/mcp-server@latest"],
84
+ "env": {
85
+ "CODINGMANTRA_API_KEY": "YOUR_CODINGMANTRA_API_KEY"
86
+ }
87
+ }
88
+ }
89
+ }
90
+ ```
42
91
 
43
- ## Development
92
+ #### C. Cline (VS Code Extension)
93
+ In Cline Settings β†’ MCP Servers, add:
44
94
 
45
- ```bash
46
- # Install dependencies
47
- npm install
95
+ ```json
96
+ {
97
+ "codingmantra": {
98
+ "command": "npx",
99
+ "args": ["-y", "@codingmantra/mcp-server@latest"],
100
+ "env": {
101
+ "CODINGMANTRA_API_KEY": "YOUR_CODINGMANTRA_API_KEY"
102
+ }
103
+ }
104
+ }
105
+ ```
48
106
 
49
- # Build
50
- npm run build
107
+ #### D. Antigravity / Agentic Workspace
108
+ Add to `.agents/mcp_config.json`:
51
109
 
52
- # Run locally
53
- CODINGMANTRA_API_KEY=your_key npm start
110
+ ```json
111
+ {
112
+ "mcpServers": {
113
+ "codingmantra": {
114
+ "command": "npx",
115
+ "args": ["-y", "@codingmantra/mcp-server@latest"],
116
+ "env": {
117
+ "CODINGMANTRA_API_KEY": "YOUR_CODINGMANTRA_API_KEY"
118
+ }
119
+ }
120
+ }
121
+ }
54
122
  ```
55
123
 
124
+ ---
125
+
126
+ ## Example Natural Language Prompts
127
+
128
+ Once configured, restart your AI assistant and try prompts like:
129
+
130
+ - *"How many credits do I have left in my CodingMantra account?"*
131
+ - *"Generate a luxury product photo of this perfume bottle on a dark reflective obsidian pedestal with subtle mist."*
132
+ - *"Virtually try on this diamond necklace on an elegant editorial model wearing a black velvet evening gown."*
133
+ - *"Create a YouTube thumbnail for my video 'Top 10 AI Tools of 2026' with bold text and high contrast."*
134
+ - *"Create a modern minimalist geometric logo for a fintech company called 'Acuity'."*
135
+ - *"Generate a UPI payment QR code for merchant@upi with an amount of 500."*
136
+ - *"Create a 4-second jewelry video showing this diamond ring rotating on a black velvet pedestal with cinematic sunbeam flares, and check its progress until it's finished."*
137
+
138
+ ---
139
+
56
140
  ## Environment Variables
57
141
 
58
- | Variable | Required | Description |
59
- |---|---|---|
60
- | `CODINGMANTRA_API_KEY` | βœ… | Your CodingMantra developer API key |
61
- | `CODINGMANTRA_API_URL` | ❌ | Custom API base URL (default: `https://codingmantra.com/api`) |
142
+ | Variable | Required | Description | Default |
143
+ |---|---|---|---|
144
+ | `CODINGMANTRA_API_KEY` | βœ… | Your CodingMantra developer API key (`cm_...`) | None |
145
+ | `CODINGMANTRA_API_URL` | ❌ | Custom API base URL | `https://codingmantra.com/api` |
146
+
147
+ ---
148
+
149
+ ## Local Development
150
+
151
+ ```bash
152
+ # Build TypeScript
153
+ npm run build
154
+
155
+ # Start server directly on stdio
156
+ CODINGMANTRA_API_KEY=your_key node build/index.js
157
+ ```
62
158
 
63
159
  ## License
64
160
 
65
- Private β€” Part of the CodingMantra Web Portal.
161
+ Private & Proprietary β€” Part of the CodingMantra Web Portal Β© 2026. All rights reserved.
@@ -1,33 +1,63 @@
1
1
  import dotenv from 'dotenv';
2
- dotenv.config();
3
- const API_KEY = process.env.CODINGMANTRA_API_KEY;
4
- const API_BASE_URL = process.env.CODINGMANTRA_API_URL || 'https://codingmantra.com/api';
5
- if (!API_KEY) {
6
- console.error('CRITICAL: CODINGMANTRA_API_KEY environment variable is missing.');
7
- console.error('Please set it in your environment or .env file before running this server.');
8
- process.exit(1);
2
+ dotenv.config({ quiet: true });
3
+ const DEFAULT_TIMEOUT_MS = 120_000; // 2 minutes for heavy generation tasks
4
+ export function getApiKey() {
5
+ return process.env.CODINGMANTRA_API_KEY;
6
+ }
7
+ export function getApiBaseUrl() {
8
+ return process.env.CODINGMANTRA_API_URL || 'https://codingmantra.com/api';
9
+ }
10
+ if (!getApiKey()) {
11
+ console.error('[CodingMantra MCP] WARNING: CODINGMANTRA_API_KEY environment variable is not set.');
12
+ console.error('[CodingMantra MCP] Please configure your API key in your MCP client settings or .env file.');
13
+ console.error('[CodingMantra MCP] Generate an API key from https://codingmantra.com/my-api');
9
14
  }
10
15
  /**
11
16
  * Helper to make authenticated requests to the CodingMantra API.
12
17
  */
13
18
  export async function apiClient(endpoint, options = {}) {
14
- const url = `${API_BASE_URL}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;
19
+ const apiKey = getApiKey();
20
+ if (!apiKey) {
21
+ throw new Error('CODINGMANTRA_API_KEY environment variable is missing. ' +
22
+ 'Please set your API key in your MCP server configuration. ' +
23
+ 'You can generate an API key at https://codingmantra.com/my-api');
24
+ }
25
+ const baseUrl = getApiBaseUrl();
26
+ const url = `${baseUrl}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;
15
27
  const headers = new Headers(options.headers || {});
16
- headers.set('Authorization', `Bearer ${API_KEY}`);
28
+ headers.set('Authorization', `Bearer ${apiKey}`);
17
29
  if (!(options.body instanceof FormData)) {
18
30
  headers.set('Content-Type', 'application/json');
19
31
  }
20
- const response = await fetch(url, {
21
- ...options,
22
- headers,
23
- });
32
+ // Set timeout if no external abort signal provided
33
+ const signal = options.signal || AbortSignal.timeout(DEFAULT_TIMEOUT_MS);
34
+ let response;
35
+ try {
36
+ response = await fetch(url, {
37
+ ...options,
38
+ headers,
39
+ signal,
40
+ });
41
+ }
42
+ catch (fetchError) {
43
+ if (fetchError?.name === 'TimeoutError' || fetchError?.name === 'AbortError') {
44
+ throw new Error(`CodingMantra API request timed out after ${DEFAULT_TIMEOUT_MS / 1000}s for ${endpoint}`);
45
+ }
46
+ throw new Error(`Failed to connect to CodingMantra API at ${url}: ${fetchError?.message || fetchError}`);
47
+ }
24
48
  if (!response.ok) {
25
- let errorMsg = `API request failed with status ${response.status} ${response.statusText}`;
49
+ let errorMsg = `API request failed (${response.status} ${response.statusText})`;
26
50
  try {
27
51
  const errorData = await response.json();
28
- if (errorData?.error?.message) {
52
+ if (typeof errorData?.error === 'string') {
53
+ errorMsg += `: ${errorData.error}`;
54
+ }
55
+ else if (errorData?.error?.message) {
29
56
  errorMsg += `: ${errorData.error.message}`;
30
57
  }
58
+ else if (errorData?.message) {
59
+ errorMsg += `: ${errorData.message}`;
60
+ }
31
61
  else {
32
62
  errorMsg += `: ${JSON.stringify(errorData)}`;
33
63
  }
@@ -0,0 +1,145 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ /**
4
+ * Extracts raw base64 data and MIME type from a data URI.
5
+ */
6
+ export function parseDataUri(dataUri) {
7
+ if (!dataUri || typeof dataUri !== 'string')
8
+ return null;
9
+ const match = dataUri.match(/^data:([^;]+);base64,(.+)$/);
10
+ if (match && match[1] && match[2]) {
11
+ return {
12
+ mimeType: match[1],
13
+ data: match[2],
14
+ };
15
+ }
16
+ return null;
17
+ }
18
+ /**
19
+ * Detects MIME type from a file path extension.
20
+ */
21
+ function getMimeTypeFromExt(filePath) {
22
+ const ext = path.extname(filePath).toLowerCase().replace('.', '');
23
+ switch (ext) {
24
+ case 'png':
25
+ return 'image/png';
26
+ case 'jpg':
27
+ case 'jpeg':
28
+ return 'image/jpeg';
29
+ case 'webp':
30
+ return 'image/webp';
31
+ case 'svg':
32
+ return 'image/svg+xml';
33
+ case 'gif':
34
+ return 'image/gif';
35
+ default:
36
+ return 'image/png';
37
+ }
38
+ }
39
+ /**
40
+ * Resolves an image input string. If it's a local file path on disk,
41
+ * reads it and converts to a base64 data URI.
42
+ * If already a URL or data URI, returns as is.
43
+ */
44
+ export function resolveImageInput(input) {
45
+ if (!input || typeof input !== 'string')
46
+ return '';
47
+ const trimmed = input.trim();
48
+ // Already a remote URL or data URI
49
+ if (trimmed.startsWith('data:') || trimmed.startsWith('http://') || trimmed.startsWith('https://')) {
50
+ return trimmed;
51
+ }
52
+ // Check if it's a local file path
53
+ try {
54
+ const resolvedPath = path.isAbsolute(trimmed) ? trimmed : path.resolve(process.cwd(), trimmed);
55
+ if (fs.existsSync(resolvedPath) && fs.statSync(resolvedPath).isFile()) {
56
+ const buffer = fs.readFileSync(resolvedPath);
57
+ const mimeType = getMimeTypeFromExt(resolvedPath);
58
+ return `data:${mimeType};base64,${buffer.toString('base64')}`;
59
+ }
60
+ }
61
+ catch {
62
+ // If any filesystem read error, fall through
63
+ }
64
+ return trimmed;
65
+ }
66
+ /**
67
+ * Helper to resolve an array of images or single image inputs.
68
+ */
69
+ export function resolveImagesArray(images) {
70
+ if (!images || !Array.isArray(images))
71
+ return [];
72
+ return images.map(item => {
73
+ const rawSrc = item.dataUrl || item.path || item.url || '';
74
+ const resolved = resolveImageInput(rawSrc);
75
+ if (resolved.startsWith('data:')) {
76
+ return { ...item, dataUrl: resolved };
77
+ }
78
+ return { ...item, url: resolved };
79
+ });
80
+ }
81
+ /**
82
+ * Standardizes synchronous image generation responses into MCP content.
83
+ * Returns both native ImageContent (for visual render in Claude/Cursor)
84
+ * and rich Markdown text.
85
+ */
86
+ export function formatImageToolResult(result, successTitle) {
87
+ const content = [];
88
+ const rawData = result?.data || result;
89
+ // Extract all potential image data URIs
90
+ const dataUris = [];
91
+ if (rawData?.photoDataUri)
92
+ dataUris.push(rawData.photoDataUri);
93
+ if (Array.isArray(rawData?.photoDataUris)) {
94
+ for (const uri of rawData.photoDataUris) {
95
+ if (uri && !dataUris.includes(uri))
96
+ dataUris.push(uri);
97
+ }
98
+ }
99
+ if (rawData?.qrCodeDataUrl)
100
+ dataUris.push(rawData.qrCodeDataUrl);
101
+ if (rawData?.upscaledImage)
102
+ dataUris.push(rawData.upscaledImage);
103
+ if (rawData?.output && typeof rawData.output === 'string' && rawData.output.startsWith('data:')) {
104
+ dataUris.push(rawData.output);
105
+ }
106
+ // Add native ImageContent blocks for each generated image
107
+ for (const uri of dataUris) {
108
+ const parsed = parseDataUri(uri);
109
+ if (parsed) {
110
+ content.push({
111
+ type: 'image',
112
+ data: parsed.data,
113
+ mimeType: parsed.mimeType,
114
+ });
115
+ }
116
+ }
117
+ // Build Markdown text summary
118
+ let text = `### βœ… ${successTitle}\n\n`;
119
+ const publicUrls = [];
120
+ if (rawData?.imageUrl)
121
+ publicUrls.push(rawData.imageUrl);
122
+ if (Array.isArray(rawData?.imageUrls)) {
123
+ for (const u of rawData.imageUrls) {
124
+ if (u && !publicUrls.includes(u))
125
+ publicUrls.push(u);
126
+ }
127
+ }
128
+ if (publicUrls.length > 0) {
129
+ if (publicUrls.length === 1) {
130
+ text += `**Public Image URL:** [View Full Resolution](${publicUrls[0]})\n\n`;
131
+ }
132
+ else {
133
+ text += `**Public Image URLs:**\n` + publicUrls.map((u, i) => `- [Image ${i + 1}](${u})`).join('\n') + `\n\n`;
134
+ }
135
+ }
136
+ if (dataUris.length > 0) {
137
+ text += `πŸ–ΌοΈ **Inline Media:** Generated ${dataUris.length} image(s) rendered directly above.\n`;
138
+ }
139
+ text += `\nπŸ“ **Gallery:** Output saved to your [CodingMantra Media Gallery](https://codingmantra.com/my-gallery).\n`;
140
+ content.push({
141
+ type: 'text',
142
+ text: text.trim(),
143
+ });
144
+ return { content };
145
+ }