@t0ken.ai/memoryx-mcp-server 2.0.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.
- package/README.md +120 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +300 -0
- package/dist/index.js.map +1 -0
- package/package.json +41 -0
- package/src/index.ts +313 -0
- package/tsconfig.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# MemoryX MCP Server
|
|
2
|
+
|
|
3
|
+
MemoryX MCP Server 用于 Cursor、VS Code、Claude Desktop 等 MCP 客户端。
|
|
4
|
+
|
|
5
|
+
## 功能
|
|
6
|
+
|
|
7
|
+
- **save_memory**: 保存重要信息到记忆系统
|
|
8
|
+
- **search_memory**: 搜索历史记忆
|
|
9
|
+
- **get_account_info**: 获取账户信息
|
|
10
|
+
|
|
11
|
+
## 特点
|
|
12
|
+
|
|
13
|
+
- 本地 SQLite 队列存储
|
|
14
|
+
- 按 conversation 分组批量发送
|
|
15
|
+
- 自动重试机制
|
|
16
|
+
- 离线支持
|
|
17
|
+
|
|
18
|
+
## 安装
|
|
19
|
+
|
|
20
|
+
### 方式一:NPM 安装
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install -g @t0ken/memoryx-mcp-server
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 方式二:从源码安装
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
cd plugins/memoryx-mcp-server
|
|
30
|
+
npm install
|
|
31
|
+
npm run build
|
|
32
|
+
npm link
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 配置
|
|
36
|
+
|
|
37
|
+
### Cursor / VS Code
|
|
38
|
+
|
|
39
|
+
在 `~/.cursor/mcp.json` 或 VS Code 的 MCP 配置中添加:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"mcpServers": {
|
|
44
|
+
"memoryx": {
|
|
45
|
+
"command": "memoryx-mcp-server",
|
|
46
|
+
"env": {
|
|
47
|
+
"MEMORYX_API_KEY": "your_api_key_here",
|
|
48
|
+
"MEMORYX_URL": "https://t0ken.ai/api"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Claude Desktop
|
|
56
|
+
|
|
57
|
+
在 Claude Desktop 配置文件中添加:
|
|
58
|
+
|
|
59
|
+
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
60
|
+
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"mcpServers": {
|
|
65
|
+
"memoryx": {
|
|
66
|
+
"command": "memoryx-mcp-server",
|
|
67
|
+
"env": {
|
|
68
|
+
"MEMORYX_API_KEY": "your_api_key_here"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 使用
|
|
76
|
+
|
|
77
|
+
### 自动注册
|
|
78
|
+
|
|
79
|
+
如果没有提供 API Key,MCP Server 会自动注册并生成一个。
|
|
80
|
+
|
|
81
|
+
### 手动绑定
|
|
82
|
+
|
|
83
|
+
1. 访问 https://t0ken.ai/portal
|
|
84
|
+
2. 登录后复制 API Key
|
|
85
|
+
3. 配置到环境变量 `MEMORYX_API_KEY`
|
|
86
|
+
|
|
87
|
+
## 本地存储
|
|
88
|
+
|
|
89
|
+
数据存储在 `~/.memoryx/mcp-server/` 目录:
|
|
90
|
+
|
|
91
|
+
- `memoryx.db` - SQLite 数据库(消息队列)
|
|
92
|
+
- `mcp-server.log` - 日志文件
|
|
93
|
+
|
|
94
|
+
## 架构
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
98
|
+
│ MCP Server 架构 │
|
|
99
|
+
├─────────────────────────────────────────────────────────────┤
|
|
100
|
+
│ │
|
|
101
|
+
│ save_memory ──→ SQLite 本地队列 ──→ 定时批量发送 ──→ API │
|
|
102
|
+
│ │
|
|
103
|
+
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────┐ │
|
|
104
|
+
│ │ MCP Tools │───→│ send_queue │───→│ /conversations│ │
|
|
105
|
+
│ │ │ │ 表 │ │ /flush │ │
|
|
106
|
+
│ └─────────────┘ └──────────────┘ └───────────────┘ │
|
|
107
|
+
│ │
|
|
108
|
+
│ 特点: │
|
|
109
|
+
│ • 每条消息先存本地 SQLite │
|
|
110
|
+
│ • 按 conversation_id 分组 │
|
|
111
|
+
│ • 2 轮对话后触发发送 │
|
|
112
|
+
│ • 定时器每 5 秒检查队列 │
|
|
113
|
+
│ • 失败重试最多 5 次 │
|
|
114
|
+
│ │
|
|
115
|
+
└─────────────────────────────────────────────────────────────┘
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MemoryX MCP Server - Model Context Protocol server for MemoryX
|
|
4
|
+
*
|
|
5
|
+
* Powered by @t0ken.ai/memoryx-sdk
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - conversation preset (30k tokens / 5min idle)
|
|
9
|
+
* - Lazy SDK initialization
|
|
10
|
+
* - Automatic memory batching and retry
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;GASG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* MemoryX MCP Server - Model Context Protocol server for MemoryX
|
|
5
|
+
*
|
|
6
|
+
* Powered by @t0ken.ai/memoryx-sdk
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - conversation preset (30k tokens / 5min idle)
|
|
10
|
+
* - Lazy SDK initialization
|
|
11
|
+
* - Automatic memory batching and retry
|
|
12
|
+
*/
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
+
var ownKeys = function(o) {
|
|
31
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
+
var ar = [];
|
|
33
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
+
return ar;
|
|
35
|
+
};
|
|
36
|
+
return ownKeys(o);
|
|
37
|
+
};
|
|
38
|
+
return function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
})();
|
|
46
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
48
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
49
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
50
|
+
const path = __importStar(require("path"));
|
|
51
|
+
const os = __importStar(require("os"));
|
|
52
|
+
const DEFAULT_API_BASE = "https://t0ken.ai/api";
|
|
53
|
+
const PLUGIN_DIR = path.join(os.homedir(), ".memoryx", "mcp-server");
|
|
54
|
+
// Lazy-loaded SDK instance
|
|
55
|
+
let sdkInstance = null;
|
|
56
|
+
let sdkInitPromise = null;
|
|
57
|
+
function log(message) {
|
|
58
|
+
const timestamp = new Date().toISOString();
|
|
59
|
+
console.error(`[MemoryX MCP] ${timestamp} ${message}`);
|
|
60
|
+
}
|
|
61
|
+
async function getSDK() {
|
|
62
|
+
if (sdkInstance)
|
|
63
|
+
return sdkInstance;
|
|
64
|
+
if (sdkInitPromise)
|
|
65
|
+
return sdkInitPromise;
|
|
66
|
+
sdkInitPromise = (async () => {
|
|
67
|
+
// Dynamic import SDK
|
|
68
|
+
const { MemoryXSDK } = await Promise.resolve().then(() => __importStar(require("@t0ken.ai/memoryx-sdk")));
|
|
69
|
+
// Get env config
|
|
70
|
+
const envApiKey = process.env.MEMORYX_API_KEY || process.env.OPENMEMORYX_API_KEY;
|
|
71
|
+
const envApiUrl = process.env.MEMORYX_URL || process.env.OPENMEMORYX_URL;
|
|
72
|
+
// Use conversation preset: maxTokens: 30000, intervalMs: 300000 (5 min)
|
|
73
|
+
sdkInstance = new MemoryXSDK({
|
|
74
|
+
preset: 'conversation',
|
|
75
|
+
apiKey: envApiKey || undefined,
|
|
76
|
+
apiUrl: envApiUrl || DEFAULT_API_BASE,
|
|
77
|
+
autoRegister: !envApiKey,
|
|
78
|
+
agentType: 'mcp',
|
|
79
|
+
storageDir: PLUGIN_DIR
|
|
80
|
+
});
|
|
81
|
+
log("SDK initialized with conversation preset (30k tokens / 5min idle)");
|
|
82
|
+
return sdkInstance;
|
|
83
|
+
})();
|
|
84
|
+
return sdkInitPromise;
|
|
85
|
+
}
|
|
86
|
+
async function saveMemory(content, metadata = {}) {
|
|
87
|
+
if (!content || content.trim().length < 2) {
|
|
88
|
+
return { success: false, message: "Content too short", queued: 0 };
|
|
89
|
+
}
|
|
90
|
+
const skipPatterns = [
|
|
91
|
+
/^[好的ok谢谢嗯啊哈哈你好hihello拜拜再见]{1,5}$/i,
|
|
92
|
+
/^[??!!。,,\s]{1,10}$/
|
|
93
|
+
];
|
|
94
|
+
for (const pattern of skipPatterns) {
|
|
95
|
+
if (pattern.test(content.trim())) {
|
|
96
|
+
return { success: false, message: "Skipped: trivial content", queued: 0 };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
const sdk = await getSDK();
|
|
101
|
+
await sdk.addMemory(content.trim(), metadata);
|
|
102
|
+
const stats = await sdk.getQueueStats();
|
|
103
|
+
return {
|
|
104
|
+
success: true,
|
|
105
|
+
message: "Memory queued for processing",
|
|
106
|
+
queued: stats.messageCount
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
log(`saveMemory failed: ${e}`);
|
|
111
|
+
return { success: false, message: String(e), queued: 0 };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function searchMemory(query, limit = 5) {
|
|
115
|
+
if (!query || query.length < 2) {
|
|
116
|
+
return { memories: [], isLimited: false, remainingQuota: 0 };
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
const sdk = await getSDK();
|
|
120
|
+
const result = await sdk.search(query, limit);
|
|
121
|
+
return {
|
|
122
|
+
memories: (result.data || []).map((m) => ({
|
|
123
|
+
id: m.id,
|
|
124
|
+
content: m.memory || m.content,
|
|
125
|
+
category: m.category || "other",
|
|
126
|
+
score: m.score || 0.5
|
|
127
|
+
})),
|
|
128
|
+
isLimited: false,
|
|
129
|
+
remainingQuota: result.remaining_quota ?? -1
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
log(`searchMemory failed: ${e}`);
|
|
134
|
+
return { memories: [], isLimited: false, remainingQuota: 0 };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async function getAccountInfo() {
|
|
138
|
+
try {
|
|
139
|
+
const sdk = await getSDK();
|
|
140
|
+
const info = await sdk.getAccountInfo();
|
|
141
|
+
const stats = await sdk.getQueueStats();
|
|
142
|
+
return {
|
|
143
|
+
apiKey: info?.apiKey ? `${info.apiKey.slice(0, 8)}...` : null,
|
|
144
|
+
projectId: info?.projectId || "default",
|
|
145
|
+
userId: info?.userId || null,
|
|
146
|
+
queueLength: stats.messageCount
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
catch (e) {
|
|
150
|
+
log(`getAccountInfo failed: ${e}`);
|
|
151
|
+
return {
|
|
152
|
+
apiKey: null,
|
|
153
|
+
projectId: "default",
|
|
154
|
+
userId: null,
|
|
155
|
+
queueLength: 0
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const server = new index_js_1.Server({
|
|
160
|
+
name: "memoryx-mcp-server",
|
|
161
|
+
version: "2.0.0",
|
|
162
|
+
}, {
|
|
163
|
+
capabilities: {
|
|
164
|
+
tools: {},
|
|
165
|
+
resources: {},
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
169
|
+
return {
|
|
170
|
+
tools: [
|
|
171
|
+
{
|
|
172
|
+
name: "save_memory",
|
|
173
|
+
description: "保存重要信息到记忆系统。当用户提到偏好、习惯、项目信息、重要决定等值得记住的内容时调用。",
|
|
174
|
+
inputSchema: {
|
|
175
|
+
type: "object",
|
|
176
|
+
properties: {
|
|
177
|
+
content: {
|
|
178
|
+
type: "string",
|
|
179
|
+
description: "要记住的内容"
|
|
180
|
+
},
|
|
181
|
+
metadata: {
|
|
182
|
+
type: "object",
|
|
183
|
+
description: "可选的元数据,如分类、标签等"
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
required: ["content"]
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: "search_memory",
|
|
191
|
+
description: "搜索历史记忆。在回答用户问题前调用,获取相关的记忆上下文。",
|
|
192
|
+
inputSchema: {
|
|
193
|
+
type: "object",
|
|
194
|
+
properties: {
|
|
195
|
+
query: {
|
|
196
|
+
type: "string",
|
|
197
|
+
description: "搜索关键词或问题"
|
|
198
|
+
},
|
|
199
|
+
limit: {
|
|
200
|
+
type: "number",
|
|
201
|
+
description: "返回结果数量,默认5",
|
|
202
|
+
default: 5
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
required: ["query"]
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: "get_account_info",
|
|
210
|
+
description: "获取当前 MemoryX 账户信息,包括 API Key、Project ID 和队列状态。",
|
|
211
|
+
inputSchema: {
|
|
212
|
+
type: "object",
|
|
213
|
+
properties: {}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
};
|
|
218
|
+
});
|
|
219
|
+
server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
220
|
+
const { name, arguments: args } = request.params;
|
|
221
|
+
switch (name) {
|
|
222
|
+
case "save_memory": {
|
|
223
|
+
const content = args?.content;
|
|
224
|
+
const metadata = args?.metadata || {};
|
|
225
|
+
const result = await saveMemory(content, metadata);
|
|
226
|
+
return {
|
|
227
|
+
content: [
|
|
228
|
+
{
|
|
229
|
+
type: "text",
|
|
230
|
+
text: JSON.stringify(result, null, 2)
|
|
231
|
+
}
|
|
232
|
+
]
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
case "search_memory": {
|
|
236
|
+
const query = args?.query;
|
|
237
|
+
const limit = args?.limit || 5;
|
|
238
|
+
const result = await searchMemory(query, limit);
|
|
239
|
+
return {
|
|
240
|
+
content: [
|
|
241
|
+
{
|
|
242
|
+
type: "text",
|
|
243
|
+
text: JSON.stringify(result, null, 2)
|
|
244
|
+
}
|
|
245
|
+
]
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
case "get_account_info": {
|
|
249
|
+
const result = await getAccountInfo();
|
|
250
|
+
return {
|
|
251
|
+
content: [
|
|
252
|
+
{
|
|
253
|
+
type: "text",
|
|
254
|
+
text: JSON.stringify(result, null, 2)
|
|
255
|
+
}
|
|
256
|
+
]
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
default:
|
|
260
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
server.setRequestHandler(types_js_1.ListResourcesRequestSchema, async () => {
|
|
264
|
+
return {
|
|
265
|
+
resources: [
|
|
266
|
+
{
|
|
267
|
+
uri: "memoryx://status",
|
|
268
|
+
name: "MemoryX Status",
|
|
269
|
+
description: "当前 MemoryX 连接状态和队列信息",
|
|
270
|
+
mimeType: "application/json"
|
|
271
|
+
}
|
|
272
|
+
]
|
|
273
|
+
};
|
|
274
|
+
});
|
|
275
|
+
server.setRequestHandler(types_js_1.ReadResourceRequestSchema, async (request) => {
|
|
276
|
+
const { uri } = request.params;
|
|
277
|
+
if (uri === "memoryx://status") {
|
|
278
|
+
const status = await getAccountInfo();
|
|
279
|
+
return {
|
|
280
|
+
contents: [
|
|
281
|
+
{
|
|
282
|
+
uri,
|
|
283
|
+
mimeType: "application/json",
|
|
284
|
+
text: JSON.stringify(status, null, 2)
|
|
285
|
+
}
|
|
286
|
+
]
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
290
|
+
});
|
|
291
|
+
async function main() {
|
|
292
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
293
|
+
await server.connect(transport);
|
|
294
|
+
log("MemoryX MCP Server v2.0.0 started (powered by SDK)");
|
|
295
|
+
}
|
|
296
|
+
main().catch((error) => {
|
|
297
|
+
console.error("Fatal error:", error);
|
|
298
|
+
process.exit(1);
|
|
299
|
+
});
|
|
300
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@t0ken.ai/memoryx-mcp-server",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "MemoryX MCP Server for Cursor/VS Code/Claude Desktop (powered by @t0ken.ai/memoryx-sdk)",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"memoryx-mcp-server": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"start": "node dist/index.js",
|
|
12
|
+
"dev": "ts-node src/index.ts"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"mcp",
|
|
16
|
+
"memory",
|
|
17
|
+
"ai",
|
|
18
|
+
"llm",
|
|
19
|
+
"cursor",
|
|
20
|
+
"vscode"
|
|
21
|
+
],
|
|
22
|
+
"author": "MemoryX Team",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
26
|
+
"@t0ken.ai/memoryx-sdk": "^1.0.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^20.0.0",
|
|
30
|
+
"ts-node": "^10.9.0",
|
|
31
|
+
"typescript": "^5.0.0"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18.0.0"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/t0ken-ai/MemoryX.git",
|
|
39
|
+
"directory": "plugins/memoryx-mcp-server"
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MemoryX MCP Server - Model Context Protocol server for MemoryX
|
|
5
|
+
*
|
|
6
|
+
* Powered by @t0ken.ai/memoryx-sdk
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - conversation preset (30k tokens / 5min idle)
|
|
10
|
+
* - Lazy SDK initialization
|
|
11
|
+
* - Automatic memory batching and retry
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
15
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
16
|
+
import {
|
|
17
|
+
CallToolRequestSchema,
|
|
18
|
+
ListToolsRequestSchema,
|
|
19
|
+
ListResourcesRequestSchema,
|
|
20
|
+
ReadResourceRequestSchema,
|
|
21
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
22
|
+
import * as path from "path";
|
|
23
|
+
import * as os from "os";
|
|
24
|
+
|
|
25
|
+
const DEFAULT_API_BASE = "https://t0ken.ai/api";
|
|
26
|
+
const PLUGIN_DIR = path.join(os.homedir(), ".memoryx", "mcp-server");
|
|
27
|
+
|
|
28
|
+
// Lazy-loaded SDK instance
|
|
29
|
+
let sdkInstance: any = null;
|
|
30
|
+
let sdkInitPromise: Promise<any> | null = null;
|
|
31
|
+
|
|
32
|
+
function log(message: string): void {
|
|
33
|
+
const timestamp = new Date().toISOString();
|
|
34
|
+
console.error(`[MemoryX MCP] ${timestamp} ${message}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function getSDK(): Promise<any> {
|
|
38
|
+
if (sdkInstance) return sdkInstance;
|
|
39
|
+
|
|
40
|
+
if (sdkInitPromise) return sdkInitPromise;
|
|
41
|
+
|
|
42
|
+
sdkInitPromise = (async () => {
|
|
43
|
+
// Dynamic import SDK
|
|
44
|
+
const { MemoryXSDK } = await import("@t0ken.ai/memoryx-sdk");
|
|
45
|
+
|
|
46
|
+
// Get env config
|
|
47
|
+
const envApiKey = process.env.MEMORYX_API_KEY || process.env.OPENMEMORYX_API_KEY;
|
|
48
|
+
const envApiUrl = process.env.MEMORYX_URL || process.env.OPENMEMORYX_URL;
|
|
49
|
+
|
|
50
|
+
// Use conversation preset: maxTokens: 30000, intervalMs: 300000 (5 min)
|
|
51
|
+
sdkInstance = new MemoryXSDK({
|
|
52
|
+
preset: 'conversation',
|
|
53
|
+
apiKey: envApiKey || undefined,
|
|
54
|
+
apiUrl: envApiUrl || DEFAULT_API_BASE,
|
|
55
|
+
autoRegister: !envApiKey,
|
|
56
|
+
agentType: 'mcp',
|
|
57
|
+
storageDir: PLUGIN_DIR
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
log("SDK initialized with conversation preset (30k tokens / 5min idle)");
|
|
61
|
+
return sdkInstance;
|
|
62
|
+
})();
|
|
63
|
+
|
|
64
|
+
return sdkInitPromise;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function saveMemory(content: string, metadata: Record<string, any> = {}): Promise<{ success: boolean; message: string; queued: number }> {
|
|
68
|
+
if (!content || content.trim().length < 2) {
|
|
69
|
+
return { success: false, message: "Content too short", queued: 0 };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const skipPatterns = [
|
|
73
|
+
/^[好的ok谢谢嗯啊哈哈你好hihello拜拜再见]{1,5}$/i,
|
|
74
|
+
/^[??!!。,,\s]{1,10}$/
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
for (const pattern of skipPatterns) {
|
|
78
|
+
if (pattern.test(content.trim())) {
|
|
79
|
+
return { success: false, message: "Skipped: trivial content", queued: 0 };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
const sdk = await getSDK();
|
|
85
|
+
await sdk.addMemory(content.trim(), metadata);
|
|
86
|
+
const stats = await sdk.getQueueStats();
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
success: true,
|
|
90
|
+
message: "Memory queued for processing",
|
|
91
|
+
queued: stats.messageCount
|
|
92
|
+
};
|
|
93
|
+
} catch (e) {
|
|
94
|
+
log(`saveMemory failed: ${e}`);
|
|
95
|
+
return { success: false, message: String(e), queued: 0 };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function searchMemory(query: string, limit: number = 5): Promise<{
|
|
100
|
+
memories: any[];
|
|
101
|
+
isLimited: boolean;
|
|
102
|
+
remainingQuota: number;
|
|
103
|
+
upgradeHint?: string;
|
|
104
|
+
}> {
|
|
105
|
+
if (!query || query.length < 2) {
|
|
106
|
+
return { memories: [], isLimited: false, remainingQuota: 0 };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const sdk = await getSDK();
|
|
111
|
+
const result = await sdk.search(query, limit);
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
memories: (result.data || []).map((m: any) => ({
|
|
115
|
+
id: m.id,
|
|
116
|
+
content: m.memory || m.content,
|
|
117
|
+
category: m.category || "other",
|
|
118
|
+
score: m.score || 0.5
|
|
119
|
+
})),
|
|
120
|
+
isLimited: false,
|
|
121
|
+
remainingQuota: result.remaining_quota ?? -1
|
|
122
|
+
};
|
|
123
|
+
} catch (e) {
|
|
124
|
+
log(`searchMemory failed: ${e}`);
|
|
125
|
+
return { memories: [], isLimited: false, remainingQuota: 0 };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function getAccountInfo(): Promise<{
|
|
130
|
+
apiKey: string | null;
|
|
131
|
+
projectId: string;
|
|
132
|
+
userId: string | null;
|
|
133
|
+
queueLength: number;
|
|
134
|
+
}> {
|
|
135
|
+
try {
|
|
136
|
+
const sdk = await getSDK();
|
|
137
|
+
const info = await sdk.getAccountInfo();
|
|
138
|
+
const stats = await sdk.getQueueStats();
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
apiKey: info?.apiKey ? `${info.apiKey.slice(0, 8)}...` : null,
|
|
142
|
+
projectId: info?.projectId || "default",
|
|
143
|
+
userId: info?.userId || null,
|
|
144
|
+
queueLength: stats.messageCount
|
|
145
|
+
};
|
|
146
|
+
} catch (e) {
|
|
147
|
+
log(`getAccountInfo failed: ${e}`);
|
|
148
|
+
return {
|
|
149
|
+
apiKey: null,
|
|
150
|
+
projectId: "default",
|
|
151
|
+
userId: null,
|
|
152
|
+
queueLength: 0
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const server = new Server(
|
|
158
|
+
{
|
|
159
|
+
name: "memoryx-mcp-server",
|
|
160
|
+
version: "2.0.0",
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
capabilities: {
|
|
164
|
+
tools: {},
|
|
165
|
+
resources: {},
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
171
|
+
return {
|
|
172
|
+
tools: [
|
|
173
|
+
{
|
|
174
|
+
name: "save_memory",
|
|
175
|
+
description: "保存重要信息到记忆系统。当用户提到偏好、习惯、项目信息、重要决定等值得记住的内容时调用。",
|
|
176
|
+
inputSchema: {
|
|
177
|
+
type: "object",
|
|
178
|
+
properties: {
|
|
179
|
+
content: {
|
|
180
|
+
type: "string",
|
|
181
|
+
description: "要记住的内容"
|
|
182
|
+
},
|
|
183
|
+
metadata: {
|
|
184
|
+
type: "object",
|
|
185
|
+
description: "可选的元数据,如分类、标签等"
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
required: ["content"]
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: "search_memory",
|
|
193
|
+
description: "搜索历史记忆。在回答用户问题前调用,获取相关的记忆上下文。",
|
|
194
|
+
inputSchema: {
|
|
195
|
+
type: "object",
|
|
196
|
+
properties: {
|
|
197
|
+
query: {
|
|
198
|
+
type: "string",
|
|
199
|
+
description: "搜索关键词或问题"
|
|
200
|
+
},
|
|
201
|
+
limit: {
|
|
202
|
+
type: "number",
|
|
203
|
+
description: "返回结果数量,默认5",
|
|
204
|
+
default: 5
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
required: ["query"]
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
name: "get_account_info",
|
|
212
|
+
description: "获取当前 MemoryX 账户信息,包括 API Key、Project ID 和队列状态。",
|
|
213
|
+
inputSchema: {
|
|
214
|
+
type: "object",
|
|
215
|
+
properties: {}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
};
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
223
|
+
const { name, arguments: args } = request.params;
|
|
224
|
+
|
|
225
|
+
switch (name) {
|
|
226
|
+
case "save_memory": {
|
|
227
|
+
const content = args?.content as string;
|
|
228
|
+
const metadata = args?.metadata as Record<string, any> || {};
|
|
229
|
+
const result = await saveMemory(content, metadata);
|
|
230
|
+
return {
|
|
231
|
+
content: [
|
|
232
|
+
{
|
|
233
|
+
type: "text",
|
|
234
|
+
text: JSON.stringify(result, null, 2)
|
|
235
|
+
}
|
|
236
|
+
]
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
case "search_memory": {
|
|
241
|
+
const query = args?.query as string;
|
|
242
|
+
const limit = (args?.limit as number) || 5;
|
|
243
|
+
const result = await searchMemory(query, limit);
|
|
244
|
+
return {
|
|
245
|
+
content: [
|
|
246
|
+
{
|
|
247
|
+
type: "text",
|
|
248
|
+
text: JSON.stringify(result, null, 2)
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
case "get_account_info": {
|
|
255
|
+
const result = await getAccountInfo();
|
|
256
|
+
return {
|
|
257
|
+
content: [
|
|
258
|
+
{
|
|
259
|
+
type: "text",
|
|
260
|
+
text: JSON.stringify(result, null, 2)
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
default:
|
|
267
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
272
|
+
return {
|
|
273
|
+
resources: [
|
|
274
|
+
{
|
|
275
|
+
uri: "memoryx://status",
|
|
276
|
+
name: "MemoryX Status",
|
|
277
|
+
description: "当前 MemoryX 连接状态和队列信息",
|
|
278
|
+
mimeType: "application/json"
|
|
279
|
+
}
|
|
280
|
+
]
|
|
281
|
+
};
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
285
|
+
const { uri } = request.params;
|
|
286
|
+
|
|
287
|
+
if (uri === "memoryx://status") {
|
|
288
|
+
const status = await getAccountInfo();
|
|
289
|
+
return {
|
|
290
|
+
contents: [
|
|
291
|
+
{
|
|
292
|
+
uri,
|
|
293
|
+
mimeType: "application/json",
|
|
294
|
+
text: JSON.stringify(status, null, 2)
|
|
295
|
+
}
|
|
296
|
+
]
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
async function main() {
|
|
304
|
+
const transport = new StdioServerTransport();
|
|
305
|
+
await server.connect(transport);
|
|
306
|
+
|
|
307
|
+
log("MemoryX MCP Server v2.0.0 started (powered by SDK)");
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
main().catch((error) => {
|
|
311
|
+
console.error("Fatal error:", error);
|
|
312
|
+
process.exit(1);
|
|
313
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "dist"]
|
|
19
|
+
}
|