@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.
- package/README.md +10 -2
- package/dist/mcp/handlers/action/index.js +3 -18
- package/dist/mcp/handlers/data/index.js +385 -41
- package/dist/mcp/handlers/data/templates.js +107 -0
- package/dist/mcp/handlers/deprecation.js +50 -0
- package/dist/mcp/handlers/env/index.js +8 -4
- package/dist/mcp/handlers/knowledge/index.js +44 -237
- package/dist/mcp/handlers/persona/create.js +47 -18
- package/dist/mcp/handlers/persona/index.js +14 -11
- package/dist/mcp/handlers/persona/update.js +4 -2
- package/dist/mcp/handlers/persona/version.js +234 -0
- package/dist/mcp/handlers/sync/index.js +3 -18
- package/dist/mcp/handlers/template/index.js +75 -10
- package/dist/mcp/handlers/workflow/analyze.js +171 -0
- package/dist/mcp/handlers/workflow/compare.js +70 -0
- package/dist/mcp/handlers/workflow/deploy.js +73 -0
- package/dist/mcp/handlers/workflow/generate.js +350 -0
- package/dist/mcp/handlers/workflow/index.js +294 -0
- package/dist/mcp/handlers/workflow/modify.js +456 -0
- package/dist/mcp/handlers/workflow/optimize.js +136 -0
- package/dist/mcp/handlers/workflow/types.js +4 -0
- package/dist/mcp/handlers/workflow/utils.js +30 -0
- package/dist/mcp/handlers-consolidated.js +73 -2696
- package/dist/mcp/prompts.js +83 -43
- package/dist/mcp/resources.js +382 -57
- package/dist/mcp/server.js +199 -391
- package/dist/mcp/{tools-v2.js → tools.js} +20 -54
- package/dist/mcp/workflow-operations.js +2 -2
- package/dist/sdk/client-adapter.js +267 -32
- package/dist/sdk/client.js +45 -16
- package/dist/sdk/ema-client.js +183 -0
- package/dist/sdk/generated/deprecated-actions.js +171 -0
- package/dist/sdk/generated/template-fallbacks.js +123 -0
- package/dist/sdk/guidance.js +65 -11
- package/dist/sdk/index.js +3 -1
- package/dist/sdk/knowledge.js +139 -86
- package/dist/sdk/workflow-intent.js +27 -0
- package/dist/sdk/workflow-transformer.js +0 -342
- package/docs/mcp-tools-guide.md +37 -45
- package/package.json +10 -4
- package/dist/mcp/handlers/persona/analyze.js +0 -275
- package/dist/mcp/handlers/persona/compare.js +0 -32
- package/dist/mcp/tools-consolidated.js +0 -875
- package/dist/mcp/tools-legacy.js +0 -736
- package/docs/CODEBASE-ANALYSIS-2026-01-23.md +0 -936
- package/docs/CODEBASE-ANALYSIS-PRIORITIZED.md +0 -774
- package/docs/api-contracts.md +0 -216
- package/docs/auto-builder-analysis.md +0 -271
- package/docs/blog/mcp-tool-design-lessons.md +0 -309
- package/docs/data-architecture.md +0 -166
- package/docs/demos/ap-invoice-generation.md +0 -347
- package/docs/demos/ap-invoice-processing.md +0 -271
- package/docs/ema-auto-builder-guide.html +0 -394
- package/docs/lessons-learned.md +0 -209
- package/docs/llm-native-workflow-design.md +0 -252
- package/docs/local-generation.md +0 -508
- package/docs/mcp-flow-diagram.md +0 -135
- package/docs/migration/action-composition-migration.md +0 -270
- package/docs/naming-conventions.md +0 -278
- package/docs/proposals/HANDOFF-tool-restructure.md +0 -526
- package/docs/proposals/action-composition.md +0 -490
- package/docs/proposals/explicit-method-restructure.md +0 -328
- package/docs/proposals/mcp-tool-restructure-2026-01.md +0 -366
- package/docs/proposals/self-contained-guidance.md +0 -427
- package/docs/proto-sdk-generation.md +0 -242
- package/docs/release-impact.md +0 -102
- package/docs/release-process.md +0 -157
- package/docs/staging.RULE.md +0 -142
- package/docs/test-persona-creation.md +0 -196
- package/docs/tool-consolidation-v2.md +0 -225
- package/docs/tool-response-standards.md +0 -256
- package/resources/demo-kits/README.md +0 -175
- package/resources/demo-kits/finance-ap/manifest.json +0 -150
- package/resources/demo-kits/tags.json +0 -91
- package/resources/docs/getting-started.md +0 -97
- package/resources/templates/auto-builder-rules.md +0 -224
- package/resources/templates/chat-ai/README.md +0 -119
- package/resources/templates/chat-ai/persona-config.json +0 -111
- package/resources/templates/dashboard-ai/README.md +0 -156
- package/resources/templates/dashboard-ai/persona-config.json +0 -180
- package/resources/templates/demo-scenarios/README.md +0 -63
- package/resources/templates/demo-scenarios/test-published-package.md +0 -116
- package/resources/templates/document-gen-ai/README.md +0 -132
- package/resources/templates/document-gen-ai/persona-config.json +0 -316
- package/resources/templates/voice-ai/README.md +0 -123
- package/resources/templates/voice-ai/persona-config.json +0 -74
- 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
|
+
}
|