@ema.co/mcp-toolkit 2026.2.27 → 2026.2.28
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/.context/public/guides/ema-user-guide.md +7 -6
- package/.context/public/guides/mcp-tools-guide.md +46 -23
- package/dist/config/index.js +11 -0
- package/dist/config/workflow-patterns.js +361 -0
- package/dist/mcp/autobuilder.js +2 -2
- package/dist/mcp/domain/generation-schema.js +15 -9
- package/dist/mcp/domain/structural-rules.js +3 -3
- package/dist/mcp/domain/validation-rules.js +20 -27
- package/dist/mcp/domain/workflow-generator.js +3 -3
- package/dist/mcp/domain/workflow-graph.js +1 -1
- package/dist/mcp/guidance.js +60 -1
- package/dist/mcp/handlers/conversation/adapter.js +13 -0
- package/dist/mcp/handlers/conversation/create.js +19 -0
- package/dist/mcp/handlers/conversation/delete.js +18 -0
- package/dist/mcp/handlers/conversation/formatters.js +62 -0
- package/dist/mcp/handlers/conversation/history.js +15 -0
- package/dist/mcp/handlers/conversation/index.js +43 -0
- package/dist/mcp/handlers/conversation/list.js +40 -0
- package/dist/mcp/handlers/conversation/messages.js +13 -0
- package/dist/mcp/handlers/conversation/rename.js +16 -0
- package/dist/mcp/handlers/conversation/send.js +90 -0
- package/dist/mcp/handlers/data/index.js +169 -3
- package/dist/mcp/handlers/feedback/client-id.js +49 -0
- package/dist/mcp/handlers/feedback/coalesce.js +167 -0
- package/dist/mcp/handlers/feedback/index.js +42 -1
- package/dist/mcp/handlers/feedback/outbox.js +301 -0
- package/dist/mcp/handlers/feedback/probes.js +127 -0
- package/dist/mcp/handlers/feedback/remote-store.js +59 -0
- package/dist/mcp/handlers/feedback/store.js +13 -1
- package/dist/mcp/handlers/persona/delete.js +7 -28
- package/dist/mcp/handlers/persona/update.js +7 -26
- package/dist/mcp/handlers/persona/version.js +30 -15
- package/dist/mcp/handlers/template/adapter.js +23 -0
- package/dist/mcp/handlers/template/crud.js +174 -0
- package/dist/mcp/handlers/template/index.js +6 -7
- package/dist/mcp/handlers/workflow/adapter.js +30 -46
- package/dist/mcp/handlers/workflow/index.js +2 -2
- package/dist/mcp/handlers/workflow/validation.js +2 -2
- package/dist/mcp/knowledge-guidance-topics.js +90 -53
- package/dist/mcp/knowledge.js +7 -357
- package/dist/mcp/prompts.js +5 -5
- package/dist/mcp/resources-dynamic.js +46 -38
- package/dist/mcp/resources-validation.js +5 -5
- package/dist/mcp/server.js +38 -5
- package/dist/mcp/tools.js +340 -8
- package/dist/sdk/client-adapter.js +90 -2
- package/dist/sdk/client.js +7 -0
- package/dist/sdk/ema-client.js +242 -27
- package/dist/sdk/generated/agent-catalog.js +96 -39
- package/dist/sdk/generated/deprecated-actions.js +1 -1
- package/dist/sdk/grpc-client.js +67 -5
- package/dist/sync/central-factory.js +86 -0
- package/dist/sync/central-version-storage.js +387 -0
- package/dist/sync/dis-port.js +75 -0
- package/dist/sync/version-policy.js +29 -31
- package/dist/sync/version-storage-interface.js +11 -0
- package/dist/sync/version-storage.js +22 -22
- package/package.json +2 -1
|
@@ -974,19 +974,17 @@ Chat workflows that process \`chat_conversation\` through search, extraction, or
|
|
|
974
974
|
|
|
975
975
|
## Correct Patterns
|
|
976
976
|
|
|
977
|
-
### Pattern 1: Search + Respond (most common)
|
|
977
|
+
### Pattern 1: Search + Respond (most common — 89% of production)
|
|
978
978
|
\`\`\`
|
|
979
979
|
chat_trigger.chat_conversation → conversation_to_search_query.conversation
|
|
980
980
|
conversation_to_search_query.summarized_conversation → search.query
|
|
981
|
-
search.search_results →
|
|
982
|
-
chat_trigger.user_query →
|
|
983
|
-
chat_trigger.chat_conversation →
|
|
984
|
-
|
|
981
|
+
search.search_results → call_llm.named_inputs_Search_Results
|
|
982
|
+
chat_trigger.user_query → call_llm.query
|
|
983
|
+
chat_trigger.chat_conversation → call_llm.named_inputs_Conversation
|
|
984
|
+
call_llm.response_with_sources → WORKFLOW_OUTPUT
|
|
985
985
|
\`\`\`
|
|
986
986
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
### Pattern 2: Tool/Action + Respond
|
|
987
|
+
### Pattern 2: Tool/Action + Respond (uses respond_for_external_actions)
|
|
990
988
|
\`\`\`
|
|
991
989
|
chat_trigger.chat_conversation → external_action_caller.conversation
|
|
992
990
|
external_action_caller.tool_execution_result → respond_for_external_actions.external_action_result
|
|
@@ -995,12 +993,14 @@ chat_trigger.chat_conversation → respond_for_external_actions.conversation
|
|
|
995
993
|
respond_for_external_actions.response → WORKFLOW_OUTPUT
|
|
996
994
|
\`\`\`
|
|
997
995
|
|
|
998
|
-
|
|
999
|
-
|
|
996
|
+
> **Note**: \`respond_for_external_actions\` is ONLY for explaining \`external_action_caller\` results (Salesforce, ServiceNow, etc). For KB Q&A after search, use \`call_llm\` with \`named_inputs\`.
|
|
997
|
+
|
|
998
|
+
### Pattern 3: Search + Respond with Citations
|
|
1000
999
|
\`\`\`
|
|
1001
|
-
|
|
1000
|
+
search.search_results → respond_with_sources.search_results
|
|
1001
|
+
chat_trigger.user_query → respond_with_sources.query
|
|
1002
|
+
respond_with_sources.response → WORKFLOW_OUTPUT
|
|
1002
1003
|
\`\`\`
|
|
1003
|
-
This ensures the LLM sees prior turns.
|
|
1004
1004
|
|
|
1005
1005
|
## Anti-Patterns
|
|
1006
1006
|
|
|
@@ -1009,6 +1009,13 @@ This ensures the LLM sees prior turns.
|
|
|
1009
1009
|
chat_trigger → search → call_llm (no conversation) → WORKFLOW_OUTPUT
|
|
1010
1010
|
\`\`\`
|
|
1011
1011
|
**Problem**: call_llm only sees search results, not prior conversation. Repeats questions.
|
|
1012
|
+
**Fix**: Wire \`chat_conversation\` into \`call_llm.named_inputs_Conversation\`.
|
|
1013
|
+
|
|
1014
|
+
### ❌ respond_for_external_actions for KB Q&A
|
|
1015
|
+
\`\`\`
|
|
1016
|
+
chat_trigger → search → respond_for_external_actions → WORKFLOW_OUTPUT
|
|
1017
|
+
\`\`\`
|
|
1018
|
+
**Problem**: \`respond_for_external_actions\` is designed for \`external_action_caller\` tool results, not search results. Use \`call_llm\` with \`named_inputs_Search_Results\` instead.
|
|
1012
1019
|
|
|
1013
1020
|
### ❌ Entity Extraction → call_llm (no history)
|
|
1014
1021
|
\`\`\`
|
|
@@ -1016,19 +1023,14 @@ chat_trigger → entity_extraction → call_llm (stateless) → WORKFLOW_OUTPUT
|
|
|
1016
1023
|
\`\`\`
|
|
1017
1024
|
**Problem**: LLM extracts entities but response node doesn't know what was already discussed.
|
|
1018
1025
|
|
|
1019
|
-
## Key Insight
|
|
1020
|
-
|
|
1021
|
-
\`respond_for_external_actions\` is **conversation-aware by design** — it incorporates conversation context via its \`conversation\` input. Generic \`call_llm\` does not — you must manually wire \`chat_conversation\` via \`named_inputs\`.
|
|
1022
|
-
|
|
1023
|
-
> **Deprecated**: \`respond_with_sources/v0\` — use \`respond_for_external_actions\` for all new workflows.
|
|
1024
|
-
|
|
1025
1026
|
## When to Use Each Response Node
|
|
1026
1027
|
|
|
1027
1028
|
| Scenario | Response Node | Why |
|
|
1028
1029
|
|----------|---------------|-----|
|
|
1029
|
-
| KB/document Q&A | \`
|
|
1030
|
-
|
|
|
1031
|
-
|
|
|
1030
|
+
| KB/document Q&A | \`call_llm\` with \`named_inputs_Search_Results\` | Most common (89%), full control via named_inputs |
|
|
1031
|
+
| KB Q&A with citations | \`respond_with_sources\` | Automatic citation grounding |
|
|
1032
|
+
| External tool results | \`respond_for_external_actions\` | ONLY for \`external_action_caller\` outputs |
|
|
1033
|
+
| Complex multi-step reasoning | \`custom_agent\` | Role context + multi-step reasoning |
|
|
1032
1034
|
| Static/template response | \`fixed_response/v1\` | No LLM needed, just template + variables |
|
|
1033
1035
|
`;
|
|
1034
1036
|
},
|
|
@@ -1239,10 +1241,10 @@ When you already have a clean extracted value and just need TEXT_WITH_SOURCES wr
|
|
|
1239
1241
|
md += `- **Outputs**: \`response_with_sources\` (TEXT_WITH_SOURCES)\n`;
|
|
1240
1242
|
md += `- **Critical**: Must wire to WORKFLOW_OUTPUT or response is lost. \`call_llm/v0\` is deprecated.\n\n`;
|
|
1241
1243
|
md += `### respond_for_external_actions\n`;
|
|
1242
|
-
md += `
|
|
1243
|
-
md += `- **Inputs**: \`query\` (TEXT_WITH_SOURCES), \`conversation\` (CHAT_CONVERSATION), \`external_action_result\` (
|
|
1244
|
+
md += `Explain results from external_action_caller (Salesforce, ServiceNow, etc) in conversation context.\n`;
|
|
1245
|
+
md += `- **Inputs**: \`query\` (TEXT_WITH_SOURCES), \`conversation\` (CHAT_CONVERSATION), \`external_action_result\` (from external_action_caller)\n`;
|
|
1244
1246
|
md += `- **Outputs**: \`response\` (TEXT_WITH_SOURCES)\n`;
|
|
1245
|
-
md += `- **Critical**:
|
|
1247
|
+
md += `- **Critical**: ONLY use after \`external_action_caller\`. For KB Q&A after search, use \`call_llm\` with \`named_inputs_Search_Results\`.\n\n`;
|
|
1246
1248
|
md += `### fixed_response/v1\n`;
|
|
1247
1249
|
md += `Return a static predefined message.\n`;
|
|
1248
1250
|
md += `- **Inputs**: \`trigger_when\` (ENUM), \`named_inputs_*\` for template variables\n`;
|
|
@@ -1280,12 +1282,12 @@ When you already have a clean extracted value and just need TEXT_WITH_SOURCES wr
|
|
|
1280
1282
|
md += `- **Inputs**: \`query\` (TEXT_WITH_SOURCES)\n`;
|
|
1281
1283
|
md += `- **Outputs**: \`web_search_results\` (SEARCH_RESULT)\n`;
|
|
1282
1284
|
md += `- **Critical**: No data upload needed (searches the web).\n\n`;
|
|
1283
|
-
md += `###
|
|
1284
|
-
md += `Merge results from multiple search sources with
|
|
1285
|
-
md += `- **Inputs**:
|
|
1286
|
-
md += `- **Outputs**:
|
|
1287
|
-
md += `- **
|
|
1288
|
-
md += `- **
|
|
1285
|
+
md += `### combine_and_rerank_search_results\n`;
|
|
1286
|
+
md += `Merge results from multiple search sources with relevance-based reranking.\n`;
|
|
1287
|
+
md += `- **Inputs**: Multiple search result inputs (SEARCH_RESULT)\n`;
|
|
1288
|
+
md += `- **Outputs**: Reranked combined results (SEARCH_RESULT)\n`;
|
|
1289
|
+
md += `- **When**: Need weighted/prioritized results from multiple sources, or need to ensure certain results rank higher\n`;
|
|
1290
|
+
md += `- **Alternative**: \`call_llm\` with multiple \`named_inputs\` gives prompt-level control over how results are synthesized.\n\n`;
|
|
1289
1291
|
md += `### response_validator\n`;
|
|
1290
1292
|
md += `Validate LLM output against quality/compliance criteria.\n`;
|
|
1291
1293
|
md += `- **Inputs**: \`reference_query\` (TEXT_WITH_SOURCES), \`response_to_validate\` (TEXT_WITH_SOURCES)\n`;
|
|
@@ -1420,15 +1422,16 @@ When you already have a clean extracted value and just need TEXT_WITH_SOURCES wr
|
|
|
1420
1422
|
{ name: "vadSettings", type: 42, purpose: "Voice activity detection, timeouts" },
|
|
1421
1423
|
],
|
|
1422
1424
|
common_patterns: {
|
|
1423
|
-
simple_qa: "chat_trigger → search →
|
|
1425
|
+
simple_qa: "chat_trigger → search → call_llm (via named_inputs_Search_Results) → WORKFLOW_OUTPUT",
|
|
1424
1426
|
with_routing: "chat_trigger → chat_categorizer → [branch per intent] → respond → WORKFLOW_OUTPUT",
|
|
1425
1427
|
with_tools: "chat_trigger → categorizer → external_action_caller → respond_for_external_actions → WORKFLOW_OUTPUT",
|
|
1426
1428
|
},
|
|
1427
1429
|
best_practices: [
|
|
1428
1430
|
"Use search/v2 (NOT v0) with datastore_configs",
|
|
1429
1431
|
"Include Fallback category in every categorizer",
|
|
1430
|
-
"
|
|
1431
|
-
"
|
|
1432
|
+
"For KB Q&A after search: use call_llm with named_inputs_Search_Results (89% of production)",
|
|
1433
|
+
"respond_for_external_actions is ONLY for external_action_caller results (Salesforce, etc)",
|
|
1434
|
+
"For approval workflows: use general_hitl (Human Collaboration Agent) or HITL flags on send_email_agent/entity_extraction_with_documents",
|
|
1432
1435
|
],
|
|
1433
1436
|
_next_step: "Call workflow(mode='get', persona_id='...') to get full schema, then generate workflow_def",
|
|
1434
1437
|
}, null, 2);
|
|
@@ -1549,7 +1552,7 @@ Wire any custom widget to a search node: \`search/v2\` → \`datastore_configs\`
|
|
|
1549
1552
|
| Deprecated | Use Instead |
|
|
1550
1553
|
|------------|-------------|
|
|
1551
1554
|
| search/v0 | search/v2 (requires datastore_configs) |
|
|
1552
|
-
| respond_with_sources |
|
|
1555
|
+
| respond_with_sources/v0 | call_llm with named_inputs (for KB Q&A) or respond_with_sources current version (for citations) |
|
|
1553
1556
|
| call_llm/v0 | call_llm/v2 |
|
|
1554
1557
|
|
|
1555
1558
|
## Anti-Patterns
|
|
@@ -1791,15 +1794,20 @@ interface ResultMapping {
|
|
|
1791
1794
|
},
|
|
1792
1795
|
{
|
|
1793
1796
|
"id": "respond",
|
|
1794
|
-
"actionType": "
|
|
1797
|
+
"actionType": "call_llm",
|
|
1795
1798
|
"displayName": "Generate Response",
|
|
1796
1799
|
"inputs": {
|
|
1797
|
-
"
|
|
1800
|
+
"query": {
|
|
1801
|
+
"type": "action_output",
|
|
1802
|
+
"actionName": "trigger",
|
|
1803
|
+
"output": "user_query"
|
|
1804
|
+
},
|
|
1805
|
+
"named_inputs_Search_Results": {
|
|
1798
1806
|
"type": "action_output",
|
|
1799
1807
|
"actionName": "search",
|
|
1800
1808
|
"output": "search_results"
|
|
1801
1809
|
},
|
|
1802
|
-
"
|
|
1810
|
+
"named_inputs_Conversation": {
|
|
1803
1811
|
"type": "action_output",
|
|
1804
1812
|
"actionName": "trigger",
|
|
1805
1813
|
"output": "chat_conversation"
|
|
@@ -1808,7 +1816,7 @@ interface ResultMapping {
|
|
|
1808
1816
|
}
|
|
1809
1817
|
],
|
|
1810
1818
|
"resultMappings": [
|
|
1811
|
-
{ "nodeId": "respond", "output": "
|
|
1819
|
+
{ "nodeId": "respond", "output": "response_with_sources" }
|
|
1812
1820
|
]
|
|
1813
1821
|
}
|
|
1814
1822
|
\`\`\`
|
|
@@ -59,9 +59,9 @@ These rules are extracted from the Go validator's static validation logic. Follo
|
|
|
59
59
|
**Good Pattern**:
|
|
60
60
|
\`\`\`json
|
|
61
61
|
{
|
|
62
|
-
"path": ["trigger", "categorizer", "billing_branch", "search", "
|
|
62
|
+
"path": ["trigger", "categorizer", "billing_branch", "search", "respond"],
|
|
63
63
|
"named_result": "response",
|
|
64
|
-
"produces": ["response"] // ✅ Produced
|
|
64
|
+
"produces": ["response"] // ✅ Produced (respond is call_llm with named_inputs)
|
|
65
65
|
}
|
|
66
66
|
\`\`\`
|
|
67
67
|
|
|
@@ -75,8 +75,8 @@ These rules are extracted from the Go validator's static validation logic. Follo
|
|
|
75
75
|
3. Connect the node's output to WORKFLOW_OUTPUT
|
|
76
76
|
|
|
77
77
|
**Common Fixes**:
|
|
78
|
-
- Add \`
|
|
79
|
-
- Add \`
|
|
78
|
+
- Add \`call_llm\` node with \`named_inputs_Search_Results\` after search (most common)
|
|
79
|
+
- Add \`respond_with_sources\` for citation-grounded responses
|
|
80
80
|
- Add \`fixed_response\` for static responses
|
|
81
81
|
|
|
82
82
|
**Prevention** (During Generation):
|
|
@@ -183,7 +183,7 @@ These rules are extracted from the Go validator's static validation logic. Follo
|
|
|
183
183
|
**Good Pattern**:
|
|
184
184
|
\`\`\`json
|
|
185
185
|
{
|
|
186
|
-
"path": ["trigger", "categorizer", "billing", "search", "
|
|
186
|
+
"path": ["trigger", "categorizer", "billing", "search", "respond"],
|
|
187
187
|
"has_response": true // ✅ Has response
|
|
188
188
|
}
|
|
189
189
|
\`\`\`
|
package/dist/mcp/server.js
CHANGED
|
@@ -29,25 +29,28 @@ import { generateTools } from "./tools.js";
|
|
|
29
29
|
// Handler imports (simple 1-2 line handlers stay inline)
|
|
30
30
|
import { handleEnv } from "./handlers/env/index.js";
|
|
31
31
|
import { handleAction } from "./handlers/action/index.js";
|
|
32
|
-
import { handleTemplate } from "./handlers/template/index.js";
|
|
33
32
|
import { handleReference } from "./handlers/reference/index.js";
|
|
34
33
|
import { handleCatalog } from "./handlers/catalog/index.js";
|
|
35
34
|
import { handleFeedback } from "./handlers/feedback/index.js";
|
|
36
35
|
import { recordTelemetry } from "./handlers/feedback/store.js";
|
|
36
|
+
import { flushOutbox, startFlushTimer, stopFlushTimer } from "./handlers/feedback/outbox.js";
|
|
37
|
+
import { maybeInjectProbe } from "./handlers/feedback/probes.js";
|
|
37
38
|
// V2 adapters (extracted from server.ts — each owns its routing/transformation logic)
|
|
38
39
|
import { handlePersonaAdapter } from "./handlers/persona/adapter.js";
|
|
39
40
|
import { handleWorkflowAdapter } from "./handlers/workflow/adapter.js";
|
|
40
41
|
import { handleSyncAdapter } from "./handlers/sync/adapter.js";
|
|
41
42
|
import { handleDemoAdapter } from "./handlers/demo/adapter.js";
|
|
42
43
|
import { handleDebugAdapter } from "./handlers/debug/adapter.js";
|
|
44
|
+
import { handleConversationAdapter } from "./handlers/conversation/adapter.js";
|
|
45
|
+
import { handleTemplateAdapter } from "./handlers/template/adapter.js";
|
|
43
46
|
// Start token initialization in background (non-blocking)
|
|
44
47
|
void initializeApiKeyTokens();
|
|
45
48
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
46
49
|
// Tool Definitions
|
|
47
50
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
48
51
|
//
|
|
49
|
-
// V2 TOOLS (
|
|
50
|
-
// - env, persona, catalog, workflow, sync, toolkit_feedback, debug
|
|
52
|
+
// V2 TOOLS (9 tools) - LLM-optimized minimal interface
|
|
53
|
+
// - env, persona, catalog, workflow, sync, toolkit_feedback, debug, conversation, template
|
|
51
54
|
// - Defined in: ./tools.ts
|
|
52
55
|
//
|
|
53
56
|
// NAMING CONVENTION:
|
|
@@ -58,7 +61,7 @@ void initializeApiKeyTokens();
|
|
|
58
61
|
/**
|
|
59
62
|
* Generate all available tools
|
|
60
63
|
*
|
|
61
|
-
* V2:
|
|
64
|
+
* V2: 9 tools (persona, catalog, workflow, sync, env, toolkit_feedback, debug, conversation, template) - LLM-optimized
|
|
62
65
|
*
|
|
63
66
|
* Why V2:
|
|
64
67
|
* - Minimal tool count optimizes LLM tool selection
|
|
@@ -73,6 +76,8 @@ function generateAllTools() {
|
|
|
73
76
|
}
|
|
74
77
|
// Generate tools (called once at module load)
|
|
75
78
|
const TOOLS = generateAllTools();
|
|
79
|
+
// Track whether the first-session opt-out notice has been shown
|
|
80
|
+
let firstNoticeShown = false;
|
|
76
81
|
const toolHandlers = {
|
|
77
82
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
78
83
|
// V2 TOOLS — LLM-optimized interface
|
|
@@ -91,7 +96,7 @@ const toolHandlers = {
|
|
|
91
96
|
return handleAction(args, client);
|
|
92
97
|
},
|
|
93
98
|
template: async (args) => {
|
|
94
|
-
return
|
|
99
|
+
return handleTemplateAdapter(args, createClient, getDefaultEnvName);
|
|
95
100
|
},
|
|
96
101
|
data: async (args) => {
|
|
97
102
|
const client = createClient(args.env);
|
|
@@ -138,6 +143,9 @@ const toolHandlers = {
|
|
|
138
143
|
debug: async (args) => {
|
|
139
144
|
return handleDebugAdapter(args, createClient, getDefaultEnvName);
|
|
140
145
|
},
|
|
146
|
+
conversation: async (args) => {
|
|
147
|
+
return handleConversationAdapter(args, createClient, getDefaultEnvName);
|
|
148
|
+
},
|
|
141
149
|
};
|
|
142
150
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
143
151
|
// Helpers
|
|
@@ -172,6 +180,12 @@ function determineOperation(toolName, args) {
|
|
|
172
180
|
if (toolName === "debug") {
|
|
173
181
|
return args.method ? String(args.method) : "conversations";
|
|
174
182
|
}
|
|
183
|
+
if (toolName === "conversation") {
|
|
184
|
+
return args.method ? String(args.method) : "create";
|
|
185
|
+
}
|
|
186
|
+
if (toolName === "template") {
|
|
187
|
+
return args.method ? String(args.method) : "list";
|
|
188
|
+
}
|
|
175
189
|
return toolName;
|
|
176
190
|
}
|
|
177
191
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -238,6 +252,15 @@ export async function startMcpServer() {
|
|
|
238
252
|
if (toolGuidance?.nextSteps?.[operation]) {
|
|
239
253
|
response._next_step = toolGuidance.nextSteps[operation];
|
|
240
254
|
}
|
|
255
|
+
// Inject targeted probe question if conditions are met
|
|
256
|
+
maybeInjectProbe(response, name, operation);
|
|
257
|
+
// First-session opt-out notice (shown once)
|
|
258
|
+
if (!firstNoticeShown && name !== "toolkit_feedback") {
|
|
259
|
+
response._notice =
|
|
260
|
+
"This toolkit collects anonymous usage telemetry to improve quality. " +
|
|
261
|
+
"Set EMA_FEEDBACK_DISABLED=1 to opt out. See ~/.ema-mcp/outbox/sent-log.jsonl for transparency.";
|
|
262
|
+
firstNoticeShown = true;
|
|
263
|
+
}
|
|
241
264
|
return {
|
|
242
265
|
content: [{ type: "text", text: JSON.stringify(response, null, 2) }],
|
|
243
266
|
};
|
|
@@ -333,6 +356,16 @@ export async function startMcpServer() {
|
|
|
333
356
|
: TOOLKIT_VERSION;
|
|
334
357
|
const toolCount = TOOLS.length;
|
|
335
358
|
console.error(`Ema MCP Server started: ${TOOLKIT_NAME}@${buildInfo} | ${toolCount} tools`);
|
|
359
|
+
// Flush any pending outbox entries from previous sessions (catches npx ephemeral runs)
|
|
360
|
+
flushOutbox(TOOLKIT_VERSION).catch(() => { });
|
|
361
|
+
startFlushTimer(TOOLKIT_VERSION);
|
|
362
|
+
// Graceful shutdown — flush remaining outbox entries before exit
|
|
363
|
+
const gracefulShutdown = () => {
|
|
364
|
+
stopFlushTimer(TOOLKIT_VERSION).catch(() => { });
|
|
365
|
+
};
|
|
366
|
+
process.on("SIGTERM", gracefulShutdown);
|
|
367
|
+
process.on("SIGINT", gracefulShutdown);
|
|
368
|
+
process.on("beforeExit", gracefulShutdown);
|
|
336
369
|
}
|
|
337
370
|
// CLI support: allow --help to exit (used by build:verify)
|
|
338
371
|
const argv = process.argv.slice(2);
|