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

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/dist/mcp/tools.js CHANGED
@@ -76,8 +76,8 @@ ${LIMITATIONS.map(l => `- ${l}`).join("\n")}
76
76
  ## Data Operations (sub-resource, requires id)
77
77
  - \`persona(id="abc", data={method:"list"})\` - list data items
78
78
  - \`persona(id="abc", data={method:"stats"})\` - get file counts by status (total, pending, success, failed)
79
- - \`persona(id="abc", data={method:"upload", path:"/file.pdf"})\` - upload file
80
- - \`persona(id="abc", data={method:"upload", items:[{...}]})\` - upload LLM-generated content
79
+ - \`persona(id="abc", data={method:"upload", path:"/file.pdf"})\` - upload file to knowledge base
80
+ - \`persona(id="abc", data={method:"upload", items:[{...}]})\` - create dashboard rows with data
81
81
  - \`persona(id="abc", data={method:"copy", from:"source-id"})\` - copy from another persona
82
82
  - \`persona(id="abc", data={method:"copy", from:"src", sanitize:true})\` - copy with PII masking
83
83
  - \`persona(id="abc", data={method:"replicate", from:"source-id"})\` - replicate by reference (no copy, fast)
@@ -88,7 +88,20 @@ ${LIMITATIONS.map(l => `- ${l}`).join("\n")}
88
88
  - \`persona(id="abc", data={method:"regenerate", document_id:"doc-123", project_id:"proj-456", selection:"intro", query:"make it shorter"})\` - modify document section
89
89
  - \`persona(id="abc", data={method:"replace", document_id:"doc-123", project_id:"proj-456", content:"new content"})\` - replace entire document content
90
90
 
91
- Note: For documents, \`replace\` is full content replacement (no partial update). For dashboard fixed inputs, use upload with existing row context.
91
+ ### Dashboard Row Upload with Files
92
+ Create dashboard rows with file attachments (triggers workflow execution):
93
+ \`\`\`
94
+ persona(id="abc", data={
95
+ method: "upload",
96
+ items: [{
97
+ "Input Document": { file: "/path/to/invoice.pdf" },
98
+ "Customer Name": "Acme Corp"
99
+ }]
100
+ })
101
+ \`\`\`
102
+ Item values support: strings, numbers, booleans, file attachments ({ file: "path" }), or inline documents ({ contents: "...", mime_type: "..." }).
103
+
104
+ Note: \`path\` uploads to knowledge base (Chat personas). \`items\` creates dashboard rows (Dashboard personas).
92
105
 
93
106
  ## Action Composition (post-operation actions)
94
107
  Use \`actions\` array for multi-step operations instead of flag parameters.
@@ -224,11 +237,17 @@ persona(
224
237
  },
225
238
  wait: { type: "boolean", description: "Wait for replication to complete (for method=replicate, default: true)" },
226
239
  // upload params
227
- path: { type: "string", description: "File path to upload (for method=upload)" },
228
- content: {
240
+ path: { type: "string", description: "File path to upload to knowledge base (for method=upload)" },
241
+ items: {
229
242
  type: "array",
230
243
  items: { type: "object" },
231
- description: "Content array - LLM-generated (for method=upload)"
244
+ description: "Dashboard rows to create. Each object maps column names to values. Values can be: strings, numbers, booleans, file attachments { file: '/path' }, or inline docs { contents: '...', mime_type: '...' }"
245
+ },
246
+ // widget_name - for targeting specific widgets in upload or filtering stats
247
+ // Especially important for Document Generation personas with multiple upload widgets
248
+ widget_name: {
249
+ type: "string",
250
+ description: "Target widget for upload OR filter for stats. For Document Proposal Manager: 'upload' (Content Repository), 'upload1' (Service Line Docs), 'upload2' (Style Guide). Default: 'fileUpload'. See catalog(type='widgets') for reference."
232
251
  },
233
252
  // delete params
234
253
  file_id: { type: "string", description: "File/item ID to delete (for method=delete)" },
@@ -236,8 +255,6 @@ persona(
236
255
  enabled: { type: "boolean", description: "Enable/disable embeddings (for method=embed)" },
237
256
  // search params
238
257
  query: { type: "string", description: "Search query (for method=search)" },
239
- // stats params
240
- widget_name: { type: "string", description: "Filter by widget name (for method=stats)" },
241
258
  },
242
259
  required: ["method"],
243
260
  },
@@ -343,10 +343,16 @@ export function generateSchemaBundle(config) {
343
343
  // Type Compatibility Matrix
344
344
  // ============================================================================
345
345
  /**
346
- * Type compatibility rules for workflow validation
346
+ * Schema validation type compatibility - maps well-known types to compatible input names.
347
+ * Used by isTypeCompatible() for workflow validation.
348
+ *
349
+ * NOTE: This is SEPARATE from knowledge.ts TYPE_COMPATIBILITY which is user-facing documentation.
350
+ * This focuses on input NAME matching for schema validation.
351
+ *
352
+ * Canonical type documentation: src/sdk/knowledge.ts → TYPE_COMPATIBILITY
347
353
  */
348
- export const TYPE_COMPATIBILITY = {
349
- // What inputs can accept each type
354
+ export const SCHEMA_TYPE_COMPATIBILITY = {
355
+ // What input names can accept each type
350
356
  WELL_KNOWN_TYPE_CHAT_CONVERSATION: ["conversation", "chat_conversation"],
351
357
  WELL_KNOWN_TYPE_TEXT_WITH_SOURCES: ["query", "text", "user_query", "input"],
352
358
  WELL_KNOWN_TYPE_SEARCH_RESULT: ["search_results", "results"],
@@ -368,8 +374,8 @@ export function isTypeCompatible(sourceType, targetType, targetInputName) {
368
374
  if (targetInputName?.startsWith("named_inputs"))
369
375
  return true;
370
376
  // Check explicit compatibility
371
- if (sourceType && TYPE_COMPATIBILITY[sourceType]) {
372
- const compatible = TYPE_COMPATIBILITY[sourceType];
377
+ if (sourceType && SCHEMA_TYPE_COMPATIBILITY[sourceType]) {
378
+ const compatible = SCHEMA_TYPE_COMPATIBILITY[sourceType];
373
379
  if (compatible.includes("*"))
374
380
  return true;
375
381
  if (targetInputName && compatible.some((c) => targetInputName.includes(c)))
@@ -17,7 +17,7 @@
17
17
  * const client = new EmaClientV2(env);
18
18
  * ```
19
19
  *
20
- * See docs/lessons-learned.md for migration guidance.
20
+ * See .ctx/docs/lessons-learned.md for migration guidance.
21
21
  */
22
22
  import { GrpcClient } from "./grpc-client.js";
23
23
  import { toJson } from "@bufbuild/protobuf";
@@ -71,30 +71,55 @@ await persona({ id: "abc", update: { workflow_spec: spec } }); // Then deploy`,
71
71
  { name: "Fallback", description: "Anything else" } // Required!
72
72
  ]`,
73
73
  },
74
+ {
75
+ id: "data-sources-before-search",
76
+ level: "critical",
77
+ category: "workflow",
78
+ title: "Upload Data Sources Before Search",
79
+ applies: "When creating workflows with search/RAG nodes",
80
+ description: "Workflows with search/v2 nodes require data sources (documents) to be uploaded to the persona. " +
81
+ "Without documents, search returns empty results and RAG is useless.",
82
+ do: "1. Upload documents: persona(id='...', data={method:'upload', path:'/path/to/doc.pdf'})\n" +
83
+ "2. Check status: persona(id='...', data={method:'stats'}) → verify 'success' count > 0\n" +
84
+ "3. Then deploy workflow with search node",
85
+ dont: "Deploy search-based workflows before uploading any documents to the knowledge base.",
86
+ example: `// Upload documents first
87
+ await persona({ id: "abc", data: { method: "upload", path: "/docs/product-faq.pdf" } });
88
+ await persona({ id: "abc", data: { method: "upload", path: "/docs/pricing.pdf" } });
89
+
90
+ // Check they're indexed
91
+ const stats = await persona({ id: "abc", data: { method: "stats" } });
92
+ // stats.success should be > 0
93
+
94
+ // Then deploy workflow with search
95
+ await workflow({ mode: "deploy", persona_id: "abc", workflow_def: workflowWithSearch });`,
96
+ antiExample: `// BAD: Deploy search workflow with no documents
97
+ await workflow({ mode: "deploy", persona_id: "abc", workflow_def: workflowWithSearch });
98
+ // Search will return empty results!`,
99
+ related: ["analyze-before-modify"],
100
+ },
74
101
  {
75
102
  id: "workflow-modification-scope",
76
103
  level: "critical",
77
104
  category: "workflow",
78
105
  title: "Structure vs Content Changes",
79
106
  applies: "When modifying workflows",
80
- description: "workflow(mode='modify') only supports STRUCTURAL changes (add/remove nodes, rewire connections). " +
107
+ description: "persona(method='update', input='...') only supports STRUCTURAL changes (add/remove nodes, rewire connections). " +
81
108
  "CONTENT changes (fixed_response data, call_llm prompts) require manual workflow_def editing.",
82
- do: "For content changes: 1) Get workflow with persona(include_workflow=true), " +
109
+ do: "For content changes: 1) Get workflow with persona(method='get', id='...'), " +
83
110
  "2) Edit the node's stringValue in the JSON, 3) Deploy with workflow(mode='deploy', workflow_def={...})",
84
- dont: "Use workflow(mode='modify') for content changes - it will silently return 0 changes.",
85
- example: `// STRUCTURAL change (supported via structured operations)
86
- persona({ mode: "modify", id: "abc", operations: [
87
- { type: "insert", insert: { action_type: "hitl", insert_before: "send_email" }}
88
- ]})
111
+ dont: "Use update with input for content changes - it will silently return 0 changes.",
112
+ example: `// STRUCTURAL change (supported via update + input)
113
+ persona({ method: "update", id: "abc", input: "add HITL before send_email" })
89
114
 
90
115
  // CONTENT change (requires manual edit)
91
- const p = await persona({ id: "abc", include_workflow: true });
116
+ const p = await persona({ method: "get", id: "abc" });
92
117
  const wf = p.workflow_def;
93
118
  // Find and edit the fixed_response node's inputs.data.stringValue
94
119
  wf.actions[2].inputs.data.stringValue = JSON.stringify(newData);
95
120
  await workflow({ mode: "deploy", persona_id: "abc", workflow_def: wf });`,
96
- antiExample: `// This will silently fail - content change via modify
97
- persona({ mode: "modify", id: "abc", operations: [...] }) // for content changes`,
121
+ antiExample: `// This will silently fail - content change via update
122
+ persona({ method: "update", id: "abc", input: "change the welcome message" }) // for content changes`,
98
123
  related: ["workflow-spec-not-def", "llm-driven-modifications"],
99
124
  },
100
125
  {
@@ -103,15 +128,16 @@ persona({ mode: "modify", id: "abc", operations: [...] }) // for content change
103
128
  category: "workflow",
104
129
  title: "LLM-Driven Workflow Modifications",
105
130
  applies: "When modifying workflows structurally",
106
- description: "The MCP does NOT parse natural language for modifications. YOU (the Agent/LLM) must build structured operations. " +
107
- "Call persona(mode='modify') first to get workflow context, then build operations array.",
108
- do: "1) Get context: persona(mode='modify', id='...') returns current_nodes, available_actions, example_operations. " +
109
- "2) Build structured operations array. 3) Execute: persona(mode='modify', id='...', operations=[...])",
110
- dont: "Pass natural language strings expecting MCP to parse them into operations.",
111
- example: `// Step 1: Get context (returns current_nodes, available_actions, examples)
112
- const ctx = await persona({ mode: "modify", id: "abc" });
113
-
114
- // Step 2: YOU build structured operations based on user intent
131
+ description: "Use persona(method='update', input='...') for incremental changes. The MCP routes this to the workflow modify handler. " +
132
+ "For structured operations, use persona(method='update', operations=[...]).",
133
+ do: "1) Analyze workflow: persona(method='analyze', id='...') returns workflow_spec and issues. " +
134
+ "2) Make changes: persona(method='update', id='...', input='add HITL before email') " +
135
+ "3) Or use structured operations: persona(method='update', id='...', operations=[...])",
136
+ dont: "Expect operations to work without understanding the current workflow structure first.",
137
+ example: `// Option 1: Natural language input (routed to modify handler)
138
+ await persona({ method: "update", id: "abc", input: "add HITL approval before send_email" });
139
+
140
+ // Option 2: Structured operations
115
141
  const operations = [
116
142
  {
117
143
  type: "insert",
@@ -123,12 +149,10 @@ const operations = [
123
149
  }
124
150
  }
125
151
  ];
126
-
127
- // Step 3: Execute
128
- await persona({ mode: "modify", id: "abc", operations });`,
129
- antiExample: `// DON'T: Pass natural language expecting MCP to understand it
130
- await persona({ mode: "modify", id: "abc", input: "add approval before email" })
131
- // The MCP will NOT parse this - it returns context instead`,
152
+ await persona({ method: "update", id: "abc", operations });`,
153
+ antiExample: `// DON'T: Try to modify without analyzing first
154
+ await persona({ method: "update", id: "abc", operations: [...] })
155
+ // Always analyze the workflow first to understand structure`,
132
156
  related: ["workflow-modification-scope", "analyze-before-modify"],
133
157
  },
134
158
  // ─────────────────────────────────────────────────────────────────────────
@@ -240,14 +264,14 @@ export const TOOL_GUIDANCE = {
240
264
  example: 'persona(id="abc", analyze=true)',
241
265
  },
242
266
  {
243
- name: "Get modify context",
244
- description: "Get current_nodes, available_actions for building operations",
245
- example: 'persona(mode="modify", id="abc")',
267
+ name: "Update with input",
268
+ description: "Incremental workflow changes via natural language",
269
+ example: 'persona(method="update", id="abc", input="add HITL before email")',
246
270
  },
247
271
  {
248
- name: "Execute modify",
272
+ name: "Update with operations",
249
273
  description: "Apply structured operations (insert/remove/rewire)",
250
- example: 'persona(mode="modify", id="abc", operations=[...])',
274
+ example: 'persona(method="update", id="abc", operations=[...])',
251
275
  },
252
276
  {
253
277
  name: "Create",
@@ -406,12 +430,11 @@ ${critical.map((r) => `- **${r.title}**: ${r.do}`).join("\n")}
406
430
  ${important.map((r) => `- **${r.title}**: ${r.do}`).join("\n")}
407
431
 
408
432
  ## LLM-Driven Architecture (CRITICAL)
409
- The MCP does NOT parse natural language for workflow modifications.
410
- **YOU (the Agent) must build structured operations:**
433
+ Use \`persona(method="update", input="...")\` for workflow modifications:
411
434
 
412
- 1. Get context: \`persona(mode="modify", id="...")\` → returns current_nodes, available_actions
413
- 2. Build operations array based on user intent
414
- 3. Execute: \`persona(mode="modify", id="...", operations=[...])\`
435
+ 1. Analyze: \`persona(method="analyze", id="...")\` → returns workflow_spec, issues
436
+ 2. Update with natural language: \`persona(method="update", id="...", input="add HITL before email")\`
437
+ 3. Or use structured operations: \`persona(method="update", id="...", operations=[...])\`
415
438
 
416
439
  Example operations: insert, remove, rewire, update_config
417
440
 
package/dist/sdk/index.js CHANGED
@@ -27,8 +27,8 @@ AGENT_CATALOG, WIDGET_CATALOG, WORKFLOW_PATTERNS, QUALIFYING_QUESTIONS, PLATFORM
27
27
  PROJECT_TYPES,
28
28
  // Helper Functions
29
29
  getAgentsByCategory, getAgentByName, getWidgetsForPersonaType, checkTypeCompatibility, getQualifyingQuestionsByCategory, getRequiredQualifyingQuestions, getConceptByTerm, suggestAgentsForUseCase, validateWorkflowPrompt,
30
- // Workflow Analysis Functions
31
- parseWorkflowDef, detectWorkflowIssues, validateWorkflowConnections, analyzeWorkflow, suggestWorkflowFixes,
30
+ // Workflow Data Functions (LLM does analysis with rules)
31
+ parseWorkflowDef, validateWorkflowConnections,
32
32
  // Validation Rules (Single Source of Truth)
33
33
  VALIDATION_INPUT_RULES, ANTI_PATTERNS, OPTIMIZATION_RULES, findInputSourceRule, findAntiPatternByIssueType, generateMarkdownDocumentation, exportRulesAsJSON, } from "./knowledge.js";
34
34
  // Workflow Compiler (Template-driven workflow generation)
@@ -57,8 +57,9 @@ export { VersionStorage, createVersionStorage, } from "./version-storage.js";
57
57
  export { VersionPolicyEngine, createVersionPolicyEngine, } from "./version-policy.js";
58
58
  // Workflow Execution Analyzer (Loop, multiple responder, redundant classifier detection)
59
59
  export { analyzeExecutionFlow, detectLoops, detectMultipleResponders, detectRedundantClassifiers, analyzeDataFlow, findDeadCodePaths, generateASCIIFlow, } from "./workflow-execution-analyzer.js";
60
- // Workflow Fixer (Auto-fix including multiple responder issues)
61
- export { autoFixWorkflow, suggestFixes, } from "./workflow-fixer.js";
60
+ // Workflow Fixer - REMOVED
61
+ // autoFixWorkflow, suggestFixes removed as part of "MCP = data, LLM = logic" refactor
62
+ // LLM now applies rules from ema://rules/* and proposes fixes
62
63
  // Intent Architect (WHY + WHAT, not HOW - with progressive enhancement)
63
64
  // NOTE: intent-decomposition.ts and intent-decomposition-v2.ts were removed as part of consolidation.
64
65
  // All intent processing now goes through the Intent Architect module.
@@ -86,12 +87,12 @@ runIntentArchitect, } from "./intent-architect.js";
86
87
  export { analyzeOptimizations, summarizeOptimizationReport, } from "./workflow-optimizer.js";
87
88
  // Workflow Tracer (Flow visualization & path analysis)
88
89
  export { traceWorkflow, generateDetailedTrace, formatFlowTrace, formatDetailedTrace, } from "./workflow-tracer.js";
89
- // Quality Gates (Pre-deploy validation)
90
- export { runQualityGates, canDeploy, getQualityGates, formatQualityReport, } from "./quality-gates.js";
90
+ // Quality Gates (Pre-deploy validation) - DEPRECATED, minimal implementation
91
+ export { runQualityGates, formatQualityReport, isDeploymentAllowed, getBlockingIssues, QUALITY_GATES, } from "./quality-gates.js";
91
92
  // Structural Rules (LLM validation context)
92
93
  export { STRUCTURAL_RULES_FOR_LLM, STRUCTURAL_INVARIANTS, EXECUTION_RULES, COMMON_STRUCTURAL_MISTAKES, getAllStructuralRules, getInvariantById, getCriticalInvariants, } from "./structural-rules.js";
93
94
  // Action Schema Parser (Parse ema_backend/grpc definitions)
94
- export { parseTextproto, parseActionDirectory, loadDocumentation, generateSchemaBundle, isTypeCompatible as isSchemaTypeCompatible, TYPE_COMPATIBILITY, } from "./action-schema-parser.js";
95
+ export { parseTextproto, parseActionDirectory, loadDocumentation, generateSchemaBundle, isTypeCompatible as isSchemaTypeCompatible, SCHEMA_TYPE_COMPATIBILITY, } from "./action-schema-parser.js";
95
96
  // Workflow Merge (Brownfield workflow comparison, merging, validation)
96
97
  export { compareWorkflows, mergeWorkflows, validateMergedWorkflow, } from "./workflow-merge.js";
97
98
  // Auto Builder Prompt Generation