@echomem/mcp 1.3.1 → 1.3.2
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/forensics.js +717 -0
- package/dist/index.js +61 -4
- package/dist/migrate.js +417 -99
- package/dist/report.js +1 -0
- package/dist/setup-page.js +852 -306
- package/dist/setup.js +606 -75
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -167,6 +167,39 @@ function safeTextAnalytics(prefix, text, previewChars = 300) {
|
|
|
167
167
|
function hashAnalyticsText(text) {
|
|
168
168
|
return `sha256:${createHash("sha256").update(text).digest("hex")}`;
|
|
169
169
|
}
|
|
170
|
+
function normalizeMcpHostPlatform(value) {
|
|
171
|
+
if (!value)
|
|
172
|
+
return undefined;
|
|
173
|
+
const normalized = value.toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
174
|
+
if (normalized.includes("cursor"))
|
|
175
|
+
return "cursor";
|
|
176
|
+
if (normalized.includes("windsurf"))
|
|
177
|
+
return "windsurf";
|
|
178
|
+
if (normalized.includes("codex"))
|
|
179
|
+
return "codex";
|
|
180
|
+
if (normalized.includes("claude_code") || (normalized.includes("claude") && normalized.includes("code"))) {
|
|
181
|
+
return "claude_code";
|
|
182
|
+
}
|
|
183
|
+
if (normalized.includes("claude_desktop"))
|
|
184
|
+
return "claude_desktop";
|
|
185
|
+
if (normalized.includes("claude"))
|
|
186
|
+
return "claude";
|
|
187
|
+
if (normalized.includes("vscode") || normalized.includes("visual_studio_code"))
|
|
188
|
+
return "vscode";
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
function detectMcpHostFromEnv() {
|
|
192
|
+
if (process.env.CURSOR_EXTENSION_HOST_ROLE || process.env.CURSOR_WORKSPACE_LABEL)
|
|
193
|
+
return "cursor";
|
|
194
|
+
if (process.env.WINDSURF_WORKSPACE_ID || process.env.WINDSURF_USER_ID)
|
|
195
|
+
return "windsurf";
|
|
196
|
+
if (process.env.CLAUDE_CODE || process.env.CLAUDECODE || process.env.ANTHROPIC_CLAUDE_CODE) {
|
|
197
|
+
return "claude_code";
|
|
198
|
+
}
|
|
199
|
+
if (process.env.CODEX_SANDBOX || process.env.CODEX_HOME)
|
|
200
|
+
return "codex";
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
170
203
|
function isUserRole(role) {
|
|
171
204
|
return typeof role === "string" && ["user", "human"].includes(role.toLowerCase());
|
|
172
205
|
}
|
|
@@ -751,6 +784,8 @@ class EchoMemMCPServer {
|
|
|
751
784
|
client;
|
|
752
785
|
mapCache = null;
|
|
753
786
|
events;
|
|
787
|
+
mcpClientName;
|
|
788
|
+
mcpClientVersion;
|
|
754
789
|
/** Whether the most recent ListTools response carried the memory map (per-session recall signal). */
|
|
755
790
|
mapInjected = false;
|
|
756
791
|
constructor(store) {
|
|
@@ -771,9 +806,23 @@ class EchoMemMCPServer {
|
|
|
771
806
|
process.exit(0);
|
|
772
807
|
});
|
|
773
808
|
}
|
|
809
|
+
getMcpClientAnalytics() {
|
|
810
|
+
const hostPlatform = normalizeMcpHostPlatform(this.mcpClientName)
|
|
811
|
+
?? detectMcpHostFromEnv()
|
|
812
|
+
?? "unknown";
|
|
813
|
+
return {
|
|
814
|
+
mcp_client_name: this.mcpClientName,
|
|
815
|
+
mcp_client_version: this.mcpClientVersion,
|
|
816
|
+
host_platform: hostPlatform,
|
|
817
|
+
platform_source: hostPlatform,
|
|
818
|
+
};
|
|
819
|
+
}
|
|
774
820
|
setupToolHandlers() {
|
|
775
821
|
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
776
|
-
this.
|
|
822
|
+
const clientVersion = this.server.getClientVersion();
|
|
823
|
+
this.mcpClientName = clientVersion?.name ?? this.mcpClientName;
|
|
824
|
+
this.mcpClientVersion = clientVersion?.version ?? this.mcpClientVersion;
|
|
825
|
+
this.events.setClient(this.mcpClientName);
|
|
777
826
|
// Inject a compact topic map of the user's memory into the search-tool description so the agent
|
|
778
827
|
// knows the boundary up front and recalls proactively (cached; best-effort — no map on failure).
|
|
779
828
|
if (this.client.hasToken() && !this.mapCache) {
|
|
@@ -793,12 +842,16 @@ class EchoMemMCPServer {
|
|
|
793
842
|
});
|
|
794
843
|
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
795
844
|
const canonicalName = resolveCanonicalToolName(request.params.name);
|
|
845
|
+
const clientVersion = this.server.getClientVersion();
|
|
846
|
+
this.mcpClientName = clientVersion?.name ?? this.mcpClientName;
|
|
847
|
+
this.mcpClientVersion = clientVersion?.version ?? this.mcpClientVersion;
|
|
796
848
|
const t0 = Date.now();
|
|
797
849
|
const analyticsBase = {
|
|
798
850
|
surface: "mcp",
|
|
799
851
|
event_family: "mcp",
|
|
800
852
|
integration: "echomem_mcp",
|
|
801
853
|
telemetry_source: "local_bridge",
|
|
854
|
+
...this.getMcpClientAnalytics(),
|
|
802
855
|
codex_session_id: this.client.getSessionId(),
|
|
803
856
|
conversation_id: this.client.getSessionId(),
|
|
804
857
|
tool_name: request.params.name,
|
|
@@ -994,17 +1047,21 @@ Details: ${m.details || "N/A"}`)
|
|
|
994
1047
|
return { content: [{ type: "text", text: `Found ${memories.length} relevant memories:\n\n${formattedResults}` }] };
|
|
995
1048
|
}
|
|
996
1049
|
async handleSave(args, rec) {
|
|
1050
|
+
const sourceFallback = this.getMcpClientAnalytics().platform_source;
|
|
1051
|
+
const enrichedArgs = isRecord(args) && !readString(args, "source")
|
|
1052
|
+
? { ...args, source: sourceFallback }
|
|
1053
|
+
: args;
|
|
997
1054
|
if (rec) {
|
|
998
|
-
const a =
|
|
1055
|
+
const a = enrichedArgs;
|
|
999
1056
|
const text = typeof a?.conversation === "string"
|
|
1000
1057
|
? a.conversation
|
|
1001
1058
|
: Array.isArray(a?.messages)
|
|
1002
1059
|
? a.messages.map((m) => String(m?.content ?? "")).join("\n")
|
|
1003
1060
|
: "";
|
|
1004
1061
|
rec.conversation_chars = text.length;
|
|
1005
|
-
rec.save_source = typeof a?.source === "string" ? a.source :
|
|
1062
|
+
rec.save_source = typeof a?.source === "string" ? a.source : sourceFallback;
|
|
1006
1063
|
}
|
|
1007
|
-
const { success, memoriesExtracted, error } = await this.client.saveConversation(
|
|
1064
|
+
const { success, memoriesExtracted, error } = await this.client.saveConversation(enrichedArgs);
|
|
1008
1065
|
if (!success)
|
|
1009
1066
|
throw new Error(`EchoMem API Error: ${error}`);
|
|
1010
1067
|
if (rec)
|