@ema.co/mcp-toolkit 0.2.3 → 1.4.0
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.
- package/dist/mcp/handlers-consolidated.js +264 -1
- package/dist/mcp/prompts.js +11 -2
- package/dist/mcp/server.js +988 -48
- package/dist/mcp/tools-consolidated.js +19 -3
- package/dist/sdk/client.js +103 -0
- package/dist/sdk/index.js +8 -0
- package/dist/sdk/knowledge.js +39 -5
- package/dist/sdk/version-policy.js +328 -0
- package/dist/sdk/version-storage.js +465 -0
- package/dist/sdk/version-tracking.js +346 -0
- package/dist/sdk/workflow-generator.js +1 -1
- package/docs/mcp-tools-guide.md +61 -10
- package/package.json +1 -1
- package/docs/advisor-comms-assistant-fixes.md +0 -175
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* Each handler dispatches based on mode/flags following Unix CLI patterns.
|
|
5
5
|
*/
|
|
6
6
|
import { fingerprintPersona } from "../sync.js";
|
|
7
|
+
import { createVersionStorage } from "../sdk/version-storage.js";
|
|
8
|
+
import { createVersionPolicyEngine } from "../sdk/version-policy.js";
|
|
7
9
|
import { AGENT_CATALOG, WORKFLOW_PATTERNS, QUALIFYING_QUESTIONS, PLATFORM_CONCEPTS, WORKFLOW_EXECUTION_MODEL, COMMON_MISTAKES, DEBUG_CHECKLIST, GUIDANCE_TOPICS, VOICE_PERSONA_TEMPLATE, getAgentByName, getWidgetsForPersonaType, checkTypeCompatibility, getQualifyingQuestionsByCategory, getRequiredQualifyingQuestions, getConceptByTerm, suggestAgentsForUseCase, validateWorkflowPrompt, detectWorkflowIssues, validateWorkflowConnections, suggestWorkflowFixes, } from "../sdk/knowledge.js";
|
|
8
10
|
import { compileWorkflow } from "../sdk/workflow-generator.js";
|
|
9
11
|
import { parseInput, intentToSpec } from "../sdk/workflow-intent.js";
|
|
@@ -23,7 +25,7 @@ export async function handleEnv(_args, getEnvironments) {
|
|
|
23
25
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
24
26
|
// PERSONA Handler
|
|
25
27
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
26
|
-
export async function handlePersona(args, client, getTemplateId, createClientForEnv) {
|
|
28
|
+
export async function handlePersona(args, client, getTemplateId, createClientForEnv, versionContext) {
|
|
27
29
|
const id = args.id;
|
|
28
30
|
const identifier = args.identifier; // deprecated alias
|
|
29
31
|
const idOrName = id ?? identifier;
|
|
@@ -171,6 +173,251 @@ export async function handlePersona(args, client, getTemplateId, createClientFor
|
|
|
171
173
|
count: templates.size,
|
|
172
174
|
};
|
|
173
175
|
}
|
|
176
|
+
// ─────────────── Version Management Modes ───────────────
|
|
177
|
+
case "version_create": {
|
|
178
|
+
if (!idOrName) {
|
|
179
|
+
return { error: "id required for version_create mode" };
|
|
180
|
+
}
|
|
181
|
+
if (!versionContext) {
|
|
182
|
+
return { error: "Version tracking not configured. Provide workspaceRoot in context." };
|
|
183
|
+
}
|
|
184
|
+
const persona = await resolvePersona(client, idOrName);
|
|
185
|
+
if (!persona) {
|
|
186
|
+
return { error: `Persona not found: ${idOrName}` };
|
|
187
|
+
}
|
|
188
|
+
// Fetch full persona with workflow
|
|
189
|
+
const fullPersona = await client.getPersonaById(persona.id);
|
|
190
|
+
if (!fullPersona) {
|
|
191
|
+
return { error: `Could not fetch full persona: ${persona.id}` };
|
|
192
|
+
}
|
|
193
|
+
const storage = createVersionStorage(versionContext.workspaceRoot);
|
|
194
|
+
const engine = createVersionPolicyEngine(storage);
|
|
195
|
+
const result = engine.forceCreateVersion(fullPersona, {
|
|
196
|
+
environment: versionContext.environment,
|
|
197
|
+
tenant_id: versionContext.tenant_id,
|
|
198
|
+
message: args.message,
|
|
199
|
+
created_by: "mcp-toolkit",
|
|
200
|
+
});
|
|
201
|
+
if (!result.created || !result.version) {
|
|
202
|
+
return { error: result.reason };
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
success: true,
|
|
206
|
+
version: {
|
|
207
|
+
id: result.version.id,
|
|
208
|
+
version_number: result.version.version_number,
|
|
209
|
+
version_name: result.version.version_name,
|
|
210
|
+
content_hash: result.version.content_hash,
|
|
211
|
+
created_at: result.version.created_at,
|
|
212
|
+
message: result.version.message,
|
|
213
|
+
},
|
|
214
|
+
changes_from_parent: result.changes_from_parent,
|
|
215
|
+
versions_pruned: result.versions_pruned,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
case "version_list": {
|
|
219
|
+
if (!idOrName) {
|
|
220
|
+
return { error: "id required for version_list mode" };
|
|
221
|
+
}
|
|
222
|
+
if (!versionContext) {
|
|
223
|
+
return { error: "Version tracking not configured. Provide workspaceRoot in context." };
|
|
224
|
+
}
|
|
225
|
+
const persona = await resolvePersona(client, idOrName);
|
|
226
|
+
if (!persona) {
|
|
227
|
+
return { error: `Persona not found: ${idOrName}` };
|
|
228
|
+
}
|
|
229
|
+
const storage = createVersionStorage(versionContext.workspaceRoot);
|
|
230
|
+
const engine = createVersionPolicyEngine(storage);
|
|
231
|
+
const versions = engine.listVersions(persona.id, {
|
|
232
|
+
limit: args.limit,
|
|
233
|
+
});
|
|
234
|
+
return {
|
|
235
|
+
persona_id: persona.id,
|
|
236
|
+
persona_name: persona.name,
|
|
237
|
+
versions,
|
|
238
|
+
count: versions.length,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
case "version_get": {
|
|
242
|
+
if (!idOrName) {
|
|
243
|
+
return { error: "id required for version_get mode" };
|
|
244
|
+
}
|
|
245
|
+
if (!versionContext) {
|
|
246
|
+
return { error: "Version tracking not configured. Provide workspaceRoot in context." };
|
|
247
|
+
}
|
|
248
|
+
const persona = await resolvePersona(client, idOrName);
|
|
249
|
+
if (!persona) {
|
|
250
|
+
return { error: `Persona not found: ${idOrName}` };
|
|
251
|
+
}
|
|
252
|
+
const versionId = args.version ?? "latest";
|
|
253
|
+
const storage = createVersionStorage(versionContext.workspaceRoot);
|
|
254
|
+
const engine = createVersionPolicyEngine(storage);
|
|
255
|
+
const version = engine.getVersion(persona.id, versionId);
|
|
256
|
+
if (!version) {
|
|
257
|
+
return { error: `Version not found: ${versionId}` };
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
persona_id: persona.id,
|
|
261
|
+
persona_name: persona.name,
|
|
262
|
+
version: {
|
|
263
|
+
id: version.id,
|
|
264
|
+
version_number: version.version_number,
|
|
265
|
+
version_name: version.version_name,
|
|
266
|
+
content_hash: version.content_hash,
|
|
267
|
+
created_at: version.created_at,
|
|
268
|
+
created_by: version.created_by,
|
|
269
|
+
trigger: version.trigger,
|
|
270
|
+
message: version.message,
|
|
271
|
+
changes_summary: version.changes_summary,
|
|
272
|
+
},
|
|
273
|
+
snapshot: {
|
|
274
|
+
display_name: version.snapshot.display_name,
|
|
275
|
+
description: version.snapshot.description,
|
|
276
|
+
workflow_id: version.snapshot.workflow_id,
|
|
277
|
+
trigger_type: version.snapshot.trigger_type,
|
|
278
|
+
embedding_enabled: version.snapshot.embedding_enabled,
|
|
279
|
+
has_workflow: !!version.snapshot.workflow_definition,
|
|
280
|
+
has_proto_config: !!version.snapshot.proto_config,
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
case "version_compare": {
|
|
285
|
+
if (!idOrName) {
|
|
286
|
+
return { error: "id required for version_compare mode" };
|
|
287
|
+
}
|
|
288
|
+
if (!versionContext) {
|
|
289
|
+
return { error: "Version tracking not configured. Provide workspaceRoot in context." };
|
|
290
|
+
}
|
|
291
|
+
const v1 = args.v1;
|
|
292
|
+
const v2 = args.v2;
|
|
293
|
+
if (!v1 || !v2) {
|
|
294
|
+
return { error: "v1 and v2 required for version_compare mode" };
|
|
295
|
+
}
|
|
296
|
+
const persona = await resolvePersona(client, idOrName);
|
|
297
|
+
if (!persona) {
|
|
298
|
+
return { error: `Persona not found: ${idOrName}` };
|
|
299
|
+
}
|
|
300
|
+
const storage = createVersionStorage(versionContext.workspaceRoot);
|
|
301
|
+
const engine = createVersionPolicyEngine(storage);
|
|
302
|
+
const result = engine.compareVersions(persona.id, v1, v2);
|
|
303
|
+
if (!result.success) {
|
|
304
|
+
return { error: result.error };
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
persona_id: persona.id,
|
|
308
|
+
persona_name: persona.name,
|
|
309
|
+
comparison: {
|
|
310
|
+
v1: result.diff?.v1,
|
|
311
|
+
v2: result.diff?.v2,
|
|
312
|
+
identical: result.diff?.identical,
|
|
313
|
+
changed_fields: result.diff?.changed_fields,
|
|
314
|
+
workflow_diff: result.diff?.workflow_diff,
|
|
315
|
+
},
|
|
316
|
+
summary: result.summary,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
case "version_restore": {
|
|
320
|
+
if (!idOrName) {
|
|
321
|
+
return { error: "id required for version_restore mode" };
|
|
322
|
+
}
|
|
323
|
+
if (!versionContext) {
|
|
324
|
+
return { error: "Version tracking not configured. Provide workspaceRoot in context." };
|
|
325
|
+
}
|
|
326
|
+
const versionId = args.version;
|
|
327
|
+
if (!versionId) {
|
|
328
|
+
return { error: "version required for version_restore mode" };
|
|
329
|
+
}
|
|
330
|
+
const persona = await resolvePersona(client, idOrName);
|
|
331
|
+
if (!persona) {
|
|
332
|
+
return { error: `Persona not found: ${idOrName}` };
|
|
333
|
+
}
|
|
334
|
+
const storage = createVersionStorage(versionContext.workspaceRoot);
|
|
335
|
+
const engine = createVersionPolicyEngine(storage);
|
|
336
|
+
const restoreData = engine.getRestoreData(persona.id, versionId);
|
|
337
|
+
if (!restoreData.success || !restoreData.restore_payload) {
|
|
338
|
+
return { error: restoreData.error ?? "Failed to get restore data" };
|
|
339
|
+
}
|
|
340
|
+
// Create a version snapshot before restoring (audit trail)
|
|
341
|
+
const fullPersona = await client.getPersonaById(persona.id);
|
|
342
|
+
if (fullPersona) {
|
|
343
|
+
engine.forceCreateVersion(fullPersona, {
|
|
344
|
+
environment: versionContext.environment,
|
|
345
|
+
tenant_id: versionContext.tenant_id,
|
|
346
|
+
message: `Before restore to ${restoreData.version?.version_name}`,
|
|
347
|
+
created_by: "mcp-toolkit",
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
// Apply the restore
|
|
351
|
+
const payload = restoreData.restore_payload;
|
|
352
|
+
await client.updateAiEmployee({
|
|
353
|
+
persona_id: payload.persona_id,
|
|
354
|
+
name: payload.name,
|
|
355
|
+
description: payload.description,
|
|
356
|
+
proto_config: payload.proto_config,
|
|
357
|
+
workflow: payload.workflow ?? undefined,
|
|
358
|
+
welcome_messages: payload.welcome_messages ?? undefined,
|
|
359
|
+
embedding_enabled: payload.embedding_enabled ?? undefined,
|
|
360
|
+
});
|
|
361
|
+
// Create post-restore version
|
|
362
|
+
const restoredPersona = await client.getPersonaById(persona.id);
|
|
363
|
+
if (restoredPersona) {
|
|
364
|
+
engine.forceCreateVersion(restoredPersona, {
|
|
365
|
+
environment: versionContext.environment,
|
|
366
|
+
tenant_id: versionContext.tenant_id,
|
|
367
|
+
message: `Restored to ${restoreData.version?.version_name}`,
|
|
368
|
+
created_by: "mcp-toolkit",
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
success: true,
|
|
373
|
+
persona_id: persona.id,
|
|
374
|
+
restored_to: {
|
|
375
|
+
version_id: restoreData.version?.id,
|
|
376
|
+
version_name: restoreData.version?.version_name,
|
|
377
|
+
version_number: restoreData.version?.version_number,
|
|
378
|
+
},
|
|
379
|
+
message: `Persona restored to ${restoreData.version?.version_name}`,
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
case "version_policy": {
|
|
383
|
+
if (!idOrName) {
|
|
384
|
+
return { error: "id required for version_policy mode" };
|
|
385
|
+
}
|
|
386
|
+
if (!versionContext) {
|
|
387
|
+
return { error: "Version tracking not configured. Provide workspaceRoot in context." };
|
|
388
|
+
}
|
|
389
|
+
const persona = await resolvePersona(client, idOrName);
|
|
390
|
+
if (!persona) {
|
|
391
|
+
return { error: `Persona not found: ${idOrName}` };
|
|
392
|
+
}
|
|
393
|
+
const storage = createVersionStorage(versionContext.workspaceRoot);
|
|
394
|
+
const engine = createVersionPolicyEngine(storage);
|
|
395
|
+
// Check if we're updating or just getting
|
|
396
|
+
const hasUpdates = args.auto_on_deploy !== undefined ||
|
|
397
|
+
args.auto_on_sync !== undefined ||
|
|
398
|
+
args.max_versions !== undefined;
|
|
399
|
+
if (hasUpdates) {
|
|
400
|
+
const updated = engine.updatePolicy(persona.id, {
|
|
401
|
+
auto_version_on_deploy: args.auto_on_deploy,
|
|
402
|
+
auto_version_on_sync: args.auto_on_sync,
|
|
403
|
+
max_versions: args.max_versions,
|
|
404
|
+
});
|
|
405
|
+
return {
|
|
406
|
+
success: true,
|
|
407
|
+
persona_id: persona.id,
|
|
408
|
+
persona_name: persona.name,
|
|
409
|
+
policy: updated,
|
|
410
|
+
message: "Policy updated",
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
// Just get current policy
|
|
414
|
+
const policy = engine.getPolicy(persona.id);
|
|
415
|
+
return {
|
|
416
|
+
persona_id: persona.id,
|
|
417
|
+
persona_name: persona.name,
|
|
418
|
+
policy,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
174
421
|
default:
|
|
175
422
|
return { error: `Unknown mode: ${effectiveMode}` };
|
|
176
423
|
}
|
|
@@ -315,6 +562,15 @@ export async function handleWorkflow(args, client) {
|
|
|
315
562
|
if (!persona) {
|
|
316
563
|
return { error: `Persona not found: ${personaId}` };
|
|
317
564
|
}
|
|
565
|
+
// Check persona status - deployment works on disabled personas but we should inform user
|
|
566
|
+
const personaStatus = persona.status?.toLowerCase();
|
|
567
|
+
const isDisabled = personaStatus === "inactive" || personaStatus === "disabled";
|
|
568
|
+
const statusWarnings = [];
|
|
569
|
+
if (isDisabled) {
|
|
570
|
+
statusWarnings.push(`⚠️ Persona "${persona.name}" is currently DISABLED (status: ${persona.status}). ` +
|
|
571
|
+
`Workflow will be deployed but won't be active until enabled. ` +
|
|
572
|
+
`Use persona(mode="update", id="${personaId}", enabled=true) to enable.`);
|
|
573
|
+
}
|
|
318
574
|
let deployWorkflow = workflowDef || persona.workflow_def;
|
|
319
575
|
// Validate if requested (default: true)
|
|
320
576
|
if (args.validate !== false) {
|
|
@@ -325,6 +581,7 @@ export async function handleWorkflow(args, client) {
|
|
|
325
581
|
error: "Workflow has errors",
|
|
326
582
|
issues: errors,
|
|
327
583
|
hint: "Set auto_fix=true to attempt automatic fixes",
|
|
584
|
+
...(statusWarnings.length > 0 && { status_warnings: statusWarnings }),
|
|
328
585
|
};
|
|
329
586
|
}
|
|
330
587
|
// Auto-fix if enabled
|
|
@@ -341,7 +598,13 @@ export async function handleWorkflow(args, client) {
|
|
|
341
598
|
return {
|
|
342
599
|
success: true,
|
|
343
600
|
persona_id: personaId,
|
|
601
|
+
persona_name: persona.name,
|
|
602
|
+
persona_status: persona.status,
|
|
344
603
|
deployed: true,
|
|
604
|
+
...(isDisabled && {
|
|
605
|
+
warning: `Persona is DISABLED - workflow deployed but inactive. Enable with: persona(mode="update", id="${personaId}", enabled=true)`,
|
|
606
|
+
}),
|
|
607
|
+
...(statusWarnings.length > 0 && { status_warnings: statusWarnings }),
|
|
345
608
|
};
|
|
346
609
|
}
|
|
347
610
|
case "compare": {
|
package/dist/mcp/prompts.js
CHANGED
|
@@ -74,9 +74,16 @@ Identify what the user is asking for:
|
|
|
74
74
|
| **Data Sources** | ✓/✗ | Knowledge base, web search, APIs? |
|
|
75
75
|
| **External Tools** | ✓/✗ | ServiceNow, Salesforce, email? |
|
|
76
76
|
| **Routing Logic** | ✓/✗ | How to handle different intents? |
|
|
77
|
-
| **HITL Requirements** | ✓/✗ |
|
|
77
|
+
| **HITL Requirements** | ✓/✗ | DEFAULT: No approval (auto-proceed). Only add if explicitly requested. |
|
|
78
78
|
| **Fallback Handling** | ✓/✗ | What if no match? |
|
|
79
79
|
|
|
80
|
+
#### HITL Policy (Default: Auto-Proceed)
|
|
81
|
+
For external side-effect actions (send_email, create_ticket, update_record):
|
|
82
|
+
- **Default**: Proceed WITHOUT approval gate unless explicitly requested
|
|
83
|
+
- **Add HITL only when**: User says "confirm before", "approval required", "human review"
|
|
84
|
+
- **Skip HITL when**: User says "auto", "directly", "no approval", or specifies direct flow
|
|
85
|
+
- **If ambiguous**: ASK "Should [action] require approval, or auto-proceed?"
|
|
86
|
+
|
|
80
87
|
#### For BROWNFIELD (extend existing):
|
|
81
88
|
| Dimension | Status | Missing Info |
|
|
82
89
|
|-----------|--------|--------------|
|
|
@@ -251,7 +258,7 @@ Verify you have answers for:
|
|
|
251
258
|
- Intents: ${args.intents || "(to be determined)"}
|
|
252
259
|
- Data Sources: (ask if not clear from use case)
|
|
253
260
|
- Actions: (ask if not clear from use case)
|
|
254
|
-
- Approvals/HITL: (ask if
|
|
261
|
+
- Approvals/HITL: DEFAULT is no approval (auto-proceed). Only ask if user seems to want approval gates.
|
|
255
262
|
|
|
256
263
|
### Step 2: Select Pattern + Agents
|
|
257
264
|
Call \`action(suggest="${args.use_case}")\` to get recommended agents and a suggested workflow pattern.
|
|
@@ -1073,6 +1080,8 @@ Where \`<requirements>\` includes:
|
|
|
1073
1080
|
${args.intents ? `- Intents: ${args.intents}` : ""}
|
|
1074
1081
|
${args.tools ? `- Tools: ${args.tools}` : ""}
|
|
1075
1082
|
|
|
1083
|
+
**HITL Policy**: DEFAULT is no approval gates. Only add HITL if user explicitly requests approval/confirmation before external actions.
|
|
1084
|
+
|
|
1076
1085
|
If the tool returns \`status="needs_input"\`, ask the missing questions, then call \`workflow(...)\` again with the additional details.
|
|
1077
1086
|
|
|
1078
1087
|
### Step 2: (Optional) Validate the generated workflow
|