memvid-mcp-server 1.0.0 → 1.0.2
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/dist/index.js +229 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -4,7 +4,235 @@
|
|
|
4
4
|
import"dotenv/config";
|
|
5
5
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
// src/tools/definitions.ts
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
var ProjectNameSchema = z.string().describe("Unique identifier for the project");
|
|
11
|
+
var CreateMemorySchema = z.object({
|
|
12
|
+
project_name: ProjectNameSchema
|
|
13
|
+
});
|
|
14
|
+
var AddContentSchema = z.object({
|
|
15
|
+
project_name: ProjectNameSchema,
|
|
16
|
+
content: z.string().describe("The text content to store"),
|
|
17
|
+
title: z.string().optional().describe("Title of the document"),
|
|
18
|
+
metadata: z.record(z.string(), z.any()).optional().describe("Key-value pairs for metadata"),
|
|
19
|
+
tags: z.array(z.string()).optional().describe("Array of string tags"),
|
|
20
|
+
enable_embedding: z.boolean().default(false).optional().describe("Enable vector embedding generation (requires AI provider setup)")
|
|
21
|
+
});
|
|
22
|
+
var SearchMemorySchema = z.object({
|
|
23
|
+
project_name: ProjectNameSchema,
|
|
24
|
+
query: z.string().describe("The search query"),
|
|
25
|
+
limit: z.number().default(5).optional(),
|
|
26
|
+
mode: z.enum(["auto", "lex", "sem"]).default("auto").optional().describe("Search mode: 'lex' (keyword), 'sem' (semantic/vector), 'auto' (smart selection)")
|
|
27
|
+
});
|
|
28
|
+
var AskMemorySchema = z.object({
|
|
29
|
+
project_name: ProjectNameSchema,
|
|
30
|
+
question: z.string().describe("The natural language question to ask")
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// src/memory_manager.ts
|
|
34
|
+
import { create, use } from "@memvid/sdk";
|
|
35
|
+
import path from "path";
|
|
36
|
+
import fs from "fs";
|
|
37
|
+
import os from "os";
|
|
38
|
+
|
|
39
|
+
class MemoryManager {
|
|
40
|
+
static instance;
|
|
41
|
+
memories;
|
|
42
|
+
storageDir;
|
|
43
|
+
constructor() {
|
|
44
|
+
this.memories = new Map;
|
|
45
|
+
this.storageDir = path.join(os.homedir(), ".memvid_mcp");
|
|
46
|
+
this.ensureStorageDir();
|
|
47
|
+
}
|
|
48
|
+
static getInstance() {
|
|
49
|
+
if (!MemoryManager.instance) {
|
|
50
|
+
MemoryManager.instance = new MemoryManager;
|
|
51
|
+
}
|
|
52
|
+
return MemoryManager.instance;
|
|
53
|
+
}
|
|
54
|
+
ensureStorageDir() {
|
|
55
|
+
if (!fs.existsSync(this.storageDir)) {
|
|
56
|
+
fs.mkdirSync(this.storageDir, { recursive: true });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
getStoragePath(projectName) {
|
|
60
|
+
const safeName = projectName.replace(/[^a-z0-9_-]/gi, "_");
|
|
61
|
+
return path.join(this.storageDir, `${safeName}.mv2`);
|
|
62
|
+
}
|
|
63
|
+
async getMemory(projectName) {
|
|
64
|
+
if (this.memories.has(projectName)) {
|
|
65
|
+
return this.memories.get(projectName);
|
|
66
|
+
}
|
|
67
|
+
const memoryPath = this.getStoragePath(projectName);
|
|
68
|
+
console.error(`[Memvid] Loading memory: ${memoryPath}`);
|
|
69
|
+
let mem;
|
|
70
|
+
try {
|
|
71
|
+
if (!fs.existsSync(memoryPath)) {
|
|
72
|
+
mem = await create(memoryPath);
|
|
73
|
+
} else {
|
|
74
|
+
mem = await use("basic", memoryPath);
|
|
75
|
+
}
|
|
76
|
+
this.memories.set(projectName, mem);
|
|
77
|
+
return mem;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error(`[Memvid] Failed to load memory for ${projectName}:`, error);
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/tools/create.ts
|
|
86
|
+
function registerCreateMemory(server) {
|
|
87
|
+
server.tool("create_or_open_memory", "Initialize or open a Memvid memory file for a specific project.", CreateMemorySchema.shape, async ({ project_name }) => {
|
|
88
|
+
const manager = MemoryManager.getInstance();
|
|
89
|
+
const path2 = manager.getStoragePath(project_name);
|
|
90
|
+
await manager.getMemory(project_name);
|
|
91
|
+
return {
|
|
92
|
+
content: [
|
|
93
|
+
{
|
|
94
|
+
type: "text",
|
|
95
|
+
text: `Successfully initialized memory for project '${project_name}' at ${path2}`
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/tools/add.ts
|
|
103
|
+
function registerAddContent(server) {
|
|
104
|
+
server.tool("add_content", "Add a text document/content to the project's memory.", AddContentSchema.shape, async (args) => {
|
|
105
|
+
const manager = MemoryManager.getInstance();
|
|
106
|
+
const mem = await manager.getMemory(args.project_name);
|
|
107
|
+
await mem.put({
|
|
108
|
+
text: args.content,
|
|
109
|
+
title: args.title,
|
|
110
|
+
metadata: args.metadata,
|
|
111
|
+
labels: args.tags,
|
|
112
|
+
enableEmbedding: args.enable_embedding
|
|
113
|
+
});
|
|
114
|
+
return {
|
|
115
|
+
content: [
|
|
116
|
+
{
|
|
117
|
+
type: "text",
|
|
118
|
+
text: `Added content to '${args.project_name}' memory.`
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/tools/search.ts
|
|
126
|
+
function registerSearchMemory(server) {
|
|
127
|
+
server.tool("search_memory", "Search for content in the project's memory using semantic search.", SearchMemorySchema.shape, async (args) => {
|
|
128
|
+
const manager = MemoryManager.getInstance();
|
|
129
|
+
const mem = await manager.getMemory(args.project_name);
|
|
130
|
+
const results = await mem.find(args.query, {
|
|
131
|
+
k: args.limit,
|
|
132
|
+
mode: args.mode
|
|
133
|
+
});
|
|
134
|
+
const hits = results.hits || [];
|
|
135
|
+
const formatted = hits.map((hit) => {
|
|
136
|
+
return `[Title: ${hit.title || "Untitled"}]
|
|
137
|
+
${hit.snippet || hit.text}
|
|
138
|
+
(Score: ${hit.score})`;
|
|
139
|
+
}).join(`
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
`);
|
|
144
|
+
return {
|
|
145
|
+
content: [
|
|
146
|
+
{
|
|
147
|
+
type: "text",
|
|
148
|
+
text: formatted || "No results found."
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// src/tools/ask.ts
|
|
156
|
+
function registerAskMemory(server) {
|
|
157
|
+
server.tool("ask_memory", "Ask a natural language question about the content in the project's memory.", AskMemorySchema.shape, async (args) => {
|
|
158
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
159
|
+
if (!apiKey) {
|
|
160
|
+
return {
|
|
161
|
+
content: [
|
|
162
|
+
{
|
|
163
|
+
type: "text",
|
|
164
|
+
text: "Error: OPENAI_API_KEY environment variable is not set."
|
|
165
|
+
}
|
|
166
|
+
],
|
|
167
|
+
isError: true
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
const manager = MemoryManager.getInstance();
|
|
172
|
+
const mem = await manager.getMemory(args.project_name);
|
|
173
|
+
const answer = await mem.ask(args.question, {
|
|
174
|
+
model: "gpt-4o",
|
|
175
|
+
modelApiKey: apiKey
|
|
176
|
+
});
|
|
177
|
+
const answerText = answer.text || answer.answer || JSON.stringify(answer);
|
|
178
|
+
return {
|
|
179
|
+
content: [
|
|
180
|
+
{
|
|
181
|
+
type: "text",
|
|
182
|
+
text: typeof answerText === "string" ? answerText : JSON.stringify(answerText)
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
};
|
|
186
|
+
} catch (e) {
|
|
187
|
+
return {
|
|
188
|
+
content: [
|
|
189
|
+
{
|
|
190
|
+
type: "text",
|
|
191
|
+
text: `Error asking question: ${e.message}`
|
|
192
|
+
}
|
|
193
|
+
],
|
|
194
|
+
isError: true
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// src/tools/context.ts
|
|
201
|
+
import { z as z2 } from "zod";
|
|
202
|
+
import path2 from "path";
|
|
203
|
+
var GetProjectContextSchema = z2.object({});
|
|
204
|
+
async function getProjectContext() {
|
|
205
|
+
const cwd = process.cwd();
|
|
206
|
+
const suggested_project_name = path2.basename(cwd);
|
|
207
|
+
return {
|
|
208
|
+
content: [
|
|
209
|
+
{
|
|
210
|
+
type: "text",
|
|
211
|
+
text: JSON.stringify({
|
|
212
|
+
suggested_project_name,
|
|
213
|
+
cwd,
|
|
214
|
+
hint: "Use 'suggested_project_name' as the 'project_name' argument for other tools if you are unsure."
|
|
215
|
+
}, null, 2)
|
|
216
|
+
}
|
|
217
|
+
]
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/tools/index.ts
|
|
222
|
+
function registerAllTools(server) {
|
|
223
|
+
server.tool("memvid_get_project_context", "Get context about the current project (e.g. inferred project name from CWD) to help the agent decide which memory project to use.", GetProjectContextSchema.shape, async () => getProjectContext());
|
|
224
|
+
registerCreateMemory(server);
|
|
225
|
+
registerAddContent(server);
|
|
226
|
+
registerSearchMemory(server);
|
|
227
|
+
if (process.env.OPENAI_API_KEY) {
|
|
228
|
+
registerAskMemory(server);
|
|
229
|
+
console.error("AskMemory tool enabled (API key found).");
|
|
230
|
+
} else {
|
|
231
|
+
console.error("AskMemory tool disabled (no OPENAI_API_KEY found).");
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/index.ts
|
|
8
236
|
var server = new McpServer({
|
|
9
237
|
name: "memvid-mcp-server",
|
|
10
238
|
version: "1.0.0"
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "memvid-mcp-server",
|
|
3
3
|
"module": "index.ts",
|
|
4
4
|
"description": "MCP Server for Memvid",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.2",
|
|
6
6
|
"logo": "https://memvid.io/logo.png",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"mcp",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"dist"
|
|
30
30
|
],
|
|
31
31
|
"scripts": {
|
|
32
|
-
"build": "bun build ./src/index.ts --outdir ./dist --target node --external
|
|
32
|
+
"build": "bun build ./src/index.ts --outdir ./dist --target node --packages external",
|
|
33
33
|
"prepublishOnly": "bun run build"
|
|
34
34
|
},
|
|
35
35
|
"type": "module",
|