@ema.co/mcp-toolkit 2026.1.25 → 2026.1.26-4

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 (87) hide show
  1. package/README.md +10 -2
  2. package/dist/mcp/handlers/action/index.js +3 -18
  3. package/dist/mcp/handlers/data/index.js +385 -41
  4. package/dist/mcp/handlers/data/templates.js +107 -0
  5. package/dist/mcp/handlers/deprecation.js +50 -0
  6. package/dist/mcp/handlers/env/index.js +8 -4
  7. package/dist/mcp/handlers/knowledge/index.js +44 -237
  8. package/dist/mcp/handlers/persona/create.js +47 -18
  9. package/dist/mcp/handlers/persona/index.js +14 -11
  10. package/dist/mcp/handlers/persona/update.js +4 -2
  11. package/dist/mcp/handlers/persona/version.js +234 -0
  12. package/dist/mcp/handlers/sync/index.js +3 -18
  13. package/dist/mcp/handlers/template/index.js +75 -10
  14. package/dist/mcp/handlers/workflow/analyze.js +171 -0
  15. package/dist/mcp/handlers/workflow/compare.js +70 -0
  16. package/dist/mcp/handlers/workflow/deploy.js +73 -0
  17. package/dist/mcp/handlers/workflow/generate.js +350 -0
  18. package/dist/mcp/handlers/workflow/index.js +294 -0
  19. package/dist/mcp/handlers/workflow/modify.js +456 -0
  20. package/dist/mcp/handlers/workflow/optimize.js +136 -0
  21. package/dist/mcp/handlers/workflow/types.js +4 -0
  22. package/dist/mcp/handlers/workflow/utils.js +30 -0
  23. package/dist/mcp/handlers-consolidated.js +73 -2696
  24. package/dist/mcp/prompts.js +83 -43
  25. package/dist/mcp/resources.js +382 -57
  26. package/dist/mcp/server.js +199 -391
  27. package/dist/mcp/{tools-v2.js → tools.js} +20 -54
  28. package/dist/mcp/workflow-operations.js +2 -2
  29. package/dist/sdk/client-adapter.js +267 -32
  30. package/dist/sdk/client.js +45 -16
  31. package/dist/sdk/ema-client.js +183 -0
  32. package/dist/sdk/generated/deprecated-actions.js +171 -0
  33. package/dist/sdk/generated/template-fallbacks.js +123 -0
  34. package/dist/sdk/guidance.js +65 -11
  35. package/dist/sdk/index.js +3 -1
  36. package/dist/sdk/knowledge.js +139 -86
  37. package/dist/sdk/workflow-intent.js +27 -0
  38. package/dist/sdk/workflow-transformer.js +0 -342
  39. package/docs/mcp-tools-guide.md +37 -45
  40. package/package.json +10 -4
  41. package/dist/mcp/handlers/persona/analyze.js +0 -275
  42. package/dist/mcp/handlers/persona/compare.js +0 -32
  43. package/dist/mcp/tools-consolidated.js +0 -875
  44. package/dist/mcp/tools-legacy.js +0 -736
  45. package/docs/CODEBASE-ANALYSIS-2026-01-23.md +0 -936
  46. package/docs/CODEBASE-ANALYSIS-PRIORITIZED.md +0 -774
  47. package/docs/api-contracts.md +0 -216
  48. package/docs/auto-builder-analysis.md +0 -271
  49. package/docs/blog/mcp-tool-design-lessons.md +0 -309
  50. package/docs/data-architecture.md +0 -166
  51. package/docs/demos/ap-invoice-generation.md +0 -347
  52. package/docs/demos/ap-invoice-processing.md +0 -271
  53. package/docs/ema-auto-builder-guide.html +0 -394
  54. package/docs/lessons-learned.md +0 -209
  55. package/docs/llm-native-workflow-design.md +0 -252
  56. package/docs/local-generation.md +0 -508
  57. package/docs/mcp-flow-diagram.md +0 -135
  58. package/docs/migration/action-composition-migration.md +0 -270
  59. package/docs/naming-conventions.md +0 -278
  60. package/docs/proposals/HANDOFF-tool-restructure.md +0 -526
  61. package/docs/proposals/action-composition.md +0 -490
  62. package/docs/proposals/explicit-method-restructure.md +0 -328
  63. package/docs/proposals/mcp-tool-restructure-2026-01.md +0 -366
  64. package/docs/proposals/self-contained-guidance.md +0 -427
  65. package/docs/proto-sdk-generation.md +0 -242
  66. package/docs/release-impact.md +0 -102
  67. package/docs/release-process.md +0 -157
  68. package/docs/staging.RULE.md +0 -142
  69. package/docs/test-persona-creation.md +0 -196
  70. package/docs/tool-consolidation-v2.md +0 -225
  71. package/docs/tool-response-standards.md +0 -256
  72. package/resources/demo-kits/README.md +0 -175
  73. package/resources/demo-kits/finance-ap/manifest.json +0 -150
  74. package/resources/demo-kits/tags.json +0 -91
  75. package/resources/docs/getting-started.md +0 -97
  76. package/resources/templates/auto-builder-rules.md +0 -224
  77. package/resources/templates/chat-ai/README.md +0 -119
  78. package/resources/templates/chat-ai/persona-config.json +0 -111
  79. package/resources/templates/dashboard-ai/README.md +0 -156
  80. package/resources/templates/dashboard-ai/persona-config.json +0 -180
  81. package/resources/templates/demo-scenarios/README.md +0 -63
  82. package/resources/templates/demo-scenarios/test-published-package.md +0 -116
  83. package/resources/templates/document-gen-ai/README.md +0 -132
  84. package/resources/templates/document-gen-ai/persona-config.json +0 -316
  85. package/resources/templates/voice-ai/README.md +0 -123
  86. package/resources/templates/voice-ai/persona-config.json +0 -74
  87. package/resources/templates/voice-ai/workflow-prompt.md +0 -121
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Workflow Handler
3
+ *
4
+ * PUBLIC TOOL MODES (workflow tool):
5
+ * - get: Return workflow data + schema for LLM to generate/modify
6
+ * - deploy: Deploy LLM-generated workflow_def
7
+ *
8
+ * INTERNAL MODES (called from persona tool, not exposed):
9
+ * - modify: Used internally by persona(method="update", input="...")
10
+ * - generate: Used internally for workflow generation
11
+ * - analyze: Used internally for workflow analysis
12
+ * - optimize: Used internally for auto-fix
13
+ * - compare: Used internally for comparison
14
+ *
15
+ * THE LLM DOES ALL THE THINKING. MCP provides data and executes.
16
+ */
17
+ import { generateSchema } from "../../../sdk/generation-schema.js";
18
+ // Re-export types
19
+ export * from "./types.js";
20
+ // Re-export utilities
21
+ export * from "./utils.js";
22
+ // Import internal handlers (not exposed as tool modes, but used internally)
23
+ import { handleWorkflowAnalyze } from "./analyze.js";
24
+ import { handleWorkflowCompare } from "./compare.js";
25
+ import { handleWorkflowOptimize } from "./optimize.js";
26
+ import { handleWorkflowDeploy } from "./deploy.js";
27
+ import { handleWorkflowGenerate } from "./generate.js";
28
+ import { handleWorkflowModify } from "./modify.js";
29
+ // Re-export for internal use (persona handler routes to these)
30
+ export { handleWorkflowAnalyze } from "./analyze.js";
31
+ export { handleWorkflowCompare } from "./compare.js";
32
+ export { handleWorkflowOptimize } from "./optimize.js";
33
+ export { handleWorkflowDeploy } from "./deploy.js";
34
+ export { handleWorkflowGenerate } from "./generate.js";
35
+ export { handleWorkflowModify } from "./modify.js";
36
+ export { applyWorkflowModifications, buildWorkflowAction, buildInputBinding, } from "./modify.js";
37
+ // Fallback deprecated actions - ONLY used when API unavailable
38
+ // Source: ema/ema_backend/grpc/workflow_actions/registered_actions.py (synced 2026-01-26)
39
+ const DEPRECATED_ACTIONS_FALLBACK = {
40
+ "search/v0": { replacement: "search/v2", notes: "v2 requires datastore_configs input" },
41
+ "web_search/v0": { replacement: "live_web_search or ai_web_search", notes: "Split into two specialized actions" },
42
+ "call_llm/v0": { replacement: "call_llm/v2" },
43
+ "human_collaboration/v0": { replacement: "general_hitl" },
44
+ "fixed_response/v0": { replacement: "fixed_response/v1" },
45
+ "custom_agent/v0": { replacement: "custom_agent/v1" },
46
+ "json_mapper/v0": { replacement: "json_mapper/v1" },
47
+ "text_categorizer/v0": { replacement: "text_categorizer/v1" },
48
+ "respond_with_sources/v0": { replacement: "respond_for_external_actions", notes: "Handles tool results better" },
49
+ };
50
+ /**
51
+ * Get deprecated actions from API (with fallback)
52
+ * Returns map of action/version -> replacement info
53
+ */
54
+ async function getDeprecatedActions(client) {
55
+ try {
56
+ const actions = await client.listActions();
57
+ const deprecated = {};
58
+ for (const action of actions) {
59
+ if (action.deprecated) {
60
+ // Use action name as key (API doesn't include version in deprecated flag)
61
+ deprecated[action.id] = {
62
+ notes: "Deprecated - check catalog for current version",
63
+ };
64
+ }
65
+ }
66
+ // Merge with fallback to get replacement info
67
+ for (const [key, info] of Object.entries(DEPRECATED_ACTIONS_FALLBACK)) {
68
+ const actionName = key.split("/")[0];
69
+ if (deprecated[actionName] || !deprecated[key]) {
70
+ deprecated[key] = { ...info, ...deprecated[key] };
71
+ }
72
+ }
73
+ return { deprecated, source: "api" };
74
+ }
75
+ catch {
76
+ // API unavailable, use fallback
77
+ return { deprecated: DEPRECATED_ACTIONS_FALLBACK, source: "fallback" };
78
+ }
79
+ }
80
+ /**
81
+ * Check if workflow uses deprecated actions
82
+ */
83
+ function checkWorkflowDeprecations(workflowDef, deprecatedActions) {
84
+ if (!workflowDef)
85
+ return [];
86
+ const warnings = [];
87
+ const actions = (workflowDef.actions ?? []);
88
+ for (const action of actions) {
89
+ const actionName = action.action?.name?.name;
90
+ const version = action.action?.name?.version || "v0";
91
+ if (!actionName)
92
+ continue;
93
+ const key = `${actionName}/${version}`;
94
+ const deprecation = deprecatedActions[key] || deprecatedActions[actionName];
95
+ if (deprecation) {
96
+ warnings.push({
97
+ action: action.name,
98
+ version,
99
+ replacement: deprecation.replacement,
100
+ notes: deprecation.notes,
101
+ severity: "warning",
102
+ });
103
+ }
104
+ }
105
+ return warnings;
106
+ }
107
+ /**
108
+ * Handle workflow(mode="get") - return data + schema + guidance for LLM
109
+ *
110
+ * Returns:
111
+ * - Current workflow_def (if exists)
112
+ * - Deprecation warnings for current workflow
113
+ * - Generation schema (agents, types, constraints)
114
+ * - Requirements and guidance (NOT hardcoded templates)
115
+ * - Available widgets
116
+ *
117
+ * LLM uses this to generate or modify workflow_def
118
+ */
119
+ async function handleWorkflowGet(args, client) {
120
+ const personaId = args.persona_id;
121
+ if (!personaId) {
122
+ return { error: "persona_id required" };
123
+ }
124
+ const persona = await client.getPersonaById(personaId);
125
+ if (!persona) {
126
+ return { error: `Persona not found: ${personaId}` };
127
+ }
128
+ const protoConfig = persona.proto_config;
129
+ const widgets = (protoConfig?.widgets ?? []);
130
+ const workflowDef = persona.workflow_def;
131
+ // Extract available widget names for LLM
132
+ const availableWidgets = widgets
133
+ .filter(w => typeof w.name === "string")
134
+ .map(w => ({
135
+ name: w.name,
136
+ type: w.type,
137
+ }));
138
+ // Get generation schema for LLM
139
+ const schema = generateSchema();
140
+ // Get deprecated actions (API-first, with fallback)
141
+ const { deprecated: deprecatedActions, source: deprecationSource } = await getDeprecatedActions(client);
142
+ // Check if current workflow uses deprecated actions
143
+ const deprecationWarnings = checkWorkflowDeprecations(workflowDef, deprecatedActions);
144
+ // Build response
145
+ const result = {
146
+ persona_id: persona.id,
147
+ persona_name: persona.name,
148
+ persona_type: persona.type,
149
+ workflow_def: workflowDef ?? null,
150
+ available_widgets: availableWidgets,
151
+ // Deprecation warnings (severity: warning)
152
+ deprecation_warnings: deprecationWarnings.length > 0 ? deprecationWarnings : undefined,
153
+ deprecated_actions_source: deprecationWarnings.length > 0 ? deprecationSource : undefined,
154
+ // Schema for LLM to generate valid workflow_def
155
+ generation_schema: {
156
+ agents: schema.agents,
157
+ constraints: schema.constraints,
158
+ input_rules: schema.inputRules,
159
+ },
160
+ // HARD REQUIREMENTS (must be satisfied)
161
+ hard_requirements: {
162
+ workflow_output: {
163
+ rule: "Every workflow MUST have results.WORKFLOW_OUTPUT mapped to a final action output",
164
+ format: '{ "results": { "WORKFLOW_OUTPUT": { "actionName": "...", "outputName": "..." } } }',
165
+ failure: "Persona cannot be activated without this",
166
+ },
167
+ workflow_name: {
168
+ rule: "workflowName must be ['ema', 'personas', '<persona_id>']",
169
+ format: '{ "workflowName": ["ema", "personas", "actual-persona-id"] }',
170
+ },
171
+ action_structure: {
172
+ rule: "Each action needs: name (unique ID), action.name (namespaces, name, version), action.inputs",
173
+ namespaces: "Most actions use ['actions', 'emainternal'], triggers use ['triggers', 'emainternal']",
174
+ },
175
+ no_deprecated_actions: deprecationWarnings.length > 0 ? {
176
+ rule: "Update deprecated actions before deploying",
177
+ warnings: deprecationWarnings,
178
+ } : undefined,
179
+ },
180
+ // GUIDANCE (best practices, not hard requirements)
181
+ guidance: {
182
+ flow_pattern: "trigger → categorizer (optional) → processing → response → WORKFLOW_OUTPUT",
183
+ categorizer: "For multi-intent workflows, use chat_categorizer early with a Fallback category",
184
+ fallback: "Every categorizer MUST have a Fallback category for unmatched intents",
185
+ hitl: "For actions with side effects (email, external calls), consider general_hitl for approval",
186
+ search: "Use search/v2 with datastore_configs. Wire query from trigger output.",
187
+ },
188
+ // Tell LLM to check for deprecated actions if any exist
189
+ _next_steps: deprecationWarnings.length > 0
190
+ ? [
191
+ "WARNING: Workflow uses deprecated actions. Update them first:",
192
+ ...deprecationWarnings.map(w => ` - ${w.action}: ${w.replacement || "check catalog for replacement"}`),
193
+ "Then deploy with: workflow(mode='deploy', persona_id='...', workflow_def={...})",
194
+ ]
195
+ : [
196
+ "Generate or modify workflow_def based on requirements above",
197
+ "Deploy with: workflow(mode='deploy', persona_id='...', workflow_def={...})",
198
+ ],
199
+ };
200
+ // Include deprecated actions reference if there are warnings or on request
201
+ if (deprecationWarnings.length > 0 || args.include_deprecated) {
202
+ result.deprecated_actions_reference = deprecatedActions;
203
+ }
204
+ return result;
205
+ }
206
+ /**
207
+ * Main workflow handler with mode-based dispatch
208
+ *
209
+ * PUBLIC modes: get, deploy
210
+ * INTERNAL modes: modify, generate, analyze, optimize, compare (called from persona tool)
211
+ */
212
+ export async function handleWorkflow(args, client, getTemplateId) {
213
+ const personaId = args.persona_id;
214
+ const workflowDef = args.workflow_def;
215
+ const input = args.input;
216
+ const optimize = args.optimize;
217
+ const compareTo = args.compare_to;
218
+ const operations = args.operations;
219
+ // Explicit mode takes priority
220
+ const mode = args.mode;
221
+ // PUBLIC MODES (from workflow tool)
222
+ if (mode === "get") {
223
+ return handleWorkflowGet(args, client);
224
+ }
225
+ if (mode === "deploy") {
226
+ return handleWorkflowDeploy(args, client);
227
+ }
228
+ // INTERNAL MODES (called from persona tool, not workflow tool)
229
+ if (mode === "modify" || mode === "extend") {
230
+ return handleWorkflowModify(args, client);
231
+ }
232
+ if (mode === "generate") {
233
+ return handleWorkflowGenerate(args, client, getTemplateId);
234
+ }
235
+ if (mode === "analyze") {
236
+ return handleWorkflowAnalyze(args, client);
237
+ }
238
+ if (mode === "optimize") {
239
+ return handleWorkflowOptimize(args, client);
240
+ }
241
+ if (mode === "compare") {
242
+ return handleWorkflowCompare(args, client);
243
+ }
244
+ // Auto-detect mode (for backwards compatibility with internal routing)
245
+ if (compareTo) {
246
+ return handleWorkflowCompare(args, client);
247
+ }
248
+ if (optimize && personaId) {
249
+ return handleWorkflowOptimize(args, client);
250
+ }
251
+ if (personaId && workflowDef) {
252
+ return handleWorkflowDeploy(args, client);
253
+ }
254
+ if (personaId && (input || operations)) {
255
+ return handleWorkflowModify(args, client);
256
+ }
257
+ if (input && !personaId) {
258
+ return handleWorkflowGenerate(args, client, getTemplateId);
259
+ }
260
+ if (personaId) {
261
+ return handleWorkflowAnalyze(args, client);
262
+ }
263
+ // Invalid mode
264
+ return {
265
+ error: `Invalid or missing mode: ${mode}`,
266
+ public_modes: ["get", "deploy"],
267
+ hint: "MCP provides data (get) and executes (deploy). LLM does all thinking.",
268
+ };
269
+ }
270
+ /**
271
+ * Check if a workflow mode has been extracted
272
+ */
273
+ export function hasExtractedWorkflowHandler(mode) {
274
+ const extractedModes = ["get", "deploy", "modify", "extend", "generate", "analyze", "optimize", "compare"];
275
+ return extractedModes.includes(mode);
276
+ }
277
+ /**
278
+ * Get handler for a specific workflow mode
279
+ */
280
+ export function getWorkflowModeHandler(mode) {
281
+ switch (mode) {
282
+ case "get":
283
+ case "deploy":
284
+ case "modify":
285
+ case "extend":
286
+ case "generate":
287
+ case "analyze":
288
+ case "optimize":
289
+ case "compare":
290
+ return handleWorkflow;
291
+ default:
292
+ return undefined;
293
+ }
294
+ }