@ema.co/mcp-toolkit 2026.2.19 → 2026.2.23
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/cli/index.js +2 -2
- package/dist/mcp/domain/loop-detection.js +46 -54
- package/dist/mcp/domain/sanitizer.js +1 -1
- package/dist/mcp/domain/workflow-graph.js +2 -2
- package/dist/mcp/domain/workflow-path-enumerator.js +7 -4
- package/dist/mcp/guidance.js +53 -0
- package/dist/mcp/handlers/debug/adapter.js +15 -0
- package/dist/mcp/handlers/debug/formatters.js +282 -0
- package/dist/mcp/handlers/debug/index.js +133 -0
- package/dist/mcp/handlers/demo/adapter.js +180 -0
- package/dist/mcp/handlers/env/config.js +2 -2
- package/dist/mcp/handlers/index.js +0 -1
- package/dist/mcp/handlers/persona/adapter.js +135 -0
- package/dist/mcp/handlers/sync/adapter.js +200 -0
- package/dist/mcp/handlers/workflow/adapter.js +174 -0
- package/dist/mcp/handlers/workflow/fix.js +11 -12
- package/dist/mcp/handlers/workflow/index.js +0 -24
- package/dist/mcp/knowledge-guidance-topics.js +615 -0
- package/dist/mcp/knowledge.js +23 -612
- package/dist/mcp/resources-dynamic.js +2395 -0
- package/dist/mcp/resources-validation.js +408 -0
- package/dist/mcp/resources.js +72 -2724
- package/dist/mcp/server.js +33 -832
- package/dist/mcp/tools.js +104 -2
- package/dist/sdk/client-adapter.js +265 -24
- package/dist/sdk/ema-client.js +100 -9
- package/dist/sdk/generated/well-known-types.js +99 -0
- package/dist/sdk/grpc-client.js +115 -1
- package/dist/sync/sdk.js +2 -2
- package/dist/sync.js +4 -3
- package/package.json +3 -2
- package/dist/mcp/handlers/knowledge/index.js +0 -54
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation Rules Generators for MCP Resources
|
|
3
|
+
*
|
|
4
|
+
* Generates LLM-friendly validation rules and best practices checklists
|
|
5
|
+
* from the canonical SDK rule definitions.
|
|
6
|
+
*
|
|
7
|
+
* Extracted from resources.ts for maintainability.
|
|
8
|
+
*/
|
|
9
|
+
import { INPUT_SOURCE_RULES, ANTI_PATTERNS, OPTIMIZATION_RULES } from "./domain/validation-rules.js";
|
|
10
|
+
import { STRUCTURAL_INVARIANTS } from "./domain/structural-rules.js";
|
|
11
|
+
/**
|
|
12
|
+
* Generate validation rules in LLM-friendly Markdown format.
|
|
13
|
+
* Includes rules from Go validator: required outputs, multiple writers, response/abstain, category hierarchy.
|
|
14
|
+
*/
|
|
15
|
+
export function generateValidationRulesForLLM() {
|
|
16
|
+
return `# Workflow Validation Rules
|
|
17
|
+
|
|
18
|
+
> **Use these rules DURING workflow generation to avoid errors proactively.**
|
|
19
|
+
|
|
20
|
+
These rules are extracted from the Go validator's static validation logic. Follow them when generating or modifying workflows.
|
|
21
|
+
|
|
22
|
+
## Rule 1: Required Output on All Paths
|
|
23
|
+
|
|
24
|
+
**Rule ID**: \`required_output_all_paths\`
|
|
25
|
+
**Severity**: Critical
|
|
26
|
+
**Applies To**: Named results, execution paths
|
|
27
|
+
|
|
28
|
+
### Logic
|
|
29
|
+
|
|
30
|
+
**Algorithm**: Enumerate all execution paths. For each path, check if all named results are produced.
|
|
31
|
+
|
|
32
|
+
**Steps**:
|
|
33
|
+
1. Enumerate all paths from trigger to completion
|
|
34
|
+
2. For each path, collect all outputs produced
|
|
35
|
+
3. For each named result, check if it's in path outputs
|
|
36
|
+
4. If missing on any path → error
|
|
37
|
+
|
|
38
|
+
**Complexity**: O(P * R) where P = paths, R = named results
|
|
39
|
+
|
|
40
|
+
### Rules
|
|
41
|
+
|
|
42
|
+
**Constraint**: Every execution path must produce all named results.
|
|
43
|
+
|
|
44
|
+
**Why**: Named results are contract guarantees. If a path doesn't produce a required output, the contract is violated.
|
|
45
|
+
|
|
46
|
+
### Examples
|
|
47
|
+
|
|
48
|
+
**Bad Pattern**:
|
|
49
|
+
\`\`\`json
|
|
50
|
+
{
|
|
51
|
+
"path": ["trigger", "categorizer", "billing_branch", "search"],
|
|
52
|
+
"named_result": "response_with_sources",
|
|
53
|
+
"produces": [] // Missing response
|
|
54
|
+
}
|
|
55
|
+
\`\`\`
|
|
56
|
+
|
|
57
|
+
**Why Bad**: Path ends without producing required output.
|
|
58
|
+
|
|
59
|
+
**Good Pattern**:
|
|
60
|
+
\`\`\`json
|
|
61
|
+
{
|
|
62
|
+
"path": ["trigger", "categorizer", "billing_branch", "search", "respond_for_external_actions"],
|
|
63
|
+
"named_result": "response",
|
|
64
|
+
"produces": ["response"] // ✅ Produced
|
|
65
|
+
}
|
|
66
|
+
\`\`\`
|
|
67
|
+
|
|
68
|
+
**Why Good**: All paths produce required output.
|
|
69
|
+
|
|
70
|
+
### Remediation
|
|
71
|
+
|
|
72
|
+
**How to Fix**:
|
|
73
|
+
1. Identify the path missing the output
|
|
74
|
+
2. Add a node that produces the required output
|
|
75
|
+
3. Connect the node's output to WORKFLOW_OUTPUT
|
|
76
|
+
|
|
77
|
+
**Common Fixes**:
|
|
78
|
+
- Add \`respond_for_external_actions\` node after search
|
|
79
|
+
- Add \`call_llm\` node for text generation
|
|
80
|
+
- Add \`fixed_response\` for static responses
|
|
81
|
+
|
|
82
|
+
**Prevention** (During Generation):
|
|
83
|
+
- Always ensure every categorizer branch has a response node
|
|
84
|
+
- Check that all paths end with nodes connected to WORKFLOW_OUTPUT
|
|
85
|
+
- Verify resultMappings include all required outputs
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Rule 2: Single Writer Per Output
|
|
90
|
+
|
|
91
|
+
**Rule ID**: \`single_writer_per_output\`
|
|
92
|
+
**Severity**: Critical
|
|
93
|
+
**Applies To**: Named results, execution paths
|
|
94
|
+
|
|
95
|
+
### Logic
|
|
96
|
+
|
|
97
|
+
**Algorithm**: For each named result, count how many nodes produce it on each path.
|
|
98
|
+
|
|
99
|
+
**Steps**:
|
|
100
|
+
1. For each named result
|
|
101
|
+
2. For each execution path
|
|
102
|
+
3. Count nodes that produce this result
|
|
103
|
+
4. If count > 1 on any path → error
|
|
104
|
+
|
|
105
|
+
### Rules
|
|
106
|
+
|
|
107
|
+
**Constraint**: A single named result can only have one producer per execution path.
|
|
108
|
+
|
|
109
|
+
**Why**: Multiple producers on the same path cause ambiguity about which value to use.
|
|
110
|
+
|
|
111
|
+
### Examples
|
|
112
|
+
|
|
113
|
+
**Bad Pattern**:
|
|
114
|
+
\`\`\`json
|
|
115
|
+
{
|
|
116
|
+
"path": ["trigger", "categorizer", "billing"],
|
|
117
|
+
"named_result": "response_with_sources",
|
|
118
|
+
"producers": ["respond_billing", "respond_general"] // ❌ Two producers
|
|
119
|
+
}
|
|
120
|
+
\`\`\`
|
|
121
|
+
|
|
122
|
+
**Why Bad**: Two nodes produce the same output on the same path.
|
|
123
|
+
|
|
124
|
+
**Good Pattern**:
|
|
125
|
+
\`\`\`json
|
|
126
|
+
{
|
|
127
|
+
"path": ["trigger", "categorizer", "billing"],
|
|
128
|
+
"named_result": "response_with_sources",
|
|
129
|
+
"producers": ["respond_billing"] // ✅ Single producer
|
|
130
|
+
}
|
|
131
|
+
\`\`\`
|
|
132
|
+
|
|
133
|
+
**Why Good**: Only one node produces the output.
|
|
134
|
+
|
|
135
|
+
### Remediation
|
|
136
|
+
|
|
137
|
+
**How to Fix**:
|
|
138
|
+
1. Identify which nodes produce the same output
|
|
139
|
+
2. Remove one producer or use different named results
|
|
140
|
+
3. Ensure only one node produces each named result per path
|
|
141
|
+
|
|
142
|
+
**Prevention** (During Generation):
|
|
143
|
+
- Use mutually exclusive runIf conditions to gate responders
|
|
144
|
+
- Ensure only one response node executes per category branch
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Rule 3: Response or Abstain Required
|
|
149
|
+
|
|
150
|
+
**Rule ID**: \`response_or_abstain_required\`
|
|
151
|
+
**Severity**: Critical
|
|
152
|
+
**Applies To**: Execution paths
|
|
153
|
+
|
|
154
|
+
### Logic
|
|
155
|
+
|
|
156
|
+
**Algorithm**: For each execution path, check if it produces a response or has an abstain reason.
|
|
157
|
+
|
|
158
|
+
**Steps**:
|
|
159
|
+
1. For each completed path
|
|
160
|
+
2. Check if path produces any response output
|
|
161
|
+
3. Check if path has abstain reason
|
|
162
|
+
4. If neither → error
|
|
163
|
+
|
|
164
|
+
### Rules
|
|
165
|
+
|
|
166
|
+
**Constraint**: Every execution path must either produce a user-visible response or explicitly abstain with a reason.
|
|
167
|
+
|
|
168
|
+
**Why**: Users expect responses. Paths that don't respond and don't explain why create poor UX.
|
|
169
|
+
|
|
170
|
+
### Examples
|
|
171
|
+
|
|
172
|
+
**Bad Pattern**:
|
|
173
|
+
\`\`\`json
|
|
174
|
+
{
|
|
175
|
+
"path": ["trigger", "categorizer", "billing", "search"],
|
|
176
|
+
"has_response": false,
|
|
177
|
+
"has_abstain": false // ❌ Neither
|
|
178
|
+
}
|
|
179
|
+
\`\`\`
|
|
180
|
+
|
|
181
|
+
**Why Bad**: Path ends without response or abstain reason.
|
|
182
|
+
|
|
183
|
+
**Good Pattern**:
|
|
184
|
+
\`\`\`json
|
|
185
|
+
{
|
|
186
|
+
"path": ["trigger", "categorizer", "billing", "search", "respond_for_external_actions"],
|
|
187
|
+
"has_response": true // ✅ Has response
|
|
188
|
+
}
|
|
189
|
+
\`\`\`
|
|
190
|
+
|
|
191
|
+
**Why Good**: Path produces a response.
|
|
192
|
+
|
|
193
|
+
### Remediation
|
|
194
|
+
|
|
195
|
+
**How to Fix**:
|
|
196
|
+
1. Add a response node to the path, OR
|
|
197
|
+
2. Add an abstain reason to the workflow configuration
|
|
198
|
+
|
|
199
|
+
**Prevention** (During Generation):
|
|
200
|
+
- Always add response nodes to every categorizer branch
|
|
201
|
+
- If a path shouldn't respond, document why with abstain reason
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Rule 4: Category Hierarchy Valid
|
|
206
|
+
|
|
207
|
+
**Rule ID**: \`category_hierarchy_valid\`
|
|
208
|
+
**Severity**: Critical
|
|
209
|
+
**Applies To**: Categorizers
|
|
210
|
+
|
|
211
|
+
### Logic
|
|
212
|
+
|
|
213
|
+
**Algorithm**: Validate categorizer structure and category definitions.
|
|
214
|
+
|
|
215
|
+
**Steps**:
|
|
216
|
+
1. Check categorizer has Fallback category
|
|
217
|
+
2. Check category hierarchy rules (TBD - need Go validator analysis)
|
|
218
|
+
3. Validate category → handler mapping
|
|
219
|
+
|
|
220
|
+
### Rules
|
|
221
|
+
|
|
222
|
+
**Constraint**: Categorizers must have proper structure and hierarchy.
|
|
223
|
+
|
|
224
|
+
**Why**: Invalid category structure causes routing failures.
|
|
225
|
+
|
|
226
|
+
### Examples
|
|
227
|
+
|
|
228
|
+
**Bad Pattern**:
|
|
229
|
+
\`\`\`json
|
|
230
|
+
{
|
|
231
|
+
"categorizer": {
|
|
232
|
+
"categories": ["Billing", "Technical"] // ❌ No Fallback
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
\`\`\`
|
|
236
|
+
|
|
237
|
+
**Why Bad**: Missing Fallback category means unrecognized intents have no handler.
|
|
238
|
+
|
|
239
|
+
**Good Pattern**:
|
|
240
|
+
\`\`\`json
|
|
241
|
+
{
|
|
242
|
+
"categorizer": {
|
|
243
|
+
"categories": ["Billing", "Technical", "Fallback"] // ✅ Has Fallback
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
\`\`\`
|
|
247
|
+
|
|
248
|
+
**Why Good**: All intents have a handler.
|
|
249
|
+
|
|
250
|
+
### Remediation
|
|
251
|
+
|
|
252
|
+
**How to Fix**:
|
|
253
|
+
1. Add Fallback category to categorizer
|
|
254
|
+
2. Ensure each category has a handler node
|
|
255
|
+
3. Validate category hierarchy (TBD)
|
|
256
|
+
|
|
257
|
+
**Prevention** (During Generation):
|
|
258
|
+
- Always include Fallback category
|
|
259
|
+
- Ensure every category has at least one handler node
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Self-Check Checklist
|
|
264
|
+
|
|
265
|
+
After generating or modifying a workflow, verify:
|
|
266
|
+
|
|
267
|
+
- [ ] All paths produce all named results
|
|
268
|
+
- [ ] No multiple writers on same path
|
|
269
|
+
- [ ] Every path has response or abstain
|
|
270
|
+
- [ ] Category hierarchy is valid
|
|
271
|
+
- [ ] Categorizer has Fallback category
|
|
272
|
+
- [ ] All categories have handler nodes
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Reference
|
|
277
|
+
|
|
278
|
+
- **Source**: workflow-engine/pkg/engine/validator.go
|
|
279
|
+
- **Error Types**: RESULT_ERROR_TYPE_REQUIRED_OUTPUT_NOT_PRODUCED, RESULT_ERROR_TYPE_MULTIPLE_WRITERS, RESULT_ERROR_TYPE_MISSING_RESPONSE_OR_ABSTAIN_REASON, RESULT_ERROR_TYPE_CATEGORY_HIERARCHY_VIOLATION
|
|
280
|
+
- **Validation Tool**: Use \`workflow(mode="validate")\` to validate workflows
|
|
281
|
+
`;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Generate best practices checklist from SDK rules.
|
|
285
|
+
* SINGLE SOURCE OF TRUTH - all best practices come from:
|
|
286
|
+
* - ANTI_PATTERNS (validation-rules.ts)
|
|
287
|
+
* - STRUCTURAL_INVARIANTS (structural-rules.ts)
|
|
288
|
+
* - INPUT_SOURCE_RULES (validation-rules.ts)
|
|
289
|
+
* - OPTIMIZATION_RULES (validation-rules.ts)
|
|
290
|
+
*/
|
|
291
|
+
export function generateBestPracticesChecklist() {
|
|
292
|
+
const criticalAntiPatterns = ANTI_PATTERNS.filter(ap => ap.severity === "critical");
|
|
293
|
+
const warningAntiPatterns = ANTI_PATTERNS.filter(ap => ap.severity === "warning");
|
|
294
|
+
const infoAntiPatterns = ANTI_PATTERNS.filter(ap => ap.severity === "info");
|
|
295
|
+
const criticalInvariants = STRUCTURAL_INVARIANTS.filter(inv => inv.severity === "critical");
|
|
296
|
+
const warningInvariants = STRUCTURAL_INVARIANTS.filter(inv => inv.severity === "warning");
|
|
297
|
+
return `# Workflow Best Practices Checklist
|
|
298
|
+
|
|
299
|
+
> **Auto-generated from SDK rules** - This is the single source of truth.
|
|
300
|
+
> Check this BEFORE deploying any workflow.
|
|
301
|
+
|
|
302
|
+
## 🛑 CRITICAL (Must Fix Before Deploy)
|
|
303
|
+
|
|
304
|
+
### Anti-Patterns to Avoid
|
|
305
|
+
|
|
306
|
+
${criticalAntiPatterns.map(ap => `
|
|
307
|
+
#### ${ap.name}
|
|
308
|
+
|
|
309
|
+
**Pattern**: ${ap.pattern}
|
|
310
|
+
|
|
311
|
+
**Problem**: ${ap.problem}
|
|
312
|
+
|
|
313
|
+
**Solution**: ${ap.solution}
|
|
314
|
+
|
|
315
|
+
**Detection**: \`${ap.detection.condition}\`
|
|
316
|
+
`).join("\n---\n")}
|
|
317
|
+
|
|
318
|
+
### Structural Requirements
|
|
319
|
+
|
|
320
|
+
${criticalInvariants.map(inv => `
|
|
321
|
+
- **${inv.name}**: ${inv.rule}
|
|
322
|
+
- Violation: ${inv.violation}
|
|
323
|
+
- Fix: ${inv.fix}
|
|
324
|
+
`).join("")}
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## ⚠️ WARNINGS (Should Fix)
|
|
329
|
+
|
|
330
|
+
### Anti-Patterns
|
|
331
|
+
|
|
332
|
+
${warningAntiPatterns.map(ap => `
|
|
333
|
+
- **${ap.name}**: ${ap.problem}
|
|
334
|
+
- Solution: ${ap.solution}
|
|
335
|
+
`).join("")}
|
|
336
|
+
|
|
337
|
+
### Structural Warnings
|
|
338
|
+
|
|
339
|
+
${warningInvariants.map(inv => `
|
|
340
|
+
- **${inv.name}**: ${inv.rule}
|
|
341
|
+
- Fix: ${inv.fix}
|
|
342
|
+
`).join("")}
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## 📋 SUGGESTIONS (Good to Have)
|
|
347
|
+
|
|
348
|
+
${infoAntiPatterns.map(ap => `
|
|
349
|
+
- **${ap.name}**: ${ap.problem}
|
|
350
|
+
- Recommendation: ${ap.solution}
|
|
351
|
+
`).join("")}
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Input Source Rules
|
|
356
|
+
|
|
357
|
+
| Action | Recommended Input | Avoid | Why |
|
|
358
|
+
|--------|-------------------|-------|-----|
|
|
359
|
+
${INPUT_SOURCE_RULES.filter(r => r.severity === "critical").map(r => `| \`${r.actionPattern}\` | \`${r.recommended}\` | ${r.avoid.join(", ") || "-"} | ${r.reason.slice(0, 60)}... |`).join("\n")}
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## Performance Optimizations
|
|
364
|
+
|
|
365
|
+
${OPTIMIZATION_RULES.map(opt => `
|
|
366
|
+
### ${opt.name} (${opt.priority})
|
|
367
|
+
|
|
368
|
+
- **Current State**: ${opt.currentState}
|
|
369
|
+
- **Recommendation**: ${opt.recommendation}
|
|
370
|
+
- **Benefit**: ${opt.benefit}
|
|
371
|
+
`).join("")}
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Quick Checklist
|
|
376
|
+
|
|
377
|
+
Before deploying, verify:
|
|
378
|
+
|
|
379
|
+
### Critical
|
|
380
|
+
- [ ] Response nodes receive \`chat_conversation\` (prevents repeated questions)
|
|
381
|
+
- [ ] Email recipients from \`entity_extraction\` (not text outputs)
|
|
382
|
+
- [ ] Categorizers have Fallback category
|
|
383
|
+
- [ ] HITL has both success AND failure paths
|
|
384
|
+
- [ ] All paths reach WORKFLOW_OUTPUT
|
|
385
|
+
- [ ] No circular dependencies
|
|
386
|
+
|
|
387
|
+
### Recommended
|
|
388
|
+
- [ ] \`max_tokens\` set on call_llm nodes
|
|
389
|
+
- [ ] No orphan nodes (unused/disconnected)
|
|
390
|
+
- [ ] No redundant search nodes
|
|
391
|
+
- [ ] Search nodes have data sources uploaded
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## Related Resources
|
|
396
|
+
|
|
397
|
+
- \`ema://rules/anti-patterns\` - Full anti-pattern definitions (JSON)
|
|
398
|
+
- \`ema://rules/input-sources\` - Input source rules (JSON)
|
|
399
|
+
- \`ema://rules/extraction-column-format\` - extraction_columns API shape (entity_extraction nodes)
|
|
400
|
+
- \`ema://rules/json-output-patterns\` - custom_agent + json_mapper pattern
|
|
401
|
+
- \`ema://rules/chat-response-wiring\` - Chat response node wiring (avoid duplicate responses)
|
|
402
|
+
- \`ema://rules/email-input-wiring\` - Email input wiring (json_mapper/fixed_response patterns)
|
|
403
|
+
- \`ema://docs/workflow-node-reference\` - Per-node I/O types, categorizer patterns, LLM config
|
|
404
|
+
- \`ema://rules/structural-invariants\` - Structural rules (JSON)
|
|
405
|
+
- \`ema://rules/optimizations\` - Optimization rules (JSON)
|
|
406
|
+
- \`ema://validation/rules\` - Go validator rules reference
|
|
407
|
+
`;
|
|
408
|
+
}
|