@codingmantra/mcp-server 0.1.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 ADDED
@@ -0,0 +1,65 @@
1
+ # @codingmantra/mcp-server
2
+
3
+ A **Model Context Protocol (MCP)** server that connects AI agents (like Claude Desktop, Cursor, and Cline) to CodingMantra's AI generation tools.
4
+
5
+ ## Features
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)
10
+
11
+ ## Setup
12
+
13
+ ### 1. Get an API Key
14
+
15
+ Generate an API key from your [CodingMantra Dashboard → My API Keys](https://codingmantra.com/my-api).
16
+
17
+ ### 2. Configure Claude Desktop
18
+
19
+ Add the following to your `claude_desktop_config.json`:
20
+
21
+ ```json
22
+ {
23
+ "mcpServers": {
24
+ "codingmantra": {
25
+ "command": "npx",
26
+ "args": ["-y", "@codingmantra/mcp-server"],
27
+ "env": {
28
+ "CODINGMANTRA_API_KEY": "YOUR_API_KEY"
29
+ }
30
+ }
31
+ }
32
+ }
33
+ ```
34
+
35
+ ### 3. Restart Claude Desktop
36
+
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"*
42
+
43
+ ## Development
44
+
45
+ ```bash
46
+ # Install dependencies
47
+ npm install
48
+
49
+ # Build
50
+ npm run build
51
+
52
+ # Run locally
53
+ CODINGMANTRA_API_KEY=your_key npm start
54
+ ```
55
+
56
+ ## Environment Variables
57
+
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`) |
62
+
63
+ ## License
64
+
65
+ Private — Part of the CodingMantra Web Portal.
@@ -0,0 +1,41 @@
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);
9
+ }
10
+ /**
11
+ * Helper to make authenticated requests to the CodingMantra API.
12
+ */
13
+ export async function apiClient(endpoint, options = {}) {
14
+ const url = `${API_BASE_URL}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;
15
+ const headers = new Headers(options.headers || {});
16
+ headers.set('Authorization', `Bearer ${API_KEY}`);
17
+ if (!(options.body instanceof FormData)) {
18
+ headers.set('Content-Type', 'application/json');
19
+ }
20
+ const response = await fetch(url, {
21
+ ...options,
22
+ headers,
23
+ });
24
+ if (!response.ok) {
25
+ let errorMsg = `API request failed with status ${response.status} ${response.statusText}`;
26
+ try {
27
+ const errorData = await response.json();
28
+ if (errorData?.error?.message) {
29
+ errorMsg += `: ${errorData.error.message}`;
30
+ }
31
+ else {
32
+ errorMsg += `: ${JSON.stringify(errorData)}`;
33
+ }
34
+ }
35
+ catch {
36
+ errorMsg += `: ${await response.text()}`;
37
+ }
38
+ throw new Error(errorMsg);
39
+ }
40
+ return response.json();
41
+ }
package/build/index.js ADDED
@@ -0,0 +1,263 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
5
+ import { apiClient } from './api-client.js';
6
+ const server = new Server({
7
+ name: "codingmantra-mcp",
8
+ version: "0.1.0",
9
+ }, {
10
+ capabilities: {
11
+ tools: {},
12
+ },
13
+ });
14
+ // ─── Tool Definitions ──────────────────────────────────────────────────────────
15
+ const GENERATE_PRODUCT_PHOTO_TOOL = {
16
+ name: "generate_product_photo",
17
+ description: "Generates an AI product photography image with a specific scene prompt. Automatically deducts credits from your CodingMantra account. Returns the generated image directly (synchronous).",
18
+ inputSchema: {
19
+ type: "object",
20
+ properties: {
21
+ productImages: {
22
+ type: "array",
23
+ items: {
24
+ type: "object",
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."
31
+ },
32
+ scenePrompt: {
33
+ type: "string",
34
+ description: "A detailed description of the background scene and setting for the product photo."
35
+ },
36
+ model: {
37
+ type: "string",
38
+ description: "The AI model slug (e.g., 'pro', 'standard', 'flash'). Default is 'pro'.",
39
+ },
40
+ resolution: {
41
+ type: "string",
42
+ description: "Output resolution (e.g., '1K', '2K', '4K'). Default is '1K'.",
43
+ },
44
+ aspectRatio: {
45
+ type: "string",
46
+ description: "Output aspect ratio (e.g., '1:1', '16:9', '9:16'). Default is '1:1'.",
47
+ },
48
+ referenceImage: {
49
+ type: "string",
50
+ description: "An optional URL or data URI of a reference image to guide style."
51
+ }
52
+ },
53
+ required: ["productImages", "scenePrompt"]
54
+ }
55
+ };
56
+ const GENERATE_LOGO_TOOL = {
57
+ name: "generate_logo",
58
+ description: "Generates an AI brand logo. Requires a company name and style description. Automatically deducts credits from your CodingMantra account. Returns the generated logo directly (synchronous).",
59
+ inputSchema: {
60
+ type: "object",
61
+ properties: {
62
+ companyName: {
63
+ type: "string",
64
+ description: "The company or brand name to feature in the logo."
65
+ },
66
+ stylePrompt: {
67
+ type: "string",
68
+ description: "A detailed style description for the logo (e.g., 'minimalist flat vector logo, dark blue and gold color scheme, modern tech feel')."
69
+ },
70
+ subtitle: {
71
+ type: "string",
72
+ description: "An optional subtitle or tagline."
73
+ },
74
+ industry: {
75
+ type: "string",
76
+ description: "The industry the company operates in (e.g., 'Technology', 'Food & Beverage')."
77
+ },
78
+ ideas: {
79
+ type: "string",
80
+ description: "User-provided ideas, keywords, or concepts for the logo."
81
+ },
82
+ colors: {
83
+ type: "string",
84
+ description: "Preferred color palette description (e.g., 'blue and silver', '#FF5733 and white')."
85
+ },
86
+ aspectRatio: {
87
+ type: "string",
88
+ description: "Output aspect ratio. Default is '1:1'.",
89
+ },
90
+ modelId: {
91
+ type: "string",
92
+ description: "The image model ID. Default uses the platform default.",
93
+ },
94
+ resolution: {
95
+ type: "string",
96
+ description: "Output resolution (e.g., '1K', '2K'). Default is '1K'.",
97
+ }
98
+ },
99
+ required: ["companyName", "stylePrompt"]
100
+ }
101
+ };
102
+ const GENERATE_QR_CODE_TOOL = {
103
+ name: "generate_qr_code",
104
+ description: "Generates a QR code for a given text, URL, WiFi, email, vCard, or UPI payment. Returns a base64 encoded image data URI. Supports customization of colors, size, error correction level, and optional logo overlay.",
105
+ inputSchema: {
106
+ type: "object",
107
+ properties: {
108
+ type: {
109
+ type: "string",
110
+ enum: ["url", "text", "wifi", "email", "vcard", "upi"],
111
+ description: "The type of QR code to generate."
112
+ },
113
+ value: {
114
+ type: "string",
115
+ description: "The text or URL to encode (required for 'url' and 'text' types)."
116
+ },
117
+ size: {
118
+ type: "number",
119
+ description: "QR code size in pixels (50-2048). Default is 512."
120
+ },
121
+ fgColor: {
122
+ type: "string",
123
+ description: "Foreground color as hex (e.g., '#000000'). Default is black."
124
+ },
125
+ bgColor: {
126
+ type: "string",
127
+ description: "Background color as hex (e.g., '#FFFFFF'). Default is white."
128
+ },
129
+ level: {
130
+ type: "string",
131
+ enum: ["L", "M", "Q", "H"],
132
+ description: "Error correction level. Default is 'L'."
133
+ }
134
+ },
135
+ required: ["type", "value"]
136
+ }
137
+ };
138
+ const GENERATE_QR_CODE_SIMPLE_TOOL = {
139
+ name: "generate_qr_code_simple",
140
+ description: "Quick QR code generation from plain text or URL. Uses a simple GET-based endpoint. Returns a base64 encoded QR code image.",
141
+ inputSchema: {
142
+ type: "object",
143
+ properties: {
144
+ text: {
145
+ type: "string",
146
+ description: "The text or URL to encode in the QR code."
147
+ }
148
+ },
149
+ required: ["text"]
150
+ }
151
+ };
152
+ // ─── Tool Registration ─────────────────────────────────────────────────────────
153
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
154
+ return {
155
+ tools: [
156
+ GENERATE_PRODUCT_PHOTO_TOOL,
157
+ GENERATE_LOGO_TOOL,
158
+ GENERATE_QR_CODE_TOOL,
159
+ GENERATE_QR_CODE_SIMPLE_TOOL,
160
+ ],
161
+ };
162
+ });
163
+ // ─── Tool Execution ─────────────────────────────────────────────────────────────
164
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
165
+ try {
166
+ const { name, arguments: args } = request.params;
167
+ // ── Product Photography (synchronous) ────────────────────────────────────
168
+ if (name === 'generate_product_photo') {
169
+ const response = await apiClient('/image/product-photography', {
170
+ method: 'POST',
171
+ body: JSON.stringify(args),
172
+ });
173
+ const result = response.data;
174
+ let text = '✅ Product photo generated successfully!\n\n';
175
+ if (result?.imageUrl) {
176
+ text += `Image URL: ${result.imageUrl}`;
177
+ }
178
+ else if (result?.photoDataUri) {
179
+ text += `Image data returned (base64). Length: ${String(result.photoDataUri).length} characters.\nData URI: ${String(result.photoDataUri).substring(0, 100)}...`;
180
+ }
181
+ else if (result?.output) {
182
+ text += `Image data returned (base64). Length: ${String(result.output).length} characters.`;
183
+ }
184
+ else {
185
+ text += `Result: ${JSON.stringify(result).substring(0, 500)}`;
186
+ }
187
+ return { content: [{ type: "text", text }] };
188
+ }
189
+ // ── Logo Creator (synchronous) ───────────────────────────────────────────
190
+ if (name === 'generate_logo') {
191
+ const response = await apiClient('/image/logo-creator', {
192
+ method: 'POST',
193
+ body: JSON.stringify(args),
194
+ });
195
+ const result = response.data;
196
+ let text = '✅ Logo generated successfully!\n\n';
197
+ if (result?.imageUrl) {
198
+ text += `Image URL: ${result.imageUrl}`;
199
+ }
200
+ else if (result?.photoDataUri) {
201
+ text += `Image data returned (base64). Length: ${String(result.photoDataUri).length} characters.\nData URI: ${String(result.photoDataUri).substring(0, 100)}...`;
202
+ }
203
+ else if (result?.output) {
204
+ text += `Image data returned (base64). Length: ${String(result.output).length} characters.`;
205
+ }
206
+ else {
207
+ text += `Result: ${JSON.stringify(result).substring(0, 500)}`;
208
+ }
209
+ return { content: [{ type: "text", text }] };
210
+ }
211
+ // ── QR Code (POST, full-featured) ────────────────────────────────────────
212
+ if (name === 'generate_qr_code') {
213
+ const response = await apiClient('/qr-code/generate', {
214
+ method: 'POST',
215
+ body: JSON.stringify(args),
216
+ });
217
+ const qrDataUrl = response.data?.qrCodeDataUrl;
218
+ if (qrDataUrl) {
219
+ return {
220
+ content: [{ type: "text", text: `✅ QR Code generated successfully!\n\nData URI: ${qrDataUrl}` }],
221
+ };
222
+ }
223
+ return {
224
+ content: [{ type: "text", text: `✅ QR Code generated. Result: ${JSON.stringify(response.data).substring(0, 500)}` }],
225
+ };
226
+ }
227
+ // ── QR Code Simple (GET, path-based — legacy/backward compatible) ────────
228
+ if (name === 'generate_qr_code_simple') {
229
+ const { text } = args;
230
+ const encodedText = encodeURIComponent(text);
231
+ const apiKey = process.env.CODINGMANTRA_API_KEY;
232
+ const response = await apiClient(`/qr-code/generate-base64/${apiKey}/${encodedText}`, {
233
+ method: 'GET',
234
+ });
235
+ const qrDataUrl = response.data?.qrCodeDataUrl;
236
+ if (qrDataUrl) {
237
+ return {
238
+ content: [{ type: "text", text: `✅ QR Code generated successfully!\n\nData URI: ${qrDataUrl}` }],
239
+ };
240
+ }
241
+ return {
242
+ content: [{ type: "text", text: `✅ QR Code generated. Result: ${JSON.stringify(response.data).substring(0, 500)}` }],
243
+ };
244
+ }
245
+ throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
246
+ }
247
+ catch (error) {
248
+ return {
249
+ content: [{ type: "text", text: `❌ Error: ${error.message}` }],
250
+ isError: true,
251
+ };
252
+ }
253
+ });
254
+ // ─── Server Startup ─────────────────────────────────────────────────────────────
255
+ async function run() {
256
+ const transport = new StdioServerTransport();
257
+ await server.connect(transport);
258
+ console.error("CodingMantra MCP Server running on stdio");
259
+ }
260
+ run().catch((error) => {
261
+ console.error("Fatal error running server:", error);
262
+ process.exit(1);
263
+ });
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@codingmantra/mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "MCP Server for CodingMantra AI Tools",
5
+ "type": "module",
6
+ "bin": "build/index.js",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "start": "node build/index.js",
10
+ "dev": "tsc --watch"
11
+ },
12
+ "dependencies": {
13
+ "@modelcontextprotocol/sdk": "^1.0.1",
14
+ "dotenv": "^16.4.5",
15
+ "zod": "^3.23.8"
16
+ },
17
+ "devDependencies": {
18
+ "@types/node": "^20.0.0",
19
+ "typescript": "^5.4.5"
20
+ }
21
+ }
@@ -0,0 +1,47 @@
1
+ import dotenv from 'dotenv';
2
+ dotenv.config();
3
+
4
+ const API_KEY = process.env.CODINGMANTRA_API_KEY;
5
+ const API_BASE_URL = process.env.CODINGMANTRA_API_URL || 'https://codingmantra.com/api';
6
+
7
+ if (!API_KEY) {
8
+ console.error('CRITICAL: CODINGMANTRA_API_KEY environment variable is missing.');
9
+ console.error('Please set it in your environment or .env file before running this server.');
10
+ process.exit(1);
11
+ }
12
+
13
+ /**
14
+ * Helper to make authenticated requests to the CodingMantra API.
15
+ */
16
+ export async function apiClient(endpoint: string, options: RequestInit = {}) {
17
+ const url = `${API_BASE_URL}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;
18
+
19
+ const headers = new Headers(options.headers || {});
20
+ headers.set('Authorization', `Bearer ${API_KEY}`);
21
+
22
+ if (!(options.body instanceof FormData)) {
23
+ headers.set('Content-Type', 'application/json');
24
+ }
25
+
26
+ const response = await fetch(url, {
27
+ ...options,
28
+ headers,
29
+ });
30
+
31
+ if (!response.ok) {
32
+ let errorMsg = `API request failed with status ${response.status} ${response.statusText}`;
33
+ try {
34
+ const errorData = await response.json();
35
+ if (errorData?.error?.message) {
36
+ errorMsg += `: ${errorData.error.message}`;
37
+ } else {
38
+ errorMsg += `: ${JSON.stringify(errorData)}`;
39
+ }
40
+ } catch {
41
+ errorMsg += `: ${await response.text()}`;
42
+ }
43
+ throw new Error(errorMsg);
44
+ }
45
+
46
+ return response.json();
47
+ }
package/src/index.ts ADDED
@@ -0,0 +1,286 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
6
+ import { apiClient } from './api-client.js';
7
+
8
+ const server = new Server(
9
+ {
10
+ name: "codingmantra-mcp",
11
+ version: "0.1.0",
12
+ },
13
+ {
14
+ capabilities: {
15
+ tools: {},
16
+ },
17
+ }
18
+ );
19
+
20
+ // ─── Tool Definitions ──────────────────────────────────────────────────────────
21
+
22
+ const GENERATE_PRODUCT_PHOTO_TOOL = {
23
+ name: "generate_product_photo",
24
+ description: "Generates an AI product photography image with a specific scene prompt. Automatically deducts credits from your CodingMantra account. Returns the generated image directly (synchronous).",
25
+ inputSchema: {
26
+ type: "object" as const,
27
+ properties: {
28
+ productImages: {
29
+ type: "array",
30
+ items: {
31
+ type: "object",
32
+ properties: {
33
+ url: { type: "string", description: "Public URL of the product image." },
34
+ dataUrl: { type: "string", description: "Base64 data URI of the product image." }
35
+ }
36
+ },
37
+ description: "Array of product images. Each must have either a 'url' or 'dataUrl'. At least one required."
38
+ },
39
+ scenePrompt: {
40
+ type: "string",
41
+ description: "A detailed description of the background scene and setting for the product photo."
42
+ },
43
+ model: {
44
+ type: "string",
45
+ description: "The AI model slug (e.g., 'pro', 'standard', 'flash'). Default is 'pro'.",
46
+ },
47
+ resolution: {
48
+ type: "string",
49
+ description: "Output resolution (e.g., '1K', '2K', '4K'). Default is '1K'.",
50
+ },
51
+ aspectRatio: {
52
+ type: "string",
53
+ description: "Output aspect ratio (e.g., '1:1', '16:9', '9:16'). Default is '1:1'.",
54
+ },
55
+ referenceImage: {
56
+ type: "string",
57
+ description: "An optional URL or data URI of a reference image to guide style."
58
+ }
59
+ },
60
+ required: ["productImages", "scenePrompt"]
61
+ }
62
+ };
63
+
64
+ const GENERATE_LOGO_TOOL = {
65
+ name: "generate_logo",
66
+ description: "Generates an AI brand logo. Requires a company name and style description. Automatically deducts credits from your CodingMantra account. Returns the generated logo directly (synchronous).",
67
+ inputSchema: {
68
+ type: "object" as const,
69
+ properties: {
70
+ companyName: {
71
+ type: "string",
72
+ description: "The company or brand name to feature in the logo."
73
+ },
74
+ stylePrompt: {
75
+ type: "string",
76
+ description: "A detailed style description for the logo (e.g., 'minimalist flat vector logo, dark blue and gold color scheme, modern tech feel')."
77
+ },
78
+ subtitle: {
79
+ type: "string",
80
+ description: "An optional subtitle or tagline."
81
+ },
82
+ industry: {
83
+ type: "string",
84
+ description: "The industry the company operates in (e.g., 'Technology', 'Food & Beverage')."
85
+ },
86
+ ideas: {
87
+ type: "string",
88
+ description: "User-provided ideas, keywords, or concepts for the logo."
89
+ },
90
+ colors: {
91
+ type: "string",
92
+ description: "Preferred color palette description (e.g., 'blue and silver', '#FF5733 and white')."
93
+ },
94
+ aspectRatio: {
95
+ type: "string",
96
+ description: "Output aspect ratio. Default is '1:1'.",
97
+ },
98
+ modelId: {
99
+ type: "string",
100
+ description: "The image model ID. Default uses the platform default.",
101
+ },
102
+ resolution: {
103
+ type: "string",
104
+ description: "Output resolution (e.g., '1K', '2K'). Default is '1K'.",
105
+ }
106
+ },
107
+ required: ["companyName", "stylePrompt"]
108
+ }
109
+ };
110
+
111
+ const GENERATE_QR_CODE_TOOL = {
112
+ name: "generate_qr_code",
113
+ description: "Generates a QR code for a given text, URL, WiFi, email, vCard, or UPI payment. Returns a base64 encoded image data URI. Supports customization of colors, size, error correction level, and optional logo overlay.",
114
+ inputSchema: {
115
+ type: "object" as const,
116
+ properties: {
117
+ type: {
118
+ type: "string",
119
+ enum: ["url", "text", "wifi", "email", "vcard", "upi"],
120
+ description: "The type of QR code to generate."
121
+ },
122
+ value: {
123
+ type: "string",
124
+ description: "The text or URL to encode (required for 'url' and 'text' types)."
125
+ },
126
+ size: {
127
+ type: "number",
128
+ description: "QR code size in pixels (50-2048). Default is 512."
129
+ },
130
+ fgColor: {
131
+ type: "string",
132
+ description: "Foreground color as hex (e.g., '#000000'). Default is black."
133
+ },
134
+ bgColor: {
135
+ type: "string",
136
+ description: "Background color as hex (e.g., '#FFFFFF'). Default is white."
137
+ },
138
+ level: {
139
+ type: "string",
140
+ enum: ["L", "M", "Q", "H"],
141
+ description: "Error correction level. Default is 'L'."
142
+ }
143
+ },
144
+ required: ["type", "value"]
145
+ }
146
+ };
147
+
148
+ const GENERATE_QR_CODE_SIMPLE_TOOL = {
149
+ name: "generate_qr_code_simple",
150
+ description: "Quick QR code generation from plain text or URL. Uses a simple GET-based endpoint. Returns a base64 encoded QR code image.",
151
+ inputSchema: {
152
+ type: "object" as const,
153
+ properties: {
154
+ text: {
155
+ type: "string",
156
+ description: "The text or URL to encode in the QR code."
157
+ }
158
+ },
159
+ required: ["text"]
160
+ }
161
+ };
162
+
163
+ // ─── Tool Registration ─────────────────────────────────────────────────────────
164
+
165
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
166
+ return {
167
+ tools: [
168
+ GENERATE_PRODUCT_PHOTO_TOOL,
169
+ GENERATE_LOGO_TOOL,
170
+ GENERATE_QR_CODE_TOOL,
171
+ GENERATE_QR_CODE_SIMPLE_TOOL,
172
+ ],
173
+ };
174
+ });
175
+
176
+ // ─── Tool Execution ─────────────────────────────────────────────────────────────
177
+
178
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
179
+ try {
180
+ const { name, arguments: args } = request.params;
181
+
182
+ // ── Product Photography (synchronous) ────────────────────────────────────
183
+ if (name === 'generate_product_photo') {
184
+ const response = await apiClient('/image/product-photography', {
185
+ method: 'POST',
186
+ body: JSON.stringify(args),
187
+ });
188
+
189
+ const result = response.data;
190
+ let text = '✅ Product photo generated successfully!\n\n';
191
+
192
+ if (result?.imageUrl) {
193
+ text += `Image URL: ${result.imageUrl}`;
194
+ } else if (result?.photoDataUri) {
195
+ text += `Image data returned (base64). Length: ${String(result.photoDataUri).length} characters.\nData URI: ${String(result.photoDataUri).substring(0, 100)}...`;
196
+ } else if (result?.output) {
197
+ text += `Image data returned (base64). Length: ${String(result.output).length} characters.`;
198
+ } else {
199
+ text += `Result: ${JSON.stringify(result).substring(0, 500)}`;
200
+ }
201
+
202
+ return { content: [{ type: "text", text }] };
203
+ }
204
+
205
+ // ── Logo Creator (synchronous) ───────────────────────────────────────────
206
+ if (name === 'generate_logo') {
207
+ const response = await apiClient('/image/logo-creator', {
208
+ method: 'POST',
209
+ body: JSON.stringify(args),
210
+ });
211
+
212
+ const result = response.data;
213
+ let text = '✅ Logo generated successfully!\n\n';
214
+
215
+ if (result?.imageUrl) {
216
+ text += `Image URL: ${result.imageUrl}`;
217
+ } else if (result?.photoDataUri) {
218
+ text += `Image data returned (base64). Length: ${String(result.photoDataUri).length} characters.\nData URI: ${String(result.photoDataUri).substring(0, 100)}...`;
219
+ } else if (result?.output) {
220
+ text += `Image data returned (base64). Length: ${String(result.output).length} characters.`;
221
+ } else {
222
+ text += `Result: ${JSON.stringify(result).substring(0, 500)}`;
223
+ }
224
+
225
+ return { content: [{ type: "text", text }] };
226
+ }
227
+
228
+ // ── QR Code (POST, full-featured) ────────────────────────────────────────
229
+ if (name === 'generate_qr_code') {
230
+ const response = await apiClient('/qr-code/generate', {
231
+ method: 'POST',
232
+ body: JSON.stringify(args),
233
+ });
234
+
235
+ const qrDataUrl = response.data?.qrCodeDataUrl;
236
+ if (qrDataUrl) {
237
+ return {
238
+ content: [{ type: "text", text: `✅ QR Code generated successfully!\n\nData URI: ${qrDataUrl}` }],
239
+ };
240
+ }
241
+ return {
242
+ content: [{ type: "text", text: `✅ QR Code generated. Result: ${JSON.stringify(response.data).substring(0, 500)}` }],
243
+ };
244
+ }
245
+
246
+ // ── QR Code Simple (GET, path-based — legacy/backward compatible) ────────
247
+ if (name === 'generate_qr_code_simple') {
248
+ const { text } = args as { text: string };
249
+ const encodedText = encodeURIComponent(text);
250
+ const apiKey = process.env.CODINGMANTRA_API_KEY;
251
+ const response = await apiClient(`/qr-code/generate-base64/${apiKey}/${encodedText}`, {
252
+ method: 'GET',
253
+ });
254
+
255
+ const qrDataUrl = response.data?.qrCodeDataUrl;
256
+ if (qrDataUrl) {
257
+ return {
258
+ content: [{ type: "text", text: `✅ QR Code generated successfully!\n\nData URI: ${qrDataUrl}` }],
259
+ };
260
+ }
261
+ return {
262
+ content: [{ type: "text", text: `✅ QR Code generated. Result: ${JSON.stringify(response.data).substring(0, 500)}` }],
263
+ };
264
+ }
265
+
266
+ throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
267
+ } catch (error: any) {
268
+ return {
269
+ content: [{ type: "text", text: `❌ Error: ${error.message}` }],
270
+ isError: true,
271
+ };
272
+ }
273
+ });
274
+
275
+ // ─── Server Startup ─────────────────────────────────────────────────────────────
276
+
277
+ async function run() {
278
+ const transport = new StdioServerTransport();
279
+ await server.connect(transport);
280
+ console.error("CodingMantra MCP Server running on stdio");
281
+ }
282
+
283
+ run().catch((error) => {
284
+ console.error("Fatal error running server:", error);
285
+ process.exit(1);
286
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "./build",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true
12
+ },
13
+ "include": ["src/**/*"]
14
+ }