@ema.co/mcp-toolkit 2026.1.27 → 2026.1.28-2
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/handlers/data/index.js +3 -0
- package/dist/mcp/handlers/persona/create.js +16 -0
- package/dist/mcp/handlers/persona/list.js +9 -4
- package/dist/mcp/handlers/persona/update.js +24 -2
- package/dist/mcp/handlers/workflow/deploy.js +20 -2
- package/dist/mcp/handlers/workflow/generate.js +39 -2
- package/dist/mcp/handlers/workflow/index.js +8 -3
- package/dist/mcp/handlers/workflow/modify.js +34 -7
- package/dist/mcp/handlers/workflow/validate.js +85 -0
- package/dist/mcp/handlers/workflow/validation.js +160 -0
- package/dist/mcp/resources.js +286 -4
- package/dist/mcp/server.js +16 -3
- package/dist/mcp/tools.js +32 -11
- package/dist/sdk/client.js +36 -9
- package/dist/sdk/ema-client.js +32 -4
- package/dist/sdk/index.js +3 -1
- package/dist/sdk/knowledge.js +5 -5
- package/dist/sdk/structural-rules.js +498 -0
- package/dist/sdk/workflow-generator.js +2 -1
- package/dist/sdk/workflow-intent.js +28 -96
- package/dist/sdk/workflow-path-enumerator.js +278 -0
- package/dist/sdk/workflow-static-validator.js +291 -0
- package/dist/sdk/workflow-validation-types.js +7 -0
- package/docs/README.md +14 -0
- package/docs/go-validator-analysis.md +323 -0
- package/docs/rule-format-specification.md +346 -0
- package/docs/validation-contract.md +397 -0
- package/docs/validation-error-format.md +326 -0
- package/package.json +1 -1
- package/dist/mcp/workflow-operations.js +0 -100
- package/dist/sdk/workflow-fixer.js +0 -48
- package/docs/dashboard-operations.md +0 -281
- package/docs/ema-user-guide.md +0 -1201
- package/docs/email-patterns.md +0 -120
- package/docs/mcp-tools-guide.md +0 -575
package/package.json
CHANGED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Workflow Operations - Single Source of Truth
|
|
3
|
-
*
|
|
4
|
-
* This file defines supported workflow modification operations.
|
|
5
|
-
* Used by:
|
|
6
|
-
* - analyzeModificationRequest() in handlers-consolidated.ts
|
|
7
|
-
* - Tool descriptions in tools.ts
|
|
8
|
-
* - Tests to verify capabilities
|
|
9
|
-
*
|
|
10
|
-
* Add new operations here, and they'll automatically appear in tool docs.
|
|
11
|
-
*/
|
|
12
|
-
/**
|
|
13
|
-
* Supported incremental workflow modifications.
|
|
14
|
-
* These are what `persona(method="update", input="...")` can handle.
|
|
15
|
-
*/
|
|
16
|
-
export const SUPPORTED_OPERATIONS = [
|
|
17
|
-
{
|
|
18
|
-
type: "add",
|
|
19
|
-
name: "Add HITL/approval",
|
|
20
|
-
triggers: ["add hitl", "add approval", "confirm before", "human review"],
|
|
21
|
-
example: "add HITL before email",
|
|
22
|
-
notes: "Adds general_hitl node before specified action",
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
type: "remove",
|
|
26
|
-
name: "Remove nodes",
|
|
27
|
-
triggers: ["remove", "delete", "clean up orphan"],
|
|
28
|
-
example: "remove the search node",
|
|
29
|
-
notes: "Can remove specific nodes or orphan nodes",
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
type: "replace",
|
|
33
|
-
name: "Replace nodes",
|
|
34
|
-
triggers: ["replace X with Y", "swap", "use instead of"],
|
|
35
|
-
example: "replace LLM extraction with entity_extraction",
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
type: "consolidate",
|
|
39
|
-
name: "Consolidate nodes",
|
|
40
|
-
triggers: ["consolidate", "merge", "combine into one"],
|
|
41
|
-
example: "consolidate the 8 custom agents into one",
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
type: "rewire",
|
|
45
|
-
name: "Rewire connections",
|
|
46
|
-
triggers: ["connect", "wire", "link X to Y"],
|
|
47
|
-
example: "connect search output to response",
|
|
48
|
-
},
|
|
49
|
-
];
|
|
50
|
-
/**
|
|
51
|
-
* Limitations of INCREMENTAL modifications (persona method="update" with input).
|
|
52
|
-
* For complex workflows, use the workflow tool instead.
|
|
53
|
-
*/
|
|
54
|
-
export const LIMITATIONS = [
|
|
55
|
-
"Build complex multi-node workflows from scratch → use workflow(mode='generate')",
|
|
56
|
-
"Add multiple interconnected nodes at once → use workflow(mode='generate')",
|
|
57
|
-
];
|
|
58
|
-
/**
|
|
59
|
-
* Alternative approaches for complex workflows.
|
|
60
|
-
*/
|
|
61
|
-
export const ALTERNATIVES = {
|
|
62
|
-
complexWorkflow: "workflow(mode='generate', input='...') for multi-node generation",
|
|
63
|
-
cloneExisting: "persona(method='create', from='similar-persona-id', name='New Name')",
|
|
64
|
-
};
|
|
65
|
-
/**
|
|
66
|
-
* Generate tool description for the `input` parameter.
|
|
67
|
-
* Called by tools.ts to ensure description matches actual capabilities.
|
|
68
|
-
*/
|
|
69
|
-
export function generateInputDescription() {
|
|
70
|
-
const ops = SUPPORTED_OPERATIONS.map(op => op.example).join("', '");
|
|
71
|
-
return `Incremental workflow changes. Supports: '${ops}'. For complex multi-node workflows, clone from existing persona instead.`;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Generate detailed capabilities for tool help text.
|
|
75
|
-
*/
|
|
76
|
-
export function generateCapabilitiesHelp() {
|
|
77
|
-
const lines = [
|
|
78
|
-
"## Supported Workflow Modifications",
|
|
79
|
-
"",
|
|
80
|
-
"The `input` parameter supports these INCREMENTAL changes:",
|
|
81
|
-
"",
|
|
82
|
-
];
|
|
83
|
-
for (const op of SUPPORTED_OPERATIONS) {
|
|
84
|
-
lines.push(`- **${op.name}**: \`${op.example}\``);
|
|
85
|
-
if (op.notes) {
|
|
86
|
-
lines.push(` - ${op.notes}`);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
lines.push("");
|
|
90
|
-
lines.push("## NOT Supported (use clone instead)");
|
|
91
|
-
lines.push("");
|
|
92
|
-
for (const limit of LIMITATIONS) {
|
|
93
|
-
lines.push(`- ${limit}`);
|
|
94
|
-
}
|
|
95
|
-
lines.push("");
|
|
96
|
-
lines.push("## For Complex Workflows");
|
|
97
|
-
lines.push("");
|
|
98
|
-
lines.push(`Clone from existing: \`${ALTERNATIVES.complexWorkflow}\``);
|
|
99
|
-
return lines.join("\n");
|
|
100
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Workflow Fixer (SDK)
|
|
3
|
-
*
|
|
4
|
-
* DEPRECATED: This module used detectWorkflowIssues which has been removed.
|
|
5
|
-
*
|
|
6
|
-
* The LLM should analyze workflows using rules from:
|
|
7
|
-
* - ema://rules/anti-patterns
|
|
8
|
-
* - ema://rules/input-sources
|
|
9
|
-
* - ema://rules/optimizations
|
|
10
|
-
*
|
|
11
|
-
* And then make structured modifications via:
|
|
12
|
-
* - workflow(mode="deploy", workflow_def={...})
|
|
13
|
-
* - persona(mode="update", operations=[...])
|
|
14
|
-
*
|
|
15
|
-
* This file is kept for backwards compatibility with minimal functionality.
|
|
16
|
-
*/
|
|
17
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
18
|
-
// DEPRECATED FUNCTIONS (no-ops)
|
|
19
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
20
|
-
/**
|
|
21
|
-
* DEPRECATED: Auto-fix workflow issues.
|
|
22
|
-
*
|
|
23
|
-
* This function now returns the workflow unchanged with a deprecation warning.
|
|
24
|
-
* Use LLM analysis with ema://rules/* instead.
|
|
25
|
-
*/
|
|
26
|
-
export function autoFixWorkflow(workflowDef) {
|
|
27
|
-
return {
|
|
28
|
-
workflowDef: workflowDef,
|
|
29
|
-
fixesApplied: [],
|
|
30
|
-
success: true,
|
|
31
|
-
warnings: [
|
|
32
|
-
"DEPRECATED: autoFixWorkflow() no longer auto-fixes issues.",
|
|
33
|
-
"Use LLM analysis with ema://rules/anti-patterns instead.",
|
|
34
|
-
],
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* DEPRECATED: Suggest fixes for workflow issues.
|
|
39
|
-
*
|
|
40
|
-
* This function now returns empty results with a deprecation warning.
|
|
41
|
-
* Use LLM analysis with ema://rules/* instead.
|
|
42
|
-
*/
|
|
43
|
-
export function suggestFixes(_workflowDef) {
|
|
44
|
-
return {
|
|
45
|
-
standardFixes: [],
|
|
46
|
-
multiResponderFixes: [],
|
|
47
|
-
};
|
|
48
|
-
}
|
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
# Dashboard Operations
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
Dashboard-type AI Employees process data in batches. Each row in a dashboard represents one execution of the workflow with specific inputs.
|
|
6
|
-
|
|
7
|
-
## Architecture
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
11
|
-
│ Dashboard Persona │
|
|
12
|
-
├─────────────────────────────────────────────────────────────────┤
|
|
13
|
-
│ workflow_dashboard_id: "dashboard-uuid" │
|
|
14
|
-
│ trigger_type: DOCUMENT_TRIGGER │
|
|
15
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
16
|
-
│
|
|
17
|
-
▼
|
|
18
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
19
|
-
│ Dashboard │
|
|
20
|
-
├────────────┬──────────────┬─────────────┬──────────────────────┤
|
|
21
|
-
│ Schema │ Input Cols │ Output Cols │ Rows │
|
|
22
|
-
├────────────┼──────────────┼─────────────┼──────────────────────┤
|
|
23
|
-
│ columnId │ name, type │ name, type │ id, state, values │
|
|
24
|
-
└────────────┴──────────────┴─────────────┴──────────────────────┘
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## SDK Methods
|
|
28
|
-
|
|
29
|
-
| Method | Purpose | Key Parameters |
|
|
30
|
-
|--------|---------|----------------|
|
|
31
|
-
| `getDashboardRows()` | List rows with schema | `dashboardId`, `personaId`, `{ limit }` |
|
|
32
|
-
| `getDashboardRowResult()` | Get single row | `personaId`, `rowId`, `includeFileContents?` |
|
|
33
|
-
| `uploadAndRunDashboardRow()` | Create new row | `personaId`, `inputs[]` |
|
|
34
|
-
| `rerunDashboardRow()` | Re-execute workflow | `personaId`, `rowId` |
|
|
35
|
-
|
|
36
|
-
### Input Types (DashboardInput)
|
|
37
|
-
|
|
38
|
-
```typescript
|
|
39
|
-
type DashboardInput = {
|
|
40
|
-
name: string; // Column name (required)
|
|
41
|
-
string_value?: string; // Text input
|
|
42
|
-
number_value?: number; // Numeric input
|
|
43
|
-
boolean_value?: boolean; // Boolean input
|
|
44
|
-
document_value?: Array<{ // File input
|
|
45
|
-
name: string; // Filename
|
|
46
|
-
contents: string; // Base64-encoded content
|
|
47
|
-
is_base64_encoded: boolean; // Always true for documents
|
|
48
|
-
mime_type: string; // e.g., "application/pdf"
|
|
49
|
-
}>;
|
|
50
|
-
};
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## MCP Tool: Data Operations
|
|
54
|
-
|
|
55
|
-
### Purpose
|
|
56
|
-
Clone rows from one dashboard persona to another. Useful for:
|
|
57
|
-
- Creating demo environments with real data structure
|
|
58
|
-
- Testing with sanitized production data
|
|
59
|
-
- Duplicating configurations across personas
|
|
60
|
-
|
|
61
|
-
### Recommended: Action Composition
|
|
62
|
-
|
|
63
|
-
Use the `actions` array when creating/cloning personas:
|
|
64
|
-
|
|
65
|
-
```typescript
|
|
66
|
-
// Clone persona with data copy and sanitization
|
|
67
|
-
persona(
|
|
68
|
-
method="create",
|
|
69
|
-
from="source-persona-uuid",
|
|
70
|
-
name="Demo Dashboard",
|
|
71
|
-
actions=[
|
|
72
|
-
{tool:"data", args:{method:"copy", from:"$source"}},
|
|
73
|
-
{tool:"data", args:{method:"sanitize", examples:["john@acme.com", "Acme Corp"]}},
|
|
74
|
-
]
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
// Or use built-in alias
|
|
78
|
-
persona(method="create", from="source-persona-uuid", name="Demo Dashboard", actions=["copy-and-sanitize"])
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Direct Data Operations
|
|
82
|
-
|
|
83
|
-
For operations on existing personas, use the `data` sub-resource:
|
|
84
|
-
|
|
85
|
-
```typescript
|
|
86
|
-
// Copy data from another persona
|
|
87
|
-
persona(id="target-persona-uuid", data={method:"copy", from:"source-persona-uuid", sanitize:true})
|
|
88
|
-
|
|
89
|
-
// List data items
|
|
90
|
-
persona(id="persona-uuid", data={method:"list"})
|
|
91
|
-
|
|
92
|
-
// Get input schema
|
|
93
|
-
persona(id="persona-uuid", data={method:"schema"})
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### Upload Dashboard Rows with Files
|
|
97
|
-
|
|
98
|
-
Create new dashboard rows with file attachments (triggers workflow execution):
|
|
99
|
-
|
|
100
|
-
```javascript
|
|
101
|
-
persona(id="dashboard-uuid", data={
|
|
102
|
-
method: "upload",
|
|
103
|
-
items: [
|
|
104
|
-
{
|
|
105
|
-
"Input Document": { file: "/path/to/invoice.pdf" },
|
|
106
|
-
"Customer Name": "Acme Corp",
|
|
107
|
-
"Amount": 1500.00,
|
|
108
|
-
"Priority": true
|
|
109
|
-
}
|
|
110
|
-
]
|
|
111
|
-
})
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
**Supported value types in `items`:**
|
|
115
|
-
|
|
116
|
-
| Type | Format | Result |
|
|
117
|
-
|------|--------|--------|
|
|
118
|
-
| String | `"value"` | `string_value` |
|
|
119
|
-
| Number | `123.45` | `number_value` |
|
|
120
|
-
| Boolean | `true` | `boolean_value` |
|
|
121
|
-
| File | `{ file: "/path/to/doc.pdf" }` | `document_value` (auto base64) |
|
|
122
|
-
| Inline Doc | `{ contents: "...", mime_type: "text/plain" }` | `document_value` |
|
|
123
|
-
|
|
124
|
-
**Key differences from knowledge base upload:**
|
|
125
|
-
|
|
126
|
-
| Operation | Target | Use Case |
|
|
127
|
-
|-----------|--------|----------|
|
|
128
|
-
| `data={method:"upload", path:"..."}` | Knowledge Base | Chat personas, RAG search |
|
|
129
|
-
| `data={method:"upload", items:[...]}` | Dashboard Rows | Dashboard personas, per-row workflow |
|
|
130
|
-
|
|
131
|
-
### Legacy Syntax (still works)
|
|
132
|
-
|
|
133
|
-
```
|
|
134
|
-
knowledge(
|
|
135
|
-
persona_id="target-persona-uuid",
|
|
136
|
-
source_persona_id="source-persona-uuid",
|
|
137
|
-
mode="dashboard_clone",
|
|
138
|
-
sanitize=true,
|
|
139
|
-
sanitize_examples=["john@acme.com", "Acme Corp"]
|
|
140
|
-
)
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### Response
|
|
144
|
-
|
|
145
|
-
```json
|
|
146
|
-
{
|
|
147
|
-
"success": true,
|
|
148
|
-
"source_persona": "Source Dashboard",
|
|
149
|
-
"target_persona": "Target Dashboard",
|
|
150
|
-
"cloned_count": 5,
|
|
151
|
-
"skipped_count": 0,
|
|
152
|
-
"details": [
|
|
153
|
-
{
|
|
154
|
-
"source_row_id": "row-1",
|
|
155
|
-
"target_row_id": "new-row-1",
|
|
156
|
-
"status": "cloned"
|
|
157
|
-
}
|
|
158
|
-
],
|
|
159
|
-
"notes": [
|
|
160
|
-
"Dashboard clone creates NEW rows in the target dashboard",
|
|
161
|
-
"Workflows will re-run on the new rows to generate output columns"
|
|
162
|
-
]
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
## Document Handling
|
|
167
|
-
|
|
168
|
-
### How Document Cloning Works
|
|
169
|
-
|
|
170
|
-
1. **Fetch source row** with file contents:
|
|
171
|
-
```typescript
|
|
172
|
-
const rowResult = await client.getDashboardRowResult(
|
|
173
|
-
sourcePersonaId,
|
|
174
|
-
rowId,
|
|
175
|
-
true // includeFileContents
|
|
176
|
-
);
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
2. **Extract file content** from `additional_column_details`:
|
|
180
|
-
```typescript
|
|
181
|
-
const fileContent = rowResult.additional_column_details?.find(
|
|
182
|
-
d => d.column_id === columnId
|
|
183
|
-
)?.file_contents; // Base64 encoded
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
3. **Build document input** for target:
|
|
187
|
-
```typescript
|
|
188
|
-
const input: DashboardInput = {
|
|
189
|
-
name: "Document Input",
|
|
190
|
-
document_value: [{
|
|
191
|
-
name: "filename.pdf",
|
|
192
|
-
contents: fileContent,
|
|
193
|
-
is_base64_encoded: true,
|
|
194
|
-
mime_type: "application/pdf",
|
|
195
|
-
}],
|
|
196
|
-
};
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
4. **Upload to target dashboard**:
|
|
200
|
-
```typescript
|
|
201
|
-
await client.uploadAndRunDashboardRow(targetPersonaId, [input]);
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
### MIME Type Inference
|
|
205
|
-
|
|
206
|
-
When document `type` is not available, inferred from extension:
|
|
207
|
-
|
|
208
|
-
| Extension | MIME Type |
|
|
209
|
-
|-----------|-----------|
|
|
210
|
-
| `.pdf` | `application/pdf` |
|
|
211
|
-
| `.docx` | `application/vnd.openxmlformats-officedocument.wordprocessingml.document` |
|
|
212
|
-
| `.xlsx` | `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` |
|
|
213
|
-
| `.csv` | `text/csv` |
|
|
214
|
-
| `.txt` | `text/plain` |
|
|
215
|
-
| `.png` | `image/png` |
|
|
216
|
-
| `.jpg`/`.jpeg` | `image/jpeg` |
|
|
217
|
-
| Other | `application/octet-stream` |
|
|
218
|
-
|
|
219
|
-
## Common Patterns
|
|
220
|
-
|
|
221
|
-
### List Dashboard Rows
|
|
222
|
-
|
|
223
|
-
```
|
|
224
|
-
knowledge(persona_id="...", mode="dashboard_rows", limit=10)
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### Clone with Sanitization
|
|
228
|
-
|
|
229
|
-
**Recommended (action composition):**
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
persona(
|
|
233
|
-
method="create",
|
|
234
|
-
from="source",
|
|
235
|
-
name="Demo Dashboard",
|
|
236
|
-
actions=[
|
|
237
|
-
{tool:"data", args:{method:"copy", from:"$source"}},
|
|
238
|
-
{tool:"data", args:{method:"sanitize", examples:["real-email@company.com", "Real Company Name"]}},
|
|
239
|
-
]
|
|
240
|
-
)
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
**Legacy syntax (still works):**
|
|
244
|
-
|
|
245
|
-
```
|
|
246
|
-
knowledge(
|
|
247
|
-
persona_id="target",
|
|
248
|
-
source_persona_id="source",
|
|
249
|
-
mode="dashboard_clone",
|
|
250
|
-
sanitize=true,
|
|
251
|
-
sanitize_examples=["real-email@company.com", "Real Company Name"]
|
|
252
|
-
)
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### Manual Row Upload
|
|
256
|
-
|
|
257
|
-
Use `uploadAndRunDashboardRow` directly for programmatic row creation:
|
|
258
|
-
|
|
259
|
-
```typescript
|
|
260
|
-
await client.uploadAndRunDashboardRow(personaId, [
|
|
261
|
-
{ name: "Input Column", string_value: "test data" },
|
|
262
|
-
{ name: "Document Column", document_value: [...] },
|
|
263
|
-
]);
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
## Error Handling
|
|
267
|
-
|
|
268
|
-
| Error | Cause | Solution |
|
|
269
|
-
|-------|-------|----------|
|
|
270
|
-
| "Persona has no dashboard" | Wrong persona type | Use only with DOCUMENT_TRIGGER personas |
|
|
271
|
-
| "Document content not available" | `includeFileContents` returned empty | Source document may have been deleted |
|
|
272
|
-
| "Source persona not found" | Invalid `source_persona_id` | Verify persona exists in environment |
|
|
273
|
-
|
|
274
|
-
## Related Files
|
|
275
|
-
|
|
276
|
-
| File | Purpose |
|
|
277
|
-
|------|---------|
|
|
278
|
-
| `src/sdk/client.ts` | SDK methods for dashboard operations |
|
|
279
|
-
| `src/mcp/handlers-consolidated.ts` | MCP handlers (dashboard_rows, dashboard_clone) |
|
|
280
|
-
| `test/integration/dashboard-clone.integration.test.ts` | Integration tests |
|
|
281
|
-
| `test/handlers-consolidated.test.ts` | Unit tests for cloning logic |
|