memoryai-mcp 2.1.0 → 2.2.0

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.
Files changed (2) hide show
  1. package/dist/index.js +185 -5
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -40,7 +40,7 @@ function err(e) {
40
40
  return { content: [{ type: "text", text: `Error: ${msg}` }], isError: true };
41
41
  }
42
42
  // --- MCP Server ---
43
- const server = new McpServer({ name: "memoryai", version: "0.9.0" }, { capabilities: { tools: {} } });
43
+ const server = new McpServer({ name: "memoryai", version: "1.0.0" }, { capabilities: { tools: {} } });
44
44
  // 1. memory_store
45
45
  server.tool("memory_store", "Store information in persistent memory. Use when you learn something important — project context, user preferences, architectural decisions, patterns, bugs, pricing/cost discussions, business plans, financial calculations, credit/billing info, revenue models, partnership details, or ANY information the user might ask about later. When in doubt, STORE — MemoryAI handles dedup automatically, so storing too much is always better than forgetting.", {
46
46
  content: z.string().describe("What to remember"),
@@ -874,12 +874,30 @@ server.tool("context_guard_compact", "Compact session context with DNA protectio
874
874
  return err(e);
875
875
  }
876
876
  });
877
- // context_guard_bootstrap — DNA-first session bootstrap
878
- server.tool("context_guard_bootstrap", "Bootstrap a new session with DNA-first context identity/preferences first, then recent activity, then task-relevant memories. For BOT clients: uses 3-tier wake-up (800 tokens). For IDE: flat layout (~4000 tokens).", {
877
+ // context_guard_bootstrap — DNA-first session bootstrap (IDE)
878
+ server.tool("context_guard_bootstrap", "Load context from previous sessions at session start. Returns preferences, recent activity, and task-relevant memories. Call once at the beginning of a session to restore context.", {
879
+ task: z.string().describe("Task description for context relevance"),
880
+ limit: z.number().optional().describe("Max memories to include (default: 10)"),
881
+ }, async (args) => {
882
+ try {
883
+ const r = (await api("POST", "/v1/context/guard/bootstrap", {
884
+ task: args.task,
885
+ limit: args.limit || 10,
886
+ }));
887
+ return ok(`Context restored: ${r.memories_restored || r.memories_included || 0} memories (${r.dna_memories || 0} DNA)\n` +
888
+ `Tokens used: ${r.tokens_used}\n\n` +
889
+ r.context_block);
890
+ }
891
+ catch (e) {
892
+ return err(e);
893
+ }
894
+ });
895
+ // bot_guard_bootstrap — 3-tier wake-up for bots (800 tokens)
896
+ server.tool("bot_guard_bootstrap", "Bot-specific bootstrap — 3-tier wake-up (Identity→Context→Details) with 800 token budget. Use for chatbots, not IDEs.", {
879
897
  task: z.string().describe("Task description for the new session"),
880
898
  limit: z.number().optional().describe("Max memories to include (default: 10)"),
881
- mode: z.enum(["default", "deep"]).optional().describe("'default' = 800 token 3-tier wake-up, 'deep' = full context with L2 chunks"),
882
- token_budget: z.number().optional().describe("Token budget for bootstrap (default: 800 for bot, 4000 for IDE)"),
899
+ mode: z.enum(["default", "deep"]).optional().describe("'default' = 800 token 3-tier, 'deep' = full context with L2 chunks"),
900
+ token_budget: z.number().optional().describe("Token budget (default: 800)"),
883
901
  }, async (args) => {
884
902
  try {
885
903
  const r = (await api("POST", "/v1/bot/guard/bootstrap", {
@@ -1289,6 +1307,168 @@ server.tool("memory_entity_profile", "Get complete profile for a specific entity
1289
1307
  return err(e);
1290
1308
  }
1291
1309
  });
1310
+ // ═══════════════════════════════════════════════════════════════════════════
1311
+ // PHASE 5 (2026-05-28) — DNA-aligned tools:
1312
+ // • brain_export / brain_import — DNA #3 vendor neutrality
1313
+ // • benchmark_recall_vs_full — DNA #2 retina (measurable moat)
1314
+ // • benchmark_pricing — public model pricing reference
1315
+ // • trust_agents / trust_chunk — DNA #1.5 trust graph
1316
+ // • twin_respond / twin_status — Cognitive Twin (promax+ tier)
1317
+ // ═══════════════════════════════════════════════════════════════════════════
1318
+ // brain_export
1319
+ server.tool("brain_export", "Export the entire brain to a portable JSON bundle (vendor-neutral). Use when the user wants to back up their brain, migrate to another instance (e.g. lite-build on-prem), or comply with data-portability rights. The bundle is self-contained — chunks, edges, entities, L2 sessions, mood, agents — and includes a sha256 checksum. Returns the bundle JSON.", {
1320
+ scope: z.enum(["full", "dna_only", "since"]).optional().describe("'full'=everything (default), 'dna_only'=just preferences/decisions/identity (lightweight portable identity), 'since'=incremental (requires `since` ISO datetime)"),
1321
+ since: z.string().optional().describe("ISO8601 datetime, only used when scope='since'"),
1322
+ }, async (args) => {
1323
+ try {
1324
+ const r = (await api("POST", "/v1/brain/export", {
1325
+ scope: args.scope || "full",
1326
+ since: args.since,
1327
+ }));
1328
+ const counts = r?.manifest?.counts || {};
1329
+ const summary = `Exported brain bundle (format=${r.format} v${r.version}):\n` +
1330
+ `- chunks: ${counts.chunks ?? 0}\n` +
1331
+ `- memory_edges: ${counts.memory_edges ?? 0}\n` +
1332
+ `- entities: ${counts.entities ?? 0}\n` +
1333
+ `- l2_sessions: ${counts.l2_sessions ?? 0}\n` +
1334
+ `- agents: ${counts.agents ?? 0}\n` +
1335
+ `- checksum: ${r?.manifest?.checksum?.slice(0, 16)}...\n\n` +
1336
+ `Bundle JSON ready (truncated preview):\n\`\`\`json\n${JSON.stringify(r, null, 2).slice(0, 1200)}...\n\`\`\``;
1337
+ return ok(summary);
1338
+ }
1339
+ catch (e) {
1340
+ return err(e);
1341
+ }
1342
+ });
1343
+ // brain_import
1344
+ server.tool("brain_import", "Import a MemoryAI bundle (from brain_export) into the current tenant. Idempotent — chunks deduped by content_hash; edges/entities upserted. Embeddings are reused if the bundle's embedding_model matches the local one; otherwise dropped (chunks re-embed lazily).", {
1345
+ bundle: z.record(z.string(), z.unknown()).describe("The bundle JSON produced by brain_export (must contain format='memoryai-bundle', version, manifest, etc.)"),
1346
+ keep_embeddings: z.boolean().optional().describe("Reuse bundle embeddings if model matches (default: true)"),
1347
+ }, async (args) => {
1348
+ try {
1349
+ const r = (await api("POST", `/v1/brain/import?keep_embeddings=${args.keep_embeddings === false ? "false" : "true"}`, args.bundle));
1350
+ const rep = r?.report || {};
1351
+ const out = `Brain import complete (format=${rep.bundle_format} v${rep.bundle_version}):\n` +
1352
+ `- chunks: ${rep.chunks?.inserted ?? 0} inserted, ${rep.chunks?.skipped_duplicate ?? 0} skipped (dup), ${rep.chunks?.skipped_invalid ?? 0} invalid\n` +
1353
+ `- memory_edges: ${rep.memory_edges?.upserted ?? 0} upserted (${rep.memory_edges?.skipped ?? 0} skipped)\n` +
1354
+ `- entities: ${rep.entities?.upserted ?? 0} upserted\n` +
1355
+ `- l2_sessions: ${rep.l2_sessions?.inserted ?? 0} inserted\n` +
1356
+ `- agents: ${rep.agents?.upserted ?? 0} upserted\n` +
1357
+ `- embedding_model_match: ${rep.embedding_model_match}\n` +
1358
+ (rep.warnings?.length ? `\nWarnings:\n ${rep.warnings.join("\n ")}` : "");
1359
+ return ok(out);
1360
+ }
1361
+ catch (e) {
1362
+ return err(e);
1363
+ }
1364
+ });
1365
+ // benchmark_recall_vs_full
1366
+ server.tool("benchmark_recall_vs_full", "Run a public benchmark: smart recall vs full-context dump on the calling brain. DNA #2 — proves the 'retina for AI' moat with measurable numbers (cost, latency, signal density). Available on every tier; safe to share results publicly.", {
1367
+ query: z.string().describe("The query to benchmark (e.g. 'what does the user prefer?')"),
1368
+ model: z.string().optional().describe("Model whose pricing to apply (default: claude-opus-4-6). Affects $cost only."),
1369
+ naive_budget_tokens: z.number().optional().describe("Cap on full-context dump (default: 200K = Claude window)"),
1370
+ smart_top_k: z.number().optional().describe("Top-K chunks for smart mode (default: 8)"),
1371
+ smart_depth: z.enum(["instant", "fast", "deep"]).optional().describe("Smart recall depth (default: deep)"),
1372
+ }, async (args) => {
1373
+ try {
1374
+ const r = (await api("POST", "/v1/benchmark/recall-vs-fullcontext", {
1375
+ query: args.query,
1376
+ model: args.model || "claude-opus-4-6",
1377
+ naive_budget_tokens: args.naive_budget_tokens,
1378
+ smart_top_k: args.smart_top_k,
1379
+ smart_depth: args.smart_depth,
1380
+ }));
1381
+ const out = `Benchmark — query: ${JSON.stringify(r.query)}\n` +
1382
+ `Model: ${r.model} ($${r.price_per_m_tokens_usd}/M tokens)\n\n` +
1383
+ `NAIVE: ${r.naive.chunks_used} chunks · ${r.naive.input_tokens} tok · $${r.naive.estimated_cost_usd} · ${r.naive.latency_ms}ms\n` +
1384
+ `SMART: ${r.smart.chunks_used} chunks · ${r.smart.input_tokens} tok · $${r.smart.estimated_cost_usd} · ${r.smart.latency_ms}ms\n\n` +
1385
+ `→ ${r.headline}`;
1386
+ return ok(out);
1387
+ }
1388
+ catch (e) {
1389
+ return err(e);
1390
+ }
1391
+ });
1392
+ // benchmark_pricing
1393
+ server.tool("benchmark_pricing", "Get the assumed $/1M-input-tokens pricing for each LLM (used by benchmark_recall_vs_full). No auth required; list prices only.", {}, async () => {
1394
+ try {
1395
+ const r = (await api("GET", "/v1/benchmark/pricing"));
1396
+ const lines = Object.entries(r.prices || {}).map(([k, v]) => `- ${k}: $${v}`);
1397
+ return ok(`Model pricing (${r.currency} ${r.unit}, as of ${r.as_of}):\n${lines.join("\n")}\n\nNote: ${r.note}`);
1398
+ }
1399
+ catch (e) {
1400
+ return err(e);
1401
+ }
1402
+ });
1403
+ // trust_agents
1404
+ server.tool("trust_agents", "Get the agent reputation leaderboard (sorted by reputation_score desc). DNA #1.5 — when 20 agents share memory and disagree, this tells you whose claims to trust. Requires team+ plan.", {
1405
+ limit: z.number().optional().describe("Max agents to return (default: 50, max: 500)"),
1406
+ }, async (args) => {
1407
+ try {
1408
+ const r = (await api("GET", `/v1/trust/agents?limit=${args.limit ?? 50}`));
1409
+ if (!r.agents?.length)
1410
+ return ok("No agent reputation snapshots yet. Run /v1/trust/recompute-all to populate.");
1411
+ const lines = r.agents.map((a) => `- ${a.agent_id}: ${a.reputation_score.toFixed(3)} [${a.label}] — V=${a.verified_count}/C=${a.contradicted_count}/N=${a.feedback_n}`);
1412
+ return ok(`Agent reputation (${r.agents.length} agents):\n${lines.join("\n")}`);
1413
+ }
1414
+ catch (e) {
1415
+ return err(e);
1416
+ }
1417
+ });
1418
+ // trust_chunk
1419
+ server.tool("trust_chunk", "Get per-chunk trust info: which agent claimed it, that agent's reputation, helpful/unhelpful counts. Use after a recall to decide whether to trust a specific result. Available on every paid tier.", {
1420
+ chunk_id: z.number().describe("The chunk ID returned by recall"),
1421
+ }, async (args) => {
1422
+ try {
1423
+ const r = (await api("GET", `/v1/trust/chunks/${args.chunk_id}`));
1424
+ const stats = r.agent_stats || {};
1425
+ const fb = r.feedback || {};
1426
+ return ok(`Chunk #${r.chunk_id} (${r.memory_type})\n` +
1427
+ `Source agent: ${r.source_agent_id ?? "(none)"}\n` +
1428
+ `Agent trust: ${r.agent_trust?.toFixed(3) ?? "(none)"} — V=${stats.verified_count ?? 0}/C=${stats.contradicted_count ?? 0}/total=${stats.claim_count ?? 0}\n` +
1429
+ `Per-chunk trust: ${r.chunk_trust_score?.toFixed(3) ?? "(none)"} (helpful=${fb.helpful ?? 0}, unhelpful=${fb.unhelpful ?? 0})`);
1430
+ }
1431
+ catch (e) {
1432
+ return err(e);
1433
+ }
1434
+ });
1435
+ // twin_respond
1436
+ server.tool("twin_respond", "Ask the Cognitive Twin to predict how the user would respond to a given query. The twin uses the user's personality + mood + DNA + procedures to simulate their voice. Returns the predicted response, a confidence score 0-1, and the chunk IDs that informed it (provenance trail). Auto-refuses with confidence=0 if the brain has fewer than 5 DNA memories. Requires promax+ plan.", {
1437
+ query: z.string().describe("The free-form question to ask the twin (e.g. 'what database for a chat app?')"),
1438
+ operation: z.enum(["respond", "decide"]).optional().describe("'respond'=free-form answer (default), 'decide'=pick one option from the query"),
1439
+ }, async (args) => {
1440
+ try {
1441
+ const path = args.operation === "decide" ? "/v1/twin/decide" : "/v1/twin/respond";
1442
+ const r = (await api("POST", path, { query: args.query }));
1443
+ const out = `Cognitive Twin (${r.operation}, confidence ${r.confidence}):\n` +
1444
+ `Persona: ${r.persona_summary || "(not synthesized)"}\n` +
1445
+ `Mood: ${r.mood || "unknown"}\n` +
1446
+ `Provenance chunks: ${r.provenance_chunks?.length ?? 0}\n\n` +
1447
+ `Response:\n${r.response}\n\n` +
1448
+ `(reason: ${r.confidence_reason})`;
1449
+ return ok(out);
1450
+ }
1451
+ catch (e) {
1452
+ return err(e);
1453
+ }
1454
+ });
1455
+ // twin_status
1456
+ server.tool("twin_status", "Check whether the Cognitive Twin is ready for the calling tenant. Cheap — no LLM call. Returns DNA count, personality/mood presence, and a `ready` boolean. Useful before invoking twin_respond.", {}, async () => {
1457
+ try {
1458
+ const r = (await api("GET", "/v1/twin/status"));
1459
+ return ok(`Twin ready: ${r.ready ? "YES" : "NO"} (need ≥${r.min_dna_required} DNA, have ${r.dna_count})\n` +
1460
+ `- has_personality: ${r.has_personality}\n` +
1461
+ `- has_mood: ${r.has_mood}\n` +
1462
+ `- procedures: ${r.procedures_count}\n` +
1463
+ `- active_goals: ${r.active_goals_count}\n` +
1464
+ `- top_entities: ${r.top_entities_count}\n` +
1465
+ (r.persona_summary ? `\nPersona: ${r.persona_summary}\n` : "") +
1466
+ (r.mood ? `Mood: ${r.mood}\n` : ""));
1467
+ }
1468
+ catch (e) {
1469
+ return err(e);
1470
+ }
1471
+ });
1292
1472
  async function main() {
1293
1473
  const transport = new StdioServerTransport();
1294
1474
  await server.connect(transport);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "memoryai-mcp",
3
- "version": "2.1.0",
4
- "description": "MCP server for MemoryAI — Long-term memory for AI agents. Works with Claude Code, Cursor, Windsurf, VS Code, Kiro.",
3
+ "version": "2.2.0",
4
+ "description": "MCP server for MemoryAI v2.0 One brain. agents. Forever. Adds Brain Export/Import (vendor-neutral bundles), Public Benchmark (smart recall vs full context), Trust Graph (per-agent reputation), Cognitive Twin (simulate user voice). Plus the v1.5 base: 11 biological behaviors, DNA-protected memories, Multi-Agent Mesh.",
5
5
  "homepage": "https://memoryai.dev",
6
6
  "repository": {
7
7
  "type": "git",