mcp-prompt-optimizer 1.5.0 → 2.2.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/index.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * Production-grade with Bayesian optimization, AG-UI real-time features, enhanced network resilience,
6
6
  * development mode, and complete backend alignment
7
7
  *
8
- * Version: 2.1.0 - Aligned with FastAPI Backend production-v2.1.0-bayesian
8
+ * Version: 2.2.0 - Aligned with FastAPI Backend production-v2.2.0-stable
9
9
  */
10
10
 
11
11
  const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
@@ -15,6 +15,53 @@ const https = require('https');
15
15
  const CloudApiKeyManager = require('./lib/api-key-manager');
16
16
  const packageJson = require('./package.json');
17
17
 
18
+ const API_KEYS_PREFIX = '/api/v1/api-keys';
19
+
20
+ const ENDPOINTS = {
21
+ /** Detect AI context (POST) */
22
+ DETECT_CONTEXT: '/api/v1/templates/detect-context',
23
+
24
+ /** Prompt optimization (POST) */
25
+ OPTIMIZE: '/api/v1/optimize',
26
+
27
+ /** CRUD on templates */
28
+ TEMPLATE: {
29
+ /** Create (POST) */
30
+ CREATE: '/api/v1/templates/',
31
+
32
+ /** Read (GET) */
33
+ GET: (id) => `/api/v1/templates/${id}`,
34
+
35
+ /** Update (PATCH) */
36
+ UPDATE: (id) => `/api/v1/templates/${id}`,
37
+
38
+ /** Delete (DELETE) */
39
+ DELETE: (id) => `/api/v1/templates/${id}`,
40
+ },
41
+
42
+ /**
43
+ * Search templates
44
+ * (In the current code‑base this is *not* a dedicated `/search` path –
45
+ * the original implementation appends query‑params to `/api/v1/templates/`.
46
+ * We keep the original path here so that the existing `handleSearchTemplates`
47
+ * handler does not need any change other than using the constant.
48
+ */
49
+ SEARCH_TEMPLATES: '/api/v1/templates/',
50
+
51
+ /** Quota status (GET) – note the plural “api‑keys” */
52
+ QUOTA_STATUS: `${API_KEYS_PREFIX}/quota-status`,
53
+
54
+ /** Validate API key (POST) – also under the plural router */
55
+ VALIDATE_KEY: `${API_KEYS_PREFIX}/validate`,
56
+
57
+ /** Bayesian insights (GET) */
58
+ ANALYTICS_BAYESIAN_INSIGHTS:
59
+ '/api/v1/analytics/bayesian-insights',
60
+
61
+ /** AG‑UI status (GET) */
62
+ AGUI_STATUS: '/api/v1/agui/status',
63
+ };
64
+
18
65
  class MCPPromptOptimizer {
19
66
  constructor() {
20
67
  this.server = new Server(
@@ -35,8 +82,8 @@ class MCPPromptOptimizer {
35
82
  this.requestTimeout = parseInt(process.env.OPTIMIZER_REQUEST_TIMEOUT) || 30000;
36
83
 
37
84
  // NEW: Feature flags aligned with backend
38
- this.bayesianOptimizationEnabled = process.env.ENABLE_BAYESIAN_OPTIMIZATION !== 'false';
39
- this.aguiFeatures = process.env.ENABLE_AGUI_FEATURES !== 'false';
85
+ this.bayesianOptimizationEnabled = process.env.ENABLE_BAYESIAN_OPTIMIZATION === 'true';
86
+ this.aguiFeatures = process.env.ENABLE_AGUI_FEATURES === 'true';
40
87
 
41
88
  this.setupMCPHandlers();
42
89
  }
@@ -82,6 +129,60 @@ class MCPPromptOptimizer {
82
129
  description: "📊 Check subscription status, quota usage, and account information with detailed insights and Bayesian optimization metrics",
83
130
  inputSchema: { type: "object", properties: {}, additionalProperties: false }
84
131
  },
132
+ {
133
+ name: "create_template",
134
+ description: "➕ Create a new optimization template.",
135
+ inputSchema: {
136
+ type: "object",
137
+ properties: {
138
+ title: { type: "string", description: "Title of the template" },
139
+ description: { type: "string", description: "Description of the template" },
140
+ original_prompt: { type: "string", description: "The original prompt text" },
141
+ optimized_prompt: { type: "string", description: "The optimized prompt text" },
142
+ optimization_goals: { type: "array", items: { type: "string" }, description: "Goals for this optimization (e.g., 'clarity', 'conciseness', 'creativity', 'technical_accuracy', 'analytical_depth', 'creative_enhancement')" },
143
+ confidence_score: { type: "number", description: "Confidence score of the optimization (0.0-1.0)" },
144
+ model_used: { type: "string", description: "Model used for optimization" },
145
+ optimization_tier: { type: "string", description: "Tier of optimization (e.g., rules, llm, hybrid)" },
146
+ ai_context_detected: { type: "string", description: "Detected AI context (e.g., code_generation, image_generation)" },
147
+ is_public: { type: "boolean", default: false, description: "Whether the template is public" },
148
+ tags: { type: "array", items: { type: "string" }, description: "Tags for the template" }
149
+ },
150
+ required: ["title", "original_prompt", "optimized_prompt", "confidence_score"]
151
+ }
152
+ },
153
+ {
154
+ name: "get_template",
155
+ description: "🔍 Retrieve a specific template by its ID.",
156
+ inputSchema: {
157
+ type: "object",
158
+ properties: {
159
+ template_id: { type: "string", description: "The ID of the template to retrieve" }
160
+ },
161
+ required: ["template_id"]
162
+ }
163
+ },
164
+ {
165
+ name: "update_template",
166
+ description: "✏️ Update an existing optimization template.",
167
+ inputSchema: {
168
+ type: "object",
169
+ properties: {
170
+ template_id: { type: "string", description: "The ID of the template to update" },
171
+ title: { type: "string", description: "New title for the template" },
172
+ description: { type: "string", description: "New description for the template" },
173
+ original_prompt: { type: "string", description: "New original prompt text" },
174
+ optimized_prompt: { type: "string", description: "New optimized prompt text" },
175
+ optimization_goals: { type: "array", items: { type: "string" }, description: "New optimization goals" },
176
+ confidence_score: { type: "number", description: "New confidence score (0.0-1.0)" },
177
+ model_used: { type: "string", description: "New model used for optimization" },
178
+ optimization_tier: { type: "string", description: "New tier of optimization" },
179
+ ai_context_detected: { type: "string", description: "New detected AI context" },
180
+ is_public: { type: "boolean", description: "Whether the template is public" },
181
+ tags: { type: "array", items: { type: "string" }, description: "New tags for the template" }
182
+ },
183
+ required: ["template_id"]
184
+ }
185
+ },
85
186
  {
86
187
  name: "search_templates",
87
188
  description: "🔍 Search your saved template library with AI-aware filtering, context-based search, and sophisticated template matching",
@@ -130,7 +231,21 @@ class MCPPromptOptimizer {
130
231
  }
131
232
  }
132
233
  }
133
- }
234
+ },
235
+ {
236
+ name: "detect_ai_context",
237
+ description: "🧠 Detects the AI context for a given prompt using advanced backend analysis.",
238
+ inputSchema: {
239
+ type: "object",
240
+ properties: {
241
+ prompt: {
242
+ type: "string",
243
+ description: "The prompt text for which to detect the AI context"
244
+ }
245
+ },
246
+ required: ["prompt"]
247
+ }
248
+ },
134
249
  ];
135
250
 
136
251
  // Add advanced tools if Bayesian optimization is enabled
@@ -176,6 +291,10 @@ class MCPPromptOptimizer {
176
291
  case "optimize_prompt": return await this.handleOptimizePrompt(args);
177
292
  case "get_quota_status": return await this.handleGetQuotaStatus();
178
293
  case "search_templates": return await this.handleSearchTemplates(args);
294
+ case "detect_ai_context": return await this.handleDetectAIContext(args);
295
+ case "create_template": return await this.handleCreateTemplate(args);
296
+ case "get_template": return await this.handleGetTemplate(args);
297
+ case "update_template": return await this.handleUpdateTemplate(args);
179
298
  case "get_optimization_insights": return await this.handleGetOptimizationInsights(args);
180
299
  case "get_real_time_status": return await this.handleGetRealTimeStatus();
181
300
  default: throw new Error(`Unknown tool: ${name}`);
@@ -186,95 +305,6 @@ class MCPPromptOptimizer {
186
305
  });
187
306
  }
188
307
 
189
- detectAIContext(prompt) {
190
- const p = prompt.toLowerCase();
191
-
192
- // Enhanced AI context detection with weighted scoring system - aligned with backend
193
- const contextScores = {
194
- image_generation: 0,
195
- code_generation: 0,
196
- api_automation: 0,
197
- technical_automation: 0,
198
- structured_output: 0,
199
- llm_interaction: 0,
200
- human_communication: 0
201
- };
202
-
203
- const contextKeywords = {
204
- image_generation: {
205
- "photorealistic": 3.0, "photography": 3.0, "create image": 3.0, "generate picture": 3.0, "--ar": 3.5,
206
- "gothic": 2.5, "aspect ratio": 2.5, "16:9": 2.5, "render": 2.5, "make visual": 2.5, "digital art": 2.5,
207
- "edits": 2.0, "style": 2.0, "high resolution": 2.0, "cinematic": 2.0, "draw": 2.0, "painting": 2.0, "illustration": 2.0,
208
- "image": 1.5, "visual": 1.5, "artwork": 1.5, "picture": 1.5, "design": 1.5, "sketch": 1.5, "logo": 1.5
209
- },
210
- code_generation: {
211
- "```": 3.5, "fibonacci": 3.0, "def ": 3.0, "class ": 3.0, "algorithm": 2.5, "debug": 2.5, "recursive": 2.5,
212
- "script": 2.0, "programming": 2.0, "python": 2.0, "javascript": 2.0, "function": 2.0, "c++": 2.0, "import": 2.0,
213
- "java": 1.5, "sql": 1.5, "loop": 1.5, "code": 1.5, "variable": 1.5, "return": 1.5, "if ": 1.0, "else": 1.0,
214
- "photography": -3.0, "photorealistic": -3.0, "gothic": -2.5, "style": -2.0, "cinematic": -2.0, "visual design": -2.0, "artwork": -2.0
215
- },
216
- api_automation: {
217
- "api": 3.0, "curl": 2.5, "endpoint": 2.5, "get request": 2.5, "post request": 2.5, "webhook": 2.5, "swagger": 2.5, "openapi": 2.5,
218
- "json": 2.0, "rest": 2.0, "http": 2.0, "put request": 2.0, "delete request": 2.0, "oauth": 2.0, "postman": 2.0, "bearer token": 2.0, "axios": 2.0, "api key": 2.0, "status code": 2.0,
219
- "authentication": 1.5, "request": 1.5, "response": 1.5, "xml": 1.5, "insomnia": 1.5, "fetch": 1.5, "requests": 1.5, "headers": 1.5, "payload": 1.5
220
- },
221
- technical_automation: {
222
- "automate": 3.0, "ci/cd": 3.0, "docker": 2.5, "kubernetes": 2.5, "deploy": 2.5, "deployment": 2.5, "automation": 2.5, "pipeline": 2.5, "github actions": 2.5, "shell script": 2.5,
223
- "jenkins": 2.0, "workflow": 2.0, "gitlab ci": 2.0, "azure devops": 2.0, "k8s": 2.0, "terraform": 2.0, "ansible": 2.0, "bash": 2.0, "powershell": 2.0, "cron": 2.0, "infrastructure": 2.0,
224
- "helm": 1.5, "chef": 1.5, "puppet": 1.5, "batch": 1.5, "scheduled": 1.5, "monitoring": 1.5
225
- },
226
- structured_output: {
227
- "json": 2.5, "csv": 2.5, "schema": 2.5, "format data": 2.5, "data structure": 2.5,
228
- "xml": 2.0, "yaml": 2.0, "format": 2.0, "table": 2.0, "spreadsheet": 2.0, "parse": 2.0, "serialize": 2.0, "deserialize": 2.0,
229
- "toml": 1.5, "structure": 1.5, "template": 1.5, "database": 1.5, "export": 1.5, "extract": 1.5, "transform": 1.5, "convert": 1.5, "organize": 1.5, "layout": 1.5, "report": 1.5, "dashboard": 1.5, "chart": 1.5
230
- },
231
- llm_interaction: {
232
- "analyze": 2.5, "analysis": 2.5, "evaluate": 2.0, "assess": 2.0, "research": 2.0, "compare": 2.0, "explain": 2.0, "summarize": 2.0, "pros and cons": 2.0,
233
- "study": 1.5, "contrast": 1.5, "examine": 1.5, "investigate": 1.5, "review": 1.5, "critique": 1.5, "describe": 1.5, "interpret": 1.5, "comprehensive": 1.5, "detailed": 1.5, "thorough": 1.5, "in-depth": 1.5, "advantages": 1.5, "disadvantages": 1.5, "opinion": 1.5, "perspective": 1.5, "viewpoint": 1.5
234
- },
235
- human_communication: {
236
- "email": 2.5, "message": 2.0, "letter": 2.0, "compose": 2.0, "communicate": 2.0, "correspondence": 2.0,
237
- "memo": 1.5, "write": 1.5, "draft": 1.5, "send": 1.5, "reply": 1.5, "respond": 1.5, "formal": 1.5, "informal": 1.5, "professional": 1.5, "business": 1.5, "greeting": 1.5, "introduction": 1.5, "conclusion": 1.5, "signature": 1.5, "meeting": 1.5, "appointment": 1.5, "schedule": 1.5, "call": 1.5, "conversation": 1.5, "discussion": 1.5, "chat": 1.5,
238
- "create": -0.5
239
- }
240
- };
241
-
242
- // Calculate scores based on keyword presence
243
- for (const [context, keywords] of Object.entries(contextKeywords)) {
244
- for (const [keyword, weight] of Object.entries(keywords)) {
245
- if (p.includes(keyword)) {
246
- contextScores[context] += weight;
247
- }
248
- }
249
- }
250
-
251
- // Find the highest scoring context
252
- const maxScore = Math.max(...Object.values(contextScores));
253
- if (maxScore <= 0) {
254
- return 'human_communication';
255
- }
256
-
257
- const detectedContext = Object.keys(contextScores).find(key => contextScores[key] === maxScore) || 'human_communication';
258
- return detectedContext;
259
- }
260
-
261
- enhanceGoalsForContext(originalGoals, aiContext) {
262
- const goals = new Set(originalGoals);
263
-
264
- const contextGoals = {
265
- image_generation: ['creative_enhancement', 'parameter_preservation', 'technical_accuracy'],
266
- llm_interaction: ['analytical_depth', 'context_specificity', 'token_efficiency'],
267
- technical_automation: ['technical_accuracy', 'parameter_preservation', 'specificity'],
268
- code_generation: ['syntax_clarity', 'best_practices', 'maintainability', 'technical_accuracy'],
269
- structured_output: ['format_compliance', 'data_validation', 'schema_adherence'],
270
- api_automation: ['endpoint_clarity', 'parameter_specification', 'error_handling'],
271
- human_communication: ['clarity', 'professionalism', 'engagement']
272
- };
273
-
274
- (contextGoals[aiContext] || ['clarity', 'actionability']).forEach(g => goals.add(g));
275
- return Array.from(goals);
276
- }
277
-
278
308
  generateMockOptimization(prompt, goals, aiContext, enableBayesian = false) {
279
309
  const optimized_prompt = `Enhanced for ${aiContext}: ${prompt}`;
280
310
  const baseResult = {
@@ -328,47 +358,98 @@ class MCPPromptOptimizer {
328
358
  return baseResult;
329
359
  }
330
360
 
361
+ generateMockContextDetection(prompt) {
362
+ let primary_context = 'human_communication'; // Default context
363
+ const lc = prompt.toLowerCase(); // one‑off lower‑case copy
364
+
365
+ /* 1️⃣ Code / programming – now includes `def` / `return`. */
366
+ if (lc.match(/def\b|return\b|import\b|class\b|for\b|while\b|if\b|else\b|elif\b|function\b|code\b|python|javascript|java|c\+\+/i)) {
367
+ primary_context = 'code_generation';
368
+
369
+ /* 2️⃣ Image / art – unchanged. */
370
+ } else if (lc.match(/image|generate|dall-e|midjourney/i)) {
371
+ primary_context = 'image_generation';
372
+
373
+ /* 3️⃣ Automation – unchanged. */
374
+ } else if (lc.match(/automate|script|api/i)) {
375
+ primary_context = 'technical_automation';
376
+
377
+ /* 4️⃣ LLM / analysis – newly added keyword “analyze”. */
378
+ } else if (lc.match(/analyze|explain|evaluate|summary|research|paper|analysis|interpret|discussion|assessment|compare|contrast/i)) {
379
+ primary_context = 'llm_interaction';
380
+ }
381
+
382
+ return {
383
+ primary_context: primary_context,
384
+ confidence: 0.75,
385
+ secondary_contexts: ['llm_interaction'],
386
+ detected_parameters: [],
387
+ mock_mode: true,
388
+ reason: 'Running in development/fallback mode.'
389
+ };
390
+ }
391
+
331
392
  async handleOptimizePrompt(args) {
332
393
  if (!args.prompt) throw new Error('Prompt is required');
333
394
 
334
- const detectedContext = args.ai_context || this.detectAIContext(args.prompt);
335
- const enhancedGoals = this.enhanceGoalsForContext(args.goals || ['clarity'], detectedContext);
336
- const enableBayesian = args.enable_bayesian !== false && this.bayesianOptimizationEnabled;
337
-
338
395
  const manager = new CloudApiKeyManager(this.apiKey, { developmentMode: this.developmentMode });
339
396
 
340
397
  try {
341
398
  const validation = await manager.validateApiKey();
342
399
 
343
400
  if (validation.mock_mode || this.developmentMode) {
344
- const mockResult = this.generateMockOptimization(args.prompt, enhancedGoals, detectedContext, enableBayesian);
345
- const formatted = this.formatOptimizationResult(mockResult, { detectedContext, enableBayesian });
401
+ // In mock/dev mode, we still need a context for mock generation
402
+ const mockContext = args.ai_context || 'human_communication';
403
+ const mockGoals = args.goals || ['clarity'];
404
+ const mockEnableBayesian = args.enable_bayesian !== false && this.bayesianOptimizationEnabled;
405
+ const mockResult = this.generateMockOptimization(args.prompt, mockGoals, mockContext, mockEnableBayesian);
406
+ const formatted = this.formatOptimizationResult(mockResult, { detectedContext: mockContext, enableBayesian: mockEnableBayesian });
346
407
  return { content: [{ type: "text", text: formatted }] };
347
408
  }
348
409
 
349
- // Use the correct backend endpoint
350
- const result = await this.callBackendAPI('/api/v1/mcp/optimize', {
410
+ // 1. Detect AI Context from backend
411
+ let detectedContext = args.ai_context;
412
+ if (!detectedContext) {
413
+ try {
414
+ const contextDetectionResult = await this.callBackendAPI(ENDPOINTS.DETECT_CONTEXT, { prompt: args.prompt });
415
+ detectedContext = contextDetectionResult.primary_context;
416
+ console.error(`Detected AI Context from backend: ${detectedContext}`);
417
+ } catch (contextError) {
418
+ console.error(`Failed to detect AI context from backend, falling back to default: ${contextError.message}`);
419
+ detectedContext = 'human_communication'; // Fallback
420
+ }
421
+ }
422
+
423
+ // 2. Call the main optimization endpoint
424
+ const enableBayesian = args.enable_bayesian !== false && this.bayesianOptimizationEnabled;
425
+ const optimizationPayload = {
351
426
  prompt: args.prompt,
352
- goals: enhancedGoals,
353
- ai_context: detectedContext,
427
+ goals: args.goals || ['clarity'], // Pass original goals, backend will enhance
428
+ context: {
429
+ ai_context: detectedContext
430
+ },
431
+ enable_bayesian: enableBayesian,
354
432
  metadata: {
355
- enable_bayesian: enableBayesian,
356
433
  mcp_version: packageJson.version,
357
434
  feature_flags: {
358
435
  bayesian_optimization: this.bayesianOptimizationEnabled,
359
436
  agui_features: this.aguiFeatures
360
437
  }
361
438
  }
362
- });
439
+ };
440
+
441
+ const result = await this.callBackendAPI(ENDPOINTS.OPTIMIZE, optimizationPayload);
363
442
 
364
443
  return { content: [{ type: "text", text: this.formatOptimizationResult(result, { detectedContext, enableBayesian }) }] };
365
444
 
366
445
  } catch (error) {
367
- if (error.message.includes('Network') || error.message.includes('DNS') || error.message.includes('timeout')) {
368
- const fallbackResult = this.generateMockOptimization(args.prompt, enhancedGoals, detectedContext, enableBayesian);
446
+ if (error.message.includes('Network') || error.message.includes('DNS') || error.message.includes('timeout') || error.message.includes('Connection')) {
447
+ const fallbackContext = args.ai_context || 'human_communication';
448
+ const fallbackEnableBayesian = args.enable_bayesian !== false && this.bayesianOptimizationEnabled;
449
+ const fallbackResult = this.generateMockOptimization(args.prompt, args.goals || ['clarity'], fallbackContext, fallbackEnableBayesian);
369
450
  fallbackResult.fallback_mode = true;
370
451
  fallbackResult.error_reason = error.message;
371
- const formatted = this.formatOptimizationResult(fallbackResult, { detectedContext, enableBayesian });
452
+ const formatted = this.formatOptimizationResult(fallbackResult, { detectedContext: fallbackContext, enableBayesian: fallbackEnableBayesian });
372
453
  return { content: [{ type: "text", text: formatted }] };
373
454
  }
374
455
  throw new Error(`Optimization failed: ${error.message}`);
@@ -396,7 +477,7 @@ class MCPPromptOptimizer {
396
477
  if (args.complexity_level) params.append('complexity_level', args.complexity_level);
397
478
  if (args.optimization_strategy) params.append('optimization_strategy', args.optimization_strategy);
398
479
 
399
- const endpoint = `/api/v1/templates/?${params.toString()}`;
480
+ const endpoint = `${ENDPOINTS.SEARCH_TEMPLATES}?${params.toString()}`;
400
481
  const result = await this.callBackendAPI(endpoint, null, 'GET');
401
482
 
402
483
  const searchResult = {
@@ -432,7 +513,7 @@ class MCPPromptOptimizer {
432
513
 
433
514
  try {
434
515
  // Try to get insights from backend
435
- const endpoint = `/api/v1/analytics/bayesian-insights?depth=${args.analysis_depth || 'detailed'}&recommendations=${args.include_recommendations !== false}`;
516
+ const endpoint = `${ENDPOINTS.ANALYTICS_BAYESIAN_INSIGHTS}?depth=${args.analysis_depth || 'detailed'}&recommendations=${args.include_recommendations !== false}`;
436
517
  const result = await this.callBackendAPI(endpoint, null, 'GET');
437
518
 
438
519
  return { content: [{ type: "text", text: this.formatOptimizationInsights(result) }] };
@@ -472,8 +553,7 @@ class MCPPromptOptimizer {
472
553
  }
473
554
 
474
555
  try {
475
- const endpoint = `/api/v1/agui/status`;
476
- const result = await this.callBackendAPI(endpoint, null, 'GET');
556
+ const result = await this.callBackendAPI(ENDPOINTS.AGUI_STATUS, null, 'GET');
477
557
 
478
558
  return { content: [{ type: "text", text: this.formatRealTimeStatus(result) }] };
479
559
 
@@ -497,9 +577,110 @@ class MCPPromptOptimizer {
497
577
  }
498
578
  }
499
579
 
580
+ async handleDetectAIContext(args) {
581
+ if (!args.prompt) throw new Error('Prompt is required');
582
+
583
+ const formatResult = (result) => {
584
+ let output = `# 🧠 AI Context Detection Result\n\n`;
585
+ output += `**Primary Context:** ${result.primary_context}\n`;
586
+ output += `**Confidence:** ${(result.confidence * 100).toFixed(1)}%\n`;
587
+ if (result.secondary_contexts && result.secondary_contexts.length > 0) {
588
+ output += `**Secondary Contexts:** ${result.secondary_contexts.join(', ')}\n`;
589
+ }
590
+
591
+ const detections = result.detected_parameters ?? [];
592
+ const safeDetections = detections.filter(d => d && d.name);
593
+
594
+ if (safeDetections.length > 0) {
595
+ output += `**Detected Parameters:** ${safeDetections.map(d => d.name).join(', ')}\n`;
596
+ }
597
+
598
+ if (result.mock_mode) {
599
+ output += `\n⚠️ **Fallback Mode Active:** Using mock data due to development mode or network issues.\n`;
600
+ }
601
+ return { content: [{ type: "text", text: output }] };
602
+ };
603
+
604
+ try {
605
+ const manager = new CloudApiKeyManager(this.apiKey, { developmentMode: this.developmentMode });
606
+ const validation = await manager.validateApiKey();
607
+
608
+ if (validation.mock_mode || this.developmentMode) {
609
+ const mockResult = this.generateMockContextDetection(args.prompt);
610
+ return formatResult(mockResult);
611
+ }
612
+
613
+ const result = await this.callBackendAPI(ENDPOINTS.DETECT_CONTEXT, { prompt: args.prompt });
614
+ return formatResult(result);
615
+
616
+ } catch (error) {
617
+ // Fallback for ANY error during the process (missing key, network, etc.)
618
+ const fallbackResult = this.generateMockContextDetection(args.prompt);
619
+ return formatResult(fallbackResult);
620
+ }
621
+ }
622
+
623
+ async handleCreateTemplate(args) {
624
+ try {
625
+ const result = await this.callBackendAPI(ENDPOINTS.TEMPLATE.CREATE, args);
626
+ let output = `# ✅ Template Created Successfully!\n\n`;
627
+ output += `**Title:** ${result.title}\n`;
628
+ output += `**ID:** \`${result.id}\`\n`;
629
+ output += `**Confidence Score:** ${(result.confidence_score * 100).toFixed(1)}%\n`;
630
+ output += `**AI Context:** ${result.ai_context_detected || 'N/A'}\n`;
631
+ output += `**Public:** ${result.is_public ? 'Yes' : 'No'}\n`;
632
+ output += `\n**Optimized Prompt Preview:**\n\`\`\`\n${result.optimized_prompt.substring(0, 150)}...\n\`\`\`\n`;
633
+ return { content: [{ type: "text", text: output }] };
634
+ } catch (error) {
635
+ throw new Error(`Failed to create template: ${error.message}`);
636
+ }
637
+ }
638
+
639
+ async handleGetTemplate(args) {
640
+ if (!args.template_id) throw new Error('Template ID is required');
641
+ try {
642
+ const result = await this.callBackendAPI(ENDPOINTS.TEMPLATE.GET(args.template_id), null, 'GET');
643
+ let output = `# 📄 Template Details\n\n`;
644
+ output += `**Title:** ${result.title}\n`;
645
+ output += `**ID:** \`${result.id}\`\n`;
646
+ output += `**Description:** ${result.description || 'N/A'}\n`;
647
+ output += `**AI Context:** ${result.ai_context_detected || 'N/A'}\n`;
648
+ output += `**Confidence Score:** ${(result.confidence_score * 100).toFixed(1)}%\n`;
649
+ output += `**Public:** ${result.is_public ? 'Yes' : 'No'}\n`;
650
+ output += `**Tags:** ${result.tags ? result.tags.join(', ') : 'None'}\n\n`;
651
+ output += `**Original Prompt:**\n\`\`\`\n${result.original_prompt}\n\`\`\`\n\n`;
652
+ output += `**Optimized Prompt:**\n\`\`\`\n${result.optimized_prompt}\n\`\`\`\n`;
653
+ return { content: [{ type: "text", text: output }] };
654
+ } catch (error) {
655
+ throw new Error(`Failed to retrieve template: ${error.message}`);
656
+ }
657
+ }
658
+
659
+ async handleUpdateTemplate(args) {
660
+ if (!args.template_id) throw new Error('Template ID is required');
661
+ try {
662
+ const { template_id, ...updateData } = args;
663
+ // Filter out undefined values so we only send fields that are being updated
664
+ Object.keys(updateData).forEach(key => updateData[key] === undefined && delete updateData[key]);
665
+
666
+ const result = await this.callBackendAPI(ENDPOINTS.TEMPLATE.UPDATE(template_id), updateData, 'PATCH'); // PATCH is better for partial updates
667
+ let output = `# ✅ Template Updated Successfully!\n\n`;
668
+ output += `**ID:** \`${result.id}\`\n`;
669
+ output += `**Title:** ${result.title}\n\n`;
670
+ output += `Use 'get_template' with the ID to see the full updated template.`;
671
+ return { content: [{ type: "text", text: output }] };
672
+ } catch (error) {
673
+ throw new Error(`Failed to update template: ${error.message}`);
674
+ }
675
+ }
676
+
677
+ async _buildUrl(path) {
678
+ return `${this.backendUrl}${path}`;
679
+ }
680
+
500
681
  async callBackendAPI(endpoint, data, method = 'POST') {
501
682
  return new Promise((resolve, reject) => {
502
- const url = `${this.backendUrl}${endpoint}`;
683
+ const url = this._buildUrl(endpoint);
503
684
 
504
685
  const options = {
505
686
  method: method,
@@ -561,8 +742,6 @@ class MCPPromptOptimizer {
561
742
  reject(new Error('Request timeout - backend may be unavailable'));
562
743
  });
563
744
 
564
- req.setTimeout(this.requestTimeout);
565
-
566
745
  if (method !== 'GET' && data) {
567
746
  req.write(JSON.stringify(data));
568
747
  }
@@ -588,10 +767,12 @@ class MCPPromptOptimizer {
588
767
 
589
768
  if (result.optimization_insights) {
590
769
  const metrics = result.optimization_insights.improvement_metrics;
591
- output += `\n📊 **Optimization Insights**\n`;
592
- if (metrics.clarity_improvement) output += `- Clarity: +${(metrics.clarity_improvement * 100).toFixed(1)}%\n`;
593
- if (metrics.specificity_improvement) output += `- Specificity: +${(metrics.specificity_improvement * 100).toFixed(1)}%\n`;
594
- if (metrics.context_alignment) output += `- Context Alignment: +${(metrics.context_alignment * 100).toFixed(1)}%\n`;
770
+ if (metrics) {
771
+ output += `\n📊 **Optimization Insights**\n`;
772
+ if (metrics.clarity_improvement) output += `- Clarity: +${(metrics.clarity_improvement * 100).toFixed(1)}%\n`;
773
+ if (metrics.specificity_improvement) output += `- Specificity: +${(metrics.specificity_improvement * 100).toFixed(1)}%\n`;
774
+ if (metrics.context_alignment) output += `- Context Alignment: +${(metrics.context_alignment * 100).toFixed(1)}%\n`;
775
+ }
595
776
 
596
777
  if (result.optimization_insights.recommendations?.length) {
597
778
  output += `\n💡 **Recommendations:**\n`;
@@ -826,9 +1007,9 @@ class MCPPromptOptimizer {
826
1007
  }
827
1008
 
828
1009
  async function startValidatedMCPServer() {
829
- console.error(`🚀 MCP Prompt Optimizer - Professional Cloud Server v${packageJson.version}\n`);
830
- console.error(`🧠 Bayesian Optimization: ${process.env.ENABLE_BAYESIAN_OPTIMIZATION !== 'false' ? 'Enabled' : 'Disabled'}`);
831
- console.error(`⚡ AG-UI Features: ${process.env.ENABLE_AGUI_FEATURES !== 'false' ? 'Enabled' : 'Disabled'}\n`);
1010
+ console.log(`🚀 MCP Prompt Optimizer - Professional Cloud Server v${packageJson.version}\n`);
1011
+ console.log(`🧠 Bayesian Optimization: ${process.env.ENABLE_BAYESIAN_OPTIMIZATION === 'true' ? 'Enabled' : 'Disabled'}`);
1012
+ console.log(`⚡ AG-UI Features: ${process.env.ENABLE_AGUI_FEATURES === 'true' ? 'Enabled' : 'Disabled'}\n`);
832
1013
 
833
1014
  try {
834
1015
  const apiKey = process.env.OPTIMIZER_API_KEY;
@@ -838,24 +1019,24 @@ async function startValidatedMCPServer() {
838
1019
  }
839
1020
 
840
1021
  const manager = new CloudApiKeyManager(apiKey, { developmentMode: process.env.OPTIMIZER_DEV_MODE === 'true' });
841
- console.error('🔧 Validating API key...\n');
1022
+ console.log('🔧 Validating API key...\n');
842
1023
  const validation = await manager.validateAndPrepare();
843
1024
 
844
- console.error('🔧 Starting MCP server...\n');
1025
+ console.log('🔧 Starting MCP server...\n');
845
1026
  const mcpServer = new MCPPromptOptimizer();
846
- console.error('✅ MCP server ready for connections');
1027
+ console.log('✅ MCP server ready for connections');
847
1028
 
848
1029
  // Enhanced status display
849
1030
  const quotaDisplay = validation.quotaStatus.unlimited ?
850
1031
  'Unlimited' :
851
1032
  `${validation.quotaStatus.remaining}/${validation.quotaStatus.limit} remaining`;
852
1033
 
853
- console.error(`📊 Plan: ${validation.tier} | Quota: ${quotaDisplay}`);
1034
+ console.log(`📊 Plan: ${validation.tier} | Quota: ${quotaDisplay}`);
854
1035
 
855
- if (validation.mode.mock) console.error('🎭 Running in mock mode');
856
- if (validation.mode.development) console.error('⚙️ Development mode active');
857
- if (validation.mode.fallback) console.error('🔄 Fallback mode active');
858
- if (validation.mode.offline) console.error('📱 Offline mode active');
1036
+ if (validation.mode.mock) console.log('🎭 Running in mock mode');
1037
+ if (validation.mode.development) console.log('⚙️ Development mode active');
1038
+ if (validation.mode.fallback) console.log('🔄 Fallback mode active');
1039
+ if (validation.mode.offline) console.log('📱 Offline mode active');
859
1040
 
860
1041
  await mcpServer.run();
861
1042
  } catch (error) {