@mnemoverse/mcp-memory-server 0.1.0 → 0.3.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/dist/index.js CHANGED
@@ -4,6 +4,10 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
4
4
  import { z } from "zod";
5
5
  const API_URL = process.env.MNEMOVERSE_API_URL || "https://core.mnemoverse.com/api/v1";
6
6
  const API_KEY = process.env.MNEMOVERSE_API_KEY || "";
7
+ // Hard cap on tool result size — required by Claude Connectors Directory
8
+ // (https://support.claude.com/en/articles/12922490-remote-mcp-server-submission-guide).
9
+ // Approximate token count = chars / 4. Cap at 24,000 tokens to leave headroom under the 25K limit.
10
+ const MAX_RESULT_CHARS = 24_000 * 4;
7
11
  if (!API_KEY) {
8
12
  console.error("Error: MNEMOVERSE_API_KEY environment variable is required.\n" +
9
13
  "Get your free key at https://console.mnemoverse.com");
@@ -24,26 +28,47 @@ async function apiFetch(path, options = {}) {
24
28
  }
25
29
  return res.json();
26
30
  }
31
+ /**
32
+ * Truncate a result string to MAX_RESULT_CHARS, appending a notice if truncated.
33
+ * Required by Claude Connectors Directory submission policy.
34
+ */
35
+ function capResult(text) {
36
+ if (text.length <= MAX_RESULT_CHARS)
37
+ return text;
38
+ const truncated = text.slice(0, MAX_RESULT_CHARS - 200);
39
+ return (truncated +
40
+ `\n\n[…truncated to fit 25K token limit. Use a more specific query or smaller top_k to see all results.]`);
41
+ }
27
42
  // --- Server setup ---
28
43
  const server = new McpServer({
29
44
  name: "mnemoverse-memory",
30
- version: "0.1.0",
45
+ version: "0.3.0",
31
46
  });
32
47
  // --- Tool: memory_write ---
33
- server.tool("memory_write", "Store a memory — insight, pattern, preference, or fact. Persists across sessions. Use this when the user teaches you something worth remembering, or when you learn a lesson from a task.", {
34
- content: z
35
- .string()
36
- .min(1)
37
- .max(10000)
38
- .describe("The memory to store — what happened, what was learned"),
39
- concepts: z
40
- .array(z.string())
41
- .optional()
42
- .describe("Key concepts for linking related memories (e.g. ['deploy', 'friday', 'staging'])"),
43
- domain: z
44
- .string()
45
- .optional()
46
- .describe("Namespace to organize memories (e.g. 'engineering', 'user:alice', 'project:acme')"),
48
+ server.registerTool("memory_write", {
49
+ description: "Store a memory that should persist across sessions — preferences, decisions, lessons learned, project facts, people and roles. Memories you store are also accessible from Claude, ChatGPT, Cursor, VS Code, and any other AI tool the user connects to Mnemoverse — write once, recall everywhere. Call this PROACTIVELY whenever the user states a preference, makes a decision, or you learn something important. Don't wait to be asked — if it's worth remembering, store it now.",
50
+ inputSchema: {
51
+ content: z
52
+ .string()
53
+ .min(1)
54
+ .max(10000)
55
+ .describe("The memory to store — what happened, what was learned"),
56
+ concepts: z
57
+ .array(z.string())
58
+ .optional()
59
+ .describe("Key concepts for linking related memories (e.g. ['deploy', 'friday', 'staging'])"),
60
+ domain: z
61
+ .string()
62
+ .optional()
63
+ .describe("Namespace to organize memories (e.g. 'engineering', 'user:alice', 'project:acme')"),
64
+ },
65
+ annotations: {
66
+ title: "Store Memory",
67
+ readOnlyHint: false,
68
+ destructiveHint: false,
69
+ idempotentHint: false,
70
+ openWorldHint: true,
71
+ },
47
72
  }, async ({ content, concepts, domain }) => {
48
73
  const result = await apiFetch("/memory/write", {
49
74
  method: "POST",
@@ -74,23 +99,33 @@ server.tool("memory_write", "Store a memory — insight, pattern, preference, or
74
99
  };
75
100
  });
76
101
  // --- Tool: memory_read ---
77
- server.tool("memory_read", "Search memories by natural language query. Returns the most relevant stored memories. Use this before starting a task to check if you already know something about it.", {
78
- query: z
79
- .string()
80
- .min(1)
81
- .max(5000)
82
- .describe("Natural language query — what are you looking for?"),
83
- top_k: z
84
- .number()
85
- .int()
86
- .min(1)
87
- .max(50)
88
- .optional()
89
- .describe("Max results to return (default: 5)"),
90
- domain: z
91
- .string()
92
- .optional()
93
- .describe("Filter by domain namespace"),
102
+ server.registerTool("memory_read", {
103
+ description: "ALWAYS call this tool first when the user asks a question about preferences, past decisions, project setup, people, or anything that might have been discussed before. This is your long-term memory — it persists across sessions and tools (Claude, ChatGPT, Cursor, VS Code, and any other AI tool the user connects). Search by natural language query. If you have any doubt whether you know something — check memory first.",
104
+ inputSchema: {
105
+ query: z
106
+ .string()
107
+ .min(1)
108
+ .max(5000)
109
+ .describe("Natural language query — what are you looking for?"),
110
+ top_k: z
111
+ .number()
112
+ .int()
113
+ .min(1)
114
+ .max(50)
115
+ .optional()
116
+ .describe("Max results to return (default: 5)"),
117
+ domain: z
118
+ .string()
119
+ .optional()
120
+ .describe("Filter by domain namespace"),
121
+ },
122
+ annotations: {
123
+ title: "Search Memories",
124
+ readOnlyHint: true,
125
+ destructiveHint: false,
126
+ idempotentHint: true,
127
+ openWorldHint: true,
128
+ },
94
129
  }, async ({ query, top_k, domain }) => {
95
130
  const result = await apiFetch("/memory/read", {
96
131
  method: "POST",
@@ -113,26 +148,37 @@ server.tool("memory_read", "Search memories by natural language query. Returns t
113
148
  (item.concepts.length > 0
114
149
  ? ` (${item.concepts.join(", ")})`
115
150
  : ""));
151
+ const text = lines.join("\n\n") + `\n\n(${r.search_time_ms.toFixed(0)}ms)`;
116
152
  return {
117
153
  content: [
118
154
  {
119
155
  type: "text",
120
- text: lines.join("\n\n") + `\n\n(${r.search_time_ms.toFixed(0)}ms)`,
156
+ text: capResult(text),
121
157
  },
122
158
  ],
123
159
  };
124
160
  });
125
161
  // --- Tool: memory_feedback ---
126
- server.tool("memory_feedback", "Report whether a retrieved memory was helpful. Positive feedback makes memories easier to find next time. Negative feedback lets them fade. Call this after using memories from memory_read.", {
127
- atom_ids: z
128
- .array(z.string())
129
- .min(1)
130
- .describe("IDs of memories to give feedback on (from memory_read results)"),
131
- outcome: z
132
- .number()
133
- .min(-1)
134
- .max(1)
135
- .describe("How helpful was this? 1.0 = very helpful, 0 = neutral, -1.0 = harmful/wrong"),
162
+ server.registerTool("memory_feedback", {
163
+ description: "Report whether a retrieved memory was helpful. Positive feedback makes memories easier to find next time across all tools. Negative feedback lets them fade. Call this after using memories from memory_read.",
164
+ inputSchema: {
165
+ atom_ids: z
166
+ .array(z.string())
167
+ .min(1)
168
+ .describe("IDs of memories to give feedback on (from memory_read results)"),
169
+ outcome: z
170
+ .number()
171
+ .min(-1)
172
+ .max(1)
173
+ .describe("How helpful was this? 1.0 = very helpful, 0 = neutral, -1.0 = harmful/wrong"),
174
+ },
175
+ annotations: {
176
+ title: "Rate Memory Helpfulness",
177
+ readOnlyHint: false,
178
+ destructiveHint: false,
179
+ idempotentHint: false,
180
+ openWorldHint: true,
181
+ },
136
182
  }, async ({ atom_ids, outcome }) => {
137
183
  const result = await apiFetch("/memory/feedback", {
138
184
  method: "POST",
@@ -149,7 +195,17 @@ server.tool("memory_feedback", "Report whether a retrieved memory was helpful. P
149
195
  };
150
196
  });
151
197
  // --- Tool: memory_stats ---
152
- server.tool("memory_stats", "Get memory statistics — how many memories are stored, which domains exist, average quality scores. Useful for understanding the current state of memory.", {}, async () => {
198
+ server.registerTool("memory_stats", {
199
+ description: "Get memory statistics — how many memories are stored, which domains exist, average quality scores. These memories are shared with all AI tools the user has connected to Mnemoverse. Useful for understanding the current state of memory.",
200
+ inputSchema: {},
201
+ annotations: {
202
+ title: "Memory Statistics",
203
+ readOnlyHint: true,
204
+ destructiveHint: false,
205
+ idempotentHint: true,
206
+ openWorldHint: true,
207
+ },
208
+ }, async () => {
153
209
  const result = await apiFetch("/memory/stats");
154
210
  const r = result;
155
211
  const text = [
@@ -160,6 +216,85 @@ server.tool("memory_stats", "Get memory statistics — how many memories are sto
160
216
  ].join("\n");
161
217
  return { content: [{ type: "text", text }] };
162
218
  });
219
+ // --- Tool: memory_delete ---
220
+ server.registerTool("memory_delete", {
221
+ description: "Permanently delete a single memory by its atom_id. Use when the user explicitly asks to forget something specific, or when you stored a wrong fact that needs correcting. The deletion is irreversible — the memory is gone for good. For broad cleanup of an entire topic, prefer memory_delete_domain.",
222
+ inputSchema: {
223
+ atom_id: z
224
+ .string()
225
+ .min(1)
226
+ .describe("The atom_id of the memory to delete (from memory_read results — each item has an id)"),
227
+ },
228
+ annotations: {
229
+ title: "Delete a Memory",
230
+ readOnlyHint: false,
231
+ destructiveHint: true,
232
+ idempotentHint: true,
233
+ openWorldHint: true,
234
+ },
235
+ }, async ({ atom_id }) => {
236
+ const result = await apiFetch(`/memory/atoms/${encodeURIComponent(atom_id)}`, {
237
+ method: "DELETE",
238
+ });
239
+ // Core API returns { deleted: <count>, atom_id }. count == 0 means
240
+ // the atom didn't exist (or was already removed). count >= 1 means it was deleted.
241
+ const r = result;
242
+ if (!r.deleted) {
243
+ return {
244
+ content: [
245
+ {
246
+ type: "text",
247
+ text: `No memory found with id ${atom_id}.`,
248
+ },
249
+ ],
250
+ };
251
+ }
252
+ return {
253
+ content: [
254
+ {
255
+ type: "text",
256
+ text: `Deleted memory ${atom_id}.`,
257
+ },
258
+ ],
259
+ };
260
+ });
261
+ // --- Tool: memory_delete_domain ---
262
+ server.registerTool("memory_delete_domain", {
263
+ description: "Permanently delete ALL memories in a given domain. Use when the user wants to clean up an entire topic — e.g., 'forget everything about project X' or 'wipe my benchmark experiments'. The deletion is irreversible. List domains first with memory_stats to confirm the exact name. Refuse to call this without an explicit user request — it is much more destructive than memory_delete.",
264
+ inputSchema: {
265
+ domain: z
266
+ .string()
267
+ .min(1)
268
+ .max(200)
269
+ .describe("The domain namespace to wipe (e.g., 'project:old', 'experiments-2025'). Must match exactly."),
270
+ confirm: z
271
+ .literal(true)
272
+ .describe("Must be exactly true to proceed. Acts as a safety interlock against accidental invocation."),
273
+ },
274
+ annotations: {
275
+ title: "Delete an Entire Memory Domain",
276
+ readOnlyHint: false,
277
+ destructiveHint: true,
278
+ idempotentHint: true,
279
+ openWorldHint: true,
280
+ },
281
+ }, async ({ domain, confirm }) => {
282
+ if (confirm !== true) {
283
+ throw new Error("memory_delete_domain requires confirm=true as a safety interlock.");
284
+ }
285
+ const result = await apiFetch(`/memory/domain/${encodeURIComponent(domain)}`, {
286
+ method: "DELETE",
287
+ });
288
+ const r = result;
289
+ return {
290
+ content: [
291
+ {
292
+ type: "text",
293
+ text: `Deleted ${r.deleted} ${r.deleted === 1 ? "memory" : "memories"} from domain "${r.domain}".`,
294
+ },
295
+ ],
296
+ };
297
+ });
163
298
  // --- Start ---
164
299
  async function main() {
165
300
  const transport = new StdioServerTransport();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env bash
2
+ claude mcp add mnemoverse \
3
+ -e MNEMOVERSE_API_KEY=mk_live_YOUR_KEY \
4
+ -- npx -y @mnemoverse/mcp-memory-server
@@ -0,0 +1,14 @@
1
+ {
2
+ "mcpServers": {
3
+ "mnemoverse": {
4
+ "command": "npx",
5
+ "args": [
6
+ "-y",
7
+ "@mnemoverse/mcp-memory-server"
8
+ ],
9
+ "env": {
10
+ "MNEMOVERSE_API_KEY": "mk_live_YOUR_KEY"
11
+ }
12
+ }
13
+ }
14
+ }
@@ -0,0 +1 @@
1
+ cursor://anysphere.cursor-deeplink/mcp/install?name=mnemoverse&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBtbmVtb3ZlcnNlL21jcC1tZW1vcnktc2VydmVyIl0sImVudiI6eyJNTkVNT1ZFUlNFX0FQSV9LRVkiOiJta19saXZlX1lPVVJfS0VZIn19
@@ -0,0 +1,14 @@
1
+ {
2
+ "mcpServers": {
3
+ "mnemoverse": {
4
+ "command": "npx",
5
+ "args": [
6
+ "-y",
7
+ "@mnemoverse/mcp-memory-server"
8
+ ],
9
+ "env": {
10
+ "MNEMOVERSE_API_KEY": "mk_live_YOUR_KEY"
11
+ }
12
+ }
13
+ }
14
+ }
@@ -0,0 +1 @@
1
+ vscode:mcp/install?%7B%22name%22%3A%22mnemoverse%22%2C%22type%22%3A%22stdio%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40mnemoverse%2Fmcp-memory-server%22%5D%2C%22env%22%3A%7B%22MNEMOVERSE_API_KEY%22%3A%22mk_live_YOUR_KEY%22%7D%7D
@@ -0,0 +1,15 @@
1
+ {
2
+ "servers": {
3
+ "mnemoverse": {
4
+ "type": "stdio",
5
+ "command": "npx",
6
+ "args": [
7
+ "-y",
8
+ "@mnemoverse/mcp-memory-server"
9
+ ],
10
+ "env": {
11
+ "MNEMOVERSE_API_KEY": "mk_live_YOUR_KEY"
12
+ }
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "mcpServers": {
3
+ "mnemoverse": {
4
+ "command": "npx",
5
+ "args": [
6
+ "-y",
7
+ "@mnemoverse/mcp-memory-server"
8
+ ],
9
+ "env": {
10
+ "MNEMOVERSE_API_KEY": "mk_live_YOUR_KEY"
11
+ }
12
+ }
13
+ }
14
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnemoverse/mcp-memory-server",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "MCP server for Mnemoverse Memory API — persistent AI memory across Claude Code, Cursor, VS Code, and any MCP client",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,8 +12,12 @@
12
12
  "build": "tsc",
13
13
  "dev": "tsc --watch",
14
14
  "start": "node dist/index.js",
15
+ "generate:configs": "node scripts/generate-configs.mjs",
16
+ "verify:configs": "node scripts/generate-configs.mjs --check",
17
+ "prebuild": "npm run generate:configs",
15
18
  "prepublishOnly": "npm run build"
16
19
  },
20
+ "mcpName": "io.github.mnemoverse/mcp-memory-server",
17
21
  "keywords": [
18
22
  "mcp",
19
23
  "memory",
@@ -0,0 +1,306 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * generate-configs.mjs
4
+ *
5
+ * Single source of truth → all distribution channel configs.
6
+ *
7
+ * Reads: src/configs/source.json
8
+ * Writes: docs/configs/*, smithery.yaml, server.json
9
+ *
10
+ * Usage:
11
+ * node scripts/generate-configs.mjs # generate
12
+ * node scripts/generate-configs.mjs --check # CI: regenerate + diff (fail if changed)
13
+ *
14
+ * When you add a new distribution channel, add a new generator function below.
15
+ * Never edit generated files by hand — they will be overwritten.
16
+ */
17
+
18
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
19
+ import { dirname, resolve } from "node:path";
20
+ import { fileURLToPath } from "node:url";
21
+ import { execSync } from "node:child_process";
22
+
23
+ const __filename = fileURLToPath(import.meta.url);
24
+ const __dirname = dirname(__filename);
25
+ const ROOT = resolve(__dirname, "..");
26
+
27
+ // ─── Load source ─────────────────────────────────────────────────────────────
28
+
29
+ const SOURCE_PATH = resolve(ROOT, "src/configs/source.json");
30
+ const source = JSON.parse(readFileSync(SOURCE_PATH, "utf8"));
31
+
32
+ const PACKAGE_VERSION = JSON.parse(
33
+ readFileSync(resolve(ROOT, "package.json"), "utf8"),
34
+ ).version;
35
+
36
+ // Helper: extract { KEY: "value" } from source.env (which has nested {value, description, ...})
37
+ function envValues(envObj) {
38
+ const result = {};
39
+ for (const [key, meta] of Object.entries(envObj)) {
40
+ result[key] = meta.value;
41
+ }
42
+ return result;
43
+ }
44
+
45
+ const ENV_VALUES = envValues(source.env);
46
+
47
+ // ─── Generators ──────────────────────────────────────────────────────────────
48
+
49
+ /**
50
+ * Cursor / Claude Desktop / Windsurf format (mcpServers key, stdio).
51
+ */
52
+ function genMcpServersFormat() {
53
+ return {
54
+ mcpServers: {
55
+ [source.name]: {
56
+ command: source.command,
57
+ args: source.args,
58
+ env: ENV_VALUES,
59
+ },
60
+ },
61
+ };
62
+ }
63
+
64
+ /**
65
+ * VS Code (Copilot Chat) format — uses `servers` key (not `mcpServers`).
66
+ */
67
+ function genVscodeFormat() {
68
+ return {
69
+ servers: {
70
+ [source.name]: {
71
+ type: source.type,
72
+ command: source.command,
73
+ args: source.args,
74
+ env: ENV_VALUES,
75
+ },
76
+ },
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Cursor deep link.
82
+ *
83
+ * Format: cursor://anysphere.cursor-deeplink/mcp/install?name=NAME&config=BASE64
84
+ * The base64 payload is the inner server object (NOT wrapped in mcpServers).
85
+ */
86
+ function genCursorDeepLink() {
87
+ const inner = {
88
+ command: source.command,
89
+ args: source.args,
90
+ env: ENV_VALUES,
91
+ };
92
+ const config = Buffer.from(JSON.stringify(inner)).toString("base64");
93
+ return `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(
94
+ source.name,
95
+ )}&config=${config}`;
96
+ }
97
+
98
+ /**
99
+ * VS Code deep link.
100
+ *
101
+ * Format: vscode:mcp/install?{URL_ENCODED_JSON}
102
+ * The JSON contains name + the server object (not wrapped in `servers`).
103
+ */
104
+ function genVscodeDeepLink() {
105
+ const inner = {
106
+ name: source.name,
107
+ type: source.type,
108
+ command: source.command,
109
+ args: source.args,
110
+ env: ENV_VALUES,
111
+ };
112
+ return `vscode:mcp/install?${encodeURIComponent(JSON.stringify(inner))}`;
113
+ }
114
+
115
+ /**
116
+ * Claude Code CLI command.
117
+ *
118
+ * Format: claude mcp add NAME -e KEY=VAL ... -- command args...
119
+ */
120
+ function genClaudeCodeCli() {
121
+ const envFlags = Object.entries(ENV_VALUES)
122
+ .map(([k, v]) => ` -e ${k}=${v}`)
123
+ .join(" \\\n");
124
+ return `claude mcp add ${source.name} \\\n${envFlags} \\\n -- ${source.command} ${source.args.join(" ")}\n`;
125
+ }
126
+
127
+ /**
128
+ * Smithery.ai config — custom yaml with configSchema + commandFunction.
129
+ *
130
+ * Smithery shows configSchema fields to user as form, then calls commandFunction(config)
131
+ * to build the launch command.
132
+ */
133
+ function genSmitheryYaml() {
134
+ // Build configSchema properties from source.env
135
+ const schemaProperties = {};
136
+ const required = [];
137
+ const camelCaseEnvMap = {}; // Smithery uses camelCase keys, then we map back to ENV_VAR
138
+
139
+ for (const [envKey, meta] of Object.entries(source.env)) {
140
+ // Convert MNEMOVERSE_API_KEY → mnemoverseApiKey
141
+ const camelKey = envKey
142
+ .toLowerCase()
143
+ .split("_")
144
+ .map((part, i) =>
145
+ i === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1),
146
+ )
147
+ .join("");
148
+
149
+ camelCaseEnvMap[camelKey] = envKey;
150
+ schemaProperties[camelKey] = {
151
+ type: "string",
152
+ description: meta.description,
153
+ };
154
+ if (meta.required) required.push(camelKey);
155
+ }
156
+
157
+ // Build commandFunction body
158
+ const envAssignments = Object.entries(camelCaseEnvMap)
159
+ .map(([camel, envVar]) => ` ${envVar}: config.${camel},`)
160
+ .join("\n");
161
+
162
+ const yaml = `# Smithery configuration — AUTO-GENERATED from src/configs/source.json
163
+ # Do not edit by hand. Run \`npm run generate:configs\` to regenerate.
164
+ # Docs: https://smithery.ai/docs/build/project-config/smithery.yaml
165
+
166
+ startCommand:
167
+ type: ${source.type}
168
+ configSchema:
169
+ type: object
170
+ required:
171
+ ${required.map((k) => ` - ${k}`).join("\n")}
172
+ properties:
173
+ ${Object.entries(schemaProperties)
174
+ .map(
175
+ ([key, prop]) => ` ${key}:
176
+ type: ${prop.type}
177
+ description: |
178
+ ${prop.description}`,
179
+ )
180
+ .join("\n")}
181
+ commandFunction:
182
+ |-
183
+ (config) => ({
184
+ command: '${source.command}',
185
+ args: ${JSON.stringify(source.args)},
186
+ env: {
187
+ ${envAssignments}
188
+ }
189
+ })
190
+ `;
191
+ return yaml;
192
+ }
193
+
194
+ /**
195
+ * Official MCP Registry server.json.
196
+ *
197
+ * https://registry.modelcontextprotocol.io/
198
+ * Schema: https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json
199
+ */
200
+ function genServerJson() {
201
+ return {
202
+ $schema:
203
+ "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
204
+ name: "io.github.mnemoverse/mcp-memory-server",
205
+ description: source.description,
206
+ repository: {
207
+ url: source.metadata.repository,
208
+ source: "github",
209
+ },
210
+ version: PACKAGE_VERSION,
211
+ packages: [
212
+ {
213
+ registryName: source.package.registry,
214
+ name: source.package.name,
215
+ version: PACKAGE_VERSION,
216
+ runtimeArguments: source.args.slice(1), // skip "-y"
217
+ environmentVariables: Object.entries(source.env).map(([key, meta]) => ({
218
+ name: key,
219
+ description: meta.description,
220
+ isRequired: meta.required ?? false,
221
+ isSecret: meta.secret ?? false,
222
+ })),
223
+ },
224
+ ],
225
+ };
226
+ }
227
+
228
+ // ─── Output ──────────────────────────────────────────────────────────────────
229
+
230
+ const OUTPUTS = [
231
+ {
232
+ path: "docs/configs/cursor.json",
233
+ content: JSON.stringify(genMcpServersFormat(), null, 2) + "\n",
234
+ },
235
+ {
236
+ path: "docs/configs/claude-desktop.json",
237
+ content: JSON.stringify(genMcpServersFormat(), null, 2) + "\n",
238
+ },
239
+ {
240
+ path: "docs/configs/windsurf.json",
241
+ content: JSON.stringify(genMcpServersFormat(), null, 2) + "\n",
242
+ },
243
+ {
244
+ path: "docs/configs/vscode.json",
245
+ content: JSON.stringify(genVscodeFormat(), null, 2) + "\n",
246
+ },
247
+ {
248
+ path: "docs/configs/cursor-deep-link.txt",
249
+ content: genCursorDeepLink() + "\n",
250
+ },
251
+ {
252
+ path: "docs/configs/vscode-deep-link.txt",
253
+ content: genVscodeDeepLink() + "\n",
254
+ },
255
+ {
256
+ path: "docs/configs/claude-code-cli.sh",
257
+ content: "#!/usr/bin/env bash\n" + genClaudeCodeCli(),
258
+ },
259
+ {
260
+ path: "smithery.yaml",
261
+ content: genSmitheryYaml(),
262
+ },
263
+ {
264
+ path: "server.json",
265
+ content: JSON.stringify(genServerJson(), null, 2) + "\n",
266
+ },
267
+ ];
268
+
269
+ // ─── Write files ─────────────────────────────────────────────────────────────
270
+
271
+ const checkMode = process.argv.includes("--check");
272
+
273
+ let written = 0;
274
+ let unchanged = 0;
275
+
276
+ for (const { path, content } of OUTPUTS) {
277
+ const fullPath = resolve(ROOT, path);
278
+ mkdirSync(dirname(fullPath), { recursive: true });
279
+
280
+ const existing = existsSync(fullPath) ? readFileSync(fullPath, "utf8") : "";
281
+ if (existing === content) {
282
+ unchanged++;
283
+ continue;
284
+ }
285
+
286
+ if (checkMode) {
287
+ console.error(`✗ Drift detected: ${path}`);
288
+ console.error(" Expected (regenerated):");
289
+ console.error(" " + content.slice(0, 200).split("\n").join("\n "));
290
+ console.error(" Got (committed):");
291
+ console.error(" " + existing.slice(0, 200).split("\n").join("\n "));
292
+ process.exit(1);
293
+ }
294
+
295
+ writeFileSync(fullPath, content, "utf8");
296
+ console.log(`✓ Generated ${path}`);
297
+ written++;
298
+ }
299
+
300
+ if (checkMode) {
301
+ console.log(`✓ All ${OUTPUTS.length} configs in sync with source.json`);
302
+ } else {
303
+ console.log(
304
+ `\nDone: ${written} written, ${unchanged} unchanged (${OUTPUTS.length} total)`,
305
+ );
306
+ }
package/server.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
3
+ "name": "io.github.mnemoverse/mcp-memory-server",
4
+ "description": "Persistent memory for AI agents — write once, recall anywhere across all your AI tools",
5
+ "repository": {
6
+ "url": "https://github.com/mnemoverse/mcp-memory-server",
7
+ "source": "github"
8
+ },
9
+ "version": "0.3.0",
10
+ "packages": [
11
+ {
12
+ "registryName": "npm",
13
+ "name": "@mnemoverse/mcp-memory-server",
14
+ "version": "0.3.0",
15
+ "runtimeArguments": [
16
+ "@mnemoverse/mcp-memory-server"
17
+ ],
18
+ "environmentVariables": [
19
+ {
20
+ "name": "MNEMOVERSE_API_KEY",
21
+ "description": "Your Mnemoverse API key (starts with mk_live_). Get one free at https://console.mnemoverse.com",
22
+ "isRequired": true,
23
+ "isSecret": true
24
+ }
25
+ ]
26
+ }
27
+ ]
28
+ }
package/smithery.yaml ADDED
@@ -0,0 +1,24 @@
1
+ # Smithery configuration — AUTO-GENERATED from src/configs/source.json
2
+ # Do not edit by hand. Run `npm run generate:configs` to regenerate.
3
+ # Docs: https://smithery.ai/docs/build/project-config/smithery.yaml
4
+
5
+ startCommand:
6
+ type: stdio
7
+ configSchema:
8
+ type: object
9
+ required:
10
+ - mnemoverseApiKey
11
+ properties:
12
+ mnemoverseApiKey:
13
+ type: string
14
+ description: |
15
+ Your Mnemoverse API key (starts with mk_live_). Get one free at https://console.mnemoverse.com
16
+ commandFunction:
17
+ |-
18
+ (config) => ({
19
+ command: 'npx',
20
+ args: ["-y","@mnemoverse/mcp-memory-server"],
21
+ env: {
22
+ MNEMOVERSE_API_KEY: config.mnemoverseApiKey,
23
+ }
24
+ })
@@ -0,0 +1,28 @@
1
+ {
2
+ "$comment": "SINGLE SOURCE OF TRUTH for all distribution channel configs. Edit this file → run `npm run generate:configs` → all 9+ artifacts regenerate. CI verifies committed artifacts match source.",
3
+ "name": "mnemoverse",
4
+ "displayName": "Mnemoverse Memory",
5
+ "description": "Persistent memory for AI agents — write once, recall anywhere across all your AI tools",
6
+ "type": "stdio",
7
+ "command": "npx",
8
+ "args": ["-y", "@mnemoverse/mcp-memory-server"],
9
+ "env": {
10
+ "MNEMOVERSE_API_KEY": {
11
+ "value": "mk_live_YOUR_KEY",
12
+ "description": "Your Mnemoverse API key (starts with mk_live_). Get one free at https://console.mnemoverse.com",
13
+ "required": true,
14
+ "secret": true
15
+ }
16
+ },
17
+ "package": {
18
+ "registry": "npm",
19
+ "name": "@mnemoverse/mcp-memory-server"
20
+ },
21
+ "metadata": {
22
+ "homepage": "https://mnemoverse.com/docs/api/mcp-server",
23
+ "repository": "https://github.com/mnemoverse/mcp-memory-server",
24
+ "license": "MIT",
25
+ "author": "Mnemoverse",
26
+ "tags": ["memory", "persistent", "ai-agents", "cross-tool", "oauth"]
27
+ }
28
+ }
package/src/index.ts CHANGED
@@ -8,17 +8,22 @@ const API_URL =
8
8
  process.env.MNEMOVERSE_API_URL || "https://core.mnemoverse.com/api/v1";
9
9
  const API_KEY = process.env.MNEMOVERSE_API_KEY || "";
10
10
 
11
+ // Hard cap on tool result size — required by Claude Connectors Directory
12
+ // (https://support.claude.com/en/articles/12922490-remote-mcp-server-submission-guide).
13
+ // Approximate token count = chars / 4. Cap at 24,000 tokens to leave headroom under the 25K limit.
14
+ const MAX_RESULT_CHARS = 24_000 * 4;
15
+
11
16
  if (!API_KEY) {
12
17
  console.error(
13
18
  "Error: MNEMOVERSE_API_KEY environment variable is required.\n" +
14
- "Get your free key at https://console.mnemoverse.com"
19
+ "Get your free key at https://console.mnemoverse.com",
15
20
  );
16
21
  process.exit(1);
17
22
  }
18
23
 
19
24
  async function apiFetch(
20
25
  path: string,
21
- options: RequestInit = {}
26
+ options: RequestInit = {},
22
27
  ): Promise<unknown> {
23
28
  const res = await fetch(`${API_URL}${path}`, {
24
29
  ...options,
@@ -37,32 +42,59 @@ async function apiFetch(
37
42
  return res.json();
38
43
  }
39
44
 
45
+ /**
46
+ * Truncate a result string to MAX_RESULT_CHARS, appending a notice if truncated.
47
+ * Required by Claude Connectors Directory submission policy.
48
+ */
49
+ function capResult(text: string): string {
50
+ if (text.length <= MAX_RESULT_CHARS) return text;
51
+ const truncated = text.slice(0, MAX_RESULT_CHARS - 200);
52
+ return (
53
+ truncated +
54
+ `\n\n[…truncated to fit 25K token limit. Use a more specific query or smaller top_k to see all results.]`
55
+ );
56
+ }
57
+
40
58
  // --- Server setup ---
41
59
 
42
60
  const server = new McpServer({
43
61
  name: "mnemoverse-memory",
44
- version: "0.1.0",
62
+ version: "0.3.0",
45
63
  });
46
64
 
47
65
  // --- Tool: memory_write ---
48
66
 
49
- server.tool(
67
+ server.registerTool(
50
68
  "memory_write",
51
- "Store a memory — insight, pattern, preference, or fact. Persists across sessions. Use this when the user teaches you something worth remembering, or when you learn a lesson from a task.",
52
69
  {
53
- content: z
54
- .string()
55
- .min(1)
56
- .max(10000)
57
- .describe("The memory to store — what happened, what was learned"),
58
- concepts: z
59
- .array(z.string())
60
- .optional()
61
- .describe("Key concepts for linking related memories (e.g. ['deploy', 'friday', 'staging'])"),
62
- domain: z
63
- .string()
64
- .optional()
65
- .describe("Namespace to organize memories (e.g. 'engineering', 'user:alice', 'project:acme')"),
70
+ description:
71
+ "Store a memory that should persist across sessions — preferences, decisions, lessons learned, project facts, people and roles. Memories you store are also accessible from Claude, ChatGPT, Cursor, VS Code, and any other AI tool the user connects to Mnemoverse — write once, recall everywhere. Call this PROACTIVELY whenever the user states a preference, makes a decision, or you learn something important. Don't wait to be asked — if it's worth remembering, store it now.",
72
+ inputSchema: {
73
+ content: z
74
+ .string()
75
+ .min(1)
76
+ .max(10000)
77
+ .describe("The memory to store — what happened, what was learned"),
78
+ concepts: z
79
+ .array(z.string())
80
+ .optional()
81
+ .describe(
82
+ "Key concepts for linking related memories (e.g. ['deploy', 'friday', 'staging'])",
83
+ ),
84
+ domain: z
85
+ .string()
86
+ .optional()
87
+ .describe(
88
+ "Namespace to organize memories (e.g. 'engineering', 'user:alice', 'project:acme')",
89
+ ),
90
+ },
91
+ annotations: {
92
+ title: "Store Memory",
93
+ readOnlyHint: false,
94
+ destructiveHint: false,
95
+ idempotentHint: false,
96
+ openWorldHint: true,
97
+ },
66
98
  },
67
99
  async ({ content, concepts, domain }) => {
68
100
  const result = await apiFetch("/memory/write", {
@@ -99,31 +131,41 @@ server.tool(
99
131
  },
100
132
  ],
101
133
  };
102
- }
134
+ },
103
135
  );
104
136
 
105
137
  // --- Tool: memory_read ---
106
138
 
107
- server.tool(
139
+ server.registerTool(
108
140
  "memory_read",
109
- "Search memories by natural language query. Returns the most relevant stored memories. Use this before starting a task to check if you already know something about it.",
110
141
  {
111
- query: z
112
- .string()
113
- .min(1)
114
- .max(5000)
115
- .describe("Natural language query — what are you looking for?"),
116
- top_k: z
117
- .number()
118
- .int()
119
- .min(1)
120
- .max(50)
121
- .optional()
122
- .describe("Max results to return (default: 5)"),
123
- domain: z
124
- .string()
125
- .optional()
126
- .describe("Filter by domain namespace"),
142
+ description:
143
+ "ALWAYS call this tool first when the user asks a question about preferences, past decisions, project setup, people, or anything that might have been discussed before. This is your long-term memory — it persists across sessions and tools (Claude, ChatGPT, Cursor, VS Code, and any other AI tool the user connects). Search by natural language query. If you have any doubt whether you know something — check memory first.",
144
+ inputSchema: {
145
+ query: z
146
+ .string()
147
+ .min(1)
148
+ .max(5000)
149
+ .describe("Natural language query — what are you looking for?"),
150
+ top_k: z
151
+ .number()
152
+ .int()
153
+ .min(1)
154
+ .max(50)
155
+ .optional()
156
+ .describe("Max results to return (default: 5)"),
157
+ domain: z
158
+ .string()
159
+ .optional()
160
+ .describe("Filter by domain namespace"),
161
+ },
162
+ annotations: {
163
+ title: "Search Memories",
164
+ readOnlyHint: true,
165
+ destructiveHint: false,
166
+ idempotentHint: true,
167
+ openWorldHint: true,
168
+ },
127
169
  },
128
170
  async ({ query, top_k, domain }) => {
129
171
  const result = await apiFetch("/memory/read", {
@@ -159,35 +201,47 @@ server.tool(
159
201
  `${i + 1}. [${(item.relevance * 100).toFixed(0)}%] ${item.content}` +
160
202
  (item.concepts.length > 0
161
203
  ? ` (${item.concepts.join(", ")})`
162
- : "")
204
+ : ""),
163
205
  );
164
206
 
207
+ const text = lines.join("\n\n") + `\n\n(${r.search_time_ms.toFixed(0)}ms)`;
208
+
165
209
  return {
166
210
  content: [
167
211
  {
168
212
  type: "text" as const,
169
- text: lines.join("\n\n") + `\n\n(${r.search_time_ms.toFixed(0)}ms)`,
213
+ text: capResult(text),
170
214
  },
171
215
  ],
172
216
  };
173
- }
217
+ },
174
218
  );
175
219
 
176
220
  // --- Tool: memory_feedback ---
177
221
 
178
- server.tool(
222
+ server.registerTool(
179
223
  "memory_feedback",
180
- "Report whether a retrieved memory was helpful. Positive feedback makes memories easier to find next time. Negative feedback lets them fade. Call this after using memories from memory_read.",
181
224
  {
182
- atom_ids: z
183
- .array(z.string())
184
- .min(1)
185
- .describe("IDs of memories to give feedback on (from memory_read results)"),
186
- outcome: z
187
- .number()
188
- .min(-1)
189
- .max(1)
190
- .describe("How helpful was this? 1.0 = very helpful, 0 = neutral, -1.0 = harmful/wrong"),
225
+ description:
226
+ "Report whether a retrieved memory was helpful. Positive feedback makes memories easier to find next time across all tools. Negative feedback lets them fade. Call this after using memories from memory_read.",
227
+ inputSchema: {
228
+ atom_ids: z
229
+ .array(z.string())
230
+ .min(1)
231
+ .describe("IDs of memories to give feedback on (from memory_read results)"),
232
+ outcome: z
233
+ .number()
234
+ .min(-1)
235
+ .max(1)
236
+ .describe("How helpful was this? 1.0 = very helpful, 0 = neutral, -1.0 = harmful/wrong"),
237
+ },
238
+ annotations: {
239
+ title: "Rate Memory Helpfulness",
240
+ readOnlyHint: false,
241
+ destructiveHint: false,
242
+ idempotentHint: false,
243
+ openWorldHint: true,
244
+ },
191
245
  },
192
246
  async ({ atom_ids, outcome }) => {
193
247
  const result = await apiFetch("/memory/feedback", {
@@ -205,15 +259,25 @@ server.tool(
205
259
  },
206
260
  ],
207
261
  };
208
- }
262
+ },
209
263
  );
210
264
 
211
265
  // --- Tool: memory_stats ---
212
266
 
213
- server.tool(
267
+ server.registerTool(
214
268
  "memory_stats",
215
- "Get memory statistics — how many memories are stored, which domains exist, average quality scores. Useful for understanding the current state of memory.",
216
- {},
269
+ {
270
+ description:
271
+ "Get memory statistics — how many memories are stored, which domains exist, average quality scores. These memories are shared with all AI tools the user has connected to Mnemoverse. Useful for understanding the current state of memory.",
272
+ inputSchema: {},
273
+ annotations: {
274
+ title: "Memory Statistics",
275
+ readOnlyHint: true,
276
+ destructiveHint: false,
277
+ idempotentHint: true,
278
+ openWorldHint: true,
279
+ },
280
+ },
217
281
  async () => {
218
282
  const result = await apiFetch("/memory/stats");
219
283
 
@@ -235,7 +299,114 @@ server.tool(
235
299
  ].join("\n");
236
300
 
237
301
  return { content: [{ type: "text" as const, text }] };
238
- }
302
+ },
303
+ );
304
+
305
+ // --- Tool: memory_delete ---
306
+
307
+ server.registerTool(
308
+ "memory_delete",
309
+ {
310
+ description:
311
+ "Permanently delete a single memory by its atom_id. Use when the user explicitly asks to forget something specific, or when you stored a wrong fact that needs correcting. The deletion is irreversible — the memory is gone for good. For broad cleanup of an entire topic, prefer memory_delete_domain.",
312
+ inputSchema: {
313
+ atom_id: z
314
+ .string()
315
+ .min(1)
316
+ .describe(
317
+ "The atom_id of the memory to delete (from memory_read results — each item has an id)",
318
+ ),
319
+ },
320
+ annotations: {
321
+ title: "Delete a Memory",
322
+ readOnlyHint: false,
323
+ destructiveHint: true,
324
+ idempotentHint: true,
325
+ openWorldHint: true,
326
+ },
327
+ },
328
+ async ({ atom_id }) => {
329
+ const result = await apiFetch(`/memory/atoms/${encodeURIComponent(atom_id)}`, {
330
+ method: "DELETE",
331
+ });
332
+
333
+ // Core API returns { deleted: <count>, atom_id }. count == 0 means
334
+ // the atom didn't exist (or was already removed). count >= 1 means it was deleted.
335
+ const r = result as { deleted: number; atom_id?: string };
336
+
337
+ if (!r.deleted) {
338
+ return {
339
+ content: [
340
+ {
341
+ type: "text" as const,
342
+ text: `No memory found with id ${atom_id}.`,
343
+ },
344
+ ],
345
+ };
346
+ }
347
+
348
+ return {
349
+ content: [
350
+ {
351
+ type: "text" as const,
352
+ text: `Deleted memory ${atom_id}.`,
353
+ },
354
+ ],
355
+ };
356
+ },
357
+ );
358
+
359
+ // --- Tool: memory_delete_domain ---
360
+
361
+ server.registerTool(
362
+ "memory_delete_domain",
363
+ {
364
+ description:
365
+ "Permanently delete ALL memories in a given domain. Use when the user wants to clean up an entire topic — e.g., 'forget everything about project X' or 'wipe my benchmark experiments'. The deletion is irreversible. List domains first with memory_stats to confirm the exact name. Refuse to call this without an explicit user request — it is much more destructive than memory_delete.",
366
+ inputSchema: {
367
+ domain: z
368
+ .string()
369
+ .min(1)
370
+ .max(200)
371
+ .describe(
372
+ "The domain namespace to wipe (e.g., 'project:old', 'experiments-2025'). Must match exactly.",
373
+ ),
374
+ confirm: z
375
+ .literal(true)
376
+ .describe(
377
+ "Must be exactly true to proceed. Acts as a safety interlock against accidental invocation.",
378
+ ),
379
+ },
380
+ annotations: {
381
+ title: "Delete an Entire Memory Domain",
382
+ readOnlyHint: false,
383
+ destructiveHint: true,
384
+ idempotentHint: true,
385
+ openWorldHint: true,
386
+ },
387
+ },
388
+ async ({ domain, confirm }) => {
389
+ if (confirm !== true) {
390
+ throw new Error(
391
+ "memory_delete_domain requires confirm=true as a safety interlock.",
392
+ );
393
+ }
394
+
395
+ const result = await apiFetch(`/memory/domain/${encodeURIComponent(domain)}`, {
396
+ method: "DELETE",
397
+ });
398
+
399
+ const r = result as { deleted: number; domain: string };
400
+
401
+ return {
402
+ content: [
403
+ {
404
+ type: "text" as const,
405
+ text: `Deleted ${r.deleted} ${r.deleted === 1 ? "memory" : "memories"} from domain "${r.domain}".`,
406
+ },
407
+ ],
408
+ };
409
+ },
239
410
  );
240
411
 
241
412
  // --- Start ---