@ema.co/mcp-toolkit 2026.1.26 → 2026.1.27-10

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.

Potentially problematic release.


This version of @ema.co/mcp-toolkit might be problematic. Click here for more details.

Files changed (45) hide show
  1. package/dist/mcp/handlers/action/index.js +17 -20
  2. package/dist/mcp/handlers/data/index.js +75 -6
  3. package/dist/mcp/handlers/deprecation.js +50 -0
  4. package/dist/mcp/handlers/env/index.js +3 -3
  5. package/dist/mcp/handlers/knowledge/index.js +44 -237
  6. package/dist/mcp/handlers/persona/create.js +63 -18
  7. package/dist/mcp/handlers/persona/index.js +9 -10
  8. package/dist/mcp/handlers/persona/update.js +6 -3
  9. package/dist/mcp/handlers/reference/index.js +15 -2
  10. package/dist/mcp/handlers/sync/index.js +3 -18
  11. package/dist/mcp/handlers/workflow/analyze.js +53 -105
  12. package/dist/mcp/handlers/workflow/deploy.js +160 -1
  13. package/dist/mcp/handlers/workflow/generate.js +8 -28
  14. package/dist/mcp/handlers/workflow/index.js +258 -85
  15. package/dist/mcp/handlers/workflow/modify.js +69 -26
  16. package/dist/mcp/handlers/workflow/optimize.js +22 -108
  17. package/dist/mcp/handlers/workflow/utils.js +0 -102
  18. package/dist/mcp/handlers-consolidated.js +15 -38
  19. package/dist/mcp/prompts.js +82 -44
  20. package/dist/mcp/resources.js +335 -3
  21. package/dist/mcp/server.js +242 -457
  22. package/dist/mcp/tools.js +44 -61
  23. package/dist/sdk/action-schema-parser.js +11 -5
  24. package/dist/sdk/client.js +81 -25
  25. package/dist/sdk/ema-client.js +11 -0
  26. package/dist/sdk/generated/deprecated-actions.js +171 -0
  27. package/dist/sdk/guidance.js +58 -35
  28. package/dist/sdk/index.js +8 -7
  29. package/dist/sdk/knowledge.js +216 -1932
  30. package/dist/sdk/quality-gates.js +60 -336
  31. package/dist/sdk/validation-rules.js +33 -0
  32. package/dist/sdk/workflow-fixer.js +29 -360
  33. package/dist/sdk/workflow-generator.js +2 -1
  34. package/dist/sdk/workflow-intent.js +43 -3
  35. package/dist/sdk/workflow-transformer.js +0 -342
  36. package/docs/dashboard-operations.md +35 -0
  37. package/docs/ema-user-guide.md +66 -0
  38. package/docs/mcp-tools-guide.md +74 -45
  39. package/package.json +2 -2
  40. package/dist/mcp/handlers/persona/analyze.js +0 -275
  41. package/dist/mcp/handlers/persona/compare.js +0 -32
  42. package/dist/mcp/handlers/workflow/compile.js +0 -39
  43. package/docs/DEBUG-ANALYSIS-unused-category-type-mismatch.md +0 -481
  44. package/docs/TODO-fix-analyzer-and-modify.md +0 -182
  45. package/resources/action-schema.json +0 -5678
@@ -27,6 +27,22 @@ const packageJsonPath = join(__dirname, "..", "..", "package.json");
27
27
  const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
28
28
  export const TOOLKIT_NAME = packageJson.name;
29
29
  export const TOOLKIT_VERSION = packageJson.version;
30
+ // Try to read git commit for build info (optional, doesn't fail if not available)
31
+ import { execSync } from "node:child_process";
32
+ function getGitCommit() {
33
+ try {
34
+ const commit = execSync("git rev-parse --short HEAD", {
35
+ cwd: join(__dirname, "..", ".."),
36
+ encoding: "utf-8",
37
+ stdio: ["pipe", "pipe", "pipe"]
38
+ }).trim();
39
+ return commit;
40
+ }
41
+ catch {
42
+ return undefined;
43
+ }
44
+ }
45
+ export const TOOLKIT_COMMIT = getGitCommit();
30
46
  // Prompts, Resources, and Guidance
31
47
  import { PromptRegistry, isPromptError } from "./prompts.js";
32
48
  import { ResourceRegistry, isResourceError } from "./resources.js";
@@ -42,8 +58,8 @@ import { getToolkitRoot } from "../sdk/paths.js";
42
58
  import { SYNC_METADATA_KEY } from "../sdk/models.js";
43
59
  // Auto Builder Knowledge
44
60
  import { AGENT_CATALOG, WIDGET_CATALOG, WORKFLOW_PATTERNS, QUALIFYING_QUESTIONS, PLATFORM_CONCEPTS, WORKFLOW_EXECUTION_MODEL, COMMON_MISTAKES, DEBUG_CHECKLIST, GUIDANCE_TOPICS, PROJECT_TYPES, getAgentsByCategory, getAgentByName, getWidgetsForPersonaType, checkTypeCompatibility, getQualifyingQuestionsByCategory, getConceptByTerm, suggestAgentsForUseCase, validateWorkflowPrompt,
45
- // Workflow Analysis
46
- analyzeWorkflow, detectWorkflowIssues, validateWorkflowConnections, suggestWorkflowFixes, } from "../sdk/knowledge.js";
61
+ // Workflow Data (LLM does analysis with rules from ema://rules/*)
62
+ validateWorkflowConnections, parseWorkflowDef, } from "../sdk/knowledge.js";
47
63
  // Template fallbacks (generated from protos, used when API unavailable)
48
64
  import { getTemplateFallback, getTemplateFieldDocs, VOICE_TEMPLATE_FALLBACK } from "../sdk/generated/template-fallbacks.js";
49
65
  // Workflow Compiler (Template-driven)
@@ -92,6 +108,9 @@ function summarizeWorkflow(workflowDef) {
92
108
  if (nodeNames.length > 0) {
93
109
  lines.push(`\nNodes: ${nodeNames.slice(0, 20).join(", ")}${nodeNames.length > 20 ? "..." : ""}`);
94
110
  }
111
+ // TODO: This uses keyword matching to detect workflow features.
112
+ // Consider using ActionRegistry metadata instead for consistency with LLM-driven architecture.
113
+ // Current approach is acceptable for Auto Builder descriptions but could be improved.
95
114
  // Check for categorizer (indicates intent routing)
96
115
  const hasCategorizer = Array.from(actionTypes.keys()).some(t => t.includes("categorizer"));
97
116
  if (hasCategorizer) {
@@ -111,8 +130,19 @@ function summarizeWorkflow(workflowDef) {
111
130
  * Apply automatic fixes to a workflow based on detected issues.
112
131
  * This function attempts to fix common issues like missing WORKFLOW_OUTPUT,
113
132
  * wrong input sources, and other structural problems.
133
+ *
134
+ * @deprecated This function violates the LLM-driven architecture principle.
135
+ * MCP should not auto-fix workflows - it should return suggestions for the Agent to apply.
136
+ * Per CLAUDE.md: "Auto-fix issues | ❌ FORBIDDEN | ✅ Proposes fixes"
137
+ *
138
+ * This function will be removed in a future version. Instead:
139
+ * 1. Use analyzeWorkflow() to detect issues
140
+ * 2. Return issues as suggestions to the Agent
141
+ * 3. Let Agent apply fixes via persona(id="...", operations=[...])
114
142
  */
115
143
  function applyWorkflowFixes(workflowDef, issues, persona) {
144
+ // Log deprecation warning
145
+ console.warn("[DEPRECATED] applyWorkflowFixes() called - this function violates LLM-driven architecture and will be removed");
116
146
  // Deep clone the workflow to avoid mutating the original
117
147
  const fixedWorkflow = JSON.parse(JSON.stringify(workflowDef));
118
148
  const appliedFixes = [];
@@ -1909,30 +1939,30 @@ const toolHandlers = {
1909
1939
  // Track fixes applied
1910
1940
  const appliedFixes = [];
1911
1941
  let fixAttempted = false;
1912
- // Validate workflow if requested and provided
1913
- let validationResults = { valid: true, issues: [] };
1942
+ // Validation is now done by backend when workflow is deployed
1943
+ // LLM should use ema://rules/* for pre-validation guidance
1944
+ const validationResults = { valid: true, issues: [] };
1914
1945
  if (validateFirst && workflowDef) {
1915
- const analysis = analyzeWorkflow(workflowDef, {
1916
- persona_id: personaId,
1917
- persona_name: persona.name ?? "Unknown"
1918
- });
1919
- if (!analysis.validation_passed) {
1920
- validationResults.valid = false;
1921
- validationResults.issues = analysis.issues ?? [];
1922
- // Auto-fix if enabled
1923
- if (autoFix && validationResults.issues.length > 0) {
1924
- fixAttempted = true;
1925
- const fixResult = applyWorkflowFixes(workflowDef, validationResults.issues, persona);
1926
- workflowDef = fixResult.fixedWorkflow;
1927
- appliedFixes.push(...fixResult.appliedFixes);
1928
- // Re-validate after fixes
1929
- const reAnalysis = analyzeWorkflow(workflowDef, {
1930
- persona_id: personaId,
1931
- persona_name: persona.name ?? "Unknown"
1932
- });
1933
- validationResults.valid = reAnalysis.validation_passed;
1934
- validationResults.issues = reAnalysis.issues ?? [];
1935
- }
1946
+ // DEPRECATED: MCP no longer pre-validates workflows
1947
+ // Backend validation happens on deploy
1948
+ // LLM uses ema://rules/anti-patterns for analysis
1949
+ console.warn("[DEPRECATED] validateFirst is deprecated - backend validates on deploy");
1950
+ if (autoFix) {
1951
+ // Auto-fix is removed - return guidance for LLM
1952
+ return {
1953
+ environment: client["env"].name,
1954
+ success: false,
1955
+ persona_id: personaId,
1956
+ persona_name: persona.name,
1957
+ _deprecation_notice: "autoFix is deprecated. Use LLM analysis with ema://rules/* instead.",
1958
+ _guidance: [
1959
+ "1. Fetch ema://rules/anti-patterns",
1960
+ "2. Analyze workflow against rules",
1961
+ "3. Make structured modifications",
1962
+ "4. Deploy via workflow(mode='deploy')",
1963
+ ],
1964
+ applied_fixes: [],
1965
+ };
1936
1966
  }
1937
1967
  }
1938
1968
  // If validation failed and not forcing, return the issues
@@ -2124,152 +2154,27 @@ const toolHandlers = {
2124
2154
  message: "This AI Employee has no workflow. Use prompt parameter to generate one: optimize_workflow(persona_id=\"...\", prompt=\"description of what it should do\")",
2125
2155
  };
2126
2156
  }
2127
- // Step 2: Analyze workflow for issues
2128
- const analysis = analyzeWorkflow(workflowDef, {
2129
- persona_id: personaId,
2130
- persona_name: persona.name ?? "Unknown",
2131
- });
2132
- const issues = analysis.issues ?? [];
2133
- const criticalIssues = issues.filter(i => i.severity === "critical");
2134
- // If no issues, workflow is healthy
2135
- if (issues.length === 0) {
2136
- const result = {
2137
- success: true,
2138
- persona: persona.name,
2139
- status: "✅ Workflow is healthy",
2140
- nodes: analysis.summary?.total_nodes ?? 0,
2141
- message: "No issues found - workflow is already optimized!",
2142
- };
2143
- // If enhancement prompt was provided, note that it can't be auto-applied
2144
- if (enhancementPrompt) {
2145
- result.enhancement_note = `Enhancement requested: "${enhancementPrompt}". Since there are no issues to fix, use the Ema UI Auto Builder to make this change manually.`;
2146
- }
2147
- return result;
2148
- }
2149
- // Step 3: Apply fixes
2150
- let fixedWorkflow = workflowDef;
2151
- const appliedFixes = [];
2152
- if (issues.length > 0) {
2153
- const fixResult = applyWorkflowFixes(workflowDef, issues, persona);
2154
- fixedWorkflow = fixResult.fixedWorkflow;
2155
- appliedFixes.push(...fixResult.appliedFixes);
2156
- }
2157
- // Re-analyze after fixes
2158
- const postFixAnalysis = analyzeWorkflow(fixedWorkflow, {
2159
- persona_id: personaId,
2160
- persona_name: persona.name ?? "Unknown",
2161
- });
2162
- const remainingIssues = postFixAnalysis.issues ?? [];
2163
- const remainingCritical = remainingIssues.filter(i => i.severity === "critical");
2164
- // If preview mode, show what would happen without deploying
2165
- if (preview) {
2166
- const fixedCount = appliedFixes.filter(f => f.applied).length;
2167
- const failedCount = appliedFixes.filter(f => !f.applied).length;
2168
- const previewResult = {
2169
- success: true,
2170
- persona: persona.name,
2171
- status: "📋 Preview - Fixes Available",
2172
- mode: "optimize",
2173
- nodes: fixedWorkflow.actions?.length ?? 0,
2174
- found_issues: issues.length,
2175
- can_fix: fixedCount,
2176
- cannot_fix: failedCount,
2177
- ready_to_deploy: remainingCritical.length === 0,
2178
- issues: issues.length > 0 ? issues.map(i => `${i.severity === "critical" ? "❌" : "⚠️"} ${i.type}: ${i.reason}`) : ["No issues found"],
2179
- fixes: appliedFixes.length > 0 ? appliedFixes.map(f => `${f.applied ? "✅" : "❌"} ${f.description}`) : [],
2180
- next_step: remainingCritical.length === 0
2181
- ? `Run workflow(persona_id="${personaId}", mode="optimize") without preview to deploy fixes.`
2182
- : `${remainingCritical.length} critical issue(s) need manual fix in Ema UI.`,
2183
- };
2184
- if (enhancementPrompt) {
2185
- previewResult.enhancement_note = `Enhancement "${enhancementPrompt}" noted. Auto-fixes will be applied first; use Ema UI Auto Builder for the enhancement.`;
2186
- }
2187
- return previewResult;
2188
- }
2189
- // Step 4: Deploy if no critical issues remain
2190
- if (remainingCritical.length > 0) {
2191
- return {
2192
- success: false,
2193
- persona: persona.name,
2194
- status: "❌ Cannot auto-fix",
2195
- fixed: appliedFixes.filter(f => f.applied).length,
2196
- remaining_critical: remainingCritical.length,
2197
- manual_fixes_needed: remainingCritical.map(i => ({
2198
- problem: i.type,
2199
- details: i.reason,
2200
- fix: i.recommendation,
2201
- })),
2202
- message: `${remainingCritical.length} issue(s) need manual fix in the Ema UI Auto Builder.`,
2203
- };
2204
- }
2205
- // Sanitize workflow before deployment
2206
- // Fix enumTypes - check nested structure
2207
- const enumTypes = fixedWorkflow.enumTypes;
2208
- if (Array.isArray(enumTypes)) {
2209
- const validEnumTypes = enumTypes.filter(e => {
2210
- const outerName = e.name;
2211
- const innerName = outerName?.name;
2212
- const actualName = innerName?.name;
2213
- return typeof actualName === "string" && actualName.trim().length > 0;
2214
- });
2215
- if (validEnumTypes.length > 0) {
2216
- fixedWorkflow.enumTypes = validEnumTypes;
2217
- }
2218
- else {
2219
- delete fixedWorkflow.enumTypes;
2220
- }
2221
- }
2222
- // Copy workflowName from existing
2223
- const existingWfName = workflowDef.workflowName;
2224
- if (existingWfName) {
2225
- fixedWorkflow.workflowName = JSON.parse(JSON.stringify(existingWfName));
2226
- }
2227
- // Sanitize existing proto_config widgets
2228
- const mergedProtoConfig = mergeProtoConfig(persona.proto_config, undefined);
2229
- // Build and send request
2230
- const req = {
2157
+ // DEPRECATED: MCP no longer pre-analyzes workflows
2158
+ // LLM should use ema://rules/* for analysis
2159
+ console.warn("[DEPRECATED] optimize_workflow tool is deprecated - use LLM analysis with ema://rules/*");
2160
+ const nodes = parseWorkflowDef(workflowDef);
2161
+ return {
2162
+ success: true,
2163
+ persona: persona?.name ?? "Unknown",
2231
2164
  persona_id: personaId,
2232
- proto_config: mergedProtoConfig,
2233
- workflow: fixedWorkflow,
2165
+ status: "DEPRECATED - use LLM analysis",
2166
+ node_count: nodes.length,
2167
+ workflow_def: workflowDef,
2168
+ _deprecation_notice: {
2169
+ message: "optimize_workflow is deprecated. MCP does not pre-compute issues.",
2170
+ new_workflow: [
2171
+ "1. Fetch rules: ema://rules/anti-patterns, ema://rules/optimizations",
2172
+ "2. Apply rules to find issues (LLM does this, not MCP)",
2173
+ "3. Make structured modifications based on your analysis",
2174
+ "4. Deploy via workflow(mode='deploy', persona_id='...', workflow_def={...})",
2175
+ ],
2176
+ },
2234
2177
  };
2235
- const actionsArr = fixedWorkflow.actions ?? [];
2236
- try {
2237
- await client.updateAiEmployee(req);
2238
- const fixedCount = appliedFixes.filter(f => f.applied).length;
2239
- const deployResult = {
2240
- success: true,
2241
- persona: persona.name,
2242
- status: "✅ Optimized & Deployed",
2243
- mode: "optimized",
2244
- issues_found: issues.length,
2245
- issues_fixed: fixedCount,
2246
- nodes: postFixAnalysis.summary?.total_nodes ?? actionsArr.length,
2247
- message: fixedCount > 0
2248
- ? `Fixed ${fixedCount} issue(s) and deployed!`
2249
- : "Deployed successfully!",
2250
- next_step: "Test in the Ema simulator to verify behavior.",
2251
- };
2252
- if (enhancementPrompt) {
2253
- deployResult.enhancement_note = `Fixes applied. Enhancement "${enhancementPrompt}" requires manual implementation via Ema UI Auto Builder.`;
2254
- }
2255
- return deployResult;
2256
- }
2257
- catch (err) {
2258
- const errorMessage = err instanceof Error ? err.message : String(err);
2259
- // Extract EmaApiError body if available
2260
- const apiBody = err?.body;
2261
- const statusCode = err?.statusCode;
2262
- return {
2263
- success: false,
2264
- persona: persona.name,
2265
- status: "❌ Deploy Failed",
2266
- error: errorMessage,
2267
- status_code: statusCode,
2268
- api_response: apiBody ? JSON.parse(apiBody) : undefined,
2269
- fixes_attempted: appliedFixes.filter(f => f.applied).length,
2270
- suggestion: "Check the api_response field for the actual backend error.",
2271
- };
2272
- }
2273
2178
  },
2274
2179
  // ─────────────────────────────────────────────────────────────────────────
2275
2180
  // Action Handlers (Consolidated)
@@ -2884,40 +2789,41 @@ const toolHandlers = {
2884
2789
  // Workflow Review & Audit Handlers
2885
2790
  // ─────────────────────────────────────────────────────────────────────────────
2886
2791
  analyze_workflow: async (args) => {
2792
+ // DEPRECATED: MCP no longer pre-analyzes workflows
2793
+ // LLM should use ema://rules/* for analysis
2887
2794
  const client = createClient(args.env);
2888
2795
  const personaId = String(args.persona_id);
2889
2796
  const persona = await client.getPersonaById(personaId);
2890
2797
  if (!persona)
2891
2798
  throw new Error(`AI Employee not found: ${personaId}`);
2892
- if (!persona.workflow_def) {
2893
- return {
2894
- environment: client["env"].name,
2895
- persona_id: personaId,
2896
- persona_name: persona.name,
2897
- error: "AI Employee has no workflow_def",
2898
- recommendation: "This persona may not have a generated workflow. Use Auto Builder to create one.",
2899
- };
2900
- }
2901
- const analysis = analyzeWorkflow(persona.workflow_def, {
2799
+ const nodes = persona.workflow_def ? parseWorkflowDef(persona.workflow_def) : [];
2800
+ const connections = persona.workflow_def ? validateWorkflowConnections(persona.workflow_def) : [];
2801
+ return {
2802
+ environment: client["env"].name,
2902
2803
  persona_id: personaId,
2903
2804
  persona_name: persona.name,
2904
- environment: client["env"].name,
2905
- });
2906
- return {
2907
- ...analysis,
2908
- recommendations: analysis.validation_passed
2909
- ? ["Workflow structure looks valid. Test with sample queries to verify behavior."]
2910
- : [
2911
- "Fix all critical issues before deployment",
2912
- ...analysis.issues
2913
- .filter(i => i.severity === "critical")
2914
- .slice(0, 3)
2915
- .map(i => `Priority: ${i.reason}`),
2916
- "Use suggest_workflow_fixes to get fix proposals",
2805
+ status: "DEPRECATED - use LLM analysis",
2806
+ node_count: nodes.length,
2807
+ workflow_def: persona.workflow_def,
2808
+ connections: connections.map(c => ({
2809
+ edge: c.edge_id,
2810
+ source_type: c.source_type,
2811
+ target_type: c.target_type,
2812
+ compatible: c.compatible,
2813
+ })),
2814
+ _deprecation_notice: {
2815
+ message: "analyze_workflow is deprecated. MCP does not pre-compute issues.",
2816
+ new_workflow: [
2817
+ "1. Fetch rules: ema://rules/anti-patterns",
2818
+ "2. Apply rules to find issues (LLM does this, not MCP)",
2819
+ "3. Report your findings",
2917
2820
  ],
2821
+ },
2918
2822
  };
2919
2823
  },
2920
2824
  detect_workflow_issues: async (args) => {
2825
+ // DEPRECATED: MCP no longer detects workflow issues
2826
+ // LLM should use ema://rules/* for analysis
2921
2827
  const workflowDef = args.workflow_def;
2922
2828
  if (!workflowDef || typeof workflowDef !== "object") {
2923
2829
  return {
@@ -2925,21 +2831,19 @@ const toolHandlers = {
2925
2831
  hint: "Get workflow_def from get_ai_employee_full(persona_id).ai_employee.workflow_def",
2926
2832
  };
2927
2833
  }
2928
- const issues = detectWorkflowIssues(workflowDef);
2929
- const summary = {
2930
- total: issues.length,
2931
- critical: issues.filter(i => i.severity === "critical").length,
2932
- warning: issues.filter(i => i.severity === "warning").length,
2933
- info: issues.filter(i => i.severity === "info").length,
2934
- };
2834
+ const nodes = parseWorkflowDef(workflowDef);
2935
2835
  return {
2936
- issues,
2937
- summary,
2938
- validation_passed: summary.critical === 0,
2939
- issue_types_found: [...new Set(issues.map(i => i.type))],
2940
- next_steps: issues.length > 0
2941
- ? ["Use suggest_workflow_fixes(issues) to get fix proposals"]
2942
- : ["No issues detected - workflow structure looks valid"],
2836
+ status: "DEPRECATED - use LLM analysis",
2837
+ node_count: nodes.length,
2838
+ nodes: nodes.map(n => ({ id: n.id, action: n.action_name })),
2839
+ _deprecation_notice: {
2840
+ message: "detect_workflow_issues is deprecated. MCP does not pre-compute issues.",
2841
+ new_workflow: [
2842
+ "1. Fetch rules: ema://rules/anti-patterns",
2843
+ "2. Apply rules to this workflow (LLM does this)",
2844
+ "3. Report issues YOU find",
2845
+ ],
2846
+ },
2943
2847
  };
2944
2848
  },
2945
2849
  validate_workflow_connections: async (args) => {
@@ -2976,38 +2880,25 @@ const toolHandlers = {
2976
2880
  })),
2977
2881
  };
2978
2882
  },
2979
- suggest_workflow_fixes: async (args) => {
2980
- const issues = args.issues;
2981
- if (!Array.isArray(issues)) {
2982
- return {
2983
- error: "Invalid issues array",
2984
- hint: "Pass issues from detect_workflow_issues or analyze_workflow",
2985
- example_input: [
2986
- { type: "missing_fallback", severity: "critical", node: "intent_classifier", reason: "..." },
2987
- { type: "type_mismatch", severity: "critical", source: "trigger.chat_conversation", target: "search.query", reason: "..." },
2988
- ],
2989
- };
2990
- }
2991
- if (issues.length === 0) {
2992
- return {
2993
- message: "No issues to fix",
2994
- fixes: [],
2995
- };
2996
- }
2997
- const fixes = suggestWorkflowFixes(issues);
2883
+ suggest_workflow_fixes: async (_args) => {
2884
+ // DEPRECATED: MCP no longer suggests fixes
2885
+ // LLM should reason about fixes using ema://rules/*
2998
2886
  return {
2999
- issue_count: issues.length,
3000
- fix_count: fixes.length,
3001
- fixes,
3002
- application_order: [
3003
- "1. Fix critical issues first (missing_fallback, incomplete_hitl, cycles)",
3004
- "2. Fix type mismatches (may require adding intermediate nodes)",
3005
- "3. Address warnings (wrong_input_source, orphan nodes)",
3006
- "4. Re-run detect_workflow_issues to verify fixes",
3007
- ],
2887
+ status: "DEPRECATED - use LLM reasoning",
2888
+ _deprecation_notice: {
2889
+ message: "suggest_workflow_fixes is deprecated. LLM should propose fixes.",
2890
+ new_workflow: [
2891
+ "1. Analyze workflow with ema://rules/anti-patterns",
2892
+ "2. For each issue found, reason about the fix",
2893
+ "3. Build structured modifications",
2894
+ "4. Apply via persona(mode='update', operations=[...])",
2895
+ ],
2896
+ },
3008
2897
  };
3009
2898
  },
3010
2899
  compare_workflow_versions: async (args) => {
2900
+ // DEPRECATED: MCP no longer pre-analyzes for comparison
2901
+ // LLM should compare workflows directly
3011
2902
  const client = createClient(args.env);
3012
2903
  const idBefore = String(args.persona_id_before);
3013
2904
  const idAfter = String(args.persona_id_after);
@@ -3019,59 +2910,38 @@ const toolHandlers = {
3019
2910
  throw new Error(`AI Employee not found (before): ${idBefore}`);
3020
2911
  if (!personaAfter)
3021
2912
  throw new Error(`AI Employee not found (after): ${idAfter}`);
3022
- const analysisBefore = personaBefore.workflow_def
3023
- ? analyzeWorkflow(personaBefore.workflow_def, { persona_id: idBefore, persona_name: personaBefore.name })
3024
- : null;
3025
- const analysisAfter = personaAfter.workflow_def
3026
- ? analyzeWorkflow(personaAfter.workflow_def, { persona_id: idAfter, persona_name: personaAfter.name })
3027
- : null;
2913
+ const nodesBefore = personaBefore.workflow_def ? parseWorkflowDef(personaBefore.workflow_def) : [];
2914
+ const nodesAfter = personaAfter.workflow_def ? parseWorkflowDef(personaAfter.workflow_def) : [];
3028
2915
  // Compare fingerprints
3029
2916
  const fpBefore = personaBefore.workflow_def ? fingerprintPersona(personaBefore) : null;
3030
2917
  const fpAfter = personaAfter.workflow_def ? fingerprintPersona(personaAfter) : null;
3031
2918
  return {
3032
2919
  environment: client["env"].name,
2920
+ status: "DEPRECATED - LLM should compare",
3033
2921
  before: {
3034
2922
  persona_id: idBefore,
3035
2923
  name: personaBefore.name,
3036
2924
  fingerprint: fpBefore,
3037
2925
  has_workflow: !!personaBefore.workflow_def,
3038
- node_count: analysisBefore?.summary.total_nodes ?? 0,
3039
- edge_count: analysisBefore?.summary.total_edges ?? 0,
3040
- critical_issues: analysisBefore?.issue_summary.critical ?? 0,
3041
- validation_passed: analysisBefore?.validation_passed ?? false,
2926
+ node_count: nodesBefore.length,
2927
+ workflow_def: personaBefore.workflow_def,
3042
2928
  },
3043
2929
  after: {
3044
2930
  persona_id: idAfter,
3045
2931
  name: personaAfter.name,
3046
2932
  fingerprint: fpAfter,
3047
2933
  has_workflow: !!personaAfter.workflow_def,
3048
- node_count: analysisAfter?.summary.total_nodes ?? 0,
3049
- edge_count: analysisAfter?.summary.total_edges ?? 0,
3050
- critical_issues: analysisAfter?.issue_summary.critical ?? 0,
3051
- validation_passed: analysisAfter?.validation_passed ?? false,
2934
+ node_count: nodesAfter.length,
2935
+ workflow_def: personaAfter.workflow_def,
3052
2936
  },
3053
2937
  comparison: {
3054
2938
  fingerprints_match: fpBefore === fpAfter,
3055
- node_count_change: (analysisAfter?.summary.total_nodes ?? 0) - (analysisBefore?.summary.total_nodes ?? 0),
3056
- edge_count_change: (analysisAfter?.summary.total_edges ?? 0) - (analysisBefore?.summary.total_edges ?? 0),
3057
- critical_issues_change: (analysisAfter?.issue_summary.critical ?? 0) - (analysisBefore?.issue_summary.critical ?? 0),
3058
- validation_improved: !analysisBefore?.validation_passed && (analysisAfter?.validation_passed ?? false),
3059
- validation_regressed: (analysisBefore?.validation_passed ?? false) && !analysisAfter?.validation_passed,
2939
+ node_count_change: nodesAfter.length - nodesBefore.length,
2940
+ },
2941
+ _deprecation_notice: {
2942
+ message: "compare_workflow_versions is deprecated. LLM should compare workflows directly.",
2943
+ guidance: "Compare the workflow_def objects returned above. Use ema://rules/anti-patterns to check each.",
3060
2944
  },
3061
- issues_before: analysisBefore?.issues.slice(0, 5) ?? [],
3062
- issues_after: analysisAfter?.issues.slice(0, 5) ?? [],
3063
- recommendations: fpBefore === fpAfter
3064
- ? ["No workflow changes detected between versions"]
3065
- : [
3066
- analysisAfter?.validation_passed
3067
- ? "After version passes validation"
3068
- : "After version has validation issues - review before deploying",
3069
- (analysisAfter?.issue_summary.critical ?? 0) > (analysisBefore?.issue_summary.critical ?? 0)
3070
- ? "Warning: More critical issues in after version"
3071
- : (analysisAfter?.issue_summary.critical ?? 0) < (analysisBefore?.issue_summary.critical ?? 0)
3072
- ? "Good: Fewer critical issues in after version"
3073
- : "Same number of critical issues",
3074
- ],
3075
2945
  };
3076
2946
  },
3077
2947
  get_workflow_metrics: async (args) => {
@@ -3088,54 +2958,39 @@ const toolHandlers = {
3088
2958
  error: "AI Employee has no workflow_def",
3089
2959
  };
3090
2960
  }
3091
- const analysis = analyzeWorkflow(persona.workflow_def, {
3092
- persona_id: personaId,
3093
- persona_name: persona.name,
3094
- environment: client["env"].name,
3095
- });
3096
- // Calculate complexity indicators
3097
- const avgEdgesPerNode = analysis.summary.total_nodes > 0
3098
- ? (analysis.summary.total_edges / analysis.summary.total_nodes).toFixed(2)
2961
+ const nodes = parseWorkflowDef(persona.workflow_def);
2962
+ const connections = validateWorkflowConnections(persona.workflow_def);
2963
+ // Calculate basic metrics
2964
+ const totalEdges = nodes.reduce((sum, n) => sum + (n.incoming_edges?.length ?? 0), 0);
2965
+ const avgEdgesPerNode = nodes.length > 0
2966
+ ? (totalEdges / nodes.length).toFixed(2)
3099
2967
  : 0;
3100
- // Estimate parallel vs sequential
3101
- const hasParallelBranches = analysis.summary.categorizers_count > 0;
2968
+ // Check for categorizers and HITL
2969
+ const categorizerCount = nodes.filter(n => n.action_name?.includes("categorizer")).length;
2970
+ const hitlCount = nodes.filter(n => n.action_name?.includes("hitl") || n.id?.includes("hitl")).length;
2971
+ const hasTrigger = nodes.some(n => n.action_name === "trigger" || n.id === "trigger");
3102
2972
  return {
3103
2973
  environment: client["env"].name,
3104
2974
  persona_id: personaId,
3105
2975
  persona_name: persona.name,
3106
2976
  structure: {
3107
- total_nodes: analysis.summary.total_nodes,
3108
- total_edges: analysis.summary.total_edges,
3109
- has_trigger: analysis.summary.has_trigger,
3110
- has_workflow_output: analysis.summary.has_workflow_output,
2977
+ total_nodes: nodes.length,
2978
+ total_edges: totalEdges,
2979
+ has_trigger: hasTrigger,
2980
+ connection_count: connections.length,
3111
2981
  },
3112
2982
  routing: {
3113
- categorizers_count: analysis.summary.categorizers_count,
3114
- hitl_nodes_count: analysis.summary.hitl_nodes_count,
3115
- has_parallel_branches: hasParallelBranches,
3116
- },
3117
- quality: {
3118
- validation_passed: analysis.validation_passed,
3119
- critical_issues: analysis.issue_summary.critical,
3120
- warnings: analysis.issue_summary.warning,
2983
+ categorizers_count: categorizerCount,
2984
+ hitl_nodes_count: hitlCount,
2985
+ has_parallel_branches: categorizerCount > 0,
3121
2986
  },
3122
2987
  complexity: {
3123
2988
  avg_edges_per_node: avgEdgesPerNode,
3124
- complexity_rating: analysis.summary.total_nodes <= 5 ? "simple"
3125
- : analysis.summary.total_nodes <= 15 ? "moderate"
2989
+ complexity_rating: nodes.length <= 5 ? "simple"
2990
+ : nodes.length <= 15 ? "moderate"
3126
2991
  : "complex",
3127
2992
  },
3128
- recommendations: [
3129
- analysis.summary.categorizers_count === 0 && analysis.summary.total_nodes > 3
3130
- ? "Consider adding intent routing with chat_categorizer for better user experience"
3131
- : null,
3132
- analysis.summary.hitl_nodes_count === 0
3133
- ? "No HITL nodes - consider adding human approval for sensitive actions"
3134
- : null,
3135
- analysis.issue_summary.critical > 0
3136
- ? `${analysis.issue_summary.critical} critical issues need attention - use analyze_workflow for details`
3137
- : null,
3138
- ].filter(Boolean),
2993
+ _note: "Use ema://rules/anti-patterns for quality analysis. MCP no longer pre-computes issues.",
3139
2994
  };
3140
2995
  },
3141
2996
  // ─────────────────────────────────────────────────────────────────────────
@@ -3856,7 +3711,7 @@ const toolHandlers = {
3856
3711
  return handleEnv({}, () => getAvailableEnvironments().map(e => ({
3857
3712
  name: e.name,
3858
3713
  isDefault: e.name === getDefaultEnvName(),
3859
- })), { name: TOOLKIT_NAME, version: TOOLKIT_VERSION });
3714
+ })), { name: TOOLKIT_NAME, version: TOOLKIT_VERSION, commit: TOOLKIT_COMMIT });
3860
3715
  },
3861
3716
  persona: async (args) => {
3862
3717
  const targetEnv = args.env ?? getDefaultEnvName();
@@ -4104,7 +3959,11 @@ const toolHandlers = {
4104
3959
  name: e.name,
4105
3960
  isDefault: e.name === getDefaultEnvName(),
4106
3961
  })),
4107
- toolkit: { name: TOOLKIT_NAME, version: TOOLKIT_VERSION },
3962
+ toolkit: {
3963
+ name: TOOLKIT_NAME,
3964
+ version: TOOLKIT_VERSION,
3965
+ commit: TOOLKIT_COMMIT,
3966
+ },
4108
3967
  client,
4109
3968
  });
4110
3969
  },
@@ -4129,7 +3988,8 @@ const toolHandlers = {
4129
3988
  }
4130
3989
  switch (catalogType) {
4131
3990
  case "actions": {
4132
- // Route to action handler
3991
+ // API-FIRST: Try API, fall back to static AGENT_CATALOG
3992
+ // Senior review: Use API as primary source for live data
4133
3993
  if (method === "recommend" && forUseCase) {
4134
3994
  const suggestions = suggestAgentsForUseCase(forUseCase);
4135
3995
  return {
@@ -4141,18 +4001,55 @@ const toolHandlers = {
4141
4001
  : "No specific recommendations. Try browsing with catalog(method=\"list\", type=\"actions\").",
4142
4002
  };
4143
4003
  }
4004
+ // Try API first for live data
4005
+ try {
4006
+ let apiActions = await client.listActions();
4007
+ if (id) {
4008
+ const action = apiActions.find(a => a.name === id || a.name?.toLowerCase() === id.toLowerCase());
4009
+ if (action) {
4010
+ // Merge with docs from catalog for richer info
4011
+ const docs = getAgentByName(id);
4012
+ return {
4013
+ type: "actions",
4014
+ action: { ...action, documentation: docs },
4015
+ source: "api",
4016
+ };
4017
+ }
4018
+ // Fall through to catalog
4019
+ }
4020
+ if (category) {
4021
+ apiActions = apiActions.filter(a => a.category === category);
4022
+ }
4023
+ if (query) {
4024
+ const q = query.toLowerCase();
4025
+ apiActions = apiActions.filter(a => a.name?.toLowerCase().includes(q) ||
4026
+ a.category?.toLowerCase().includes(q));
4027
+ }
4028
+ return {
4029
+ type: "actions",
4030
+ count: apiActions.length,
4031
+ actions: apiActions.map(a => ({ name: a.name, category: a.category, enabled: a.enabled })),
4032
+ source: "api",
4033
+ _tip: "Get details: catalog(method=\"get\", type=\"actions\", id=\"<name>\")",
4034
+ _next_step: apiActions.length > 0 ? `catalog(method="get", type="actions", id="${apiActions[0].name}")` : undefined,
4035
+ };
4036
+ }
4037
+ catch {
4038
+ // Fallback to static catalog
4039
+ }
4040
+ // Fallback: Use static AGENT_CATALOG
4144
4041
  if (id) {
4145
4042
  const action = getAgentByName(id);
4146
4043
  if (!action) {
4147
4044
  return { error: `Action not found: ${id}` };
4148
4045
  }
4149
- return { type: "actions", action };
4046
+ return { type: "actions", action, source: "catalog" };
4150
4047
  }
4151
4048
  if (category) {
4152
4049
  const actions = getAgentsByCategory(category);
4153
- return { type: "actions", category, count: actions.length, actions };
4050
+ return { type: "actions", category, count: actions.length, actions, source: "catalog" };
4154
4051
  }
4155
- // List all
4052
+ // List all from catalog
4156
4053
  let actions = Object.values(AGENT_CATALOG);
4157
4054
  if (query) {
4158
4055
  const q = query.toLowerCase();
@@ -4164,6 +4061,7 @@ const toolHandlers = {
4164
4061
  type: "actions",
4165
4062
  count: actions.length,
4166
4063
  actions: actions.map(a => ({ name: a.actionName, displayName: a.displayName, category: a.category, description: a.description })),
4064
+ source: "catalog",
4167
4065
  _tip: "Get details: catalog(method=\"get\", type=\"actions\", id=\"<name>\")",
4168
4066
  _next_step: actions.length > 0 ? `catalog(method="get", type="actions", id="${actions[0].actionName}")` : undefined,
4169
4067
  };
@@ -4316,110 +4214,27 @@ const legacyConsolidateDemoData = toolHandlers.consolidate_demo_data;
4316
4214
  const legacyGenerateDemoDocument = toolHandlers.generate_demo_document;
4317
4215
  const legacyValidateDemoDocument = toolHandlers.validate_demo_document;
4318
4216
  const legacyGetDemoDataTemplate = toolHandlers.get_demo_data_template;
4319
- // Unify workflow modes: generate | analyze | deploy | optimize | compare | compile
4217
+ // Workflow tool: MCP provides data (get) and executes (deploy). LLM does all thinking.
4320
4218
  toolHandlers.workflow = async (args) => {
4321
- // Normalize persona type alias: tool schema uses "type", internal uses "persona_type"
4322
4219
  const normalizedArgs = { ...(args ?? {}) };
4323
- if (normalizedArgs.persona_type === undefined && normalizedArgs.type !== undefined) {
4324
- normalizedArgs.persona_type = normalizedArgs.type;
4325
- }
4326
4220
  const personaId = normalizedArgs.persona_id ? String(normalizedArgs.persona_id) : undefined;
4327
4221
  const workflowDef = normalizedArgs.workflow_def;
4328
- const inputProvided = normalizedArgs.input !== undefined;
4329
- // Normalize mode aliases
4330
- const rawMode = normalizedArgs.mode ? String(normalizedArgs.mode) : undefined;
4331
- const mode = rawMode === "improve" ? "optimize" : rawMode;
4332
- // Default mode selection:
4333
- // - persona_id + workflow_def deploy (direct deployment, no input needed)
4334
- // - persona_id + input → modify (BROWNFIELD: generate new workflow from input)
4335
- // - persona_id only or workflow_def → analyze (inspect)
4336
- // - input only → generate (GREENFIELD: create from scratch)
4337
- // - Otherwise → generate (and prompt for missing info)
4338
- const effectiveMode = mode ??
4339
- (personaId && workflowDef ? "deploy" : // Direct deployment (no input required)
4340
- personaId && inputProvided ? "modify" : // BROWNFIELD: existing persona + new requirements
4341
- workflowDef || personaId ? "analyze" : // Inspect existing
4342
- "generate"); // GREENFIELD: new workflow
4343
- switch (effectiveMode) {
4344
- case "generate": {
4345
- const result = await legacyWorkflowTool({ ...normalizedArgs, mode: "generate" });
4346
- // Ensure next_steps point at consolidated tools by default
4347
- if (result && typeof result === "object") {
4348
- const obj = result;
4349
- const persona_id = obj.persona_id ? String(obj.persona_id) : personaId;
4350
- const deployed = obj.deployed === true;
4351
- obj.next_steps = deployed
4352
- ? persona_id
4353
- ? [`Verify: persona(id="${persona_id}", include_workflow=true)`]
4354
- : ["Verify the deployed AI Employee in the Ema UI"]
4355
- : persona_id
4356
- ? [
4357
- `Deploy: workflow(mode="deploy", persona_id="${persona_id}", workflow_def=<workflow_def>, proto_config=<proto_config>)`,
4358
- `Verify: persona(id="${persona_id}", include_workflow=true)`,
4359
- ]
4360
- : [
4361
- "Create an AI Employee in Ema, then deploy:",
4362
- `workflow(mode="deploy", persona_id="<persona_id>", workflow_def=<workflow_def>, proto_config=<proto_config>)`,
4363
- ];
4364
- }
4365
- return result;
4366
- }
4367
- case "analyze": {
4368
- const include = Array.isArray(normalizedArgs.include)
4369
- ? normalizedArgs.include.map(String)
4370
- : ["issues", "connections", "fixes", "metrics"];
4371
- let wf = workflowDef;
4372
- let meta;
4373
- if (!wf && personaId) {
4374
- const client = createClient(normalizedArgs.env);
4375
- const persona = await client.getPersonaById(personaId);
4376
- if (!persona)
4377
- throw new Error(`AI Employee not found: ${personaId}`);
4378
- wf = persona.workflow_def;
4379
- meta = {
4380
- persona_id: personaId,
4381
- persona_name: persona.name,
4382
- environment: client["env"].name,
4383
- };
4384
- }
4385
- if (!wf) {
4386
- return {
4387
- error: "Missing workflow to analyze. Provide persona_id or workflow_def.",
4388
- hint: 'Examples: workflow(mode="analyze", persona_id="...") or workflow(mode="analyze", workflow_def={...})',
4389
- };
4390
- }
4391
- const out = { mode: "analyze", ...(meta ?? {}) };
4392
- // Issues + summary (source of truth)
4393
- const issuesResult = await legacyDetectWorkflowIssues({ workflow_def: wf });
4394
- const issues = issuesResult.issues;
4395
- if (include.includes("issues")) {
4396
- out.issues = issuesResult.issues;
4397
- out.issue_summary = issuesResult.summary;
4398
- out.validation_passed = issuesResult.validation_passed;
4399
- }
4400
- if (include.includes("connections")) {
4401
- out.connections = await legacyValidateWorkflowConnections({ workflow_def: wf });
4402
- }
4403
- if (include.includes("fixes")) {
4404
- out.fixes = Array.isArray(issues) ? await legacySuggestWorkflowFixes({ issues }) : { error: "No issues array available to generate fixes" };
4405
- }
4406
- if (include.includes("metrics")) {
4407
- const actions = wf.actions ?? [];
4408
- const edges = wf.edges ?? [];
4409
- out.metrics = {
4410
- node_count: Array.isArray(actions) ? actions.length : 0,
4411
- edge_count: Array.isArray(edges) ? edges.length : 0,
4412
- };
4413
- }
4414
- return out;
4222
+ const mode = normalizedArgs.mode ? String(normalizedArgs.mode) : undefined;
4223
+ // Route to handleWorkflow for get/deploy (the only public modes)
4224
+ const client = createClient(normalizedArgs.env);
4225
+ switch (mode) {
4226
+ case "get": {
4227
+ // Return workflow data for LLM to analyze/modify
4228
+ return handleWorkflow({
4229
+ mode: "get",
4230
+ persona_id: personaId,
4231
+ env: normalizedArgs.env,
4232
+ }, client, () => undefined);
4415
4233
  }
4416
4234
  case "deploy": {
4417
4235
  if (!personaId) {
4418
- throw new Error('persona_id is required for workflow(mode="deploy")');
4236
+ return { error: 'persona_id is required for workflow(mode="deploy")' };
4419
4237
  }
4420
- // Use clean deploy path via handleWorkflow (no brownfield merge, no excessive validation)
4421
- // User can still request validation via validate=true, but default is now direct deploy
4422
- const client = createClient(normalizedArgs.env);
4423
4238
  // Optional: pre-deploy version snapshot
4424
4239
  const targetEnv = normalizedArgs.env ?? getDefaultEnvName();
4425
4240
  let versionCreated;
@@ -4445,8 +4260,7 @@ toolHandlers.workflow = async (args) => {
4445
4260
  catch {
4446
4261
  // Version tracking is best-effort
4447
4262
  }
4448
- // Route to clean handleWorkflow deploy (handlers-consolidated.ts)
4449
- // This path: sanitizes workflow → calls client.updateAiEmployee → done
4263
+ // Route to handleWorkflow deploy
4450
4264
  const deployResult = await handleWorkflow({
4451
4265
  mode: "deploy",
4452
4266
  persona_id: personaId,
@@ -4460,58 +4274,25 @@ toolHandlers.workflow = async (args) => {
4460
4274
  }
4461
4275
  return deployResult;
4462
4276
  }
4463
- case "optimize": {
4464
- // optimize_workflow supports both:
4465
- // - fix mode: id (name/id) OR persona_id
4466
- // - generate mode: persona_id + prompt
4467
- const preview = normalizedArgs.preview === true;
4468
- const id = normalizedArgs.id ? String(normalizedArgs.id) : undefined;
4469
- const identifier = normalizedArgs.identifier ? String(normalizedArgs.identifier) : undefined; // deprecated alias
4470
- const idOrIdentifier = id ?? identifier;
4471
- // If a natural-language workflow "input" is provided, treat it as a prompt to optimize_workflow.
4472
- const input = normalizedArgs.input;
4473
- const prompt = typeof input === "string" ? input : undefined;
4474
- return legacyOptimizeWorkflow({
4475
- identifier: idOrIdentifier ?? personaId,
4476
- persona_id: personaId,
4477
- prompt,
4478
- type: normalizedArgs.persona_type,
4479
- preview,
4480
- env: normalizedArgs.env,
4481
- });
4482
- }
4483
- case "compare": {
4484
- if (!personaId) {
4485
- throw new Error('persona_id is required for workflow(mode="compare")');
4486
- }
4487
- const compareTo = normalizedArgs.compare_to ? String(normalizedArgs.compare_to) : undefined;
4488
- if (!compareTo) {
4489
- throw new Error('compare_to is required for workflow(mode="compare")');
4490
- }
4491
- return legacyCompareWorkflowVersions({
4492
- persona_id_before: personaId,
4493
- persona_id_after: compareTo,
4494
- env: normalizedArgs.env,
4495
- });
4496
- }
4497
- case "compile": {
4498
- // Compile requires node specs + result mappings.
4499
- if (!normalizedArgs.name || !normalizedArgs.description) {
4500
- throw new Error('workflow(mode="compile") requires name and description');
4501
- }
4502
- if (!normalizedArgs.persona_type) {
4503
- throw new Error('workflow(mode="compile") requires persona type via type="voice|chat|dashboard"');
4504
- }
4505
- return legacyCompileWorkflow({
4506
- name: normalizedArgs.name,
4507
- description: normalizedArgs.description,
4508
- persona_type: normalizedArgs.persona_type,
4509
- nodes: normalizedArgs.nodes,
4510
- result_mappings: normalizedArgs.result_mappings,
4511
- });
4277
+ // REMOVED modes - LLM does these
4278
+ case "analyze":
4279
+ case "compare":
4280
+ case "compile":
4281
+ case "optimize":
4282
+ case "generate": {
4283
+ return {
4284
+ error: `Mode "${mode}" removed - LLM does this thinking`,
4285
+ hint: "Use workflow(mode='get') to fetch data, then analyze/generate in your reasoning. Deploy with workflow(mode='deploy').",
4286
+ valid_modes: ["get", "deploy"],
4287
+ };
4512
4288
  }
4513
4289
  default: {
4514
- return legacyWorkflowTool({ ...normalizedArgs, mode: effectiveMode });
4290
+ // No mode or unknown mode - require explicit mode
4291
+ return {
4292
+ error: `Mode required. Valid modes: get, deploy`,
4293
+ hint: "workflow(mode='get') returns data for LLM. workflow(mode='deploy') executes LLM's workflow_def.",
4294
+ example: `workflow(mode="get", persona_id="...")`,
4295
+ };
4515
4296
  }
4516
4297
  }
4517
4298
  };
@@ -5017,7 +4798,11 @@ export async function startMcpServer() {
5017
4798
  });
5018
4799
  const transport = new StdioServerTransport();
5019
4800
  await server.connect(transport);
5020
- console.error("Ema MCP Server started (multi-env) with prompts and resources");
4801
+ // Log startup with version and commit info
4802
+ const buildInfo = TOOLKIT_COMMIT
4803
+ ? `${TOOLKIT_VERSION} (${TOOLKIT_COMMIT})`
4804
+ : TOOLKIT_VERSION;
4805
+ console.error(`Ema MCP Server started: ${TOOLKIT_NAME}@${buildInfo}`);
5021
4806
  }
5022
4807
  startMcpServer().catch((error) => {
5023
4808
  console.error("Failed to start MCP server:", error);