memory-agent-mcp 1.1.7 → 1.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 (3) hide show
  1. package/README.md +33 -10
  2. package/index.js +115 -7
  3. package/package.json +9 -6
package/README.md CHANGED
@@ -4,12 +4,13 @@ MCP wrapper for [Memory01](https://memory.node01.org) — agentic memory for AI
4
4
 
5
5
  ## Features
6
6
 
7
- - **Store**: Free memory storage (first call returns a write_token)
7
+ - **Store**: Free memory storage (first call returns a write_token + recovery_code)
8
+ - **Upsert**: Re-store with the same key updates in place (no duplicates)
8
9
  - **Search**: Semantic search across 50+ languages (free tier: 30/day, then $0.01 USDC)
10
+ - **Base memories**: Small (max 2KB) contextual memories (preferences, style, details). Excluded from normal search by default; include with `include_base=true`. Bootstrap creates conventional ones.
11
+ - **Recovery**: Recovery code issued at first store lets you re-bind your token to a new IP if your host changes IP.
9
12
  - **Subscribe**: Subscription plans (Starter $2/500, Pro $9/mo, Enterprise $20/mo)
10
- - **Health**: Service health check (free)
11
- - **Stats**: Global memory statistics (free)
12
- - **Sample**: Free demo (store + search)
13
+ - **Health / Stats / Sample**: Free utilities
13
14
 
14
15
  ## Installation
15
16
 
@@ -27,11 +28,13 @@ Optional environment variables:
27
28
  - `MEMORY_PRIVATE_KEY` (optional: private key for x402 payment signing — enables paid operations beyond free tier)
28
29
 
29
30
  ### Free tier (no wallet needed)
30
- - Store memories: free
31
+ - Store memories: free (up to 50KB per value; 2KB for base memories)
31
32
  - Search: 30 free searches/day
32
33
  - Health check: free
33
34
  - Stats: free
34
35
  - Sample: free
36
+ - Bootstrap base memories: free
37
+ - Get a single memory: free
35
38
 
36
39
  ### Paid operations (requires MEMORY_PRIVATE_KEY)
37
40
  - Search beyond 30/day: $0.01 USDC
@@ -46,9 +49,17 @@ environment variables.
46
49
  Your write_token is bound to the **(IP, agent_id)** pair that created it.
47
50
  - Multiple agents can share the same IP (NAT, serverless, office, VPN): each agent_id gets its own token.
48
51
  - If you call `store` without a token for an `(IP, agent_id)` pair that already has one, you get `403 token_required`. Include the token you saved.
49
- - If you lose the token, you cannot recover your memories. Create a new agent_id and start fresh.
50
- - If your IP changes, the token stops working. Create a new token.
51
- - Treat the write_token like a password. Never log it in plaintext.
52
+ - First `store` also returns a `recovery_code` (shown once). Save it offline (chmod 600). If your IP changes, use `recover` with the recovery code to get a new token for the new IP. Regenerate the recovery code (from the original IP) if lost.
53
+ - Treat the write_token and recovery_code like passwords. Never log them in plaintext. Never store secrets in memory — store only a pointer (see "Base memory" pattern).
54
+
55
+ ### Base memory pattern
56
+ Base memories are small contextual memories (preferences, style, details). They are excluded from normal search to keep task search focused. Use `include_base=true` to load them (e.g. at session start). Sensitive ones like `credentials-location` are never searchable — retrieve via `get`.
57
+
58
+ Store a pointer, never secrets:
59
+ ```
60
+ key: "credentials-location"
61
+ value: "Token and recovery code saved at /path/to/file (chmod 600). Do not store secrets in memory."
62
+ ```
52
63
 
53
64
  ### Agent docs
54
65
  Read the agent-facing guide first: https://memory.node01.org/agents.md
@@ -74,10 +85,22 @@ Add to your `opencode.json`:
74
85
  ## Tools
75
86
 
76
87
  ### store
77
- Store a memory. First call returns a write_token — save it! All future operations require it.
88
+ Store a memory (free). First call returns a write_token and recovery_code — save both! All future operations require the write_token. Re-storing with the same key updates in place (upsert). Supports `base: true` for small (2KB) contextual memories.
78
89
 
79
90
  ### search
80
- Search memories semantically. Free tier: 30 searches/day. After that, $0.01 USDC per search.
91
+ Search memories semantically. Free tier: 30 searches/day. After that, $0.01 USDC per search. Use `includeBase: true` to include searchable base memories.
92
+
93
+ ### bootstrap
94
+ Initialize conventional base memories (credentials-location, user-preferences, user-details, code-style) if missing. Idempotent. Free.
95
+
96
+ ### get
97
+ Retrieve a single memory by key (useful for sensitive base memories like credentials-location). Free.
98
+
99
+ ### recover
100
+ Recover a write_token on a new IP using a recovery code. Use when your host's IP changed.
101
+
102
+ ### regenerate_recovery
103
+ Issue a new recovery code (invalidates the old one). Requires the original write_token from the original IP.
81
104
 
82
105
  ### subscribe
83
106
  Subscribe to a plan for more searches.
package/index.js CHANGED
@@ -3,8 +3,12 @@
3
3
  * memory-agent-mcp — MCP stdio server for Memory01 agentic memory service
4
4
  *
5
5
  * Provides tools to interact with the Memory01 API:
6
- * - store(agentId, key, value, writeToken?, sessionId?, metadata?) -> Store a memory (free)
7
- * - search(agentId, query, writeToken, topK?, sessionId?, cursor?) -> Search memories (free tier 30/day, then $0.01)
6
+ * - store(agentId, key, value, writeToken?, sessionId?, metadata?, base?) -> Store a memory (free; base=true for 2KB contextual memories)
7
+ * - search(agentId, query, writeToken, topK?, sessionId?, cursor?, includeBase?) -> Search memories (free tier 30/day, then $0.01)
8
+ * - bootstrap(agentId, writeToken, keys?) -> Initialize conventional base memories (free, idempotent)
9
+ * - get(agentId, writeToken, key) -> Retrieve a single memory by key (free)
10
+ * - recover(agentId, recoveryCode) -> Recover a write_token on a new IP (free)
11
+ * - regenerateRecovery(writeToken) -> Issue a new recovery code (free)
8
12
  * - subscribe(agentId, writeToken, plan) -> Subscribe to a plan (x402)
9
13
  * - health() -> Service health check (free)
10
14
  * - stats() -> Global memory stats (free)
@@ -184,7 +188,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
184
188
  tools: [
185
189
  {
186
190
  name: "store",
187
- description: "Store a memory (free). First call returns a write_token — save it! All future operations require it. Memories are scoped per write_token.",
191
+ description: "Store a memory (free). First call returns a write_token and recovery_code — save both! All future operations require the write_token. Re-storing with the same key updates in place (upsert). Supports base:true for small (2KB) contextual memories.",
188
192
  inputSchema: {
189
193
  type: "object",
190
194
  properties: {
@@ -194,13 +198,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
194
198
  writeToken: { type: "string", description: "Write token from first store (omit on first call)" },
195
199
  sessionId: { type: "string", description: "Optional session ID to scope memories" },
196
200
  metadata: { type: "object", description: "Optional metadata (max 2KB)" },
201
+ base: { type: "boolean", description: "Mark as base memory (max 2KB). Excluded from normal search unless includeBase=true." },
197
202
  },
198
203
  required: ["agentId", "key", "value"],
199
204
  },
200
205
  },
201
206
  {
202
207
  name: "search",
203
- description: "Search memories semantically (free tier: 30/day, then $0.01 USDC). Returns matching memories with relevance scores. Supports 50+ languages, cross-lingual search.",
208
+ description: "Search memories semantically (free tier: 30/day, then $0.01 USDC). Returns matching memories with relevance scores. Supports 50+ languages, cross-lingual search. Use includeBase:true to include base memories.",
204
209
  inputSchema: {
205
210
  type: "object",
206
211
  properties: {
@@ -210,6 +215,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
210
215
  topK: { type: "number", description: "Max results (default 10, max 50)", default: 10 },
211
216
  sessionId: { type: "string", description: "Optional: scope to session. Omit query for chronological listing." },
212
217
  cursor: { type: "string", description: "Pagination cursor from previous response" },
218
+ includeBase: { type: "boolean", description: "Include searchable base memories in results (default false)" },
213
219
  },
214
220
  required: ["agentId", "writeToken"],
215
221
  },
@@ -242,6 +248,55 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
242
248
  description: "Get a free sample: store a demo memory and search it. Shows the shape of responses without paying.",
243
249
  inputSchema: { type: "object", properties: {} },
244
250
  },
251
+ {
252
+ name: "bootstrap",
253
+ description: "Initialize conventional base memories (credentials-location, user-preferences, user-details, code-style) if missing. Idempotent. Free.",
254
+ inputSchema: {
255
+ type: "object",
256
+ properties: {
257
+ agentId: { type: "string", description: "Your agent identifier" },
258
+ writeToken: { type: "string", description: "Write token (required)" },
259
+ keys: { type: "array", items: { type: "string" }, description: "Optional list of base keys to create (defaults to all conventional)" },
260
+ },
261
+ required: ["agentId", "writeToken"],
262
+ },
263
+ },
264
+ {
265
+ name: "get",
266
+ description: "Retrieve a single memory by key (free). Useful for sensitive base memories like credentials-location.",
267
+ inputSchema: {
268
+ type: "object",
269
+ properties: {
270
+ agentId: { type: "string", description: "Your agent identifier" },
271
+ writeToken: { type: "string", description: "Write token (required)" },
272
+ key: { type: "string", description: "Memory key to retrieve" },
273
+ },
274
+ required: ["agentId", "writeToken", "key"],
275
+ },
276
+ },
277
+ {
278
+ name: "recover",
279
+ description: "Recover a write_token on a new IP using a recovery code (free). Use when your host's IP changed.",
280
+ inputSchema: {
281
+ type: "object",
282
+ properties: {
283
+ agentId: { type: "string", description: "Your agent identifier" },
284
+ recoveryCode: { type: "string", description: "Recovery code (rc_...) issued at first store" },
285
+ },
286
+ required: ["agentId", "recoveryCode"],
287
+ },
288
+ },
289
+ {
290
+ name: "regenerate_recovery",
291
+ description: "Issue a new recovery code (invalidates the old one). Requires the original write_token from the original IP. Free.",
292
+ inputSchema: {
293
+ type: "object",
294
+ properties: {
295
+ writeToken: { type: "string", description: "Write token from the original IP (required)" },
296
+ },
297
+ required: ["writeToken"],
298
+ },
299
+ },
245
300
  ],
246
301
  };
247
302
  });
@@ -252,16 +307,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
252
307
  try {
253
308
  switch (name) {
254
309
  case "store": {
255
- const { agentId, key, value, writeToken, sessionId, metadata } = args;
310
+ const { agentId, key, value, writeToken, sessionId, metadata, base } = args;
256
311
  if (!agentId || !key || !value) {
257
312
  throw new McpError(ErrorCode.InvalidParams, "agentId, key, and value are required");
258
313
  }
259
314
  if (key.length > 256) throw new McpError(ErrorCode.InvalidParams, "key max 256 chars");
260
- if (value.length > 10240) throw new McpError(ErrorCode.InvalidParams, "value max 10KB");
315
+ const valueLimit = (args.base ? 2048 : 51200);
316
+ if (value.length > valueLimit) throw new McpError(ErrorCode.InvalidParams, `value max ${args.base ? '2KB (base)' : '50KB'}`);
261
317
  if (metadata && JSON.stringify(metadata).length > 2048) throw new McpError(ErrorCode.InvalidParams, "metadata max 2KB");
262
318
 
263
319
  const body = { agent_id: agentId, key, value };
264
320
  if (writeToken) body.write_token = writeToken;
321
+ if (base) body.base = true;
265
322
  if (sessionId) body.session_id = sessionId;
266
323
  if (metadata) body.metadata = metadata;
267
324
 
@@ -288,7 +345,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
288
345
  }
289
346
 
290
347
  case "search": {
291
- const { agentId, query, writeToken, topK = 10, sessionId, cursor } = args;
348
+ const { agentId, query, writeToken, topK = 10, sessionId, cursor, includeBase } = args;
292
349
  if (!agentId || !writeToken) {
293
350
  throw new McpError(ErrorCode.InvalidParams, "agentId and writeToken are required");
294
351
  }
@@ -298,6 +355,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
298
355
  if (query) body.query = query;
299
356
  if (sessionId) body.session_id = sessionId;
300
357
  if (cursor) body.cursor = cursor;
358
+ if (includeBase) body.include_base = true;
301
359
 
302
360
  // Try free first
303
361
  const freeResult = await callFree("/api/memory/search", "POST", body);
@@ -405,6 +463,56 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
405
463
  };
406
464
  }
407
465
 
466
+ case "bootstrap": {
467
+ const { agentId, writeToken, keys } = args;
468
+ if (!agentId || !writeToken) {
469
+ throw new McpError(ErrorCode.InvalidParams, "agentId and writeToken are required");
470
+ }
471
+ const body = { agent_id: agentId, write_token: writeToken };
472
+ if (keys) body.keys = keys;
473
+ const result = await callFree("/api/memory/bootstrap", "POST", body);
474
+ if (result.status >= 400) {
475
+ throw new McpError(ErrorCode.InternalError, `API error: ${JSON.stringify(result.data)}`);
476
+ }
477
+ return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
478
+ }
479
+
480
+ case "get": {
481
+ const { agentId, writeToken, key } = args;
482
+ if (!agentId || !writeToken || !key) {
483
+ throw new McpError(ErrorCode.InvalidParams, "agentId, writeToken, and key are required");
484
+ }
485
+ const result = await callFree("/api/memory/get", "POST", { agent_id: agentId, write_token: writeToken, key });
486
+ if (result.status >= 400) {
487
+ throw new McpError(ErrorCode.InternalError, `API error: ${JSON.stringify(result.data)}`);
488
+ }
489
+ return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
490
+ }
491
+
492
+ case "recover": {
493
+ const { agentId, recoveryCode } = args;
494
+ if (!agentId || !recoveryCode) {
495
+ throw new McpError(ErrorCode.InvalidParams, "agentId and recoveryCode are required");
496
+ }
497
+ const result = await callFree("/api/memory/recover", "POST", { agent_id: agentId, recovery_code: recoveryCode });
498
+ if (result.status >= 400) {
499
+ throw new McpError(ErrorCode.InternalError, `API error: ${JSON.stringify(result.data)}`);
500
+ }
501
+ return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
502
+ }
503
+
504
+ case "regenerate_recovery": {
505
+ const { writeToken } = args;
506
+ if (!writeToken) {
507
+ throw new McpError(ErrorCode.InvalidParams, "writeToken is required");
508
+ }
509
+ const result = await callFree("/api/memory/recovery/regenerate", "POST", { write_token: writeToken });
510
+ if (result.status >= 400) {
511
+ throw new McpError(ErrorCode.InternalError, `API error: ${JSON.stringify(result.data)}`);
512
+ }
513
+ return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
514
+ }
515
+
408
516
  default:
409
517
  throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
410
518
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "memory-agent-mcp",
3
- "version": "1.1.7",
4
- "description": "MCP wrapper for Memory01 agentic memory service - persistent memory for AI agents, free to store and search",
3
+ "version": "1.2.0",
4
+ "description": "MCP wrapper for Memory01 agentic memory service - persistent memory for AI agents, free to store and search. Base memories, recovery codes, upsert, 50+ languages.",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "bin": {
@@ -12,13 +12,16 @@
12
12
  "test": "node test.js"
13
13
  },
14
14
  "keywords": [
15
- "mcp",
16
- "memory",
17
15
  "agent",
18
- "x402",
19
16
  "ai",
20
17
  "base",
21
- "storage"
18
+ "base-memory",
19
+ "mcp",
20
+ "memory",
21
+ "recovery",
22
+ "storage",
23
+ "upsert",
24
+ "x402"
22
25
  ],
23
26
  "author": "node01.org",
24
27
  "license": "MIT",