@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
@@ -1,275 +0,0 @@
1
- /**
2
- * Persona ANALYZE mode handler
3
- *
4
- * Analyzes a persona for issues in workflow, config, and data.
5
- * Returns decompiled WorkflowSpec + schema for LLM-native modifications.
6
- *
7
- * ARCHITECTURE NOTE: MCP provides context, Agent proposes fixes.
8
- * The `fix` parameter is DEPRECATED - agent should build workflow_spec fixes.
9
- */
10
- import { resolvePersona } from "../utils.js";
11
- import { detectWorkflowIssues, suggestWorkflowFixes } from "../../../sdk/knowledge.js";
12
- import { autoFixWorkflow } from "../../../sdk/workflow-fixer.js";
13
- import { decompileWorkflow, summarizeSpec, WORKFLOW_SCHEMA_FOR_LLM } from "../../../sdk/workflow-transformer.js";
14
- import { hasFallback, GUIDANCE_RULES } from "../../../sdk/guidance.js";
15
- /**
16
- * Handle persona(mode="analyze") - analyze persona for issues
17
- *
18
- * @param args.id - Persona ID or name (required)
19
- * @param args.fix - DEPRECATED: Returns preview instead of deploying. Agent should build workflow_spec.
20
- * @param args.include - Aspects to analyze (workflow, config, data)
21
- */
22
- export async function handleAnalyze(args, client) {
23
- const idOrName = (args.id ?? args.identifier);
24
- if (!idOrName) {
25
- return { status: "error", error: "id required for analyze mode" };
26
- }
27
- const persona = await resolvePersona(client, idOrName);
28
- if (!persona) {
29
- return { status: "error", error: `Persona not found: ${idOrName}` };
30
- }
31
- const fix = args.fix;
32
- const includeAspects = args.include ?? ["workflow", "config", "data"];
33
- // Collect issues across all aspects
34
- const issues = [];
35
- const fixesApplied = [];
36
- // ── Analyze Workflow ──
37
- if (includeAspects.includes("workflow") && persona.workflow_def) {
38
- const workflowDef = persona.workflow_def;
39
- // Use the sophisticated workflow issue detection
40
- const workflowIssues = detectWorkflowIssues(workflowDef);
41
- const suggestedFixes = suggestWorkflowFixes(workflowIssues);
42
- // Map workflow issues to our uniform format
43
- for (const issue of workflowIssues) {
44
- const wfIssue = issue;
45
- const severityMap = {
46
- "critical": "critical",
47
- "warning": "warning",
48
- "info": "info",
49
- };
50
- const matchingFix = suggestedFixes.find(f => f.issue_type === wfIssue.type);
51
- issues.push({
52
- id: `wf-${wfIssue.type}-${wfIssue.node || "global"}`,
53
- severity: severityMap[wfIssue.severity] || "warning",
54
- category: "workflow",
55
- title: `${wfIssue.type}${wfIssue.node ? `: ${wfIssue.node}` : ""}`,
56
- description: wfIssue.reason,
57
- auto_fixable: !!matchingFix,
58
- fix_description: matchingFix?.description,
59
- });
60
- }
61
- }
62
- // ── Analyze Config ──
63
- if (includeAspects.includes("config") && persona.proto_config) {
64
- const protoConfig = persona.proto_config;
65
- const widgets = (protoConfig.widgets || []);
66
- // Check for malformed widgets
67
- for (const widget of widgets) {
68
- const widgetName = widget.name;
69
- if (!widgetName || widgetName.trim() === "") {
70
- issues.push({
71
- id: `widget-empty-name`,
72
- severity: "warning",
73
- category: "config",
74
- title: "Widget with empty name",
75
- description: "A widget has an empty or missing name field",
76
- auto_fixable: false,
77
- });
78
- }
79
- }
80
- // Check for generic description
81
- const description = persona.description;
82
- if (!description || description.length < 20 || description.includes("template")) {
83
- issues.push({
84
- id: `generic-description`,
85
- severity: "info",
86
- category: "metadata",
87
- title: "Generic or missing description",
88
- description: "Persona description appears to be a template default or too short",
89
- auto_fixable: false,
90
- });
91
- }
92
- }
93
- // ── Analyze Data Sources ──
94
- if (includeAspects.includes("data")) {
95
- try {
96
- const dataSources = await client.listDataSourceFiles(persona.id);
97
- const files = dataSources.files || [];
98
- // Check data source health
99
- if (files.length === 0) {
100
- issues.push({
101
- id: `no-data-sources`,
102
- severity: "info",
103
- category: "data",
104
- title: "No data sources uploaded",
105
- description: "Persona has no knowledge files - Knowledge Agent won't have context to search",
106
- auto_fixable: false,
107
- });
108
- }
109
- // Check for failed uploads
110
- for (const file of files) {
111
- if (file.status === "failed" || file.status === "error") {
112
- issues.push({
113
- id: `failed-upload-${file.id}`,
114
- severity: "warning",
115
- category: "data",
116
- title: `Failed upload: ${file.filename}`,
117
- description: `File upload failed with status: ${file.status}`,
118
- auto_fixable: false,
119
- });
120
- }
121
- }
122
- }
123
- catch {
124
- // Data source listing may fail for some persona types
125
- }
126
- }
127
- // ── Handle fix parameter (DEPRECATED) ──
128
- // DEPRECATED: fix=true no longer auto-deploys. Returns preview for agent to review.
129
- // Architecture: MCP provides context, Agent proposes and builds fixes.
130
- let fixPreview;
131
- if (fix && persona.workflow_def) {
132
- // Log deprecation warning
133
- console.warn("[DEPRECATED] fix=true is deprecated. MCP should not auto-fix - agent builds workflow_spec.\n" +
134
- "See CLAUDE.md 'MCP vs Agent: Separation of Duties'.\n" +
135
- "Returning preview instead of deploying.");
136
- const workflowDef = persona.workflow_def;
137
- const fixResult = autoFixWorkflow(workflowDef);
138
- // Record what would be fixed
139
- for (const applied of fixResult.fixesApplied) {
140
- fixesApplied.push({
141
- issue_id: applied.issueType,
142
- action: applied.description,
143
- result: "preview", // Changed from success/failed to preview
144
- });
145
- }
146
- // Return preview instead of deploying
147
- if (fixResult.fixesApplied.length > 0 && fixResult.success) {
148
- // Determine persona type for decompile
149
- const protoConfig = persona.proto_config;
150
- const projectSettings = protoConfig?.projectSettings;
151
- const personaType = projectSettings?.projectType === 5 ? "voice" : "chat";
152
- try {
153
- fixPreview = {
154
- proposed_spec: decompileWorkflow(fixResult.workflowDef, personaType),
155
- changes: fixResult.fixesApplied.map(f => f.description),
156
- };
157
- }
158
- catch {
159
- // Decompile failed, just note the changes
160
- fixPreview = {
161
- changes: fixResult.fixesApplied.map(f => f.description),
162
- };
163
- }
164
- }
165
- }
166
- // ── Build Response ──
167
- const analysisSummary = {
168
- total_issues: issues.length,
169
- by_severity: {
170
- critical: issues.filter(i => i.severity === "critical").length,
171
- warning: issues.filter(i => i.severity === "warning").length,
172
- info: issues.filter(i => i.severity === "info").length,
173
- },
174
- by_category: {
175
- workflow: issues.filter(i => i.category === "workflow").length,
176
- config: issues.filter(i => i.category === "config").length,
177
- data: issues.filter(i => i.category === "data").length,
178
- metadata: issues.filter(i => i.category === "metadata").length,
179
- },
180
- };
181
- const status = analysisSummary.by_severity.critical > 0
182
- ? "critical"
183
- : analysisSummary.total_issues > 0
184
- ? "issues_found"
185
- : "healthy";
186
- // ── Decompile Workflow for LLM-native modifications ──
187
- let workflowSpec;
188
- let workflowSummary;
189
- if (persona.workflow_def) {
190
- const workflowDef = persona.workflow_def;
191
- // Determine persona type
192
- const protoConfig = persona.proto_config;
193
- const projectSettings = protoConfig?.projectSettings;
194
- const personaType = projectSettings?.projectType === 5 ? "voice" : "chat";
195
- try {
196
- workflowSpec = decompileWorkflow(workflowDef, personaType);
197
- workflowSummary = summarizeSpec(workflowSpec);
198
- }
199
- catch (e) {
200
- // Decompile failed - include error in response
201
- workflowSummary = `Decompile failed: ${e instanceof Error ? e.message : String(e)}`;
202
- }
203
- }
204
- const result = {
205
- status,
206
- persona: { id: persona.id, name: persona.name },
207
- summary: analysisSummary,
208
- issues,
209
- };
210
- // Include workflow_spec for LLM-native modifications (unless include_spec=false)
211
- const includeSpec = args.include_spec !== false;
212
- if (includeSpec && workflowSpec) {
213
- result.workflow_spec = workflowSpec;
214
- result.workflow_summary = workflowSummary;
215
- result.schema = WORKFLOW_SCHEMA_FOR_LLM;
216
- result.modification_hint =
217
- "To modify this workflow:\n" +
218
- "1. Analyze the workflow_spec above\n" +
219
- "2. Modify the spec (add/remove/update nodes, change inputs/outputs)\n" +
220
- "3. Call persona(id=\"" + persona.id + "\", update={workflow_spec: <modified_spec>})\n" +
221
- "\n" +
222
- "The SDK will compile your WorkflowSpec to workflow_def and deploy it.";
223
- // Add workflow-specific guidance based on state
224
- const workflowGuidance = [];
225
- // Check for Fallback in categorizers
226
- if (!hasFallback(workflowSpec)) {
227
- const fallbackRule = GUIDANCE_RULES.find(r => r.id === "categorizer-fallback");
228
- if (fallbackRule) {
229
- workflowGuidance.push(`⚠️ ${fallbackRule.title}: ${fallbackRule.do}`);
230
- }
231
- }
232
- // Add general workflow tips
233
- const previewRule = GUIDANCE_RULES.find(r => r.id === "preview-before-deploy");
234
- if (previewRule) {
235
- workflowGuidance.push(`💡 ${previewRule.title}: ${previewRule.do}`);
236
- }
237
- if (workflowGuidance.length > 0) {
238
- result.workflow_guidance = workflowGuidance;
239
- }
240
- }
241
- if (fix) {
242
- // DEPRECATED: Return preview, not deployment result
243
- result.deprecation_warning =
244
- "fix=true is DEPRECATED. MCP should not auto-fix workflows.\n" +
245
- "The agent should review issues, ask the user which to fix, " +
246
- "build the workflow_spec, and call persona(update={workflow_spec: ...})";
247
- if (fixPreview) {
248
- result.fix_preview = {
249
- status: "preview_only",
250
- proposed_changes: fixPreview.changes,
251
- proposed_spec: fixPreview.proposed_spec,
252
- deploy_command: `persona(id="${persona.id}", update={workflow_spec: <proposed_spec above>})`,
253
- };
254
- }
255
- else {
256
- result.fix_preview = {
257
- status: "no_fixes_available",
258
- message: "No auto-fixable issues found. Review issues above and build fixes manually.",
259
- };
260
- }
261
- }
262
- else {
263
- // Guide agent to the correct flow (no mention of fix=true)
264
- result.next_steps = {
265
- has_issues: issues.length > 0,
266
- agent_action: issues.length > 0
267
- ? "Review issues above. Ask user which to fix. Build workflow_spec with fixes. Deploy via update."
268
- : "No issues found. Persona is healthy.",
269
- manual_actions: issues
270
- .filter(i => !i.auto_fixable)
271
- .map(i => `${i.title}: ${i.description}`),
272
- };
273
- }
274
- return result;
275
- }
@@ -1,32 +0,0 @@
1
- /**
2
- * Persona COMPARE mode handler
3
- *
4
- * Compares two personas, optionally across environments.
5
- */
6
- import { resolvePersona, comparePersonas } from "../utils.js";
7
- /**
8
- * Handle persona(mode="compare") - compare two personas
9
- *
10
- * @param args.id - First persona ID or name (required)
11
- * @param args.compare_to - Second persona ID or name (required)
12
- * @param args.compare_env - Optional environment for second persona
13
- * @param createClientForEnv - Factory to create client for different env
14
- */
15
- export async function handleCompare(args, client, createClientForEnv) {
16
- const idOrName = (args.id ?? args.identifier);
17
- if (!idOrName || !args.compare_to) {
18
- return { error: "id and compare_to required for compare mode" };
19
- }
20
- const persona1 = await resolvePersona(client, idOrName);
21
- const compareEnv = args.compare_env;
22
- const client2 = compareEnv && createClientForEnv ? createClientForEnv(compareEnv) : client;
23
- const persona2 = await resolvePersona(client2, args.compare_to);
24
- if (!persona1 || !persona2) {
25
- return { error: "One or both personas not found" };
26
- }
27
- return {
28
- persona_1: { id: persona1.id, name: persona1.name },
29
- persona_2: { id: persona2.id, name: persona2.name, env: compareEnv },
30
- differences: comparePersonas(persona1, persona2),
31
- };
32
- }
@@ -1,39 +0,0 @@
1
- /**
2
- * Workflow Compile Handler
3
- *
4
- * Compiles a WorkflowSpec (simplified nodes array) into a full workflow_def.
5
- */
6
- import { compileWorkflow } from "../../../sdk/workflow-generator.js";
7
- import { ensureActionRegistry } from "../../../sdk/action-registry.js";
8
- /**
9
- * Handle workflow compile mode
10
- *
11
- * Accepts nodes in simplified format and compiles to workflow_def.
12
- * Uses the same pattern as the monolith - passes through to compileWorkflow.
13
- */
14
- export async function handleWorkflowCompile(args, client) {
15
- const nodes = args.nodes;
16
- const resultMappings = args.result_mappings;
17
- if (!nodes) {
18
- return { error: "nodes required for compile mode" };
19
- }
20
- // Load action registry for API-driven action versions/namespaces
21
- const compileRegistry = await ensureActionRegistry(client);
22
- // Build spec - use any to allow flexible node format from API
23
- // compileWorkflow will validate and transform as needed
24
- const spec = {
25
- name: args.name || "Compiled Workflow",
26
- description: args.description || "Generated workflow",
27
- personaType: args.type || "chat",
28
- nodes: nodes,
29
- resultMappings: resultMappings || [],
30
- };
31
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
- const compiled = compileWorkflow(spec, { registry: compileRegistry });
33
- return {
34
- mode: "compile",
35
- workflow_def: compiled.workflow_def,
36
- proto_config: compiled.proto_config,
37
- registry_loaded: compileRegistry.isLoaded(),
38
- };
39
- }