@mnemoverse/mcp-memory-server 0.3.1 → 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.
@@ -0,0 +1,138 @@
1
+ name: release
2
+
3
+ # Automated release pipeline for @mnemoverse/mcp-memory-server.
4
+ #
5
+ # Trigger: push a semver tag `vX.Y.Z` to main (e.g. `git tag v0.3.2 && git push origin v0.3.2`).
6
+ #
7
+ # What this workflow does, in order:
8
+ # 1. Checks that the tag's version matches package.json#version (catches "forgot to bump" mistakes).
9
+ # 2. npm ci + npm run build (prebuild regenerates every generated artifact from source.json).
10
+ # 3. npm run verify:configs — drift check, fails fast if anything is out of sync with source.json.
11
+ # 4. npm publish — uses a repo-scoped automation token stored in the NPM_TOKEN secret.
12
+ # 5. Installs mcp-publisher CLI (Linux amd64 bottle from the releases bucket).
13
+ # 6. mcp-publisher login github-oidc — uses GitHub Actions' OIDC token, NO stored PAT.
14
+ # 7. mcp-publisher publish — uploads the freshly-generated server.json to registry.modelcontextprotocol.io.
15
+ # 8. gh release create — posts a GitHub release with auto-generated notes.
16
+ #
17
+ # Why OIDC instead of a PAT:
18
+ # The GitHub OIDC provider issues a short-lived JWT that the MCP Registry trusts on the basis
19
+ # of the repo's owner (mnemoverse) and branch/tag claim. No long-lived secret sits in the repo.
20
+ # Prereq: `permissions: id-token: write` on the job, and the authenticating user's org
21
+ # membership (izgorodin in mnemoverse) must be public — already done.
22
+ #
23
+ # Prerequisite secrets you must add at repo Settings > Secrets and variables > Actions:
24
+ # - NPM_TOKEN — npm automation token from npmjs.com/settings/{org}/tokens/granular-access-tokens/new
25
+ # (select "Automation", grant publish access to @mnemoverse/mcp-memory-server).
26
+ #
27
+ # To release:
28
+ # 1. Bump version in package.json + src/index.ts on main (keep them in sync).
29
+ # 2. `npm run generate:configs` to propagate the new version to server.json.
30
+ # 3. Commit, push to main (through PR, drift CI passes).
31
+ # 4. `git tag v$(node -p "require('./package.json').version")`.
32
+ # 5. `git push origin v0.x.y`.
33
+ # The workflow does the rest.
34
+
35
+ on:
36
+ push:
37
+ tags:
38
+ - "v*"
39
+ workflow_dispatch:
40
+ inputs:
41
+ tag:
42
+ description: "Tag to release (e.g. v0.3.2). Must already exist."
43
+ required: true
44
+
45
+ jobs:
46
+ release:
47
+ runs-on: ubuntu-latest
48
+ permissions:
49
+ # contents:write — needed to create the GitHub release.
50
+ # id-token:write — required by `mcp-publisher login github-oidc`.
51
+ contents: write
52
+ id-token: write
53
+
54
+ steps:
55
+ - name: Checkout tag
56
+ uses: actions/checkout@v4
57
+ with:
58
+ ref: ${{ github.event.inputs.tag || github.ref }}
59
+ fetch-depth: 0
60
+
61
+ - name: Setup Node
62
+ uses: actions/setup-node@v4
63
+ with:
64
+ node-version: "20"
65
+ registry-url: "https://registry.npmjs.org"
66
+
67
+ - name: Verify tag matches package.json#version
68
+ run: |
69
+ set -euo pipefail
70
+ TAG="${{ github.event.inputs.tag || github.ref_name }}"
71
+ TAG_VERSION="${TAG#v}"
72
+ PKG_VERSION="$(node -p "require('./package.json').version")"
73
+ echo "tag: $TAG"
74
+ echo "tag version: $TAG_VERSION"
75
+ echo "pkg version: $PKG_VERSION"
76
+ if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
77
+ echo "::error::Tag $TAG (version $TAG_VERSION) does not match package.json version $PKG_VERSION"
78
+ exit 1
79
+ fi
80
+
81
+ - name: Install dependencies
82
+ run: npm ci
83
+
84
+ - name: Build (runs generate:configs via prebuild)
85
+ run: npm run build
86
+
87
+ - name: Verify no drift between source.json and generated artifacts
88
+ run: npm run verify:configs
89
+
90
+ - name: Publish to npm
91
+ run: npm publish --access public
92
+ env:
93
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
94
+
95
+ - name: Install mcp-publisher CLI
96
+ run: |
97
+ set -euo pipefail
98
+ curl -sSL \
99
+ "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_linux_amd64.tar.gz" \
100
+ | tar xz mcp-publisher
101
+ ./mcp-publisher --help
102
+
103
+ - name: Authenticate with MCP Registry via GitHub OIDC
104
+ run: ./mcp-publisher login github-oidc
105
+
106
+ - name: Publish to Official MCP Registry
107
+ run: ./mcp-publisher publish
108
+
109
+ - name: Verify the registry entry shows the new version
110
+ run: |
111
+ set -euo pipefail
112
+ TAG="${{ github.event.inputs.tag || github.ref_name }}"
113
+ VERSION="${TAG#v}"
114
+ echo "Waiting a few seconds for the registry to propagate..."
115
+ sleep 3
116
+ RESULT="$(curl -sS "https://registry.modelcontextprotocol.io/v0.1/servers/io.github.mnemoverse%2Fmcp-memory-server/versions/$VERSION")"
117
+ echo "$RESULT" | python3 -m json.tool
118
+ echo "$RESULT" | python3 -c "
119
+ import sys, json
120
+ d = json.load(sys.stdin)
121
+ srv = d['server']
122
+ assert srv['version'] == '$VERSION', f\"registry version {srv['version']} != $VERSION\"
123
+ print(f'✓ Registry shows {srv[\"name\"]}@{srv[\"version\"]}')
124
+ "
125
+
126
+ - name: Create GitHub release
127
+ uses: softprops/action-gh-release@v2
128
+ with:
129
+ tag_name: ${{ github.event.inputs.tag || github.ref_name }}
130
+ name: ${{ github.event.inputs.tag || github.ref_name }}
131
+ generate_release_notes: true
132
+ body: |
133
+ Published via automated release pipeline (`.github/workflows/release.yml`).
134
+
135
+ - npm: https://www.npmjs.com/package/@mnemoverse/mcp-memory-server
136
+ - MCP Registry: https://registry.modelcontextprotocol.io/v0.1/servers?search=mnemoverse
137
+
138
+ Full changelog below.
package/CONTRIBUTING.md CHANGED
@@ -103,9 +103,13 @@ The generator is **idempotent**: running it twice in a row produces zero changes
103
103
 
104
104
  `package.json#version` → `src/index.ts#version` (server name reported to MCP clients) → `server.json#version` (Official MCP Registry).
105
105
 
106
- Today these are bumped manually and kept in sync by hand. If they drift, the generator's drift check on `server.json` will catch it (because `server.json` is generated from `package.json#version`).
106
+ These are bumped manually in the first two files and propagated by the generator to the third. If they drift, the drift check on `server.json` catches it on every PR.
107
107
 
108
- When releasing:
108
+ ### Automated release pipeline
109
+
110
+ Releases are automated by [`.github/workflows/release.yml`](.github/workflows/release.yml). You bump the version on `main`, push a semver tag, and the workflow does the rest: npm publish, MCP Registry publish (via GitHub OIDC — no stored PAT), GitHub release.
111
+
112
+ The workflow is triggered by any tag matching `v*` pushed to the repo. To release:
109
113
 
110
114
  ```bash
111
115
  # 1. Bump version in package.json
@@ -117,19 +121,55 @@ $EDITOR src/index.ts
117
121
  # 3. Regenerate (this updates server.json to match)
118
122
  npm run generate:configs
119
123
 
120
- # 4. Build and run e2e
124
+ # 4. Build and run any local checks you want before tagging
121
125
  npm run build
122
- # ... live e2e against production ...
123
-
124
- # 5. Commit, tag, push, publish
125
- git add -A && git commit -m "chore: release vX.Y.Z"
126
- git tag -a vX.Y.Z -m "..."
127
- git push origin main vX.Y.Z
128
- npm publish
129
- gh release create vX.Y.Z --notes "..."
126
+ npm run verify:configs
127
+
128
+ # 5. PR + squash-merge to main (drift CI runs on the PR)
129
+ git checkout -b release/vX.Y.Z
130
+ git add -A && git commit -m "release: vX.Y.Z"
131
+ git push -u origin release/vX.Y.Z
132
+ gh pr create --fill && gh pr merge --squash --delete-branch
133
+ git checkout main && git pull --ff-only
134
+
135
+ # 6. Tag main and push the tag
136
+ git tag -a vX.Y.Z -m "vX.Y.Z"
137
+ git push origin vX.Y.Z
138
+ ```
139
+
140
+ That push fires [`.github/workflows/release.yml`](.github/workflows/release.yml), which:
141
+
142
+ 1. Verifies the tag matches `package.json#version` (belt and suspenders).
143
+ 2. Runs `npm ci && npm run build` (which also runs `generate:configs` via `prebuild`).
144
+ 3. Runs `npm run verify:configs` for drift.
145
+ 4. `npm publish` using the `NPM_TOKEN` secret.
146
+ 5. Installs `mcp-publisher` from its Linux amd64 release bottle.
147
+ 6. Authenticates to the Registry via `mcp-publisher login github-oidc` — this uses GitHub Actions' OIDC identity token. **No long-lived PAT is stored anywhere.** The prerequisite is that the authenticating GitHub account's membership in the `mnemoverse` org be **public** (already the case for `izgorodin`).
148
+ 7. `mcp-publisher publish` uploads the freshly-generated `server.json`.
149
+ 8. Verifies the registry entry via a direct curl against the public API.
150
+ 9. Creates a GitHub release with auto-generated notes.
151
+
152
+ If any step fails, the release is aborted — nothing partial gets published. You can re-push the same tag after fixing the issue.
153
+
154
+ ### One-time setup for the workflow
155
+
156
+ A single secret must be added at [Settings → Secrets → Actions](https://github.com/mnemoverse/mcp-memory-server/settings/secrets/actions):
157
+
158
+ | Secret | How to get it |
159
+ | ------ | ------------- |
160
+ | `NPM_TOKEN` | [npmjs.com → Settings → Access Tokens → Generate New Token](https://www.npmjs.com/settings/mnemoverse/tokens/granular-access-tokens/new) → **Automation** token, scope: publish to `@mnemoverse/mcp-memory-server`. |
161
+
162
+ Nothing else. GitHub OIDC provides the MCP Registry credential at run time, so we do not store an `MCP_GITHUB_TOKEN` secret at all.
163
+
164
+ ### Manual trigger
165
+
166
+ If you need to re-run the pipeline for a tag that was already pushed (e.g. the workflow was added after the tag), use `workflow_dispatch`:
167
+
168
+ ```bash
169
+ gh workflow run release.yml -f tag=v0.3.1
130
170
  ```
131
171
 
132
- A future PR will templatize `src/index.ts#version` so `package.json` is the only place to edit it.
172
+ Or click **Run workflow** on the Actions tab and enter the tag.
133
173
 
134
174
  ## Testing changes locally
135
175
 
package/dist/index.js CHANGED
@@ -1,7 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
2
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
5
  import { z } from "zod";
6
+ // Version is read at runtime from package.json so there is exactly one place
7
+ // to bump on each release. Works both from `dist/` during local dev and from
8
+ // `node_modules/@mnemoverse/mcp-memory-server/dist/` after an npm install.
9
+ const require = createRequire(import.meta.url);
10
+ const pkg = require("../package.json");
5
11
  const API_URL = process.env.MNEMOVERSE_API_URL || "https://core.mnemoverse.com/api/v1";
6
12
  const API_KEY = process.env.MNEMOVERSE_API_KEY || "";
7
13
  // Hard cap on tool result size — required by Claude Connectors Directory
@@ -13,6 +19,19 @@ if (!API_KEY) {
13
19
  "Get your free key at https://console.mnemoverse.com");
14
20
  process.exit(1);
15
21
  }
22
+ /**
23
+ * Fetch from the Mnemoverse core API with authentication.
24
+ *
25
+ * Generic so call sites can declare the expected response shape:
26
+ *
27
+ * const r = await apiFetch<{ stored: boolean; atom_id: string }>("/memory/write", { ... });
28
+ *
29
+ * Handles 204 No Content and empty bodies defensively — FastAPI DELETE
30
+ * handlers may switch to 204 in the future even though today they return
31
+ * a JSON body.
32
+ *
33
+ * @throws Error with message `Mnemoverse API error {status}: {body}` on non-2xx.
34
+ */
16
35
  async function apiFetch(path, options = {}) {
17
36
  const res = await fetch(`${API_URL}${path}`, {
18
37
  ...options,
@@ -26,23 +45,37 @@ async function apiFetch(path, options = {}) {
26
45
  const text = await res.text();
27
46
  throw new Error(`Mnemoverse API error ${res.status}: ${text}`);
28
47
  }
29
- return res.json();
48
+ // 204 No Content or empty body — return an empty object cast as T so
49
+ // call sites using optional chaining still work without crashing.
50
+ if (res.status === 204 || res.headers.get("content-length") === "0") {
51
+ return {};
52
+ }
53
+ return (await res.json());
30
54
  }
31
55
  /**
32
56
  * Truncate a result string to MAX_RESULT_CHARS, appending a notice if truncated.
33
57
  * Required by Claude Connectors Directory submission policy.
58
+ *
59
+ * Defensive against splitting UTF-16 surrogate pairs: if the character right
60
+ * before the cut point is a high surrogate (U+D800–U+DBFF), drop it so the
61
+ * result stays well-formed. Otherwise an emoji or non-BMP character at the
62
+ * boundary can produce a lone surrogate and corrupt downstream JSON encoding.
34
63
  */
35
64
  function capResult(text) {
36
65
  if (text.length <= MAX_RESULT_CHARS)
37
66
  return text;
38
- const truncated = text.slice(0, MAX_RESULT_CHARS - 200);
67
+ let truncated = text.slice(0, MAX_RESULT_CHARS - 200);
68
+ const lastCode = truncated.charCodeAt(truncated.length - 1);
69
+ if (lastCode >= 0xd800 && lastCode <= 0xdbff) {
70
+ truncated = truncated.slice(0, -1);
71
+ }
39
72
  return (truncated +
40
73
  `\n\n[…truncated to fit 25K token limit. Use a more specific query or smaller top_k to see all results.]`);
41
74
  }
42
75
  // --- Server setup ---
43
76
  const server = new McpServer({
44
77
  name: "mnemoverse-memory",
45
- version: "0.3.1",
78
+ version: pkg.version,
46
79
  });
47
80
  // --- Tool: memory_write ---
48
81
  server.registerTool("memory_write", {
@@ -70,7 +103,7 @@ server.registerTool("memory_write", {
70
103
  openWorldHint: true,
71
104
  },
72
105
  }, async ({ content, concepts, domain }) => {
73
- const result = await apiFetch("/memory/write", {
106
+ const r = await apiFetch("/memory/write", {
74
107
  method: "POST",
75
108
  body: JSON.stringify({
76
109
  content,
@@ -78,13 +111,13 @@ server.registerTool("memory_write", {
78
111
  domain: domain || "general",
79
112
  }),
80
113
  });
81
- const r = result;
82
- if (r.stored) {
114
+ const importance = (r?.importance ?? 0).toFixed(2);
115
+ if (r?.stored) {
83
116
  return {
84
117
  content: [
85
118
  {
86
119
  type: "text",
87
- text: `Stored (importance: ${r.importance.toFixed(2)}). ID: ${r.atom_id}`,
120
+ text: `Stored (importance: ${importance}). ID: ${r.atom_id ?? "unknown"}`,
88
121
  },
89
122
  ],
90
123
  };
@@ -93,7 +126,7 @@ server.registerTool("memory_write", {
93
126
  content: [
94
127
  {
95
128
  type: "text",
96
- text: `Filtered — ${r.reason} (importance: ${r.importance.toFixed(2)})`,
129
+ text: `Filtered — ${r?.reason ?? "unknown reason"} (importance: ${importance})`,
97
130
  },
98
131
  ],
99
132
  };
@@ -127,7 +160,7 @@ server.registerTool("memory_read", {
127
160
  openWorldHint: true,
128
161
  },
129
162
  }, async ({ query, top_k, domain }) => {
130
- const result = await apiFetch("/memory/read", {
163
+ const r = await apiFetch("/memory/read", {
131
164
  method: "POST",
132
165
  body: JSON.stringify({
133
166
  query,
@@ -136,19 +169,24 @@ server.registerTool("memory_read", {
136
169
  include_associations: true,
137
170
  }),
138
171
  });
139
- const r = result;
140
- if (r.items.length === 0) {
172
+ const items = Array.isArray(r?.items) ? r.items : [];
173
+ if (items.length === 0) {
141
174
  return {
142
175
  content: [
143
176
  { type: "text", text: "No memories found for this query." },
144
177
  ],
145
178
  };
146
179
  }
147
- const lines = r.items.map((item, i) => `${i + 1}. [${(item.relevance * 100).toFixed(0)}%] ${item.content}` +
148
- (item.concepts.length > 0
180
+ const lines = items.map((item, i) => {
181
+ const relevance = ((item?.relevance ?? 0) * 100).toFixed(0);
182
+ const content = item?.content ?? "(empty)";
183
+ const concepts = Array.isArray(item?.concepts) && item.concepts.length > 0
149
184
  ? ` (${item.concepts.join(", ")})`
150
- : ""));
151
- const text = lines.join("\n\n") + `\n\n(${r.search_time_ms.toFixed(0)}ms)`;
185
+ : "";
186
+ return `${i + 1}. [${relevance}%] ${content}${concepts}`;
187
+ });
188
+ const searchMs = (r?.search_time_ms ?? 0).toFixed(0);
189
+ const text = lines.join("\n\n") + `\n\n(${searchMs}ms)`;
152
190
  return {
153
191
  content: [
154
192
  {
@@ -175,21 +213,25 @@ server.registerTool("memory_feedback", {
175
213
  annotations: {
176
214
  title: "Rate Memory Helpfulness",
177
215
  readOnlyHint: false,
178
- destructiveHint: false,
216
+ // Feedback permanently mutates the memory's valence and importance
217
+ // scores on the backend — per MCP spec, that is a destructive update
218
+ // to the stored state (cf. ToolAnnotations.destructiveHint), even
219
+ // though the caller intends it as quality signal rather than delete.
220
+ destructiveHint: true,
179
221
  idempotentHint: false,
180
222
  openWorldHint: true,
181
223
  },
182
224
  }, async ({ atom_ids, outcome }) => {
183
- const result = await apiFetch("/memory/feedback", {
225
+ const r = await apiFetch("/memory/feedback", {
184
226
  method: "POST",
185
227
  body: JSON.stringify({ atom_ids, outcome }),
186
228
  });
187
- const r = result;
229
+ const count = r?.updated_count ?? 0;
188
230
  return {
189
231
  content: [
190
232
  {
191
233
  type: "text",
192
- text: `Feedback recorded for ${r.updated_count} memor${r.updated_count === 1 ? "y" : "ies"}.`,
234
+ text: `Feedback recorded for ${count} memor${count === 1 ? "y" : "ies"}.`,
193
235
  },
194
236
  ],
195
237
  };
@@ -206,13 +248,15 @@ server.registerTool("memory_stats", {
206
248
  openWorldHint: true,
207
249
  },
208
250
  }, async () => {
209
- const result = await apiFetch("/memory/stats");
210
- const r = result;
251
+ const r = await apiFetch("/memory/stats");
252
+ const domains = Array.isArray(r?.domains) && r.domains.length > 0
253
+ ? r.domains.join(", ")
254
+ : "general";
211
255
  const text = [
212
- `Memories: ${r.total_atoms} (${r.episodes} episodes, ${r.prototypes} prototypes)`,
213
- `Associations: ${r.hebbian_edges} Hebbian edges`,
214
- `Domains: ${r.domains.length > 0 ? r.domains.join(", ") : "general"}`,
215
- `Avg quality: valence ${r.avg_valence.toFixed(2)}, importance ${r.avg_importance.toFixed(2)}`,
256
+ `Memories: ${r?.total_atoms ?? 0} (${r?.episodes ?? 0} episodes, ${r?.prototypes ?? 0} prototypes)`,
257
+ `Associations: ${r?.hebbian_edges ?? 0} Hebbian edges`,
258
+ `Domains: ${domains}`,
259
+ `Avg quality: valence ${(r?.avg_valence ?? 0).toFixed(2)}, importance ${(r?.avg_importance ?? 0).toFixed(2)}`,
216
260
  ].join("\n");
217
261
  return { content: [{ type: "text", text }] };
218
262
  });
@@ -233,13 +277,11 @@ server.registerTool("memory_delete", {
233
277
  openWorldHint: true,
234
278
  },
235
279
  }, async ({ atom_id }) => {
236
- const result = await apiFetch(`/memory/atoms/${encodeURIComponent(atom_id)}`, {
237
- method: "DELETE",
238
- });
239
280
  // 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) {
281
+ // the atom didn't exist (or was already removed). count >= 1 means
282
+ // it was deleted.
283
+ const r = await apiFetch(`/memory/atoms/${encodeURIComponent(atom_id)}`, { method: "DELETE" });
284
+ if (!r?.deleted) {
243
285
  return {
244
286
  content: [
245
287
  {
@@ -278,19 +320,19 @@ server.registerTool("memory_delete_domain", {
278
320
  idempotentHint: true,
279
321
  openWorldHint: true,
280
322
  },
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;
323
+ },
324
+ // The `confirm: z.literal(true)` in the input schema is the safety
325
+ // interlock Zod rejects any call without confirm === true before it
326
+ // reaches this handler, so no runtime re-check is needed here.
327
+ async ({ domain }) => {
328
+ const r = await apiFetch(`/memory/domain/${encodeURIComponent(domain)}`, { method: "DELETE" });
329
+ const count = r?.deleted ?? 0;
330
+ const domainName = r?.domain ?? domain;
289
331
  return {
290
332
  content: [
291
333
  {
292
334
  type: "text",
293
- text: `Deleted ${r.deleted} ${r.deleted === 1 ? "memory" : "memories"} from domain "${r.domain}".`,
335
+ text: `Deleted ${count} ${count === 1 ? "memory" : "memories"} from domain "${domainName}".`,
294
336
  },
295
337
  ],
296
338
  };
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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnemoverse/mcp-memory-server",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
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": {
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/mnemoverse/mcp-memory-server",
7
7
  "source": "github"
8
8
  },
9
- "version": "0.3.1",
9
+ "version": "0.3.2",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "@mnemoverse/mcp-memory-server",
14
- "version": "0.3.1",
14
+ "version": "0.3.2",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },
package/src/index.ts CHANGED
@@ -1,9 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { createRequire } from "node:module";
3
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
6
  import { z } from "zod";
6
7
 
8
+ // Version is read at runtime from package.json so there is exactly one place
9
+ // to bump on each release. Works both from `dist/` during local dev and from
10
+ // `node_modules/@mnemoverse/mcp-memory-server/dist/` after an npm install.
11
+ const require = createRequire(import.meta.url);
12
+ const pkg = require("../package.json") as { version: string };
13
+
7
14
  const API_URL =
8
15
  process.env.MNEMOVERSE_API_URL || "https://core.mnemoverse.com/api/v1";
9
16
  const API_KEY = process.env.MNEMOVERSE_API_KEY || "";
@@ -21,10 +28,23 @@ if (!API_KEY) {
21
28
  process.exit(1);
22
29
  }
23
30
 
24
- async function apiFetch(
31
+ /**
32
+ * Fetch from the Mnemoverse core API with authentication.
33
+ *
34
+ * Generic so call sites can declare the expected response shape:
35
+ *
36
+ * const r = await apiFetch<{ stored: boolean; atom_id: string }>("/memory/write", { ... });
37
+ *
38
+ * Handles 204 No Content and empty bodies defensively — FastAPI DELETE
39
+ * handlers may switch to 204 in the future even though today they return
40
+ * a JSON body.
41
+ *
42
+ * @throws Error with message `Mnemoverse API error {status}: {body}` on non-2xx.
43
+ */
44
+ async function apiFetch<T = unknown>(
25
45
  path: string,
26
46
  options: RequestInit = {},
27
- ): Promise<unknown> {
47
+ ): Promise<T> {
28
48
  const res = await fetch(`${API_URL}${path}`, {
29
49
  ...options,
30
50
  headers: {
@@ -39,16 +59,31 @@ async function apiFetch(
39
59
  throw new Error(`Mnemoverse API error ${res.status}: ${text}`);
40
60
  }
41
61
 
42
- return res.json();
62
+ // 204 No Content or empty body — return an empty object cast as T so
63
+ // call sites using optional chaining still work without crashing.
64
+ if (res.status === 204 || res.headers.get("content-length") === "0") {
65
+ return {} as T;
66
+ }
67
+
68
+ return (await res.json()) as T;
43
69
  }
44
70
 
45
71
  /**
46
72
  * Truncate a result string to MAX_RESULT_CHARS, appending a notice if truncated.
47
73
  * Required by Claude Connectors Directory submission policy.
74
+ *
75
+ * Defensive against splitting UTF-16 surrogate pairs: if the character right
76
+ * before the cut point is a high surrogate (U+D800–U+DBFF), drop it so the
77
+ * result stays well-formed. Otherwise an emoji or non-BMP character at the
78
+ * boundary can produce a lone surrogate and corrupt downstream JSON encoding.
48
79
  */
49
80
  function capResult(text: string): string {
50
81
  if (text.length <= MAX_RESULT_CHARS) return text;
51
- const truncated = text.slice(0, MAX_RESULT_CHARS - 200);
82
+ let truncated = text.slice(0, MAX_RESULT_CHARS - 200);
83
+ const lastCode = truncated.charCodeAt(truncated.length - 1);
84
+ if (lastCode >= 0xd800 && lastCode <= 0xdbff) {
85
+ truncated = truncated.slice(0, -1);
86
+ }
52
87
  return (
53
88
  truncated +
54
89
  `\n\n[…truncated to fit 25K token limit. Use a more specific query or smaller top_k to see all results.]`
@@ -59,7 +94,7 @@ function capResult(text: string): string {
59
94
 
60
95
  const server = new McpServer({
61
96
  name: "mnemoverse-memory",
62
- version: "0.3.1",
97
+ version: pkg.version,
63
98
  });
64
99
 
65
100
  // --- Tool: memory_write ---
@@ -97,7 +132,12 @@ server.registerTool(
97
132
  },
98
133
  },
99
134
  async ({ content, concepts, domain }) => {
100
- const result = await apiFetch("/memory/write", {
135
+ const r = await apiFetch<{
136
+ stored?: boolean;
137
+ atom_id?: string | null;
138
+ importance?: number;
139
+ reason?: string;
140
+ }>("/memory/write", {
101
141
  method: "POST",
102
142
  body: JSON.stringify({
103
143
  content,
@@ -106,19 +146,14 @@ server.registerTool(
106
146
  }),
107
147
  });
108
148
 
109
- const r = result as {
110
- stored: boolean;
111
- atom_id: string | null;
112
- importance: number;
113
- reason: string;
114
- };
149
+ const importance = (r?.importance ?? 0).toFixed(2);
115
150
 
116
- if (r.stored) {
151
+ if (r?.stored) {
117
152
  return {
118
153
  content: [
119
154
  {
120
155
  type: "text" as const,
121
- text: `Stored (importance: ${r.importance.toFixed(2)}). ID: ${r.atom_id}`,
156
+ text: `Stored (importance: ${importance}). ID: ${r.atom_id ?? "unknown"}`,
122
157
  },
123
158
  ],
124
159
  };
@@ -127,7 +162,7 @@ server.registerTool(
127
162
  content: [
128
163
  {
129
164
  type: "text" as const,
130
- text: `Filtered — ${r.reason} (importance: ${r.importance.toFixed(2)})`,
165
+ text: `Filtered — ${r?.reason ?? "unknown reason"} (importance: ${importance})`,
131
166
  },
132
167
  ],
133
168
  };
@@ -168,7 +203,15 @@ server.registerTool(
168
203
  },
169
204
  },
170
205
  async ({ query, top_k, domain }) => {
171
- const result = await apiFetch("/memory/read", {
206
+ const r = await apiFetch<{
207
+ items?: Array<{
208
+ content?: string;
209
+ relevance?: number;
210
+ concepts?: string[];
211
+ domain?: string;
212
+ }>;
213
+ search_time_ms?: number;
214
+ }>("/memory/read", {
172
215
  method: "POST",
173
216
  body: JSON.stringify({
174
217
  query,
@@ -178,17 +221,9 @@ server.registerTool(
178
221
  }),
179
222
  });
180
223
 
181
- const r = result as {
182
- items: Array<{
183
- content: string;
184
- relevance: number;
185
- concepts: string[];
186
- domain: string;
187
- }>;
188
- search_time_ms: number;
189
- };
224
+ const items = Array.isArray(r?.items) ? r.items : [];
190
225
 
191
- if (r.items.length === 0) {
226
+ if (items.length === 0) {
192
227
  return {
193
228
  content: [
194
229
  { type: "text" as const, text: "No memories found for this query." },
@@ -196,15 +231,17 @@ server.registerTool(
196
231
  };
197
232
  }
198
233
 
199
- const lines = r.items.map(
200
- (item, i) =>
201
- `${i + 1}. [${(item.relevance * 100).toFixed(0)}%] ${item.content}` +
202
- (item.concepts.length > 0
203
- ? ` (${item.concepts.join(", ")})`
204
- : ""),
205
- );
234
+ const lines = items.map((item, i) => {
235
+ const relevance = ((item?.relevance ?? 0) * 100).toFixed(0);
236
+ const content = item?.content ?? "(empty)";
237
+ const concepts = Array.isArray(item?.concepts) && item.concepts.length > 0
238
+ ? ` (${item.concepts.join(", ")})`
239
+ : "";
240
+ return `${i + 1}. [${relevance}%] ${content}${concepts}`;
241
+ });
206
242
 
207
- const text = lines.join("\n\n") + `\n\n(${r.search_time_ms.toFixed(0)}ms)`;
243
+ const searchMs = (r?.search_time_ms ?? 0).toFixed(0);
244
+ const text = lines.join("\n\n") + `\n\n(${searchMs}ms)`;
208
245
 
209
246
  return {
210
247
  content: [
@@ -238,24 +275,28 @@ server.registerTool(
238
275
  annotations: {
239
276
  title: "Rate Memory Helpfulness",
240
277
  readOnlyHint: false,
241
- destructiveHint: false,
278
+ // Feedback permanently mutates the memory's valence and importance
279
+ // scores on the backend — per MCP spec, that is a destructive update
280
+ // to the stored state (cf. ToolAnnotations.destructiveHint), even
281
+ // though the caller intends it as quality signal rather than delete.
282
+ destructiveHint: true,
242
283
  idempotentHint: false,
243
284
  openWorldHint: true,
244
285
  },
245
286
  },
246
287
  async ({ atom_ids, outcome }) => {
247
- const result = await apiFetch("/memory/feedback", {
288
+ const r = await apiFetch<{ updated_count?: number }>("/memory/feedback", {
248
289
  method: "POST",
249
290
  body: JSON.stringify({ atom_ids, outcome }),
250
291
  });
251
292
 
252
- const r = result as { updated_count: number };
293
+ const count = r?.updated_count ?? 0;
253
294
 
254
295
  return {
255
296
  content: [
256
297
  {
257
298
  type: "text" as const,
258
- text: `Feedback recorded for ${r.updated_count} memor${r.updated_count === 1 ? "y" : "ies"}.`,
299
+ text: `Feedback recorded for ${count} memor${count === 1 ? "y" : "ies"}.`,
259
300
  },
260
301
  ],
261
302
  };
@@ -279,23 +320,25 @@ server.registerTool(
279
320
  },
280
321
  },
281
322
  async () => {
282
- const result = await apiFetch("/memory/stats");
283
-
284
- const r = result as {
285
- total_atoms: number;
286
- episodes: number;
287
- prototypes: number;
288
- hebbian_edges: number;
289
- domains: string[];
290
- avg_valence: number;
291
- avg_importance: number;
292
- };
323
+ const r = await apiFetch<{
324
+ total_atoms?: number;
325
+ episodes?: number;
326
+ prototypes?: number;
327
+ hebbian_edges?: number;
328
+ domains?: string[];
329
+ avg_valence?: number;
330
+ avg_importance?: number;
331
+ }>("/memory/stats");
332
+
333
+ const domains = Array.isArray(r?.domains) && r.domains.length > 0
334
+ ? r.domains.join(", ")
335
+ : "general";
293
336
 
294
337
  const text = [
295
- `Memories: ${r.total_atoms} (${r.episodes} episodes, ${r.prototypes} prototypes)`,
296
- `Associations: ${r.hebbian_edges} Hebbian edges`,
297
- `Domains: ${r.domains.length > 0 ? r.domains.join(", ") : "general"}`,
298
- `Avg quality: valence ${r.avg_valence.toFixed(2)}, importance ${r.avg_importance.toFixed(2)}`,
338
+ `Memories: ${r?.total_atoms ?? 0} (${r?.episodes ?? 0} episodes, ${r?.prototypes ?? 0} prototypes)`,
339
+ `Associations: ${r?.hebbian_edges ?? 0} Hebbian edges`,
340
+ `Domains: ${domains}`,
341
+ `Avg quality: valence ${(r?.avg_valence ?? 0).toFixed(2)}, importance ${(r?.avg_importance ?? 0).toFixed(2)}`,
299
342
  ].join("\n");
300
343
 
301
344
  return { content: [{ type: "text" as const, text }] };
@@ -326,15 +369,15 @@ server.registerTool(
326
369
  },
327
370
  },
328
371
  async ({ atom_id }) => {
329
- const result = await apiFetch(`/memory/atoms/${encodeURIComponent(atom_id)}`, {
330
- method: "DELETE",
331
- });
332
-
333
372
  // 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 };
373
+ // the atom didn't exist (or was already removed). count >= 1 means
374
+ // it was deleted.
375
+ const r = await apiFetch<{ deleted?: number; atom_id?: string }>(
376
+ `/memory/atoms/${encodeURIComponent(atom_id)}`,
377
+ { method: "DELETE" },
378
+ );
336
379
 
337
- if (!r.deleted) {
380
+ if (!r?.deleted) {
338
381
  return {
339
382
  content: [
340
383
  {
@@ -385,24 +428,23 @@ server.registerTool(
385
428
  openWorldHint: true,
386
429
  },
387
430
  },
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
- });
431
+ // The `confirm: z.literal(true)` in the input schema is the safety
432
+ // interlock — Zod rejects any call without confirm === true before it
433
+ // reaches this handler, so no runtime re-check is needed here.
434
+ async ({ domain }) => {
435
+ const r = await apiFetch<{ deleted?: number; domain?: string }>(
436
+ `/memory/domain/${encodeURIComponent(domain)}`,
437
+ { method: "DELETE" },
438
+ );
398
439
 
399
- const r = result as { deleted: number; domain: string };
440
+ const count = r?.deleted ?? 0;
441
+ const domainName = r?.domain ?? domain;
400
442
 
401
443
  return {
402
444
  content: [
403
445
  {
404
446
  type: "text" as const,
405
- text: `Deleted ${r.deleted} ${r.deleted === 1 ? "memory" : "memories"} from domain "${r.domain}".`,
447
+ text: `Deleted ${count} ${count === 1 ? "memory" : "memories"} from domain "${domainName}".`,
406
448
  },
407
449
  ],
408
450
  };