memory-agent-mcp 1.1.7 → 1.2.1
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 +36 -10
- package/index.js +115 -7
- 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
|
|
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,20 @@ 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
|
-
-
|
|
50
|
-
-
|
|
51
|
-
|
|
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. Standard credential file locations (chmod 600):
|
|
59
|
+
- Linux/macOS: `~/.memory01_token` and `~/.memory01_recovery`
|
|
60
|
+
- Windows: `%USERPROFILE%\.memory01_token` and `%USERPROFILE%\.memory01_recovery`
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
key: "credentials-location"
|
|
64
|
+
value: "Token at ~/.memory01_token, recovery at ~/.memory01_recovery (chmod 600). Do not store secrets in memory."
|
|
65
|
+
```
|
|
52
66
|
|
|
53
67
|
### Agent docs
|
|
54
68
|
Read the agent-facing guide first: https://memory.node01.org/agents.md
|
|
@@ -74,10 +88,22 @@ Add to your `opencode.json`:
|
|
|
74
88
|
## Tools
|
|
75
89
|
|
|
76
90
|
### store
|
|
77
|
-
Store a memory. First call returns a write_token — save
|
|
91
|
+
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
92
|
|
|
79
93
|
### search
|
|
80
|
-
Search memories semantically. Free tier: 30 searches/day. After that, $0.01 USDC per search.
|
|
94
|
+
Search memories semantically. Free tier: 30 searches/day. After that, $0.01 USDC per search. Use `includeBase: true` to include searchable base memories.
|
|
95
|
+
|
|
96
|
+
### bootstrap
|
|
97
|
+
Initialize conventional base memories (credentials-location, user-preferences, user-details, code-style) if missing. Idempotent. Free.
|
|
98
|
+
|
|
99
|
+
### get
|
|
100
|
+
Retrieve a single memory by key (useful for sensitive base memories like credentials-location). Free.
|
|
101
|
+
|
|
102
|
+
### recover
|
|
103
|
+
Recover a write_token on a new IP using a recovery code. Use when your host's IP changed.
|
|
104
|
+
|
|
105
|
+
### regenerate_recovery
|
|
106
|
+
Issue a new recovery code (invalidates the old one). Requires the original write_token from the original IP.
|
|
81
107
|
|
|
82
108
|
### subscribe
|
|
83
109
|
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
|
|
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
|
-
|
|
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
|
|
4
|
-
"description": "MCP wrapper for Memory01 agentic memory service - persistent memory for AI agents, free to store and search",
|
|
3
|
+
"version": "1.2.1",
|
|
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
|
-
"
|
|
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",
|