@echomem/mcp 1.4.34 → 1.4.36
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/README.md +12 -45
- package/dist/codex-sync.js +1 -1
- package/dist/context-analysis/claude-native-canonical.js +87 -29
- package/dist/forensics.js +12 -9
- package/dist/index.js +94 -17
- package/dist/package-metadata.js +10 -3
- package/dist/save-checkpoint-hook.js +1 -1
- package/dist/setup-page/client-extraction.js +35 -11
- package/dist/setup-page.js +1 -1
- package/dist/setup-preview.js +25 -2
- package/dist/setup.js +132 -79
- package/dist/v1-contract.js +106 -92
- package/package.json +11 -6
package/dist/v1-contract.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { MEMORY_CITATION_INSTRUCTION, SAVED_MEMORY_RECEIPT_INSTRUCTION, withMcpVersion, } from "./package-metadata.js";
|
|
2
|
+
import { MCP_DESKTOP_MANAGED, MCP_VAULT_UNLOCK_INSTRUCTION, MEMORY_CITATION_INSTRUCTION, SAVED_MEMORY_RECEIPT_INSTRUCTION, withMcpVersion, } from "./package-metadata.js";
|
|
3
3
|
export const canonicalToolNames = {
|
|
4
4
|
search: "search_memories",
|
|
5
5
|
save: "save_conversation",
|
|
@@ -34,7 +34,6 @@ export const canonicalToolNames = {
|
|
|
34
34
|
};
|
|
35
35
|
export const legacyAliasToCanonical = {
|
|
36
36
|
search_memories_by_description_semantic: canonicalToolNames.search,
|
|
37
|
-
search_memories_by_time_range: canonicalToolNames.timeRange,
|
|
38
37
|
};
|
|
39
38
|
export function resolveCanonicalToolName(toolName) {
|
|
40
39
|
return legacyAliasToCanonical[toolName] ?? toolName;
|
|
@@ -44,7 +43,6 @@ const READ_ONLY_TOOL_NAMES = new Set([
|
|
|
44
43
|
canonicalToolNames.search,
|
|
45
44
|
"search_memories_by_description_semantic",
|
|
46
45
|
canonicalToolNames.timeRange,
|
|
47
|
-
"search_memories_by_time_range",
|
|
48
46
|
canonicalToolNames.keywords,
|
|
49
47
|
canonicalToolNames.friends,
|
|
50
48
|
canonicalToolNames.searchUsers,
|
|
@@ -166,11 +164,11 @@ const triggerMetadataSchema = {
|
|
|
166
164
|
};
|
|
167
165
|
export const searchMemoriesSchema = z.object({
|
|
168
166
|
...triggerMetadataSchema,
|
|
169
|
-
query: z.string().optional(),
|
|
170
|
-
k: z.number().optional(),
|
|
171
|
-
limit: z.number().optional(),
|
|
172
|
-
threshold: z.number().optional().default(0.1),
|
|
173
|
-
timeFrameDays: z.number().optional(),
|
|
167
|
+
query: z.string().trim().min(1).optional(),
|
|
168
|
+
k: z.number().int().min(1).max(50).optional(),
|
|
169
|
+
limit: z.number().int().min(1).max(50).optional(),
|
|
170
|
+
threshold: z.number().min(0).max(1).optional().default(0.1),
|
|
171
|
+
timeFrameDays: z.number().int().min(1).max(3650).optional(),
|
|
174
172
|
includeAnswer: z.boolean().optional().default(false),
|
|
175
173
|
});
|
|
176
174
|
export const saveConversationSchema = z.object({
|
|
@@ -189,11 +187,20 @@ export const saveConversationSchema = z.object({
|
|
|
189
187
|
}))
|
|
190
188
|
.optional(),
|
|
191
189
|
});
|
|
190
|
+
const dateBoundarySchema = z.string().trim().min(1).refine((value) => Number.isFinite(Date.parse(value)), "Expected an ISO-8601 date or date-time string");
|
|
192
191
|
export const timeRangeSchema = z.object({
|
|
193
192
|
...triggerMetadataSchema,
|
|
194
|
-
startDate:
|
|
195
|
-
endDate:
|
|
196
|
-
limit: z.number().optional().default(50),
|
|
193
|
+
startDate: dateBoundarySchema,
|
|
194
|
+
endDate: dateBoundarySchema,
|
|
195
|
+
limit: z.number().int().min(1).max(100).optional().default(50),
|
|
196
|
+
}).superRefine((value, ctx) => {
|
|
197
|
+
if (Date.parse(value.startDate) > Date.parse(value.endDate)) {
|
|
198
|
+
ctx.addIssue({
|
|
199
|
+
code: z.ZodIssueCode.custom,
|
|
200
|
+
path: ["startDate"],
|
|
201
|
+
message: "startDate must be earlier than or equal to endDate",
|
|
202
|
+
});
|
|
203
|
+
}
|
|
197
204
|
});
|
|
198
205
|
const keywordListSchema = z.preprocess((value) => {
|
|
199
206
|
if (typeof value !== "string")
|
|
@@ -206,15 +213,15 @@ const keywordListSchema = z.preprocess((value) => {
|
|
|
206
213
|
export const keywordsSchema = z.object({
|
|
207
214
|
...triggerMetadataSchema,
|
|
208
215
|
keywords: keywordListSchema,
|
|
209
|
-
limit: z.number().optional().default(10),
|
|
216
|
+
limit: z.number().int().min(1).max(50).optional().default(10),
|
|
210
217
|
});
|
|
211
218
|
export const listFriendsSchema = z.object({
|
|
212
219
|
...triggerMetadataSchema,
|
|
213
220
|
});
|
|
214
221
|
export const searchUsersSchema = z.object({
|
|
215
222
|
...triggerMetadataSchema,
|
|
216
|
-
query: z.string().min(1),
|
|
217
|
-
limit: z.number().optional().default(10),
|
|
223
|
+
query: z.string().trim().min(1),
|
|
224
|
+
limit: z.number().int().min(1).max(50).optional().default(10),
|
|
218
225
|
});
|
|
219
226
|
export const sendFriendRequestSchema = z.object({
|
|
220
227
|
...triggerMetadataSchema,
|
|
@@ -222,17 +229,17 @@ export const sendFriendRequestSchema = z.object({
|
|
|
222
229
|
});
|
|
223
230
|
export const othersSchema = z.object({
|
|
224
231
|
...triggerMetadataSchema,
|
|
225
|
-
query: z.string().optional().default(""),
|
|
226
|
-
limit: z.number().optional().default(10),
|
|
232
|
+
query: z.string().trim().optional().default(""),
|
|
233
|
+
limit: z.number().int().min(1).max(50).optional().default(10),
|
|
227
234
|
target: z.string().optional(),
|
|
228
235
|
ownerUserId: z.string().optional(),
|
|
229
236
|
ownerName: z.string().optional(),
|
|
230
237
|
targetFriendIds: z.array(z.string()).optional(),
|
|
231
238
|
targetFriendNames: z.array(z.string()).optional(),
|
|
232
239
|
recordAccess: z.boolean().optional(),
|
|
233
|
-
kPerUser: z.number().optional(),
|
|
234
|
-
similarityThreshold: z.number().optional(),
|
|
235
|
-
timeFrameDays: z.number().optional(),
|
|
240
|
+
kPerUser: z.number().int().min(1).max(50).optional(),
|
|
241
|
+
similarityThreshold: z.number().min(0).max(1).optional(),
|
|
242
|
+
timeFrameDays: z.number().int().min(1).max(3650).optional(),
|
|
236
243
|
});
|
|
237
244
|
export const publicMemorySchema = z.object({
|
|
238
245
|
...triggerMetadataSchema,
|
|
@@ -329,8 +336,8 @@ export const deleteMemorySchema = z.object({
|
|
|
329
336
|
});
|
|
330
337
|
export const getByContextSchema = z.object({
|
|
331
338
|
...triggerMetadataSchema,
|
|
332
|
-
contextId: z.string().min(1),
|
|
333
|
-
limit: z.number().optional().default(50),
|
|
339
|
+
contextId: z.string().trim().min(1),
|
|
340
|
+
limit: z.number().int().min(1).max(100).optional().default(50),
|
|
334
341
|
});
|
|
335
342
|
export function listToolSpecs(opts = {}) {
|
|
336
343
|
const currentTime = new Date().toISOString();
|
|
@@ -349,46 +356,68 @@ export function listToolSpecs(opts = {}) {
|
|
|
349
356
|
const groupMapSection = groupMap
|
|
350
357
|
? `\n\nThis user's company group currently shares work in these areas (a relevance guide — search the group when the task relates to one of these people or topics):\n${compactGroupRoster(groupMap)}\n${groupMap}\n`
|
|
351
358
|
: "";
|
|
359
|
+
const semanticSearchInputSchema = {
|
|
360
|
+
type: "object",
|
|
361
|
+
properties: {
|
|
362
|
+
query: {
|
|
363
|
+
type: "string",
|
|
364
|
+
minLength: 1,
|
|
365
|
+
description: "Required topic or question to search for. Never omit this field or send it as conversation.",
|
|
366
|
+
},
|
|
367
|
+
limit: { type: "integer", minimum: 1, maximum: 50, default: 10 },
|
|
368
|
+
threshold: { type: "number", minimum: 0, maximum: 1, default: 0.1 },
|
|
369
|
+
timeFrameDays: {
|
|
370
|
+
type: "integer",
|
|
371
|
+
minimum: 1,
|
|
372
|
+
maximum: 3650,
|
|
373
|
+
description: "Optional recency filter for this query, such as 14 for the last two weeks.",
|
|
374
|
+
},
|
|
375
|
+
triggerMessage: {
|
|
376
|
+
type: "string",
|
|
377
|
+
description: "Optional: the user's message that caused this recall. EchoMem stores only a redacted analytics preview and hash.",
|
|
378
|
+
},
|
|
379
|
+
triggerMessageRole: { type: "string", default: "user" },
|
|
380
|
+
},
|
|
381
|
+
required: ["query"],
|
|
382
|
+
};
|
|
383
|
+
const timeRangeInputSchema = {
|
|
384
|
+
type: "object",
|
|
385
|
+
properties: {
|
|
386
|
+
startDate: {
|
|
387
|
+
type: "string",
|
|
388
|
+
minLength: 1,
|
|
389
|
+
description: "Required ISO-8601 start date or date-time. Must not be later than endDate.",
|
|
390
|
+
},
|
|
391
|
+
endDate: {
|
|
392
|
+
type: "string",
|
|
393
|
+
minLength: 1,
|
|
394
|
+
description: "Required ISO-8601 end date or date-time. Must not be earlier than startDate.",
|
|
395
|
+
},
|
|
396
|
+
limit: { type: "integer", minimum: 1, maximum: 100, default: 50 },
|
|
397
|
+
triggerMessage: {
|
|
398
|
+
type: "string",
|
|
399
|
+
description: "Optional: the user's message that caused this lookup. EchoMem stores only a redacted analytics preview and hash.",
|
|
400
|
+
},
|
|
401
|
+
triggerMessageRole: { type: "string", default: "user" },
|
|
402
|
+
},
|
|
403
|
+
required: ["startDate", "endDate"],
|
|
404
|
+
};
|
|
352
405
|
const tools = [
|
|
353
406
|
{
|
|
354
407
|
name: canonicalToolNames.search,
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
properties: {
|
|
359
|
-
query: { type: "string" },
|
|
360
|
-
limit: { type: "number", default: 10 },
|
|
361
|
-
threshold: { type: "number", default: 0.1 },
|
|
362
|
-
timeFrameDays: { type: "number" },
|
|
363
|
-
triggerMessage: {
|
|
364
|
-
type: "string",
|
|
365
|
-
description: "Optional: the user's message that caused this recall. EchoMem stores only a redacted analytics preview and hash.",
|
|
366
|
-
},
|
|
367
|
-
triggerMessageRole: { type: "string", default: "user" },
|
|
368
|
-
},
|
|
369
|
-
},
|
|
408
|
+
title: "Search your memories by topic",
|
|
409
|
+
description: withMcpVersion(`TOPIC SEARCH for the user's own EchoMem memories across all AI tools. Always pass a non-empty query; optionally add timeFrameDays to filter that topic to recent memories. Do not pass keywords, startDate, or endDate. For exact memory-key terms use search_memories_by_keywords. For an explicit calendar range use get_memories_by_time_range. Use this tool instead of re-deriving or re-asking what the user already settled. ${recallPlanNote} ${searchBillingReplyInstruction} ${memoryCitationInstruction}${mapSection}\nReturns ranked memories only; the MCP host model writes the final answer. Current time: ${currentTime}.${updateSection}`),
|
|
410
|
+
inputSchema: semanticSearchInputSchema,
|
|
370
411
|
},
|
|
371
412
|
{
|
|
372
413
|
name: "search_memories_by_description_semantic",
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
properties: {
|
|
377
|
-
query: { type: "string" },
|
|
378
|
-
limit: { type: "number", default: 10 },
|
|
379
|
-
threshold: { type: "number", default: 0.1 },
|
|
380
|
-
timeFrameDays: { type: "number" },
|
|
381
|
-
triggerMessage: {
|
|
382
|
-
type: "string",
|
|
383
|
-
description: "Optional: the user's message that caused this recall. EchoMem stores only a redacted analytics preview and hash.",
|
|
384
|
-
},
|
|
385
|
-
triggerMessageRole: { type: "string", default: "user" },
|
|
386
|
-
},
|
|
387
|
-
},
|
|
414
|
+
title: "Legacy topic search (compatibility)",
|
|
415
|
+
description: `LEGACY TOPIC SEARCH alias for search_memories. Prefer search_memories. Always pass a non-empty query; timeFrameDays is only an optional recency filter. Do not pass keywords, startDate, or endDate. ${recallPlanNote} ${searchBillingReplyInstruction} ${memoryCitationInstruction}`,
|
|
416
|
+
inputSchema: semanticSearchInputSchema,
|
|
388
417
|
},
|
|
389
418
|
{
|
|
390
419
|
name: canonicalToolNames.save,
|
|
391
|
-
description: `Save durable knowledge from this conversation into the user's private EchoMem (durable memories are extracted automatically). Call before the final response when work produced a durable decision, confirmed preference, implementation, resolved bug, commit, passing verification, release, or project milestone; this private checkpoint does not require a separate user request. Omit secrets, incidental chatter, and trivial read-only work. If the encrypted vault is locked, tell the user to
|
|
420
|
+
description: `Save durable knowledge from this conversation into the user's private EchoMem (durable memories are extracted automatically). Call before the final response when work produced a durable decision, confirmed preference, implementation, resolved bug, commit, passing verification, release, or project milestone; this private checkpoint does not require a separate user request. Omit secrets, incidental chatter, and trivial read-only work. If the encrypted vault is locked, tell the user to ${MCP_VAULT_UNLOCK_INSTRUCTION} and never silently skip a qualifying checkpoint. Private persistence happens first. For group sharing, reuse the exact groupSharingScopeId returned by get_group_session_sharing, request_group_session_sharing, or an earlier save in this conversation. Never reuse it in another conversation or save it as memory. Each group has an independent decision under the same conversation scope; eligible memories sync automatically to every approved group, while flagged memories stay private. If a selected group has no decision yet, call request_group_session_sharing so supported hosts render a choice UI; its fallback tells you when a text Yes/No prompt is required. Silence leaves consent unset; never infer the answer. New extraction input uses the plan's weekly processing allowance; if the limit is reached, nothing is saved. passthrough=true stores the text verbatim as a session capsule. ${SAVED_MEMORY_RECEIPT_INSTRUCTION}`,
|
|
392
421
|
inputSchema: {
|
|
393
422
|
type: "object",
|
|
394
423
|
properties: {
|
|
@@ -426,25 +455,14 @@ export function listToolSpecs(opts = {}) {
|
|
|
426
455
|
},
|
|
427
456
|
{
|
|
428
457
|
name: canonicalToolNames.timeRange,
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
properties: {
|
|
433
|
-
startDate: { type: "string" },
|
|
434
|
-
endDate: { type: "string" },
|
|
435
|
-
limit: { type: "number", default: 50 },
|
|
436
|
-
triggerMessage: {
|
|
437
|
-
type: "string",
|
|
438
|
-
description: "Optional: the user's message that caused this lookup. EchoMem stores only a redacted analytics preview and hash.",
|
|
439
|
-
},
|
|
440
|
-
triggerMessageRole: { type: "string", default: "user" },
|
|
441
|
-
},
|
|
442
|
-
required: ["startDate", "endDate"],
|
|
443
|
-
},
|
|
458
|
+
title: "Get your memories by date range",
|
|
459
|
+
description: `DATE-RANGE FETCH for the user's own memories. Always pass both startDate and endDate as ISO-8601 strings. Do not pass query, keywords, or timeFrameDays. For a topic with a recency filter use search_memories instead. ${recallPlanNote} ${memoryCitationInstruction} Current time: ${currentTime}.`,
|
|
460
|
+
inputSchema: timeRangeInputSchema,
|
|
444
461
|
},
|
|
445
462
|
{
|
|
446
463
|
name: canonicalToolNames.keywords,
|
|
447
|
-
|
|
464
|
+
title: "Search your memory keys exactly",
|
|
465
|
+
description: `EXACT-KEYWORD SEARCH over the keys field of the user's own memories. Pass keywords as valid JSON: preferably an array of quoted strings, for example {"keywords":["flow-lab","flow.html","Rive"],"limit":8}. Do not pass query, timeFrameDays, startDate, or endDate. For natural-language topic search use search_memories. A comma-separated JSON string is accepted only as a compatibility fallback. Never emit bare comma-separated tokens. ${recallPlanNote} ${memoryCitationInstruction}`,
|
|
448
466
|
inputSchema: {
|
|
449
467
|
type: "object",
|
|
450
468
|
properties: {
|
|
@@ -477,6 +495,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
477
495
|
},
|
|
478
496
|
{
|
|
479
497
|
name: canonicalToolNames.friends,
|
|
498
|
+
title: "List accepted EchoMem friends",
|
|
480
499
|
description: "Friends: list accepted EchoMem friends with each friend's public memory count. Use this before asking a specific friend by name.",
|
|
481
500
|
inputSchema: {
|
|
482
501
|
type: "object",
|
|
@@ -491,7 +510,8 @@ export function listToolSpecs(opts = {}) {
|
|
|
491
510
|
},
|
|
492
511
|
{
|
|
493
512
|
name: canonicalToolNames.searchUsers,
|
|
494
|
-
|
|
513
|
+
title: "Search the EchoMem user directory",
|
|
514
|
+
description: "USER-DIRECTORY SEARCH by display name or username before sending a friend request. This searches people/accounts, not memory content. Results include total memories, public memories, and current relationship state.",
|
|
495
515
|
inputSchema: {
|
|
496
516
|
type: "object",
|
|
497
517
|
properties: {
|
|
@@ -530,12 +550,16 @@ export function listToolSpecs(opts = {}) {
|
|
|
530
550
|
},
|
|
531
551
|
{
|
|
532
552
|
name: canonicalToolNames.others,
|
|
533
|
-
|
|
553
|
+
title: "Search teammates' and friends' memories",
|
|
554
|
+
description: `PEER-MEMORY SEARCH for public memories owned by accepted friends or company-group members—not the user's own memories. Pass query for a topic; omit it only when intentionally browsing peer memories, and optionally use target to scope a person. Do not use this tool for the user's private memories or the EchoMem user directory. EchoMem identifies the caller from the EchoMem credential and has already excluded only that authenticated user's own memories. Present every returned owner; never filter again using a Claude account, host profile, git identity, or inference. For onboarding and division-of-work questions, call get_group_context first. Returned memories are recorded in memory_views for the owners. ${memoryCitationInstruction}${groupMapSection}`,
|
|
534
555
|
inputSchema: {
|
|
535
556
|
type: "object",
|
|
536
557
|
properties: {
|
|
537
|
-
query: {
|
|
538
|
-
|
|
558
|
+
query: {
|
|
559
|
+
type: "string",
|
|
560
|
+
description: "Optional peer-memory topic. Omit only for an intentional broad browse; never send this field as conversation.",
|
|
561
|
+
},
|
|
562
|
+
limit: { type: "integer", minimum: 1, maximum: 50, default: 10 },
|
|
539
563
|
target: {
|
|
540
564
|
type: "string",
|
|
541
565
|
description: "Accessible friend or group-member user id or exact display name. Prefer this for @Name asks.",
|
|
@@ -562,9 +586,9 @@ export function listToolSpecs(opts = {}) {
|
|
|
562
586
|
type: "boolean",
|
|
563
587
|
description: "Defaults true. When true, returned public memories are recorded in memory_views.",
|
|
564
588
|
},
|
|
565
|
-
kPerUser: { type: "
|
|
566
|
-
similarityThreshold: { type: "number", default: 0.1 },
|
|
567
|
-
timeFrameDays: { type: "
|
|
589
|
+
kPerUser: { type: "integer", minimum: 1, maximum: 50, default: 5 },
|
|
590
|
+
similarityThreshold: { type: "number", minimum: 0, maximum: 1, default: 0.1 },
|
|
591
|
+
timeFrameDays: { type: "integer", minimum: 1, maximum: 3650 },
|
|
568
592
|
triggerMessage: {
|
|
569
593
|
type: "string",
|
|
570
594
|
description: "Optional: the user's message that caused this public-memory search. EchoMem stores only a redacted analytics preview and hash.",
|
|
@@ -575,6 +599,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
575
599
|
},
|
|
576
600
|
{
|
|
577
601
|
name: canonicalToolNames.publicMemory,
|
|
602
|
+
title: "Get one teammate or friend memory",
|
|
578
603
|
description: `Fetch one public memory by id when its owner is an accepted friend or shares your company group. If the caller is not the owner, EchoMem records the access in memory_views. ${memoryCitationInstruction}`,
|
|
579
604
|
inputSchema: {
|
|
580
605
|
type: "object",
|
|
@@ -892,6 +917,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
892
917
|
},
|
|
893
918
|
{
|
|
894
919
|
name: canonicalToolNames.getByContext,
|
|
920
|
+
title: "Get the exact memories from a saved context",
|
|
895
921
|
description: withMcpVersion(`Deterministically re-fetch the exact batch of memories saved under one contextId — no semantic search, no ranking, just that session's saved capsule. ${recallPlanNote} save_conversation returns a contextId; pass it here to pull back precisely those memories, e.g. to warm up a fresh session with what a prior session saved, or to verify the saved facts are still present. ${memoryCitationInstruction} Current time: ${currentTime}.`),
|
|
896
922
|
inputSchema: {
|
|
897
923
|
type: "object",
|
|
@@ -909,11 +935,12 @@ export function listToolSpecs(opts = {}) {
|
|
|
909
935
|
},
|
|
910
936
|
{
|
|
911
937
|
name: canonicalToolNames.checkpointByContext,
|
|
912
|
-
|
|
938
|
+
title: "Rebuild a checkpoint from a saved context",
|
|
939
|
+
description: withMcpVersion(`Rebuild a clean-context checkpoint / decision log from one EchoMem contextId. ${recallPlanNote} Use this when the user or EchoMem returns a contextId for a renewed coding session and you need the session handoff, not a raw memory dump. It deterministically fetches that context and formats it as orientation state: decisions, carryover, constraints, and checkpoints. ${memoryCitationInstruction} Current time: ${currentTime}.`),
|
|
913
940
|
inputSchema: {
|
|
914
941
|
type: "object",
|
|
915
942
|
properties: {
|
|
916
|
-
contextId: { type: "string", description: "The EchoMem contextId
|
|
943
|
+
contextId: { type: "string", description: "The EchoMem contextId returned by save_conversation or Renew session." },
|
|
917
944
|
limit: { type: "number", default: 100 },
|
|
918
945
|
triggerMessage: {
|
|
919
946
|
type: "string",
|
|
@@ -931,7 +958,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
931
958
|
},
|
|
932
959
|
{
|
|
933
960
|
name: canonicalToolNames.updateStatus,
|
|
934
|
-
description: `Check whether this installed EchoMem MCP bridge is behind the latest
|
|
961
|
+
description: `Check whether this installed EchoMem MCP bridge is behind the latest version. Works without login, uploads no user transcript, and normal background checks are cached. ${MCP_DESKTOP_MANAGED ? "Echo Desktop owns updates for this runtime; direct the user back to the desktop app." : "If it reports an update, tell the user and offer to run the returned update command."} After updating, the user must start a new agent/MCP session.${updateSection}`,
|
|
935
962
|
inputSchema: {
|
|
936
963
|
type: "object",
|
|
937
964
|
properties: {
|
|
@@ -945,7 +972,7 @@ export function listToolSpecs(opts = {}) {
|
|
|
945
972
|
},
|
|
946
973
|
{
|
|
947
974
|
name: canonicalToolNames.contextHealth,
|
|
948
|
-
description: "Show the current local Codex/Claude context-health score as markdown: clean percentage, tracked lower-bound dead-weight, redundant reads, source client, and token-count source. Use when the user asks about
|
|
975
|
+
description: "Show the current local Codex/Claude context-health score as markdown: clean percentage, tracked lower-bound dead-weight, redundant reads, source client, and token-count source. Use when the user asks about dirty context, context pollution, or whether cleanup is worth it. This on-demand tool reads local agent logs only and needs no login.",
|
|
949
976
|
inputSchema: {
|
|
950
977
|
type: "object",
|
|
951
978
|
properties: {
|
|
@@ -971,19 +998,6 @@ export function listToolSpecs(opts = {}) {
|
|
|
971
998
|
},
|
|
972
999
|
},
|
|
973
1000
|
},
|
|
974
|
-
{
|
|
975
|
-
name: "search_memories_by_time_range",
|
|
976
|
-
description: "Legacy alias for get_memories_by_time_range.",
|
|
977
|
-
inputSchema: {
|
|
978
|
-
type: "object",
|
|
979
|
-
properties: {
|
|
980
|
-
startDate: { type: "string" },
|
|
981
|
-
endDate: { type: "string" },
|
|
982
|
-
limit: { type: "number", default: 50 },
|
|
983
|
-
},
|
|
984
|
-
required: ["startDate", "endDate"],
|
|
985
|
-
},
|
|
986
|
-
},
|
|
987
1001
|
];
|
|
988
1002
|
return tools.map(decorateLocalToolSpec);
|
|
989
1003
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@echomem/mcp",
|
|
3
|
-
"version": "1.4.
|
|
4
|
-
"description": "EchoMem MCP bridge: cloud-first memory tools
|
|
3
|
+
"version": "1.4.36",
|
|
4
|
+
"description": "EchoMem MCP bridge: cloud-first memory tools and the Agent Doctor workspace forensics report (cost ledger + 3D repo city)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"echoDesktop": {
|
|
8
|
+
"minimumVersion": "1.0.0",
|
|
9
|
+
"runtimeLayout": 1
|
|
10
|
+
},
|
|
7
11
|
"bin": {
|
|
8
12
|
"mcp": "dist/index.js",
|
|
9
|
-
"echomem-mcp": "dist/index.js"
|
|
10
|
-
"echomem-hud": "dist/hud/cli.js"
|
|
13
|
+
"echomem-mcp": "dist/index.js"
|
|
11
14
|
},
|
|
12
15
|
"files": [
|
|
13
16
|
"dist",
|
|
@@ -23,22 +26,24 @@
|
|
|
23
26
|
"smoke": "node smoke.mjs",
|
|
24
27
|
"preview:extraction": "npm run build && node scripts/preview-extraction.mjs",
|
|
25
28
|
"stress:long-history": "npm run build && node scripts/stress-long-history.mjs",
|
|
29
|
+
"stress:long-claude-history": "npm run build && node scripts/stress-long-claude-history.mjs",
|
|
26
30
|
"test:artifact": "npm run build && node test/package-artifact.test.mjs",
|
|
27
31
|
"test:registry": "node test/registry-artifact.test.mjs",
|
|
28
32
|
"test:registry-ui": "npm run build && node test/registry-ui.test.mjs",
|
|
29
33
|
"test:ui": "npm run build && node test/setup-ui.test.mjs",
|
|
34
|
+
"test:onboarding-resilience": "npm run build && node test/onboarding-resilience.test.mjs",
|
|
30
35
|
"test:billing-ui": "npm run build && node test/setup-ui.test.mjs billing",
|
|
31
|
-
"test": "npm run build && node test/local-data-paths.test.mjs && node test/crypto.test.mjs && node test/integration.test.mjs && node test/local-auth.test.mjs && node test/retrieval-only.test.mjs && node test/no-restart.test.mjs && node test/report.test.mjs && node test/forensics.test.mjs && node test/canonical-golden.test.mjs && node test/tools.test.mjs && node test/group-map.test.mjs && node test/update-check.test.mjs && node test/delete.test.mjs && node test/low-touch-tools.test.mjs && node test/migrate.test.mjs && node test/restart-recovery.test.mjs && node test/
|
|
36
|
+
"test": "npm run build && node test/local-data-paths.test.mjs && node test/crypto.test.mjs && node test/integration.test.mjs && node test/onboarding-resilience.test.mjs && node test/local-auth.test.mjs && node test/retrieval-only.test.mjs && node test/no-restart.test.mjs && node test/report.test.mjs && node test/forensics.test.mjs && node test/canonical-golden.test.mjs && node test/tools.test.mjs && node test/group-map.test.mjs && node test/update-check.test.mjs && node test/delete.test.mjs && node test/low-touch-tools.test.mjs && node test/migrate.test.mjs && node test/restart-recovery.test.mjs && node test/save-checkpoint-hook.test.mjs",
|
|
32
37
|
"prepack": "npm run build && node scripts/bundle-city.mjs"
|
|
33
38
|
},
|
|
34
39
|
"dependencies": {
|
|
35
40
|
"@modelcontextprotocol/sdk": "^1.0.1",
|
|
36
41
|
"axios": "^1.6.8",
|
|
37
|
-
"electron": "41.7.1",
|
|
38
42
|
"zod": "^3.22.4"
|
|
39
43
|
},
|
|
40
44
|
"devDependencies": {
|
|
41
45
|
"@types/node": "^20.11.0",
|
|
46
|
+
"electron": "41.7.1",
|
|
42
47
|
"tsx": "^4.22.4",
|
|
43
48
|
"typescript": "^5.3.3"
|
|
44
49
|
}
|