memory-agent-mcp 0.0.0-stage → 1.0.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/PLAN.md +42 -0
- package/README.md +64 -2
- package/index.js +422 -0
- package/package.json +30 -4
package/PLAN.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Memory MCP Wrapper — Plan & Status
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
Build and publish `memory-agent-mcp` npm package following `vibe-token-mcp` pattern.
|
|
5
|
+
|
|
6
|
+
## Status: ✅ BUILT & TESTED
|
|
7
|
+
|
|
8
|
+
## Completed
|
|
9
|
+
- [x] Create package.json
|
|
10
|
+
- [x] Create index.js with MCP tools: store, search, subscribe, health, stats, sample
|
|
11
|
+
- [x] Create README.md
|
|
12
|
+
- [x] Install dependencies (@modelcontextprotocol/sdk, viem)
|
|
13
|
+
- [x] Test MCP server startup (stdio)
|
|
14
|
+
- [x] Test tools/list (6 tools registered)
|
|
15
|
+
- [x] Test health tool (returns service status)
|
|
16
|
+
- [x] Test sample tool (handles IP token conflict gracefully)
|
|
17
|
+
|
|
18
|
+
## TODO
|
|
19
|
+
- [ ] Test store tool with fresh IP (or handle existing token)
|
|
20
|
+
- [ ] Test search tool (free tier + paid)
|
|
21
|
+
- [ ] Test subscribe tool (x402 payment)
|
|
22
|
+
- [ ] Fix sample tool to handle existing write_token
|
|
23
|
+
- [ ] Publish to npm as `memory-agent-mcp`
|
|
24
|
+
- [ ] Add to x402-list MCP registry
|
|
25
|
+
- [ ] Create README for npm page
|
|
26
|
+
- [ ] Test end-to-end with real payment
|
|
27
|
+
|
|
28
|
+
## Tools
|
|
29
|
+
| Tool | Description | Payment |
|
|
30
|
+
|------|-------------|---------|
|
|
31
|
+
| store | Store a memory (free) | Free |
|
|
32
|
+
| search | Semantic search (30/day free, then $0.01) | Free tier + x402 |
|
|
33
|
+
| subscribe | Subscribe to plan | x402 ($2/$9/$20) |
|
|
34
|
+
| health | Service health | Free |
|
|
35
|
+
| stats | Global stats | Free |
|
|
36
|
+
| sample | Demo store+search | Free |
|
|
37
|
+
|
|
38
|
+
## Next Steps
|
|
39
|
+
1. Publish to npm
|
|
40
|
+
2. Add memory-mcp to OpenCode config
|
|
41
|
+
3. Test with real wallet
|
|
42
|
+
4. Update llms.txt and openapi.json to mention MCP
|
package/README.md
CHANGED
|
@@ -1,3 +1,65 @@
|
|
|
1
|
-
#
|
|
1
|
+
# memory-agent-mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
MCP wrapper for [Memory01](https://memory.node01.org) — agentic memory for AI agents.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Store**: Free memory storage (first call returns a write_token)
|
|
8
|
+
- **Search**: Semantic search across 50+ languages (free tier: 30/day, then $0.01 USDC)
|
|
9
|
+
- **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
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install -g memory-agent-mcp
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Configuration
|
|
21
|
+
|
|
22
|
+
Set these environment variables:
|
|
23
|
+
|
|
24
|
+
- `MEMORY_BASE_URL` (default: https://memory.node01.org)
|
|
25
|
+
- `MEMORY_PAYTO` (USDC wallet address on Base for paid calls)
|
|
26
|
+
- `MEMORY_PRIVATE_KEY` (private key for x402 payment signing)
|
|
27
|
+
|
|
28
|
+
## Usage with OpenCode
|
|
29
|
+
|
|
30
|
+
Add to your `opencode.json`:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcp": {
|
|
35
|
+
"memory": {
|
|
36
|
+
"type": "local",
|
|
37
|
+
"command": ["npx", "-y", "memory-agent-mcp"],
|
|
38
|
+
"environment": {
|
|
39
|
+
"MEMORY_PAYTO": "0x...",
|
|
40
|
+
"MEMORY_PRIVATE_KEY": "0x..."
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Tools
|
|
48
|
+
|
|
49
|
+
### store
|
|
50
|
+
Store a memory. First call returns a write_token — save it! All future operations require it.
|
|
51
|
+
|
|
52
|
+
### search
|
|
53
|
+
Search memories semantically. Free tier: 30 searches/day. After that, $0.01 USDC per search.
|
|
54
|
+
|
|
55
|
+
### subscribe
|
|
56
|
+
Subscribe to a plan for more searches.
|
|
57
|
+
|
|
58
|
+
### health
|
|
59
|
+
Check service health.
|
|
60
|
+
|
|
61
|
+
### stats
|
|
62
|
+
Get global statistics.
|
|
63
|
+
|
|
64
|
+
### sample
|
|
65
|
+
Free demo: store and search a sample memory.
|
package/index.js
ADDED
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* memory-agent-mcp — MCP stdio server for Memory01 agentic memory service
|
|
4
|
+
*
|
|
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)
|
|
8
|
+
* - subscribe(agentId, writeToken, plan) -> Subscribe to a plan (x402)
|
|
9
|
+
* - health() -> Service health check (free)
|
|
10
|
+
* - stats() -> Global memory stats (free)
|
|
11
|
+
* - sample() -> Free sample (store + search demo)
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* npx memory-agent-mcp
|
|
15
|
+
* or: node index.js
|
|
16
|
+
*
|
|
17
|
+
* Configure with environment variables:
|
|
18
|
+
* MEMORY_BASE_URL (default: https://memory.node01.org)
|
|
19
|
+
* MEMORY_PAYTO (required for paid calls - USDC wallet address)
|
|
20
|
+
* MEMORY_PRIVATE_KEY (required for x402 payment signing)
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
24
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
25
|
+
import {
|
|
26
|
+
CallToolRequestSchema,
|
|
27
|
+
ListToolsRequestSchema,
|
|
28
|
+
ErrorCode,
|
|
29
|
+
McpError,
|
|
30
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
31
|
+
import { createWalletClient, http, parseEther } from "viem";
|
|
32
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
33
|
+
import { base } from "viem/chains";
|
|
34
|
+
|
|
35
|
+
// ============================= Config =============================
|
|
36
|
+
const MEMORY_BASE_URL = process.env.MEMORY_BASE_URL || "https://memory.node01.org";
|
|
37
|
+
const MEMORY_PAYTO = process.env.MEMORY_PAYTO;
|
|
38
|
+
const MEMORY_PRIVATE_KEY = process.env.MEMORY_PRIVATE_KEY;
|
|
39
|
+
|
|
40
|
+
if (!MEMORY_PAYTO) {
|
|
41
|
+
console.error("MEMORY_PAYTO environment variable required for paid calls");
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!MEMORY_PRIVATE_KEY) {
|
|
46
|
+
console.error("MEMORY_PRIVATE_KEY environment variable required for x402 payment signing");
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const privateKey = MEMORY_PRIVATE_KEY.startsWith("0x") ? MEMORY_PRIVATE_KEY : `0x${MEMORY_PRIVATE_KEY}`;
|
|
51
|
+
const account = privateKeyToAccount(privateKey);
|
|
52
|
+
|
|
53
|
+
// ============================= x402 Payment Helper =============================
|
|
54
|
+
async function payAndRetry(endpoint, body, priceUsd = "0.01") {
|
|
55
|
+
const walletClient = createWalletClient({
|
|
56
|
+
account,
|
|
57
|
+
chain: base,
|
|
58
|
+
transport: http(),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// First call to get 402
|
|
62
|
+
const response = await fetch(`${MEMORY_BASE_URL}${endpoint}`, {
|
|
63
|
+
method: "POST",
|
|
64
|
+
headers: { "Content-Type": "application/json", "Accept": "application/json" },
|
|
65
|
+
body: JSON.stringify(body),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (response.status !== 402) {
|
|
69
|
+
const data = await response.json();
|
|
70
|
+
return { data, status: response.status };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const paymentRequired = await response.json();
|
|
74
|
+
const accepts = paymentRequired.accepts || [];
|
|
75
|
+
const exactOption = accepts.find(
|
|
76
|
+
(a) => a.scheme === "exact" && a.network === "eip155:8453"
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
if (!exactOption) {
|
|
80
|
+
throw new Error("No exact payment option for Base network found");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const facilitatorUrl = paymentRequired.extensions?.["pay-with-x"]?.facilitator || "https://facilitator.payai.network";
|
|
84
|
+
|
|
85
|
+
const paymentPayload = {
|
|
86
|
+
x402Version: paymentRequired.x402Version || 2,
|
|
87
|
+
scheme: "exact",
|
|
88
|
+
network: "eip155:8453",
|
|
89
|
+
payload: {
|
|
90
|
+
authorization: {
|
|
91
|
+
from: account.address,
|
|
92
|
+
to: exactOption.payTo,
|
|
93
|
+
value: priceUsd,
|
|
94
|
+
validAfter: Math.floor(Date.now() / 1000),
|
|
95
|
+
validBefore: Math.floor(Date.now() / 1000) + 300,
|
|
96
|
+
nonce: Math.floor(Math.random() * 1000000),
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const signature = await walletClient.signTypedData({
|
|
102
|
+
domain: {
|
|
103
|
+
name: "x402 Payment",
|
|
104
|
+
version: "1",
|
|
105
|
+
chainId: 8453,
|
|
106
|
+
verifyingContract: exactOption.payTo,
|
|
107
|
+
},
|
|
108
|
+
types: {
|
|
109
|
+
ExactPayment: [
|
|
110
|
+
{ name: "from", type: "address" },
|
|
111
|
+
{ name: "to", type: "address" },
|
|
112
|
+
{ name: "value", type: "uint256" },
|
|
113
|
+
{ name: "validAfter", type: "uint256" },
|
|
114
|
+
{ name: "validBefore", type: "uint256" },
|
|
115
|
+
{ name: "nonce", type: "uint256" },
|
|
116
|
+
],
|
|
117
|
+
},
|
|
118
|
+
primaryType: "ExactPayment",
|
|
119
|
+
message: {
|
|
120
|
+
from: account.address,
|
|
121
|
+
to: exactOption.payTo,
|
|
122
|
+
value: priceUsd,
|
|
123
|
+
validAfter: Math.floor(Date.now() / 1000),
|
|
124
|
+
validBefore: Math.floor(Date.now() / 1000) + 300,
|
|
125
|
+
nonce: Math.floor(Math.random() * 1000000),
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
paymentPayload.payload.authorization.signature = signature;
|
|
130
|
+
|
|
131
|
+
const settleResponse = await fetch(`${facilitatorUrl}/settle`, {
|
|
132
|
+
method: "POST",
|
|
133
|
+
headers: { "Content-Type": "application/json" },
|
|
134
|
+
body: JSON.stringify(paymentPayload),
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
if (!settleResponse.ok) {
|
|
138
|
+
const err = await settleResponse.text();
|
|
139
|
+
throw new Error(`Payment settlement failed: ${settleResponse.status} ${err}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const settleResult = await settleResponse.json();
|
|
143
|
+
const paymentHeader = settleResult.paymentHeader || settleResult.header || settleResult.payment;
|
|
144
|
+
|
|
145
|
+
// Retry with payment header
|
|
146
|
+
const finalResponse = await fetch(`${MEMORY_BASE_URL}${endpoint}`, {
|
|
147
|
+
method: "POST",
|
|
148
|
+
headers: {
|
|
149
|
+
"Content-Type": "application/json",
|
|
150
|
+
"Accept": "application/json",
|
|
151
|
+
"X-Payment": paymentHeader,
|
|
152
|
+
},
|
|
153
|
+
body: JSON.stringify(body),
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const data = await finalResponse.json();
|
|
157
|
+
return { data, status: finalResponse.status };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ============================= Free API Calls =============================
|
|
161
|
+
async function callFree(endpoint, method = "GET", body = null) {
|
|
162
|
+
const opts = { method, headers: { "Accept": "application/json" } };
|
|
163
|
+
if (body) {
|
|
164
|
+
opts.headers["Content-Type"] = "application/json";
|
|
165
|
+
opts.body = JSON.stringify(body);
|
|
166
|
+
}
|
|
167
|
+
const response = await fetch(`${MEMORY_BASE_URL}${endpoint}`, opts);
|
|
168
|
+
return { data: await response.json(), status: response.status };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ============================= MCP Server =============================
|
|
172
|
+
const server = new Server(
|
|
173
|
+
{ name: "memory-agent-mcp", version: "1.0.0" },
|
|
174
|
+
{ capabilities: { tools: {} } }
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
178
|
+
return {
|
|
179
|
+
tools: [
|
|
180
|
+
{
|
|
181
|
+
name: "store",
|
|
182
|
+
description: "Store a memory (free). First call returns a write_token — save it! All future operations require it. Memories are scoped per write_token.",
|
|
183
|
+
inputSchema: {
|
|
184
|
+
type: "object",
|
|
185
|
+
properties: {
|
|
186
|
+
agentId: { type: "string", description: "Your agent identifier" },
|
|
187
|
+
key: { type: "string", description: "Memory key (max 256 chars)" },
|
|
188
|
+
value: { type: "string", description: "Memory value (max 10KB)" },
|
|
189
|
+
writeToken: { type: "string", description: "Write token from first store (omit on first call)" },
|
|
190
|
+
sessionId: { type: "string", description: "Optional session ID to scope memories" },
|
|
191
|
+
metadata: { type: "object", description: "Optional metadata (max 2KB)" },
|
|
192
|
+
},
|
|
193
|
+
required: ["agentId", "key", "value"],
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
name: "search",
|
|
198
|
+
description: "Search memories semantically (free tier: 30/day, then $0.01 USDC). Returns matching memories with relevance scores. Supports 50+ languages, cross-lingual search.",
|
|
199
|
+
inputSchema: {
|
|
200
|
+
type: "object",
|
|
201
|
+
properties: {
|
|
202
|
+
agentId: { type: "string", description: "Your agent identifier" },
|
|
203
|
+
query: { type: "string", description: "Search query (max 500 chars). Omit for session-only chronological listing." },
|
|
204
|
+
writeToken: { type: "string", description: "Write token (required)" },
|
|
205
|
+
topK: { type: "number", description: "Max results (default 10, max 50)", default: 10 },
|
|
206
|
+
sessionId: { type: "string", description: "Optional: scope to session. Omit query for chronological listing." },
|
|
207
|
+
cursor: { type: "string", description: "Pagination cursor from previous response" },
|
|
208
|
+
},
|
|
209
|
+
required: ["agentId", "writeToken"],
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
name: "subscribe",
|
|
214
|
+
description: "Subscribe to a memory plan (x402). Starter: $2/500 credits. Pro: $9/mo unlimited. Enterprise: $20/mo unlimited+priority.",
|
|
215
|
+
inputSchema: {
|
|
216
|
+
type: "object",
|
|
217
|
+
properties: {
|
|
218
|
+
agentId: { type: "string", description: "Your agent identifier" },
|
|
219
|
+
writeToken: { type: "string", description: "Write token (required)" },
|
|
220
|
+
plan: { type: "string", enum: ["starter", "pro", "enterprise"], description: "Plan to subscribe to" },
|
|
221
|
+
},
|
|
222
|
+
required: ["agentId", "writeToken", "plan"],
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
name: "health",
|
|
227
|
+
description: "Check Memory01 service health (free). Returns service status, free tier info, plans.",
|
|
228
|
+
inputSchema: { type: "object", properties: {} },
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: "stats",
|
|
232
|
+
description: "Get global memory statistics (free). Returns total agents, entries, searches.",
|
|
233
|
+
inputSchema: { type: "object", properties: {} },
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
name: "sample",
|
|
237
|
+
description: "Get a free sample: store a demo memory and search it. Shows the shape of responses without paying.",
|
|
238
|
+
inputSchema: { type: "object", properties: {} },
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
};
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
245
|
+
const { name, arguments: args } = request.params;
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
switch (name) {
|
|
249
|
+
case "store": {
|
|
250
|
+
const { agentId, key, value, writeToken, sessionId, metadata } = args;
|
|
251
|
+
if (!agentId || !key || !value) {
|
|
252
|
+
throw new McpError(ErrorCode.InvalidParams, "agentId, key, and value are required");
|
|
253
|
+
}
|
|
254
|
+
if (key.length > 256) throw new McpError(ErrorCode.InvalidParams, "key max 256 chars");
|
|
255
|
+
if (value.length > 10240) throw new McpError(ErrorCode.InvalidParams, "value max 10KB");
|
|
256
|
+
if (metadata && JSON.stringify(metadata).length > 2048) throw new McpError(ErrorCode.InvalidParams, "metadata max 2KB");
|
|
257
|
+
|
|
258
|
+
const body = { agent_id: agentId, key, value };
|
|
259
|
+
if (writeToken) body.write_token = writeToken;
|
|
260
|
+
if (sessionId) body.session_id = sessionId;
|
|
261
|
+
if (metadata) body.metadata = metadata;
|
|
262
|
+
|
|
263
|
+
const result = await callFree("/api/memory/store", "POST", body);
|
|
264
|
+
if (result.status >= 400) {
|
|
265
|
+
throw new McpError(ErrorCode.InternalError, `API error: ${JSON.stringify(result.data)}`);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const r = result.data;
|
|
269
|
+
return {
|
|
270
|
+
content: [{
|
|
271
|
+
type: "text",
|
|
272
|
+
text: JSON.stringify({
|
|
273
|
+
ok: r.ok,
|
|
274
|
+
stored: r.stored,
|
|
275
|
+
write_token: r.write_token,
|
|
276
|
+
message: r.message,
|
|
277
|
+
key: r.key,
|
|
278
|
+
stored_at: r.stored_at,
|
|
279
|
+
updated_at: r.updated_at,
|
|
280
|
+
}, null, 2),
|
|
281
|
+
}],
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
case "search": {
|
|
286
|
+
const { agentId, query, writeToken, topK = 10, sessionId, cursor } = args;
|
|
287
|
+
if (!agentId || !writeToken) {
|
|
288
|
+
throw new McpError(ErrorCode.InvalidParams, "agentId and writeToken are required");
|
|
289
|
+
}
|
|
290
|
+
if (query && query.length > 500) throw new McpError(ErrorCode.InvalidParams, "query max 500 chars");
|
|
291
|
+
|
|
292
|
+
const body = { agent_id: agentId, write_token: writeToken, top_k: topK };
|
|
293
|
+
if (query) body.query = query;
|
|
294
|
+
if (sessionId) body.session_id = sessionId;
|
|
295
|
+
if (cursor) body.cursor = cursor;
|
|
296
|
+
|
|
297
|
+
// Try free first
|
|
298
|
+
const freeResult = await callFree("/api/memory/search", "POST", body);
|
|
299
|
+
|
|
300
|
+
if (freeResult.status === 402) {
|
|
301
|
+
// Free tier exhausted, pay
|
|
302
|
+
const paidResult = await payAndRetry("/api/memory/search", body, "0.01");
|
|
303
|
+
if (paidResult.status >= 400) {
|
|
304
|
+
throw new McpError(ErrorCode.InternalError, `API error: ${JSON.stringify(paidResult.data)}`);
|
|
305
|
+
}
|
|
306
|
+
const r = paidResult.data;
|
|
307
|
+
return {
|
|
308
|
+
content: [{
|
|
309
|
+
type: "text",
|
|
310
|
+
text: JSON.stringify({
|
|
311
|
+
results: r.results,
|
|
312
|
+
free_tier: r.free_tier,
|
|
313
|
+
tier: r.tier,
|
|
314
|
+
searched_at: r.searched_at,
|
|
315
|
+
next_cursor: r.next_cursor,
|
|
316
|
+
cursor_expires_in: r.cursor_expires_in,
|
|
317
|
+
}, null, 2),
|
|
318
|
+
}],
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (freeResult.status >= 400) {
|
|
323
|
+
throw new McpError(ErrorCode.InternalError, `API error: ${JSON.stringify(freeResult.data)}`);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const r = freeResult.data;
|
|
327
|
+
return {
|
|
328
|
+
content: [{
|
|
329
|
+
type: "text",
|
|
330
|
+
text: JSON.stringify({
|
|
331
|
+
results: r.results,
|
|
332
|
+
free_tier: r.free_tier,
|
|
333
|
+
tier: r.tier,
|
|
334
|
+
searched_at: r.searched_at,
|
|
335
|
+
next_cursor: r.next_cursor,
|
|
336
|
+
cursor_expires_in: r.cursor_expires_in,
|
|
337
|
+
}, null, 2),
|
|
338
|
+
}],
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
case "subscribe": {
|
|
343
|
+
const { agentId, writeToken, plan } = args;
|
|
344
|
+
if (!agentId || !writeToken || !plan) {
|
|
345
|
+
throw new McpError(ErrorCode.InvalidParams, "agentId, writeToken, and plan are required");
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const body = { agent_id: agentId, write_token: writeToken, plan };
|
|
349
|
+
const priceMap = { starter: "2.00", pro: "9.00", enterprise: "20.00" };
|
|
350
|
+
const paidResult = await payAndRetry("/api/memory/subscribe", body, priceMap[plan] || "2.00");
|
|
351
|
+
|
|
352
|
+
if (paidResult.status >= 400) {
|
|
353
|
+
throw new McpError(ErrorCode.InternalError, `API error: ${JSON.stringify(paidResult.data)}`);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return {
|
|
357
|
+
content: [{
|
|
358
|
+
type: "text",
|
|
359
|
+
text: JSON.stringify(paidResult.data, null, 2),
|
|
360
|
+
}],
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
case "health": {
|
|
365
|
+
const result = await callFree("/api/health");
|
|
366
|
+
return {
|
|
367
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
case "stats": {
|
|
372
|
+
const result = await callFree("/api/memory/stats");
|
|
373
|
+
return {
|
|
374
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
case "sample": {
|
|
379
|
+
// Store a demo memory, then search it
|
|
380
|
+
const storeResult = await callFree("/api/memory/store", "POST", {
|
|
381
|
+
agent_id: "sample-agent",
|
|
382
|
+
key: "demo",
|
|
383
|
+
value: "This is a sample memory for testing Memory01 service",
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
const searchResult = await callFree("/api/memory/search", "POST", {
|
|
387
|
+
agent_id: "sample-agent",
|
|
388
|
+
write_token: storeResult.data.write_token,
|
|
389
|
+
query: "sample memory",
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
return {
|
|
393
|
+
content: [{
|
|
394
|
+
type: "text",
|
|
395
|
+
text: JSON.stringify({
|
|
396
|
+
store: storeResult.data,
|
|
397
|
+
search: searchResult.data,
|
|
398
|
+
}, null, 2),
|
|
399
|
+
}],
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
default:
|
|
404
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
405
|
+
}
|
|
406
|
+
} catch (error) {
|
|
407
|
+
if (error instanceof McpError) throw error;
|
|
408
|
+
console.error(`Tool ${name} error:`, error);
|
|
409
|
+
throw new McpError(ErrorCode.InternalError, String(error));
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
async function main() {
|
|
414
|
+
const transport = new StdioServerTransport();
|
|
415
|
+
await server.connect(transport);
|
|
416
|
+
console.error("memory-agent-mcp running on stdio");
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
main().catch((err) => {
|
|
420
|
+
console.error("Fatal error:", err);
|
|
421
|
+
process.exit(1);
|
|
422
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memory-agent-mcp",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "MCP wrapper for Memory01 agentic memory service - free to store, paid to search",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"memory-mcp": "index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node index.js",
|
|
12
|
+
"test": "node test.js"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"mcp",
|
|
16
|
+
"memory",
|
|
17
|
+
"agent",
|
|
18
|
+
"x402",
|
|
19
|
+
"ai",
|
|
20
|
+
"base",
|
|
21
|
+
"storage"
|
|
22
|
+
],
|
|
23
|
+
"author": "node01.org",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
27
|
+
"viem": "^2.57.16"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=20.0.0"
|
|
31
|
+
}
|
|
32
|
+
}
|