@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 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
@@ -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
+ }