@echomem/mcp 1.4.13 → 1.4.14
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/index.js +26 -22
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -467,11 +467,11 @@ class EchoMemApiClient {
|
|
|
467
467
|
getSessionId() {
|
|
468
468
|
return this.sessionId;
|
|
469
469
|
}
|
|
470
|
-
async trackMcpAnalyticsEvent(eventType, eventProperties) {
|
|
470
|
+
async trackMcpAnalyticsEvent(eventType, eventProperties, insertId) {
|
|
471
471
|
if (!this.hasToken())
|
|
472
472
|
return;
|
|
473
473
|
try {
|
|
474
|
-
await this.axios.post("/api/extension/mcp/events", { eventType, eventProperties }, { timeout: 1500 });
|
|
474
|
+
await this.axios.post("/api/extension/mcp/events", { eventType, eventProperties, insertId }, { timeout: 1500 });
|
|
475
475
|
}
|
|
476
476
|
catch {
|
|
477
477
|
// Remote analytics is best-effort and must never change MCP behavior.
|
|
@@ -575,6 +575,8 @@ class EchoMemApiClient {
|
|
|
575
575
|
k: opts.limit,
|
|
576
576
|
similarityThreshold: opts.threshold,
|
|
577
577
|
timeFrameDays: opts.timeFrameDays,
|
|
578
|
+
requestId: opts.requestId,
|
|
579
|
+
sessionId: this.sessionId,
|
|
578
580
|
});
|
|
579
581
|
const data = enc.enabled ? await this.decryptResult(response.data, enc.key) : response.data;
|
|
580
582
|
return retrievalOnly && isRecord(data)
|
|
@@ -584,7 +586,8 @@ class EchoMemApiClient {
|
|
|
584
586
|
async searchMemoriesRetrieved(query, opts, enc) {
|
|
585
587
|
const response = await this.axios.post("/api/extension/memories/deep-search/candidates", {
|
|
586
588
|
query,
|
|
587
|
-
requestId:
|
|
589
|
+
requestId: opts.requestId,
|
|
590
|
+
logicalRequestId: opts.requestId,
|
|
588
591
|
sessionId: this.sessionId,
|
|
589
592
|
userTimeZone: Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC",
|
|
590
593
|
});
|
|
@@ -645,9 +648,12 @@ class EchoMemApiClient {
|
|
|
645
648
|
// never hits dg-web directly, so no new auth is needed and no other caller is
|
|
646
649
|
// disrupted. NOTE: encrypted users still get server-side plaintext only; the
|
|
647
650
|
// phase-1 + bridge-local-decrypt + phase-2 flow (spec §11) is the remaining work.
|
|
648
|
-
async searchMemoriesTuned(query) {
|
|
651
|
+
async searchMemoriesTuned(query, requestId) {
|
|
649
652
|
const response = await this.axios.post("/api/extension/memories/deep-search", {
|
|
650
653
|
query,
|
|
654
|
+
requestId,
|
|
655
|
+
logicalRequestId: requestId,
|
|
656
|
+
sessionId: this.sessionId,
|
|
651
657
|
userTimeZone: Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC",
|
|
652
658
|
});
|
|
653
659
|
const data = response.data ?? {};
|
|
@@ -682,27 +688,24 @@ class EchoMemApiClient {
|
|
|
682
688
|
});
|
|
683
689
|
return enc.enabled ? await this.decryptResult(response.data, enc.key) : response.data;
|
|
684
690
|
}
|
|
685
|
-
const searchOpts = {
|
|
691
|
+
const searchOpts = {
|
|
692
|
+
limit,
|
|
693
|
+
threshold,
|
|
694
|
+
timeFrameDays: parsed.timeFrameDays,
|
|
695
|
+
requestId: randomUUID(),
|
|
696
|
+
};
|
|
686
697
|
if (!parsed.includeAnswer) {
|
|
687
|
-
|
|
688
|
-
return await this.searchMemoriesRetrieved(query, searchOpts, enc);
|
|
689
|
-
}
|
|
690
|
-
catch {
|
|
691
|
-
return await this.searchMemoriesRaw(query, searchOpts, enc, true);
|
|
692
|
-
}
|
|
698
|
+
return this.searchMemoriesRetrieved(query, searchOpts, enc);
|
|
693
699
|
}
|
|
694
700
|
// Encrypted account: the server can't synthesize over plaintext it doesn't hold, so use the raw
|
|
695
701
|
// retriever (returns ciphertext) and decrypt locally — zero-knowledge preserved end-to-end.
|
|
696
702
|
if (enc.enabled) {
|
|
697
703
|
return await this.searchMemoriesRaw(query, searchOpts, enc);
|
|
698
704
|
}
|
|
699
|
-
//
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
catch {
|
|
704
|
-
return await this.searchMemoriesRaw(query, searchOpts, enc);
|
|
705
|
-
}
|
|
705
|
+
// A synthesized answer is metered through the legacy route. Do not fall
|
|
706
|
+
// back to raw retrieval after a ledger outage: that would return a result
|
|
707
|
+
// without a durable usage fact.
|
|
708
|
+
return this.searchMemoriesTuned(query, searchOpts.requestId);
|
|
706
709
|
}
|
|
707
710
|
/** Decrypt the model-visible fields on a `{ memories: [...] }` response locally. */
|
|
708
711
|
async decryptResult(data, key) {
|
|
@@ -971,6 +974,7 @@ class EchoMemMCPServer {
|
|
|
971
974
|
...triggerAnalyticsForTool(canonicalName, request.params.arguments),
|
|
972
975
|
...inputAnalyticsForTool(canonicalName, request.params.arguments),
|
|
973
976
|
};
|
|
977
|
+
const analyticsCallId = randomUUID();
|
|
974
978
|
// One event per call. Handlers enrich `rec` with tool-specific detail; we finalize + log in `finally`.
|
|
975
979
|
const rec = {
|
|
976
980
|
type: "tool_call",
|
|
@@ -1030,8 +1034,8 @@ class EchoMemMCPServer {
|
|
|
1030
1034
|
if (!this.client.hasToken())
|
|
1031
1035
|
throw new NoTokenError();
|
|
1032
1036
|
if (canonicalName !== canonicalToolNames.save) {
|
|
1033
|
-
void this.client.trackMcpAnalyticsEvent("[MCP] EchoMem Tool Called", analyticsBase);
|
|
1034
|
-
void this.client.trackMcpAnalyticsEvent(toolEventName(canonicalName, "Called"), analyticsBase);
|
|
1037
|
+
void this.client.trackMcpAnalyticsEvent("[MCP] EchoMem Tool Called", analyticsBase, `${analyticsCallId}:generic-called`);
|
|
1038
|
+
void this.client.trackMcpAnalyticsEvent(toolEventName(canonicalName, "Called"), analyticsBase, `${analyticsCallId}:called`);
|
|
1035
1039
|
}
|
|
1036
1040
|
if (canonicalName !== canonicalToolNames.save && analyticsBase.trigger_message_available === true) {
|
|
1037
1041
|
void this.client.trackMcpAnalyticsEvent("[MCP] EchoMem Triggered By User Turn", analyticsBase);
|
|
@@ -1126,8 +1130,8 @@ class EchoMemMCPServer {
|
|
|
1126
1130
|
encrypted_user: rec.encrypted,
|
|
1127
1131
|
extracted_memory_count: rec.memories_extracted,
|
|
1128
1132
|
};
|
|
1129
|
-
void this.client.trackMcpAnalyticsEvent(rec.ok ? "[MCP] EchoMem Tool Succeeded" : "[MCP] EchoMem Tool Failed", finalAnalytics);
|
|
1130
|
-
void this.client.trackMcpAnalyticsEvent(toolEventName(canonicalName, rec.ok ? "Succeeded" : "Failed"), finalAnalytics);
|
|
1133
|
+
void this.client.trackMcpAnalyticsEvent(rec.ok ? "[MCP] EchoMem Tool Succeeded" : "[MCP] EchoMem Tool Failed", finalAnalytics, `${analyticsCallId}:generic-completed`);
|
|
1134
|
+
void this.client.trackMcpAnalyticsEvent(toolEventName(canonicalName, rec.ok ? "Succeeded" : "Failed"), finalAnalytics, `${analyticsCallId}:completed`);
|
|
1131
1135
|
}
|
|
1132
1136
|
}
|
|
1133
1137
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@echomem/mcp",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.14",
|
|
4
4
|
"description": "EchoMem MCP bridge: cloud-first memory tools, local context HUD, and the Agent Doctor workspace forensics report (cost ledger + 3D repo city)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|