@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
@@ -4,10 +4,13 @@
4
4
  * Provides static and file-backed resources for the Ema MCP Server.
5
5
  *
6
6
  * Resources are the canonical source of truth for:
7
- * - Templates: Persona configuration templates (voice, chat, dashboard)
8
- * - Agent Catalog: Dynamic list of available workflow agents
7
+ * - Agent Catalog: Dynamic list of available workflow agents + API templates
9
8
  * - Validation Rules: Input/output compatibility rules
10
9
  * - Documentation: User guides and references
10
+ * - Schemas: Action schemas and type definitions
11
+ *
12
+ * Note: File-backed templates (ema://templates/*) were removed.
13
+ * Use API templates via ema://catalog/persona-templates or template() tool.
11
14
  *
12
15
  * Why resources vs tools:
13
16
  * - Resources: Static/reference content the AI assistant reads to understand context
@@ -27,11 +30,12 @@ import { dirname } from "node:path";
27
30
  const __filename = fileURLToPath(import.meta.url);
28
31
  const __dirname = dirname(__filename);
29
32
  // Import knowledge catalogs for dynamic resources
30
- import { AGENT_CATALOG, WORKFLOW_PATTERNS, WIDGET_CATALOG } from "../sdk/knowledge.js";
33
+ import { AGENT_CATALOG, WORKFLOW_PATTERNS, WIDGET_CATALOG, ALL_DEPRECATED_ACTIONS, DEPRECATED_ACTIONS_WITH_REPLACEMENT, DEPRECATED_ACTIONS_NO_REPLACEMENT, WORKFLOW_ENABLING_CONSTRAINTS, MINIMUM_VIABLE_WORKFLOWS, } from "../sdk/knowledge.js";
31
34
  import { INPUT_SOURCE_RULES, ANTI_PATTERNS, OPTIMIZATION_RULES } from "../sdk/validation-rules.js";
32
35
  import { EmaClient } from "../sdk/client.js";
33
36
  import { APISchemaRegistry } from "../sdk/workflow-validator.js";
34
37
  import { loadConfigFromJsonEnv, loadConfigOptional, resolveBearerToken, getEnvByName, getMasterEnv, } from "../sdk/config.js";
38
+ import { VOICE_TEMPLATE_FALLBACK, VOICE_TEMPLATE_FIELD_DOCS, } from "../sdk/generated/template-fallbacks.js";
35
39
  // ─────────────────────────────────────────────────────────────────────────────
36
40
  // Security Utilities
37
41
  // ─────────────────────────────────────────────────────────────────────────────
@@ -97,7 +101,7 @@ function hasPathTraversal(uriPath) {
97
101
  const RESOURCE_MAP = {
98
102
  // Core Documentation (files that exist in this repo)
99
103
  "ema://docs/getting-started": {
100
- path: "resources/docs/getting-started.md",
104
+ path: "docs/mcp-tools-guide.md",
101
105
  description: "Quick start guide: first steps, key concepts, essential rules, common operations",
102
106
  mimeType: "text/markdown",
103
107
  },
@@ -116,42 +120,10 @@ const RESOURCE_MAP = {
116
120
  description: "MCP tools usage guide: tool categories, best practices, example call sequences, workflow review patterns",
117
121
  mimeType: "text/markdown",
118
122
  },
119
- // Templates - Persona configuration templates
120
- "ema://templates/voice-ai/config": {
121
- path: "resources/templates/voice-ai/persona-config.json",
122
- description: "Voice AI persona configuration template: voiceSettings, conversationSettings, vadSettings, dataProtection",
123
- mimeType: "application/json",
124
- },
125
- "ema://templates/voice-ai/workflow-prompt": {
126
- path: "resources/templates/voice-ai/workflow-prompt.md",
127
- description: "Voice AI Auto Builder prompt template with node definitions, connections, and validation assertions",
128
- mimeType: "text/markdown",
129
- },
130
- "ema://templates/voice-ai/readme": {
131
- path: "resources/templates/voice-ai/README.md",
132
- description: "Voice AI deployment guide: setup steps, testing checklist, maintenance procedures",
133
- mimeType: "text/markdown",
134
- },
135
- "ema://templates/chat-ai/config": {
136
- path: "resources/templates/chat-ai/persona-config.json",
137
- description: "Chat AI persona configuration template: chatbotSdkConfig, feedbackMessage, fileUpload settings",
138
- mimeType: "application/json",
139
- },
140
- "ema://templates/chat-ai/readme": {
141
- path: "resources/templates/chat-ai/README.md",
142
- description: "Chat AI deployment guide: workflow generation, widget configuration, knowledge base setup",
143
- mimeType: "text/markdown",
144
- },
145
- "ema://templates/dashboard-ai/config": {
146
- path: "resources/templates/dashboard-ai/persona-config.json",
147
- description: "Dashboard AI persona configuration template: inputSchema, batchSettings, timeout configuration",
148
- mimeType: "application/json",
149
- },
150
- "ema://templates/dashboard-ai/readme": {
151
- path: "resources/templates/dashboard-ai/README.md",
152
- description: "Dashboard AI deployment guide: batch processing setup, input configuration",
153
- mimeType: "text/markdown",
154
- },
123
+ // Templates - REMOVED (file-backed templates removed in favor of API + generated fallbacks)
124
+ // Use: client.getPersonaTemplates() for live API templates
125
+ // Use: getTemplateFallback("voice") from sdk/generated/template-fallbacks.ts for offline fallbacks
126
+ // See: ema://catalog/persona-templates for dynamic API-backed template listing
155
127
  // DEPRECATED: Use ema://docs/usage-guide (dynamic) instead
156
128
  // This static resource is kept for backwards compatibility but now generates from guidance module
157
129
  };
@@ -236,7 +208,330 @@ const DYNAMIC_RESOURCES = [
236
208
  mimeType: "application/json",
237
209
  generate: async () => JSON.stringify(OPTIMIZATION_RULES, null, 2),
238
210
  },
239
- // Persona Templates - Dynamic from API
211
+ // Deprecated Actions - API-first with fallback
212
+ {
213
+ uri: "ema://rules/deprecated-actions",
214
+ name: "rules/deprecated-actions",
215
+ description: "Deprecated actions list: actions to avoid in new workflows, with their replacements and migration notes",
216
+ mimeType: "application/json",
217
+ generate: async (ctx) => {
218
+ // Try API first using existing client infrastructure
219
+ let apiDeprecated = [];
220
+ let source = "fallback";
221
+ try {
222
+ const client = getClientForEnvName(ctx.env);
223
+ if (client) {
224
+ const actions = await client.listActions();
225
+ apiDeprecated = actions.filter(a => a.deprecated).map(a => a.id);
226
+ source = "api";
227
+ }
228
+ }
229
+ catch {
230
+ // API unavailable, use fallback
231
+ }
232
+ // Merge API deprecated with fallback replacement info
233
+ const result = {
234
+ _note: "Actions marked deprecated should not be used in new workflows. Use replacements where available.",
235
+ _source: source,
236
+ _api_deprecated_count: apiDeprecated.length,
237
+ // From API (current deprecated status)
238
+ api_deprecated: apiDeprecated.length > 0 ? apiDeprecated : undefined,
239
+ // From fallback (includes replacement info)
240
+ with_replacement: DEPRECATED_ACTIONS_WITH_REPLACEMENT.map(d => ({
241
+ action: d.action,
242
+ version: d.version,
243
+ replacement: d.replacement,
244
+ replacement_version: d.replacementVersion,
245
+ migration_notes: d.migrationNotes,
246
+ })),
247
+ no_replacement: DEPRECATED_ACTIONS_NO_REPLACEMENT.map(d => ({
248
+ action: d.action,
249
+ version: d.version,
250
+ environment: d.environment,
251
+ notes: d.migrationNotes,
252
+ })),
253
+ _tip: "Check workflow(mode='get') for deprecation_warnings on specific workflows",
254
+ };
255
+ return JSON.stringify(result, null, 2);
256
+ },
257
+ },
258
+ {
259
+ uri: "ema://rules/deprecated-actions-summary",
260
+ name: "rules/deprecated-actions-summary",
261
+ description: "Deprecated actions summary: quick reference table of deprecated actions and replacements",
262
+ mimeType: "text/markdown",
263
+ generate: async (ctx) => {
264
+ // Try API first using existing client infrastructure
265
+ let apiDeprecated = [];
266
+ let source = "fallback";
267
+ try {
268
+ const client = getClientForEnvName(ctx.env);
269
+ if (client) {
270
+ const actions = await client.listActions();
271
+ apiDeprecated = actions.filter(a => a.deprecated).map(a => a.id);
272
+ source = "api";
273
+ }
274
+ }
275
+ catch {
276
+ // API unavailable, use fallback
277
+ }
278
+ let md = "# Deprecated Actions\n\n";
279
+ md += "> Do NOT use these actions in new workflows. Use replacements where available.\n\n";
280
+ md += `> Source: ${source} (${source === "api" ? "live" : "synced 2026-01-26"})\n\n`;
281
+ if (apiDeprecated.length > 0) {
282
+ md += "## From API (Current)\n\n";
283
+ md += "| Action ID | Status |\n";
284
+ md += "|-----------|--------|\n";
285
+ for (const id of apiDeprecated) {
286
+ md += `| \`${id}\` | DEPRECATED |\n`;
287
+ }
288
+ md += "\n";
289
+ }
290
+ md += "## Actions with Known Replacements\n\n";
291
+ md += "| Deprecated Action | Version | Replacement | Notes |\n";
292
+ md += "|-------------------|---------|-------------|-------|\n";
293
+ for (const d of DEPRECATED_ACTIONS_WITH_REPLACEMENT) {
294
+ const repl = Array.isArray(d.replacement) ? d.replacement.join(" or ") : d.replacement;
295
+ const replVer = d.replacementVersion ? ` ${d.replacementVersion}` : "";
296
+ md += `| \`${d.action}\` | ${d.version} | \`${repl}\`${replVer} | ${d.migrationNotes || "-"} |\n`;
297
+ }
298
+ md += "\n## Actions with No Known Replacement\n\n";
299
+ md += "| Action | Environment | Notes |\n";
300
+ md += "|--------|-------------|-------|\n";
301
+ for (const d of DEPRECATED_ACTIONS_NO_REPLACEMENT) {
302
+ md += `| \`${d.action}\` | ${d.environment || "all"} | ${d.migrationNotes || "-"} |\n`;
303
+ }
304
+ md += `\n**Total Known Deprecated**: ${ALL_DEPRECATED_ACTIONS.length} actions\n`;
305
+ md += `\n> **Best Practice**: Use \`workflow(mode="get")\` to check for deprecation warnings in specific workflows.\n`;
306
+ return md;
307
+ },
308
+ },
309
+ // Workflow Enabling Constraints - Requirements for persona activation
310
+ {
311
+ uri: "ema://rules/workflow-constraints",
312
+ name: "rules/workflow-constraints",
313
+ description: "Workflow enabling constraints: requirements that must be met before a persona can be activated",
314
+ mimeType: "application/json",
315
+ generate: async () => JSON.stringify({
316
+ _note: "These constraints are checked by the Ema backend when enabling a persona.",
317
+ _source: "ema/ema_backend/db/models/personas_model.py:672-756",
318
+ _last_synced: "2026-01-26",
319
+ enabling_constraints: WORKFLOW_ENABLING_CONSTRAINTS,
320
+ minimum_viable_workflows: MINIMUM_VIABLE_WORKFLOWS,
321
+ }, null, 2),
322
+ },
323
+ {
324
+ uri: "ema://rules/workflow-constraints-summary",
325
+ name: "rules/workflow-constraints-summary",
326
+ description: "Workflow constraints summary: checklist of requirements for enabling a persona",
327
+ mimeType: "text/markdown",
328
+ generate: async () => {
329
+ let md = "# Workflow Enabling Constraints\n\n";
330
+ md += "> These constraints must be satisfied for a persona to be activated.\n\n";
331
+ md += "> Source: ema_backend/db/models/personas_model.py (synced 2026-01-26)\n\n";
332
+ md += "## Required Checks\n\n";
333
+ md += "| # | Constraint | Error State | Fix |\n";
334
+ md += "|---|------------|-------------|-----|\n";
335
+ for (const c of WORKFLOW_ENABLING_CONSTRAINTS) {
336
+ const critical = c.critical ? "**" : "";
337
+ md += `| ${c.id} | ${critical}${c.name}${critical} | \`${c.errorState}\` | ${c.fix} |\n`;
338
+ }
339
+ md += "\n## Minimum Viable Workflows by Type\n\n";
340
+ for (const [type, mvw] of Object.entries(MINIMUM_VIABLE_WORKFLOWS)) {
341
+ md += `### ${type}\n\n`;
342
+ md += `**Structure**: \`${mvw.exampleStructure}\`\n\n`;
343
+ md += `- Required nodes: ${mvw.requiredNodes.map(n => `\`${n}\``).join(", ")}\n`;
344
+ md += `- Required outputs: ${mvw.requiredOutputs.map(o => `\`${o}\``).join(", ")}\n`;
345
+ if (mvw.requiredWidgets) {
346
+ md += `- Required widgets: ${mvw.requiredWidgets.map(w => `\`${w}\``).join(", ")}\n`;
347
+ }
348
+ if (mvw.notes) {
349
+ md += `- Notes: ${mvw.notes}\n`;
350
+ }
351
+ md += "\n";
352
+ }
353
+ md += "## Critical Rule: WORKFLOW_OUTPUT\n\n";
354
+ md += "**Every workflow must have a `results.WORKFLOW_OUTPUT` that maps to an action output.**\n\n";
355
+ md += "```json\n";
356
+ md += '{\n "results": {\n "WORKFLOW_OUTPUT": {\n "actionName": "respond_node",\n "outputName": "response_with_sources"\n }\n }\n}\n';
357
+ md += "```\n";
358
+ return md;
359
+ },
360
+ },
361
+ // ─────────────────────────────────────────────────────────────────────────────
362
+ // Workflow Requirements & Guidance
363
+ // NOT hardcoded templates - provide requirements and let LLM generate
364
+ // ─────────────────────────────────────────────────────────────────────────────
365
+ {
366
+ uri: "ema://templates/voice-ai/requirements",
367
+ name: "templates/voice-ai/requirements",
368
+ description: "Voice AI workflow requirements and guidance. Use workflow(mode='get') for schema, then generate workflow_def.",
369
+ mimeType: "application/json",
370
+ generate: async () => {
371
+ return JSON.stringify({
372
+ _note: "Requirements and guidance for Voice AI workflows. LLM generates workflow_def based on these.",
373
+ _usage: "1) workflow(mode='get', persona_id='...') for schema, 2) Generate workflow_def, 3) workflow(mode='deploy', ...)",
374
+ hard_requirements: {
375
+ workflow_output: {
376
+ rule: "MUST have results.WORKFLOW_OUTPUT mapped to final action output",
377
+ example: '{ "results": { "WORKFLOW_OUTPUT": { "actionName": "respond", "outputName": "response" } } }',
378
+ },
379
+ workflow_name: {
380
+ rule: "workflowName MUST be ['ema', 'personas', '<actual_persona_id>']",
381
+ },
382
+ trigger: {
383
+ rule: "Voice AI uses chat_trigger (type CHAT)",
384
+ namespace: ["triggers", "emainternal"],
385
+ },
386
+ response: {
387
+ rule: "Must produce a response output that wires to WORKFLOW_OUTPUT",
388
+ },
389
+ },
390
+ required_widgets: [
391
+ { name: "conversationSettings", type: 39, purpose: "Voice identity, welcome message, instructions" },
392
+ { name: "voiceSettings", type: 40, purpose: "Language, voice model" },
393
+ { name: "callSettings", type: 41, purpose: "Call forwarding, spam prevention" },
394
+ { name: "vadSettings", type: 42, purpose: "Voice activity detection, timeouts" },
395
+ ],
396
+ common_patterns: {
397
+ simple_qa: "chat_trigger → search → respond_for_external_actions → WORKFLOW_OUTPUT",
398
+ with_routing: "chat_trigger → chat_categorizer → [branch per intent] → respond → WORKFLOW_OUTPUT",
399
+ with_tools: "chat_trigger → categorizer → external_action_caller → respond_for_external_actions → WORKFLOW_OUTPUT",
400
+ },
401
+ best_practices: [
402
+ "Use search/v2 (NOT v0) with datastore_configs",
403
+ "Include Fallback category in every categorizer",
404
+ "Use respond_for_external_actions (NOT deprecated respond_with_sources)",
405
+ "Consider general_hitl before actions with side effects",
406
+ ],
407
+ _next_step: "Call workflow(mode='get', persona_id='...') to get full schema, then generate workflow_def",
408
+ }, null, 2);
409
+ },
410
+ },
411
+ {
412
+ uri: "ema://templates/voice-ai/config",
413
+ name: "templates/voice-ai/config",
414
+ description: "Voice AI configuration template (proto_config widgets). Customize values for your use case.",
415
+ mimeType: "application/json",
416
+ generate: async () => {
417
+ const config = {
418
+ _note: "Voice AI configuration template. Customize values for your use case.",
419
+ _usage: "persona(method='update', id='<ID>', config={widgets: [<these widgets with your values>]})",
420
+ widgets: [
421
+ {
422
+ name: "conversationSettings",
423
+ type: 39,
424
+ conversationSettings: {
425
+ ...VOICE_TEMPLATE_FALLBACK.conversationSettings,
426
+ },
427
+ },
428
+ {
429
+ name: "voiceSettings",
430
+ type: 40,
431
+ voiceSettings: {
432
+ ...VOICE_TEMPLATE_FALLBACK.voiceSettings,
433
+ },
434
+ },
435
+ {
436
+ name: "callSettings",
437
+ type: 41,
438
+ callSettings: {
439
+ ...VOICE_TEMPLATE_FALLBACK.callSettings,
440
+ },
441
+ },
442
+ {
443
+ name: "vadSettings",
444
+ type: 42,
445
+ vadSettings: {
446
+ ...VOICE_TEMPLATE_FALLBACK.vadSettings,
447
+ },
448
+ },
449
+ ],
450
+ field_docs: VOICE_TEMPLATE_FIELD_DOCS,
451
+ };
452
+ return JSON.stringify(config, null, 2);
453
+ },
454
+ },
455
+ {
456
+ uri: "ema://templates/voice-ai/guide",
457
+ name: "templates/voice-ai/guide",
458
+ description: "Voice AI creation guide with requirements and step-by-step process",
459
+ mimeType: "text/markdown",
460
+ generate: async () => {
461
+ return `# Voice AI Creation Guide
462
+
463
+ ## Process (Follow This Order)
464
+
465
+ ### 1. Create Persona
466
+ \`\`\`
467
+ persona(method="create", name="Your Voice AI", type="voice")
468
+ \`\`\`
469
+
470
+ ### 2. Get Workflow Schema
471
+ \`\`\`
472
+ workflow(mode="get", persona_id="<ID>")
473
+ \`\`\`
474
+ This returns:
475
+ - Current workflow (if any)
476
+ - Deprecation warnings (fix these first!)
477
+ - Generation schema (agents, constraints)
478
+ - Requirements and guidance
479
+
480
+ ### 3. Generate Workflow
481
+ Using the schema, generate a workflow_def that:
482
+ - Has WORKFLOW_OUTPUT in results
483
+ - Uses non-deprecated actions
484
+ - Follows the flow pattern: trigger → processing → response → OUTPUT
485
+
486
+ ### 4. Deploy Workflow
487
+ \`\`\`
488
+ workflow(mode="deploy", persona_id="<ID>", workflow_def={...}, preview=true)
489
+ \`\`\`
490
+ Always preview first!
491
+
492
+ ### 5. Configure Settings
493
+ \`\`\`
494
+ persona(method="update", id="<ID>", config={widgets: [...]})
495
+ \`\`\`
496
+
497
+ ### 6. Upload Knowledge
498
+ \`\`\`
499
+ persona(id="<ID>", data={method:"upload", path:"your-data.txt"})
500
+ \`\`\`
501
+
502
+ ## Hard Requirements
503
+
504
+ | Requirement | Why |
505
+ |-------------|-----|
506
+ | WORKFLOW_OUTPUT | Persona cannot be activated without it |
507
+ | workflowName format | API rejects invalid namespaces |
508
+ | Non-deprecated actions | Deprecated actions may fail |
509
+
510
+ ## Check for Deprecated Actions
511
+
512
+ \`workflow(mode="get")\` returns \`deprecation_warnings\` if any actions are deprecated.
513
+ **Fix these BEFORE deploying.**
514
+
515
+ ## Common Deprecated Actions
516
+
517
+ | Deprecated | Use Instead |
518
+ |------------|-------------|
519
+ | search/v0 | search/v2 (requires datastore_configs) |
520
+ | respond_with_sources | respond_for_external_actions |
521
+ | call_llm/v0 | call_llm/v2 |
522
+
523
+ ## Anti-Patterns
524
+
525
+ ❌ Cloning random existing persona
526
+ ❌ Skipping workflow_def
527
+ ❌ Using deprecated actions
528
+ ❌ Deploying without preview
529
+
530
+ ${VOICE_TEMPLATE_FIELD_DOCS}
531
+ `;
532
+ },
533
+ },
534
+ // Persona Templates - Dynamic from API with fallback
240
535
  {
241
536
  uri: "ema://catalog/templates",
242
537
  name: "catalog/templates",
@@ -244,7 +539,15 @@ const DYNAMIC_RESOURCES = [
244
539
  mimeType: "application/json",
245
540
  generate: async (ctx) => {
246
541
  const templates = await getDynamicPersonaTemplates({ env: ctx.env });
247
- return JSON.stringify(templates.map(templateDtoToResource), null, 2);
542
+ if (templates.length > 0) {
543
+ return JSON.stringify(templates.map(templateDtoToResource), null, 2);
544
+ }
545
+ // Fallback when API unavailable - provide guidance
546
+ return JSON.stringify({
547
+ _note: "API templates unavailable. Use catalog(method='list', type='templates') tool which connects to API directly, or use template(config='voice|chat|dashboard') for config fallbacks.",
548
+ fallback_types: ["voice", "chat", "dashboard"],
549
+ how_to_get: "catalog(method='list', type='templates') or template(config='voice')",
550
+ }, null, 2);
248
551
  },
249
552
  },
250
553
  {
@@ -255,7 +558,28 @@ const DYNAMIC_RESOURCES = [
255
558
  generate: async (ctx) => {
256
559
  const templates = await getDynamicPersonaTemplates({ env: ctx.env });
257
560
  if (templates.length === 0) {
258
- return "# Persona Templates\n\n> No templates available from API. Check configuration or use file-backed templates at `ema://templates/*`.\n";
561
+ return `# Persona Templates
562
+
563
+ > API templates not available. Use one of these alternatives:
564
+
565
+ ## Option 1: Use the catalog tool directly
566
+ \`\`\`
567
+ catalog(method="list", type="templates")
568
+ \`\`\`
569
+ This connects to the API and may have different credentials.
570
+
571
+ ## Option 2: Use config fallbacks
572
+ \`\`\`
573
+ template(config="voice") // Voice AI config template
574
+ template(config="chat") // Chat AI config template
575
+ template(config="dashboard") // Dashboard AI config template
576
+ \`\`\`
577
+
578
+ ## Option 3: Create from scratch
579
+ \`\`\`
580
+ persona(method="create", name="My AI", type="voice|chat|dashboard")
581
+ \`\`\`
582
+ `;
259
583
  }
260
584
  const byCategory = new Map();
261
585
  for (const t of templates) {
@@ -727,10 +1051,11 @@ export class ResourceRegistry {
727
1051
  buildResourceIndex() {
728
1052
  const resources = this.list().filter((r) => r.uri !== "ema://index/all-resources");
729
1053
  // Group resources by category
1054
+ // Note: ema://templates/* file-backed resources removed - use API templates or generated fallbacks
730
1055
  const docs = resources.filter((r) => r.uri.startsWith("ema://docs/"));
731
- const templates = resources.filter((r) => r.uri.startsWith("ema://templates/"));
732
1056
  const catalog = resources.filter((r) => r.uri.startsWith("ema://catalog/"));
733
1057
  const rules = resources.filter((r) => r.uri.startsWith("ema://rules/"));
1058
+ const schemas = resources.filter((r) => r.uri.startsWith("ema://schema/"));
734
1059
  const markdown = `# Ema MCP Resources Index
735
1060
 
736
1061
  > Available resources exposed by the Ema MCP Server
@@ -742,9 +1067,9 @@ export class ResourceRegistry {
742
1067
  | Category | Count | Description |
743
1068
  |----------|-------|-------------|
744
1069
  | Documentation | ${docs.length} | User guides, README, tool references |
745
- | Templates | ${templates.length} | Persona configuration templates (voice/chat/dashboard) |
746
- | Catalog | ${catalog.length} | Agent catalog, workflow patterns, widgets |
1070
+ | Catalog | ${catalog.length} | Agent catalog, workflow patterns, templates |
747
1071
  | Rules | ${rules.length} | Validation rules, anti-patterns, optimizations |
1072
+ | Schemas | ${schemas.length} | Action schemas, type definitions |
748
1073
 
749
1074
  ## Documentation (${docs.length})
750
1075
 
@@ -752,14 +1077,6 @@ export class ResourceRegistry {
752
1077
  |-----|-------------|
753
1078
  ${docs.map((r) => `| \`${r.uri}\` | ${r.description} |`).join("\n")}
754
1079
 
755
- ## Templates (${templates.length})
756
-
757
- > Use templates as starting points for new AI Employees
758
-
759
- | URI | Description |
760
- |-----|-------------|
761
- ${templates.map((r) => `| \`${r.uri}\` | ${r.description} |`).join("\n")}
762
-
763
1080
  ## Catalog (${catalog.length})
764
1081
 
765
1082
  > Dynamic catalogs generated from SDK knowledge
@@ -776,6 +1093,14 @@ ${catalog.map((r) => `| \`${r.uri}\` | ${r.description} |`).join("\n")}
776
1093
  |-----|-------------|
777
1094
  ${rules.map((r) => `| \`${r.uri}\` | ${r.description} |`).join("\n")}
778
1095
 
1096
+ ## Schemas (${schemas.length})
1097
+
1098
+ > Action schemas and type definitions
1099
+
1100
+ | URI | Description |
1101
+ |-----|-------------|
1102
+ ${schemas.map((r) => `| \`${r.uri}\` | ${r.description} |`).join("\n")}
1103
+
779
1104
  ## Usage
780
1105
 
781
1106
  To read a resource, use the \`resources/read\` endpoint:
@@ -795,10 +1120,10 @@ To read a resource, use the \`resources/read\` endpoint:
795
1120
  |------|-----|
796
1121
  | Get agent definitions | Resource: \`ema://catalog/agents\` |
797
1122
  | Get input/output compatibility rules | Resource: \`ema://rules/input-sources\` |
798
- | Get persona template | Resource: \`ema://templates/voice-ai/config\` |
1123
+ | Get persona templates | Resource: \`ema://catalog/persona-templates\` (API) or Tool: \`template(config="voice")\` |
799
1124
  | Query live persona data | Tool: \`persona\` |
800
- | Generate a workflow | Tool: \`workflow\` |
801
- | Analyze an existing workflow | Tool: \`workflow(mode="analyze")\` |
1125
+ | Get workflow data | Tool: \`workflow(mode="get")\` |
1126
+ | Deploy workflow | Tool: \`workflow(mode="deploy")\` |
802
1127
  `;
803
1128
  return {
804
1129
  uri: "ema://index/all-resources",