@mnemoverse/mcp-memory-server 0.3.0 → 0.3.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/.github/workflows/release.yml +138 -0
- package/.github/workflows/verify-configs.yml +55 -0
- package/CONTRIBUTING.md +199 -0
- package/README.md +50 -21
- package/dist/index.js +82 -40
- package/dist/index.js.map +1 -1
- package/docs/configs/claude-code-cli.sh +1 -1
- package/docs/configs/claude-desktop.json +1 -1
- package/docs/configs/cursor-deep-link.txt +1 -1
- package/docs/configs/cursor.json +1 -1
- package/docs/configs/vscode-deep-link.txt +1 -1
- package/docs/configs/vscode.json +1 -1
- package/docs/configs/windsurf.json +1 -1
- package/docs/snippets/claude-code.md +9 -0
- package/docs/snippets/claude-desktop.md +20 -0
- package/docs/snippets/cursor.md +20 -0
- package/docs/snippets/vscode.md +21 -0
- package/docs/snippets/windsurf.md +20 -0
- package/package.json +2 -1
- package/scripts/generate-configs.mjs +196 -7
- package/scripts/install-hooks.mjs +76 -0
- package/server.json +10 -9
- package/smithery.yaml +1 -1
- package/src/configs/source.json +2 -2
- package/src/index.ts +114 -72
|
@@ -191,16 +191,128 @@ ${envAssignments}
|
|
|
191
191
|
return yaml;
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
// ─── Markdown partials ────────────────────────────────────────────────────────
|
|
195
|
+
//
|
|
196
|
+
// These are the SAME install snippets that ship to:
|
|
197
|
+
// - mcp-memory-server/README.md (assembled into the INSTALL_SNIPPETS block)
|
|
198
|
+
// - mnemoverse-docs (synced via cross-repo workflow → docs/.snippets/)
|
|
199
|
+
//
|
|
200
|
+
// One channel = one partial = one place to edit (source.json). The README's
|
|
201
|
+
// install block is rebuilt from these partials in-place — never edit it by hand.
|
|
202
|
+
|
|
203
|
+
const PARTIAL_HEADER =
|
|
204
|
+
"<!-- AUTO-GENERATED from src/configs/source.json. Run `npm run generate:configs`. Do not edit by hand. -->\n\n";
|
|
205
|
+
|
|
206
|
+
function snippetClaudeCodeCli() {
|
|
207
|
+
// shell command, multiline with backslash continuations
|
|
208
|
+
return (
|
|
209
|
+
"**Claude Code** — add via CLI:\n\n" +
|
|
210
|
+
"```bash\n" +
|
|
211
|
+
genClaudeCodeCli().trim() +
|
|
212
|
+
"\n```\n"
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function snippetMcpServersJson(label, configPath) {
|
|
217
|
+
// Cursor / Claude Desktop / Windsurf — shared mcpServers shape
|
|
218
|
+
const json = JSON.stringify(genMcpServersFormat(), null, 2);
|
|
219
|
+
return (
|
|
220
|
+
`**${label}** — add to \`${configPath}\`:\n\n` +
|
|
221
|
+
"```json\n" +
|
|
222
|
+
json +
|
|
223
|
+
"\n```\n"
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function snippetVscode() {
|
|
228
|
+
// VS Code uses `servers` (not `mcpServers`) and requires `type: "stdio"`
|
|
229
|
+
const json = JSON.stringify(genVscodeFormat(), null, 2);
|
|
230
|
+
return (
|
|
231
|
+
"**VS Code** — add to `.vscode/mcp.json` (note: VS Code uses `servers`, not `mcpServers`):\n\n" +
|
|
232
|
+
"```json\n" +
|
|
233
|
+
json +
|
|
234
|
+
"\n```\n"
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const WHY_LATEST_NOTE =
|
|
239
|
+
"> Why `@latest`? Bare `npx @mnemoverse/mcp-memory-server` is cached indefinitely by npm and stops re-checking the registry. The `@latest` suffix forces a metadata lookup on every Claude Code / Cursor / VS Code session start (~100-300ms), so you always pick up new releases.";
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Build the README install block contents (without the START/END markers).
|
|
243
|
+
* The order here matches the README — change here, README rewrites itself.
|
|
244
|
+
*/
|
|
245
|
+
function readmeInstallBlock() {
|
|
246
|
+
return [
|
|
247
|
+
snippetClaudeCodeCli(),
|
|
248
|
+
snippetMcpServersJson("Cursor", ".cursor/mcp.json"),
|
|
249
|
+
snippetVscode(),
|
|
250
|
+
snippetMcpServersJson("Windsurf", "~/.codeium/windsurf/mcp_config.json"),
|
|
251
|
+
WHY_LATEST_NOTE,
|
|
252
|
+
].join("\n");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ─── README in-place rewriter ─────────────────────────────────────────────────
|
|
256
|
+
|
|
257
|
+
const README_START =
|
|
258
|
+
"<!-- INSTALL_SNIPPETS_START — generated from src/configs/source.json. Run `npm run generate:configs` to refresh. Do not edit by hand. -->";
|
|
259
|
+
const README_END = "<!-- INSTALL_SNIPPETS_END -->";
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Take current README content + the freshly assembled install block and return
|
|
263
|
+
* the rewritten README content. Idempotent.
|
|
264
|
+
*
|
|
265
|
+
* Throws if the markers are missing — that means a contributor stripped them
|
|
266
|
+
* out and we don't know where to inject the snippets, so we fail loudly
|
|
267
|
+
* instead of silently doing the wrong thing.
|
|
268
|
+
*/
|
|
269
|
+
function rewriteReadme(currentReadme, freshBlock) {
|
|
270
|
+
const startIdx = currentReadme.indexOf("<!-- INSTALL_SNIPPETS_START");
|
|
271
|
+
const endIdx = currentReadme.indexOf("<!-- INSTALL_SNIPPETS_END -->");
|
|
272
|
+
|
|
273
|
+
if (startIdx === -1 || endIdx === -1) {
|
|
274
|
+
throw new Error(
|
|
275
|
+
"README.md is missing the INSTALL_SNIPPETS_START / INSTALL_SNIPPETS_END markers.\n" +
|
|
276
|
+
"These markers tell the generator where to inject the install snippets.\n" +
|
|
277
|
+
"Restore them around the install section and re-run `npm run generate:configs`.",
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
if (startIdx >= endIdx) {
|
|
281
|
+
throw new Error(
|
|
282
|
+
"README.md INSTALL_SNIPPETS_END marker appears before INSTALL_SNIPPETS_START.",
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const before = currentReadme.slice(0, startIdx);
|
|
287
|
+
const after = currentReadme.slice(endIdx + README_END.length);
|
|
288
|
+
|
|
289
|
+
return `${before}${README_START}\n\n${freshBlock}\n\n${README_END}${after}`;
|
|
290
|
+
}
|
|
291
|
+
|
|
194
292
|
/**
|
|
195
293
|
* Official MCP Registry server.json.
|
|
196
294
|
*
|
|
197
295
|
* https://registry.modelcontextprotocol.io/
|
|
198
|
-
* Schema: https://static.modelcontextprotocol.io/schemas/2025-
|
|
296
|
+
* Schema: https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json
|
|
297
|
+
*
|
|
298
|
+
* The canonical shape was verified empirically by running `mcp-publisher init`
|
|
299
|
+
* in a sandbox and matching its output. Key differences vs the older
|
|
300
|
+
* 2025-09-29 schema: registryName → registryType, packages[0].name →
|
|
301
|
+
* packages[0].identifier, new required `transport` object, dropped
|
|
302
|
+
* runtimeArguments (the registry runtime builds its own launch command
|
|
303
|
+
* from identifier + version), and environmentVariables entries gained a
|
|
304
|
+
* `format` field.
|
|
305
|
+
*
|
|
306
|
+
* The `@latest` pin we use in docs/configs/* does NOT belong here — that
|
|
307
|
+
* is for direct JSON-snippet installs where users stay on the bleeding
|
|
308
|
+
* edge. Registry-installed clients get the exact pinned version from
|
|
309
|
+
* server.json.version and we re-publish on each npm release to advance
|
|
310
|
+
* them.
|
|
199
311
|
*/
|
|
200
312
|
function genServerJson() {
|
|
201
313
|
return {
|
|
202
314
|
$schema:
|
|
203
|
-
"https://static.modelcontextprotocol.io/schemas/2025-
|
|
315
|
+
"https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
204
316
|
name: "io.github.mnemoverse/mcp-memory-server",
|
|
205
317
|
description: source.description,
|
|
206
318
|
repository: {
|
|
@@ -210,14 +322,17 @@ function genServerJson() {
|
|
|
210
322
|
version: PACKAGE_VERSION,
|
|
211
323
|
packages: [
|
|
212
324
|
{
|
|
213
|
-
|
|
214
|
-
|
|
325
|
+
registryType: source.package.registry,
|
|
326
|
+
identifier: source.package.name,
|
|
215
327
|
version: PACKAGE_VERSION,
|
|
216
|
-
|
|
328
|
+
transport: {
|
|
329
|
+
type: "stdio",
|
|
330
|
+
},
|
|
217
331
|
environmentVariables: Object.entries(source.env).map(([key, meta]) => ({
|
|
218
332
|
name: key,
|
|
219
333
|
description: meta.description,
|
|
220
334
|
isRequired: meta.required ?? false,
|
|
335
|
+
format: "string",
|
|
221
336
|
isSecret: meta.secret ?? false,
|
|
222
337
|
})),
|
|
223
338
|
},
|
|
@@ -264,6 +379,35 @@ const OUTPUTS = [
|
|
|
264
379
|
path: "server.json",
|
|
265
380
|
content: JSON.stringify(genServerJson(), null, 2) + "\n",
|
|
266
381
|
},
|
|
382
|
+
// ─── Markdown partials (consumed by README + mnemoverse-docs) ──────────────
|
|
383
|
+
{
|
|
384
|
+
path: "docs/snippets/claude-code.md",
|
|
385
|
+
content: PARTIAL_HEADER + snippetClaudeCodeCli(),
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
path: "docs/snippets/cursor.md",
|
|
389
|
+
content:
|
|
390
|
+
PARTIAL_HEADER + snippetMcpServersJson("Cursor", ".cursor/mcp.json"),
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
path: "docs/snippets/claude-desktop.md",
|
|
394
|
+
content:
|
|
395
|
+
PARTIAL_HEADER +
|
|
396
|
+
snippetMcpServersJson("Claude Desktop", "claude_desktop_config.json"),
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
path: "docs/snippets/vscode.md",
|
|
400
|
+
content: PARTIAL_HEADER + snippetVscode(),
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
path: "docs/snippets/windsurf.md",
|
|
404
|
+
content:
|
|
405
|
+
PARTIAL_HEADER +
|
|
406
|
+
snippetMcpServersJson(
|
|
407
|
+
"Windsurf",
|
|
408
|
+
"~/.codeium/windsurf/mcp_config.json",
|
|
409
|
+
),
|
|
410
|
+
},
|
|
267
411
|
];
|
|
268
412
|
|
|
269
413
|
// ─── Write files ─────────────────────────────────────────────────────────────
|
|
@@ -297,10 +441,55 @@ for (const { path, content } of OUTPUTS) {
|
|
|
297
441
|
written++;
|
|
298
442
|
}
|
|
299
443
|
|
|
444
|
+
// ─── README install block (in-place rewrite) ────────────────────────────────
|
|
445
|
+
//
|
|
446
|
+
// Special-cased because README is read-modify-write — we can only update the
|
|
447
|
+
// region between the INSTALL_SNIPPETS markers, the rest of the file is human-
|
|
448
|
+
// authored prose.
|
|
449
|
+
|
|
450
|
+
const README_PATH = resolve(ROOT, "README.md");
|
|
451
|
+
|
|
452
|
+
if (!existsSync(README_PATH)) {
|
|
453
|
+
console.error(`✗ README.md not found at ${README_PATH}`);
|
|
454
|
+
process.exit(1);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const currentReadme = readFileSync(README_PATH, "utf8");
|
|
458
|
+
let freshReadme;
|
|
459
|
+
try {
|
|
460
|
+
freshReadme = rewriteReadme(currentReadme, readmeInstallBlock());
|
|
461
|
+
} catch (err) {
|
|
462
|
+
console.error("✗ Cannot rewrite README.md install block:");
|
|
463
|
+
console.error(" " + (err.message || err).split("\n").join("\n "));
|
|
464
|
+
process.exit(1);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (currentReadme === freshReadme) {
|
|
468
|
+
unchanged++;
|
|
469
|
+
} else if (checkMode) {
|
|
470
|
+
console.error("✗ Drift detected: README.md install block is stale");
|
|
471
|
+
console.error(
|
|
472
|
+
" The INSTALL_SNIPPETS_START/END region in README.md does not match",
|
|
473
|
+
);
|
|
474
|
+
console.error(
|
|
475
|
+
" what the generator would emit from src/configs/source.json.",
|
|
476
|
+
);
|
|
477
|
+
console.error(" Run `npm run generate:configs` and commit the result.");
|
|
478
|
+
process.exit(1);
|
|
479
|
+
} else {
|
|
480
|
+
writeFileSync(README_PATH, freshReadme, "utf8");
|
|
481
|
+
console.log("✓ Generated README.md (install block)");
|
|
482
|
+
written++;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const totalArtifacts = OUTPUTS.length + 1; // +1 for README
|
|
486
|
+
|
|
300
487
|
if (checkMode) {
|
|
301
|
-
console.log(
|
|
488
|
+
console.log(
|
|
489
|
+
`✓ All ${totalArtifacts} artifacts in sync with source.json`,
|
|
490
|
+
);
|
|
302
491
|
} else {
|
|
303
492
|
console.log(
|
|
304
|
-
`\nDone: ${written} written, ${unchanged} unchanged (${
|
|
493
|
+
`\nDone: ${written} written, ${unchanged} unchanged (${totalArtifacts} total)`,
|
|
305
494
|
);
|
|
306
495
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* install-hooks.mjs
|
|
4
|
+
*
|
|
5
|
+
* Installs the optional pre-push hook for local drift detection. The hook
|
|
6
|
+
* runs `npm run verify:configs` before every push and aborts if any of the
|
|
7
|
+
* 15 generated artifacts is out of sync with src/configs/source.json.
|
|
8
|
+
*
|
|
9
|
+
* The hook is per-clone (.git/hooks/ is not committed) and opt-in. CI is
|
|
10
|
+
* the authoritative gate — see .github/workflows/verify-configs.yml.
|
|
11
|
+
*
|
|
12
|
+
* Usage: npm run install-hooks
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
writeFileSync,
|
|
17
|
+
chmodSync,
|
|
18
|
+
existsSync,
|
|
19
|
+
mkdirSync,
|
|
20
|
+
} from "node:fs";
|
|
21
|
+
import { resolve, dirname } from "node:path";
|
|
22
|
+
import { fileURLToPath } from "node:url";
|
|
23
|
+
|
|
24
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
const ROOT = resolve(__dirname, "..");
|
|
26
|
+
const HOOKS_DIR = resolve(ROOT, ".git/hooks");
|
|
27
|
+
const HOOK_PATH = resolve(HOOKS_DIR, "pre-push");
|
|
28
|
+
|
|
29
|
+
if (!existsSync(resolve(ROOT, ".git"))) {
|
|
30
|
+
console.error(
|
|
31
|
+
"✗ Not a git repo (no .git directory found at " + ROOT + ").",
|
|
32
|
+
);
|
|
33
|
+
console.error(" Cannot install pre-push hook.");
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
mkdirSync(HOOKS_DIR, { recursive: true });
|
|
38
|
+
|
|
39
|
+
const HOOK_BODY = `#!/usr/bin/env bash
|
|
40
|
+
# Auto-generated by scripts/install-hooks.mjs.
|
|
41
|
+
# Aborts the push if any of the 15 distribution artifacts has drifted from
|
|
42
|
+
# src/configs/source.json. Re-run install-hooks after pulling generator changes.
|
|
43
|
+
#
|
|
44
|
+
# To bypass for a one-off (NOT recommended for branches targeting main):
|
|
45
|
+
# git push --no-verify
|
|
46
|
+
|
|
47
|
+
set -e
|
|
48
|
+
|
|
49
|
+
# Find repo root so the hook works regardless of where 'git push' was invoked.
|
|
50
|
+
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
|
51
|
+
cd "$REPO_ROOT"
|
|
52
|
+
|
|
53
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
54
|
+
echo "pre-push: node not found in PATH; skipping drift check"
|
|
55
|
+
exit 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
echo "pre-push: verifying distribution config drift..."
|
|
59
|
+
if ! node scripts/generate-configs.mjs --check; then
|
|
60
|
+
echo ""
|
|
61
|
+
echo "✗ Push aborted: distribution configs are out of sync with src/configs/source.json"
|
|
62
|
+
echo " Run \\\`npm run generate:configs\\\` to fix, commit the result, then push again."
|
|
63
|
+
echo " See CONTRIBUTING.md for details."
|
|
64
|
+
exit 1
|
|
65
|
+
fi
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
writeFileSync(HOOK_PATH, HOOK_BODY, "utf8");
|
|
69
|
+
chmodSync(HOOK_PATH, 0o755);
|
|
70
|
+
|
|
71
|
+
console.log("✓ Installed pre-push hook at " + HOOK_PATH);
|
|
72
|
+
console.log(" It will run `node scripts/generate-configs.mjs --check`");
|
|
73
|
+
console.log(" before every push and abort on drift.");
|
|
74
|
+
console.log("");
|
|
75
|
+
console.log(" To remove: rm " + HOOK_PATH);
|
|
76
|
+
console.log(" To bypass once: git push --no-verify");
|
package/server.json
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
3
|
"name": "io.github.mnemoverse/mcp-memory-server",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "Shared AI memory across Claude, Cursor, VS Code, ChatGPT. Write once, recall anywhere.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/mnemoverse/mcp-memory-server",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.2",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"version": "0.3.
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
|
|
12
|
+
"registryType": "npm",
|
|
13
|
+
"identifier": "@mnemoverse/mcp-memory-server",
|
|
14
|
+
"version": "0.3.2",
|
|
15
|
+
"transport": {
|
|
16
|
+
"type": "stdio"
|
|
17
|
+
},
|
|
18
18
|
"environmentVariables": [
|
|
19
19
|
{
|
|
20
20
|
"name": "MNEMOVERSE_API_KEY",
|
|
21
21
|
"description": "Your Mnemoverse API key (starts with mk_live_). Get one free at https://console.mnemoverse.com",
|
|
22
22
|
"isRequired": true,
|
|
23
|
+
"format": "string",
|
|
23
24
|
"isSecret": true
|
|
24
25
|
}
|
|
25
26
|
]
|
package/smithery.yaml
CHANGED
package/src/configs/source.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
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
3
|
"name": "mnemoverse",
|
|
4
4
|
"displayName": "Mnemoverse Memory",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Shared AI memory across Claude, Cursor, VS Code, ChatGPT. Write once, recall anywhere.",
|
|
6
6
|
"type": "stdio",
|
|
7
7
|
"command": "npx",
|
|
8
|
-
"args": ["-y", "@mnemoverse/mcp-memory-server"],
|
|
8
|
+
"args": ["-y", "@mnemoverse/mcp-memory-server@latest"],
|
|
9
9
|
"env": {
|
|
10
10
|
"MNEMOVERSE_API_KEY": {
|
|
11
11
|
"value": "mk_live_YOUR_KEY",
|