@echomem/mcp 1.4.12 → 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 -21
- 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,6 +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,
|
|
589
|
+
requestId: opts.requestId,
|
|
590
|
+
logicalRequestId: opts.requestId,
|
|
587
591
|
sessionId: this.sessionId,
|
|
588
592
|
userTimeZone: Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC",
|
|
589
593
|
});
|
|
@@ -644,9 +648,12 @@ class EchoMemApiClient {
|
|
|
644
648
|
// never hits dg-web directly, so no new auth is needed and no other caller is
|
|
645
649
|
// disrupted. NOTE: encrypted users still get server-side plaintext only; the
|
|
646
650
|
// phase-1 + bridge-local-decrypt + phase-2 flow (spec §11) is the remaining work.
|
|
647
|
-
async searchMemoriesTuned(query) {
|
|
651
|
+
async searchMemoriesTuned(query, requestId) {
|
|
648
652
|
const response = await this.axios.post("/api/extension/memories/deep-search", {
|
|
649
653
|
query,
|
|
654
|
+
requestId,
|
|
655
|
+
logicalRequestId: requestId,
|
|
656
|
+
sessionId: this.sessionId,
|
|
650
657
|
userTimeZone: Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC",
|
|
651
658
|
});
|
|
652
659
|
const data = response.data ?? {};
|
|
@@ -681,27 +688,24 @@ class EchoMemApiClient {
|
|
|
681
688
|
});
|
|
682
689
|
return enc.enabled ? await this.decryptResult(response.data, enc.key) : response.data;
|
|
683
690
|
}
|
|
684
|
-
const searchOpts = {
|
|
691
|
+
const searchOpts = {
|
|
692
|
+
limit,
|
|
693
|
+
threshold,
|
|
694
|
+
timeFrameDays: parsed.timeFrameDays,
|
|
695
|
+
requestId: randomUUID(),
|
|
696
|
+
};
|
|
685
697
|
if (!parsed.includeAnswer) {
|
|
686
|
-
|
|
687
|
-
return await this.searchMemoriesRetrieved(query, searchOpts, enc);
|
|
688
|
-
}
|
|
689
|
-
catch {
|
|
690
|
-
return await this.searchMemoriesRaw(query, searchOpts, enc, true);
|
|
691
|
-
}
|
|
698
|
+
return this.searchMemoriesRetrieved(query, searchOpts, enc);
|
|
692
699
|
}
|
|
693
700
|
// Encrypted account: the server can't synthesize over plaintext it doesn't hold, so use the raw
|
|
694
701
|
// retriever (returns ciphertext) and decrypt locally — zero-knowledge preserved end-to-end.
|
|
695
702
|
if (enc.enabled) {
|
|
696
703
|
return await this.searchMemoriesRaw(query, searchOpts, enc);
|
|
697
704
|
}
|
|
698
|
-
//
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
catch {
|
|
703
|
-
return await this.searchMemoriesRaw(query, searchOpts, enc);
|
|
704
|
-
}
|
|
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);
|
|
705
709
|
}
|
|
706
710
|
/** Decrypt the model-visible fields on a `{ memories: [...] }` response locally. */
|
|
707
711
|
async decryptResult(data, key) {
|
|
@@ -970,6 +974,7 @@ class EchoMemMCPServer {
|
|
|
970
974
|
...triggerAnalyticsForTool(canonicalName, request.params.arguments),
|
|
971
975
|
...inputAnalyticsForTool(canonicalName, request.params.arguments),
|
|
972
976
|
};
|
|
977
|
+
const analyticsCallId = randomUUID();
|
|
973
978
|
// One event per call. Handlers enrich `rec` with tool-specific detail; we finalize + log in `finally`.
|
|
974
979
|
const rec = {
|
|
975
980
|
type: "tool_call",
|
|
@@ -1029,8 +1034,8 @@ class EchoMemMCPServer {
|
|
|
1029
1034
|
if (!this.client.hasToken())
|
|
1030
1035
|
throw new NoTokenError();
|
|
1031
1036
|
if (canonicalName !== canonicalToolNames.save) {
|
|
1032
|
-
void this.client.trackMcpAnalyticsEvent("[MCP] EchoMem Tool Called", analyticsBase);
|
|
1033
|
-
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`);
|
|
1034
1039
|
}
|
|
1035
1040
|
if (canonicalName !== canonicalToolNames.save && analyticsBase.trigger_message_available === true) {
|
|
1036
1041
|
void this.client.trackMcpAnalyticsEvent("[MCP] EchoMem Triggered By User Turn", analyticsBase);
|
|
@@ -1125,8 +1130,8 @@ class EchoMemMCPServer {
|
|
|
1125
1130
|
encrypted_user: rec.encrypted,
|
|
1126
1131
|
extracted_memory_count: rec.memories_extracted,
|
|
1127
1132
|
};
|
|
1128
|
-
void this.client.trackMcpAnalyticsEvent(rec.ok ? "[MCP] EchoMem Tool Succeeded" : "[MCP] EchoMem Tool Failed", finalAnalytics);
|
|
1129
|
-
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`);
|
|
1130
1135
|
}
|
|
1131
1136
|
}
|
|
1132
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",
|