@ema.co/mcp-toolkit 2026.2.13 → 2026.2.23-1

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 (67) hide show
  1. package/.context/public/guides/ema-user-guide.md +12 -16
  2. package/.context/public/guides/mcp-tools-guide.md +203 -334
  3. package/dist/cli/index.js +2 -2
  4. package/dist/mcp/domain/loop-detection.js +89 -0
  5. package/dist/mcp/domain/sanitizer.js +1 -1
  6. package/dist/mcp/domain/structural-rules.js +4 -5
  7. package/dist/mcp/domain/validation-rules.js +5 -5
  8. package/dist/mcp/domain/workflow-graph.js +3 -5
  9. package/dist/mcp/domain/workflow-path-enumerator.js +7 -4
  10. package/dist/mcp/guidance.js +62 -29
  11. package/dist/mcp/handlers/debug/adapter.js +15 -0
  12. package/dist/mcp/handlers/debug/formatters.js +282 -0
  13. package/dist/mcp/handlers/debug/index.js +133 -0
  14. package/dist/mcp/handlers/demo/adapter.js +180 -0
  15. package/dist/mcp/handlers/env/config.js +2 -2
  16. package/dist/mcp/handlers/feedback/index.js +1 -1
  17. package/dist/mcp/handlers/index.js +0 -1
  18. package/dist/mcp/handlers/persona/adapter.js +135 -0
  19. package/dist/mcp/handlers/persona/index.js +237 -8
  20. package/dist/mcp/handlers/persona/schema.js +27 -0
  21. package/dist/mcp/handlers/reference/index.js +6 -4
  22. package/dist/mcp/handlers/sync/adapter.js +200 -0
  23. package/dist/mcp/handlers/workflow/adapter.js +174 -0
  24. package/dist/mcp/handlers/workflow/fix.js +11 -12
  25. package/dist/mcp/handlers/workflow/index.js +12 -40
  26. package/dist/mcp/handlers/workflow/validation.js +1 -1
  27. package/dist/mcp/knowledge-guidance-topics.js +615 -0
  28. package/dist/mcp/knowledge-types.js +7 -0
  29. package/dist/mcp/knowledge.js +75 -1403
  30. package/dist/mcp/resources-dynamic.js +2395 -0
  31. package/dist/mcp/resources-validation.js +408 -0
  32. package/dist/mcp/resources.js +72 -2508
  33. package/dist/mcp/server.js +69 -2825
  34. package/dist/mcp/tools.js +106 -5
  35. package/dist/sdk/client-adapter.js +265 -24
  36. package/dist/sdk/ema-client.js +100 -9
  37. package/dist/sdk/generated/agent-catalog.js +615 -0
  38. package/dist/sdk/generated/api-client/client/client.gen.js +3 -3
  39. package/dist/sdk/generated/api-client/client/index.js +5 -5
  40. package/dist/sdk/generated/api-client/client/utils.gen.js +4 -4
  41. package/dist/sdk/generated/api-client/client.gen.js +1 -1
  42. package/dist/sdk/generated/api-client/core/utils.gen.js +1 -1
  43. package/dist/sdk/generated/api-client/index.js +1 -1
  44. package/dist/sdk/generated/api-client/sdk.gen.js +2 -2
  45. package/dist/sdk/generated/well-known-types.js +99 -0
  46. package/dist/sdk/generated/widget-catalog.js +60 -0
  47. package/dist/sdk/grpc-client.js +115 -1
  48. package/dist/sync/sdk.js +2 -2
  49. package/dist/sync.js +4 -3
  50. package/docs/README.md +17 -9
  51. package/package.json +4 -3
  52. package/.context/public/guides/dashboard-operations.md +0 -349
  53. package/.context/public/guides/email-patterns.md +0 -125
  54. package/.context/public/guides/workflow-builder-patterns.md +0 -708
  55. package/dist/mcp/domain/intent-architect.js +0 -914
  56. package/dist/mcp/domain/quality-gates.js +0 -110
  57. package/dist/mcp/domain/workflow-execution-analyzer.js +0 -412
  58. package/dist/mcp/domain/workflow-intent.js +0 -1806
  59. package/dist/mcp/domain/workflow-merge.js +0 -449
  60. package/dist/mcp/domain/workflow-tracer.js +0 -648
  61. package/dist/mcp/domain/workflow-transformer.js +0 -742
  62. package/dist/mcp/handlers/knowledge/index.js +0 -54
  63. package/dist/mcp/handlers/persona/intent.js +0 -141
  64. package/dist/mcp/handlers/workflow/analyze.js +0 -119
  65. package/dist/mcp/handlers/workflow/compare.js +0 -70
  66. package/dist/mcp/handlers/workflow/generate.js +0 -384
  67. package/dist/mcp/handlers-consolidated.js +0 -333
@@ -1,349 +0,0 @@
1
- ---
2
- title: "Dashboard Operations"
3
- date: 2026-01-27
4
- audience: public
5
- ---
6
- # Dashboard Operations
7
-
8
- ## Overview
9
-
10
- Dashboard-type AI Employees process data in batches. Each row in a dashboard represents one execution of the workflow with specific inputs.
11
-
12
- ## Architecture
13
-
14
- ```
15
- ┌─────────────────────────────────────────────────────────────────┐
16
- │ Dashboard Persona │
17
- ├─────────────────────────────────────────────────────────────────┤
18
- │ workflow_dashboard_id: "dashboard-uuid" │
19
- │ trigger_type: DOCUMENT_TRIGGER │
20
- └─────────────────────────────────────────────────────────────────┘
21
-
22
-
23
- ┌─────────────────────────────────────────────────────────────────┐
24
- │ Dashboard │
25
- ├────────────┬──────────────┬─────────────┬──────────────────────┤
26
- │ Schema │ Input Cols │ Output Cols │ Rows │
27
- ├────────────┼──────────────┼─────────────┼──────────────────────┤
28
- │ columnId │ name, type │ name, type │ id, state, values │
29
- └────────────┴──────────────┴─────────────┴──────────────────────┘
30
- ```
31
-
32
- ## SDK Methods
33
-
34
- | Method | Purpose | Key Parameters |
35
- |--------|---------|----------------|
36
- | `getDashboardRows()` | List rows with schema | `dashboardId`, `personaId`, `{ limit }` |
37
- | `getDashboardRowResult()` | Get single row | `personaId`, `rowId`, `includeFileContents?` |
38
- | `uploadAndRunDashboardRow()` | Create new row | `personaId`, `inputs[]` |
39
- | `rerunDashboardRow()` | Re-execute workflow | `personaId`, `rowId` |
40
-
41
- ### Input Types (DashboardInput)
42
-
43
- ```typescript
44
- type DashboardInput = {
45
- name: string; // Column name (required)
46
- string_value?: string; // Text input
47
- number_value?: number; // Numeric input
48
- boolean_value?: boolean; // Boolean input
49
- document_value?: Array<{ // File input
50
- name: string; // Filename
51
- contents: string; // Base64-encoded content
52
- is_base64_encoded: boolean; // Always true for documents
53
- mime_type: string; // e.g., "application/pdf"
54
- }>;
55
- };
56
- ```
57
-
58
- ## MCP Tool: Data Operations
59
-
60
- ### Purpose
61
- Clone rows from one dashboard persona to another. Useful for:
62
- - Creating demo environments with real data structure
63
- - Testing with sanitized production data
64
- - Duplicating configurations across personas
65
-
66
- ### Recommended: Action Composition
67
-
68
- Use the `actions` array when creating/cloning personas:
69
-
70
- ```typescript
71
- // Clone persona with data copy and sanitization
72
- persona(
73
- method="create",
74
- from="source-persona-uuid",
75
- name="Demo Dashboard",
76
- actions=[
77
- {tool:"data", args:{method:"copy", from:"$source"}},
78
- {tool:"data", args:{method:"sanitize", examples:["john@acme.com", "Acme Corp"]}},
79
- ]
80
- )
81
-
82
- // Or use built-in alias
83
- persona(method="create", from="source-persona-uuid", name="Demo Dashboard", actions=["copy-and-sanitize"])
84
- ```
85
-
86
- ### Direct Data Operations
87
-
88
- For operations on existing personas, use the `data` sub-resource:
89
-
90
- ```typescript
91
- // Copy data from another persona
92
- persona(id="target-persona-uuid", data={method:"copy", from:"source-persona-uuid", sanitize:true})
93
-
94
- // List data items
95
- persona(id="persona-uuid", data={method:"list"})
96
-
97
- // Get input schema
98
- persona(id="persona-uuid", data={method:"schema"})
99
- ```
100
-
101
- ### Upload Dashboard Rows with Files
102
-
103
- Create new dashboard rows with file attachments (triggers workflow execution):
104
-
105
- ```javascript
106
- persona(id="dashboard-uuid", data={
107
- method: "upload",
108
- items: [
109
- {
110
- "Input Document": { file: "/path/to/invoice.pdf" },
111
- "Customer Name": "Acme Corp",
112
- "Amount": 1500.00,
113
- "Priority": true
114
- }
115
- ]
116
- })
117
- ```
118
-
119
- **Supported value types in `items`:**
120
-
121
- | Type | Format | Result |
122
- |------|--------|--------|
123
- | String | `"value"` | `string_value` |
124
- | Number | `123.45` | `number_value` |
125
- | Boolean | `true` | `boolean_value` |
126
- | File | `{ file: "/path/to/doc.pdf" }` | `document_value` (auto base64) |
127
- | Inline Doc | `{ contents: "...", mime_type: "text/plain" }` | `document_value` |
128
-
129
- **Key differences from knowledge base upload:**
130
-
131
- | Operation | Target | Use Case |
132
- |-----------|--------|----------|
133
- | `data={method:"upload", path:"..."}` | Knowledge Base | Chat personas, RAG search |
134
- | `data={method:"upload", items:[...]}` | Dashboard Rows | Dashboard personas, per-row workflow |
135
-
136
- ### Legacy Syntax (still works)
137
-
138
- ```
139
- knowledge(
140
- persona_id="target-persona-uuid",
141
- source_persona_id="source-persona-uuid",
142
- mode="dashboard_clone",
143
- sanitize=true,
144
- sanitize_examples=["john@acme.com", "Acme Corp"]
145
- )
146
- ```
147
-
148
- ### Response
149
-
150
- ```json
151
- {
152
- "success": true,
153
- "source_persona": "Source Dashboard",
154
- "target_persona": "Target Dashboard",
155
- "cloned_count": 5,
156
- "skipped_count": 0,
157
- "details": [
158
- {
159
- "source_row_id": "row-1",
160
- "target_row_id": "new-row-1",
161
- "status": "cloned"
162
- }
163
- ],
164
- "notes": [
165
- "Dashboard clone creates NEW rows in the target dashboard",
166
- "Workflows will re-run on the new rows to generate output columns"
167
- ]
168
- }
169
- ```
170
-
171
- ## Document Handling
172
-
173
- ### How Document Cloning Works
174
-
175
- 1. **Fetch source row** with file contents:
176
- ```typescript
177
- const rowResult = await client.getDashboardRowResult(
178
- sourcePersonaId,
179
- rowId,
180
- true // includeFileContents
181
- );
182
- ```
183
-
184
- 2. **Extract file content** from `additional_column_details`:
185
- ```typescript
186
- const fileContent = rowResult.additional_column_details?.find(
187
- d => d.column_id === columnId
188
- )?.file_contents; // Base64 encoded
189
- ```
190
-
191
- 3. **Build document input** for target:
192
- ```typescript
193
- const input: DashboardInput = {
194
- name: "Document Input",
195
- document_value: [{
196
- name: "filename.pdf",
197
- contents: fileContent,
198
- is_base64_encoded: true,
199
- mime_type: "application/pdf",
200
- }],
201
- };
202
- ```
203
-
204
- 4. **Upload to target dashboard**:
205
- ```typescript
206
- await client.uploadAndRunDashboardRow(targetPersonaId, [input]);
207
- ```
208
-
209
- ### MIME Type Inference
210
-
211
- When document `type` is not available, inferred from extension:
212
-
213
- | Extension | MIME Type |
214
- |-----------|-----------|
215
- | `.pdf` | `application/pdf` |
216
- | `.docx` | `application/vnd.openxmlformats-officedocument.wordprocessingml.document` |
217
- | `.xlsx` | `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` |
218
- | `.csv` | `text/csv` |
219
- | `.txt` | `text/plain` |
220
- | `.png` | `image/png` |
221
- | `.jpg`/`.jpeg` | `image/jpeg` |
222
- | Other | `application/octet-stream` |
223
-
224
- ## Dashboard Columns: How They Work
225
-
226
- ### Output Columns Come From resultMappings
227
-
228
- For dashboard personas, the **output columns** visible in the dashboard UI are determined **entirely** by which node outputs are mapped to `WORKFLOW_OUTPUT` via `resultMappings` in the workflow_def. Each `resultMapping` entry creates one output column in the dashboard.
229
-
230
- ```json
231
- "results": {
232
- "entity_extraction.invoice_number": {
233
- "actionName": "entity_extraction",
234
- "outputName": "invoice_number"
235
- },
236
- "entity_extraction.amount": {
237
- "actionName": "entity_extraction",
238
- "outputName": "amount"
239
- },
240
- "call_llm.summary": {
241
- "actionName": "call_llm",
242
- "outputName": "response_with_sources"
243
- },
244
- "categorizer.category": {
245
- "actionName": "categorizer",
246
- "outputName": "category"
247
- }
248
- }
249
- ```
250
-
251
- This creates 4 output columns: `entity_extraction.invoice_number`, `entity_extraction.amount`, `call_llm.summary`, and `categorizer.category`.
252
-
253
- **Key rules:**
254
- - If you forget to map a node output, that column **won't appear** in the dashboard
255
- - If you map the wrong output, you'll see unexpected data
256
- - Column display name in the UI = the result mapping key (e.g., `entity_extraction.invoice_number`)
257
-
258
- ### Input Columns Come From the Trigger
259
-
260
- Dashboard input columns (what users fill in or upload per row) come from the `document_trigger` outputs:
261
- - `document_content`: For uploaded files (PDF, images, etc.)
262
- - `row_data`: For text/number inputs from dashboard columns
263
-
264
- Wire these to your processing nodes:
265
- - `entity_extraction.document` ← `trigger.document_content`
266
- - `call_llm.context` ← `trigger.row_data`
267
-
268
- ### Column Ordering
269
-
270
- **Dashboard column order is determined by the order of resultMappings in the workflow_def.**
271
-
272
- To reorder columns, you must **remove** them from the result mappings and **re-add** them in the desired order. There is no separate "reorder" API -- the order in the JSON is the order in the UI.
273
-
274
- ```
275
- // To change order from [Amount, Date, Status] to [Status, Date, Amount]:
276
- // 1. Remove all three from results
277
- // 2. Re-add in desired order:
278
- "results": {
279
- "extract.status": { "actionName": "extract", "outputName": "status" },
280
- "extract.date": { "actionName": "extract", "outputName": "date" },
281
- "extract.amount": { "actionName": "extract", "outputName": "amount" }
282
- }
283
- ```
284
-
285
- **Important:** Once columns are created and saved, the output type and multi-value settings cannot be modified via the UI. To change these, you must update the workflow_def directly.
286
-
287
- ## Common Patterns
288
-
289
- ### List Dashboard Rows
290
-
291
- ```
292
- knowledge(persona_id="...", mode="dashboard_rows", limit=10)
293
- ```
294
-
295
- ### Clone with Sanitization
296
-
297
- **Recommended (action composition):**
298
-
299
- ```typescript
300
- persona(
301
- method="create",
302
- from="source",
303
- name="Demo Dashboard",
304
- actions=[
305
- {tool:"data", args:{method:"copy", from:"$source"}},
306
- {tool:"data", args:{method:"sanitize", examples:["real-email@company.com", "Real Company Name"]}},
307
- ]
308
- )
309
- ```
310
-
311
- **Legacy syntax (still works):**
312
-
313
- ```
314
- knowledge(
315
- persona_id="target",
316
- source_persona_id="source",
317
- mode="dashboard_clone",
318
- sanitize=true,
319
- sanitize_examples=["real-email@company.com", "Real Company Name"]
320
- )
321
- ```
322
-
323
- ### Manual Row Upload
324
-
325
- Use `uploadAndRunDashboardRow` directly for programmatic row creation:
326
-
327
- ```typescript
328
- await client.uploadAndRunDashboardRow(personaId, [
329
- { name: "Input Column", string_value: "test data" },
330
- { name: "Document Column", document_value: [...] },
331
- ]);
332
- ```
333
-
334
- ## Error Handling
335
-
336
- | Error | Cause | Solution |
337
- |-------|-------|----------|
338
- | "Persona has no dashboard" | Wrong persona type | Use only with DOCUMENT_TRIGGER personas |
339
- | "Document content not available" | `includeFileContents` returned empty | Source document may have been deleted |
340
- | "Source persona not found" | Invalid `source_persona_id` | Verify persona exists in environment |
341
-
342
- ## Related Files
343
-
344
- | File | Purpose |
345
- |------|---------|
346
- | `src/sdk/client.ts` | SDK methods for dashboard operations |
347
- | `src/mcp/handlers-consolidated.ts` | MCP handlers (dashboard_rows, dashboard_clone) |
348
- | `test/integration/dashboard-clone.integration.test.ts` | Integration tests |
349
- | `test/handlers-consolidated.test.ts` | Unit tests for cloning logic |
@@ -1,125 +0,0 @@
1
- ---
2
- title: "Email Field Extraction Patterns"
3
- date: 2026-01-27
4
- audience: public
5
- ---
6
- # Email Field Extraction Patterns
7
-
8
- ## Problem
9
-
10
- `send_email_agent.to_email` expects a text email address, but `entity_extraction` outputs `extraction_columns` (a JSON object), not individual fields.
11
-
12
- **This does NOT work:**
13
- ```
14
- entity_extraction.extraction_columns → send_email.to_email
15
- ```
16
-
17
- The types are incompatible:
18
- - `extraction_columns` = `WELL_KNOWN_TYPE_ANY` (JSON object)
19
- - `to_email` = `WELL_KNOWN_TYPE_TEXT_WITH_SOURCES` (text)
20
-
21
- ## Solution Pattern
22
-
23
- ```
24
- entity_extraction.extraction_columns
25
- → fixed_response (template: "{{email}}")
26
- → send_email.to_email
27
- ```
28
-
29
- ### Why This Works
30
-
31
- 1. `entity_extraction` extracts structured data into JSON: `{"email": "user@example.com", "name": "John"}`
32
- 2. `fixed_response` with `{{email}}` template extracts the field and outputs plain text
33
- 3. `fixed_response` output type is `WELL_KNOWN_TYPE_TEXT_WITH_SOURCES` - compatible with `to_email`
34
-
35
- ### WorkflowSpec Example
36
-
37
- ```typescript
38
- {
39
- nodes: [
40
- {
41
- id: "extract_entities_abc123",
42
- actionType: "entity_extraction_with_documents",
43
- displayName: "Extract Contact Info",
44
- // outputs: extraction_columns (JSON)
45
- },
46
- {
47
- id: "format_email_def456",
48
- actionType: "fixed_response",
49
- displayName: "Format Email Address",
50
- inputs: {
51
- query: {
52
- type: "action_output",
53
- actionName: "extract_entities_abc123",
54
- output: "extraction_columns"
55
- }
56
- },
57
- config: {
58
- response_template: "{{email}}" // Extracts email field
59
- }
60
- // outputs: response (text)
61
- },
62
- {
63
- id: "send_email_ghi789",
64
- actionType: "send_email_agent",
65
- displayName: "Send Email",
66
- inputs: {
67
- to_email: {
68
- type: "action_output",
69
- actionName: "format_email_def456",
70
- output: "response"
71
- },
72
- // ... other inputs
73
- }
74
- }
75
- ]
76
- }
77
- ```
78
-
79
- ## Alternative: JSON Mapper
80
-
81
- For complex extraction or multiple fields:
82
-
83
- ```
84
- entity_extraction.extraction_columns
85
- → json_mapper (extracts specific fields)
86
- → fixed_response (formats as text)
87
- → send_email.to_email
88
- ```
89
-
90
- **Note:** `json_mapper` is not in the WorkflowSpec compiler's supported action types. Use `applySpecToWorkflow()` for workflows containing `json_mapper`.
91
-
92
- ## Common Mistakes
93
-
94
- ### 1. Direct Wiring
95
- ```
96
- ❌ entity_extraction → send_email.to_email
97
- ```
98
- Type mismatch. JSON object cannot be used as email address.
99
-
100
- ### 2. Assuming `.email_address` Output Exists
101
- ```
102
- ❌ entity_extraction.email_address → send_email.to_email
103
- ```
104
- This output doesn't exist. `entity_extraction` only outputs `extraction_columns`.
105
-
106
- ### 3. Skipping Template Step
107
- ```
108
- ❌ entity_extraction → json_mapper → send_email.to_email
109
- ```
110
- Even `json_mapper` output may not be the right type. Always use `fixed_response` as the final step before `send_email` inputs.
111
-
112
- ## Type Reference
113
-
114
- | Action | Output | Type |
115
- |--------|--------|------|
116
- | `entity_extraction` | `extraction_columns` | `WELL_KNOWN_TYPE_ANY` (JSON) |
117
- | `json_mapper` | varies | depends on mapping |
118
- | `fixed_response` | `response` | `WELL_KNOWN_TYPE_TEXT_WITH_SOURCES` |
119
- | `call_llm` | `response` | `WELL_KNOWN_TYPE_TEXT_WITH_SOURCES` |
120
-
121
- | Input | Expected Type |
122
- |-------|---------------|
123
- | `send_email.to_email` | `WELL_KNOWN_TYPE_TEXT_WITH_SOURCES` |
124
- | `send_email.subject` | `WELL_KNOWN_TYPE_TEXT_WITH_SOURCES` |
125
- | `send_email.body` | `WELL_KNOWN_TYPE_TEXT_WITH_SOURCES` |