oh-memos-mcp 2.1.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,260 +1,271 @@
1
- # oh-memos-mcp
2
-
3
- [![npm version](https://img.shields.io/npm/v/oh-memos-mcp.svg)](https://www.npmjs.com/package/oh-memos-mcp)
4
- [![Node.js >= 18](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org)
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
-
7
- MCP Server for **oh-memos** — Intelligent Persistent Memory for AI Assistants.
8
-
9
- Pure Node.js. No Python required. Works with `npx` out of the box.
10
-
11
- ---
12
-
13
- ## Prerequisites
14
-
15
- oh-memos backend API must be running before connecting this MCP server:
16
-
17
- - **oh-memos API** on `http://localhost:18000`
18
- - **Neo4j** on `localhost:7687` (Knowledge Graph)
19
- - **Qdrant** on `localhost:6333` (Vector Search)
20
-
21
- > Start all services: run `scripts\local\start.bat` from the [oh-memos repo](https://github.com/xigou/oh-memos).
22
-
23
- ---
24
-
25
- ## Quick Start
26
-
27
- Add to your Claude Code `~/.claude/settings.json`:
28
-
29
- ```json
30
- {
31
- "mcpServers": {
32
- "oh-memos": {
33
- "command": "npx",
34
- "args": ["-y", "oh-memos-mcp"],
35
- "env": {
36
- "MEMOS_URL": "http://localhost:18000",
37
- "MEMOS_USER": "dev_user",
38
- "MEMOS_DEFAULT_CUBE": "dev_cube",
39
- "MEMOS_CUBES_DIR": "G:/test/oh-memos/data/oh-memos_cubes"
40
- }
41
- }
42
- }
43
- }
44
- ```
45
-
46
- Or use a `.env` file in your working directory (the server auto-discovers it):
47
-
48
- ```bash
49
- cp node_modules/oh-memos-mcp/.env.example .env
50
- # Edit .env with your paths
51
- npx oh-memos-mcp
52
- ```
53
-
54
- ---
55
-
56
- ## Configuration Examples
57
-
58
- ### Linux / macOS
59
-
60
- ```json
61
- {
62
- "mcpServers": {
63
- "oh-memos": {
64
- "command": "npx",
65
- "args": ["-y", "oh-memos-mcp"],
66
- "env": {
67
- "MEMOS_URL": "http://localhost:18000",
68
- "MEMOS_USER": "dev_user",
69
- "MEMOS_DEFAULT_CUBE": "dev_cube",
70
- "MEMOS_CUBES_DIR": "/home/user/oh-memos/data/oh-memos_cubes"
71
- }
72
- }
73
- }
74
- }
75
- ```
76
-
77
- ### Windows
78
-
79
- ```json
80
- {
81
- "mcpServers": {
82
- "oh-memos": {
83
- "command": "npx",
84
- "args": ["-y", "oh-memos-mcp"],
85
- "env": {
86
- "MEMOS_URL": "http://localhost:18000",
87
- "MEMOS_USER": "dev_user",
88
- "MEMOS_DEFAULT_CUBE": "dev_cube",
89
- "MEMOS_CUBES_DIR": "G:/test/oh-memos/data/oh-memos_cubes"
90
- }
91
- }
92
- }
93
- }
94
- ```
95
-
96
- ### WSL2
97
-
98
- ```json
99
- {
100
- "mcpServers": {
101
- "oh-memos": {
102
- "command": "npx",
103
- "args": ["-y", "oh-memos-mcp"],
104
- "env": {
105
- "MEMOS_URL": "http://localhost:18000",
106
- "MEMOS_USER": "dev_user",
107
- "MEMOS_DEFAULT_CUBE": "dev_cube",
108
- "MEMOS_CUBES_DIR": "/mnt/g/test/oh-memos/data/oh-memos_cubes"
109
- }
110
- }
111
- }
112
- }
113
- ```
114
-
115
- ### With `alwaysAllow` (skip per-tool confirmation)
116
-
117
- `alwaysAllow` matches **tool names**, so a call form like
118
- `memos_admin(action=list_cubes)` matches nothing — list the bare name and every
119
- action of that tool is auto-approved.
120
-
121
- `memos_delete` is deliberately absent below. Auto-approving it means memories can
122
- be deleted without a prompt; add it only if you have decided you want that.
123
-
124
- ```json
125
- {
126
- "mcpServers": {
127
- "oh-memos": {
128
- "type": "stdio",
129
- "command": "npx",
130
- "args": ["-y", "oh-memos-mcp"],
131
- "env": {
132
- "MEMOS_URL": "http://localhost:18000",
133
- "MEMOS_USER": "dev_user",
134
- "MEMOS_DEFAULT_CUBE": "dev_cube",
135
- "MEMOS_CUBES_DIR": "/path/to/oh-memos/data/oh-memos_cubes"
136
- },
137
- "alwaysAllow": [
138
- "memos_context_resume",
139
- "memos_search",
140
- "memos_save",
141
- "memos_list_v2",
142
- "memos_get",
143
- "memos_suggest",
144
- "memos_think",
145
- "memos_graph",
146
- "memos_admin",
147
- "memos_export_wiki",
148
- "memos_canvas"
149
- ]
150
- }
151
- }
152
- }
153
- ```
154
-
155
- ---
156
-
157
- ## Environment Variables
158
-
159
- | Variable | Required | Default | Description |
160
- |----------|----------|---------|-------------|
161
- | `MEMOS_URL` | Yes | — | oh-memos API base URL |
162
- | `MEMOS_USER` | Yes | — | Default user ID |
163
- | `MEMOS_DEFAULT_CUBE` | Yes | — | Default memory cube ID |
164
- | `MEMOS_CUBES_DIR` | Yes | — | Absolute path to cubes storage directory |
165
- | `MEMOS_TIMEOUT_TOOL` | No | `300` | Tool call timeout (seconds) |
166
- | `MEMOS_TIMEOUT_STARTUP` | No | `30` | API startup wait timeout (seconds) |
167
- | `MEMOS_TIMEOUT_HEALTH` | No | `5` | Health check timeout (seconds) |
168
- | `MEMOS_API_WAIT_MAX` | No | `60` | Max time to wait for API on startup (seconds) |
169
- | `MEMOS_ENABLE_DELETE` | No | `false` | Enable `memos_delete` tool |
170
- | `NEO4J_HTTP_URL` | No | — | Neo4j HTTP endpoint (for direct graph queries) |
171
- | `NEO4J_USER` | No | — | Neo4j username |
172
- | `NEO4J_PASSWORD` | No | — | Neo4j password |
173
- | `MEMOS_ENV_FILE` | No | — | Explicit path to a `.env` file. Highest priority — see below |
174
-
175
- > **On locating `.env`**: without `MEMOS_ENV_FILE`, the file is found by guessing
176
- > from position (working directory, two levels above the package, then dotenv's
177
- > upward search). That works from a checkout and **never works under `npx`**,
178
- > where the package root sits in the npm cache and every candidate misses — so no
179
- > variable loads at all. Set `MEMOS_ENV_FILE` (or pass `--memos-env-file`) when the
180
- > client's working directory and the install location are both outside the project.
181
- > A path that does not exist warns on stderr rather than failing silently.
182
- >
183
- > Copy `.env.example` to get started.
184
-
185
- ---
186
-
187
- ## Tools (17)
188
-
189
- The package defines 17 tool schemas. `memos_delete` is exposed by `tools/list`
190
- only when `MEMOS_ENABLE_DELETE=true`; the other 16 are available by default.
191
-
192
- <!-- mcp-tool-inventory:start -->
193
- | Tool | Description |
194
- |------|-------------|
195
- | `memos_context_resume` | Recover project context after compaction (recent 24h + project state) |
196
- | `memos_search` | Semantic search with keyword reranking. Pass `context` (recent turns) to enable LLM intent analysis and query expansion |
197
- | `memos_save` | Save memories with explicit type (BUGFIX, DECISION, MILESTONE, SYNTHESIS…) |
198
- | `memos_list_v2` | List memories with auto-compaction |
199
- | `memos_get` | Get full memory details by ID |
200
- | `memos_suggest` | Smart search query suggestions + `memory_type` decision tree |
201
- | `memos_think` | Evidence pack for a question: retrieval + contradiction/staleness flags + gap analysis. The caller synthesizes the answer and may persist it as `SYNTHESIS` |
202
- | `memos_graph` | Explainable graph queries plus strict Graphify node-link validation — `mode`: `related` / `path` / `impact` / `schema` / `import` |
203
- | `memos_admin` | Maintenance — `action`: `list_cubes` / `register_cube` / `create_user` / `validate_cubes` / `stats` / `calendar` |
204
- | `memos_export_wiki` | Export a cube as an interlinked markdown wiki (page per memory + index + mermaid graph) |
205
- | `memos_import_wiki` | Import an exported wiki back into a cube; supports dry-run and versioning edited pages, never deletes memories |
206
- | `memos_canvas` | Symbolic task canvas — short-term task state that survives context compaction. `action`: `open` / `update` / `show` / `list`. Nodes carry greppable ids (`000-N1`) and a `ref` anchoring them to evidence: `mem:<memory_id>` / `file:<path>` / `note:<text>` |
207
- | `memos_distill_skill` | Create an inert, reviewable Skill candidate under `<project_path>/skill-candidates`; it never installs the candidate automatically |
208
- | `memos_list_skill_candidates` | List generated Skill candidates without modifying or installing them |
209
- | `memos_review_skill_candidate` | Approve or reject a candidate with reviewer audit metadata; approval does not install |
210
- | `memos_install_skill_candidate` | Install an approved candidate only into `.claude/skills/<slug>/SKILL.md`, without overwrite or script execution |
211
- | `memos_delete` | Delete selected or all memories. Disabled by default and requires explicit user confirmation when enabled |
212
- <!-- mcp-tool-inventory:end -->
213
-
214
- ### `memos_graph` modes
215
-
216
- | Mode | Main input | Result |
217
- |------|------------|--------|
218
- | `related` | `query` | Related memories and edges, with provenance explanations when available |
219
- | `path` | `source_id`, `target_id` | A bounded path between two graph nodes, including relationship evidence |
220
- | `impact` | `memory_id`, optional `max_depth` | Forward blast radius from one memory |
221
- | `schema` | Optional `sample_size` | Graph structure and statistics |
222
- | `import` | `graph_json`, optional `project_key` | Deterministic validation and dry-run plan for Graphify NetworkX node-link JSON |
223
-
224
- `import` accepts at most 5 MB of JSON and rejects duplicate node ids, dangling
225
- edges, unsafe source paths, invalid confidence values, and oversized graphs. It
226
- does **not** write Code Graph nodes to Neo4j, Qdrant, or a memory cube.
227
-
228
- ---
229
-
230
- ## How .env Loading Works
231
-
232
- Priority order for configuration values (highest first):
233
-
234
- 1. **CLI configuration flags** such as `--memos-url`
235
- 2. **Explicit env file** selected by `--memos-env-file` or inherited `MEMOS_ENV_FILE`
236
- 3. **Inherited process environment** — this is where MCP client `env` values belong
237
- 4. **Auto-discovered `process.cwd()/.env`** — provides only missing defaults
238
- 5. **Auto-discovered package-root `.env`** — provides only missing defaults
239
- 6. **dotenv upward fallback**, then built-in defaults
240
-
241
- The automatic file search never overrides explicit MCP/launcher environment values. Use `MEMOS_ENV_FILE` only when the selected file should deliberately be authoritative; this is also the reliable option for `npx` installs.
242
-
243
- ---
244
-
245
- ## Development
246
-
247
- ```bash
248
- git clone https://github.com/xigou/oh-memos.git
249
- cd oh-memos/mcp-server-node
250
- npm install
251
- npm run dev # Run with tsx (no build needed)
252
- npm run build # Compile to dist/
253
- ```
254
-
255
- ---
256
-
257
- ## Requirements
258
-
259
- - Node.js >= 18.0.0
260
- - oh-memos backend API running (`scripts\local\start.bat`)
1
+ # oh-memos-mcp
2
+
3
+ [![npm version](https://img.shields.io/npm/v/oh-memos-mcp.svg)](https://www.npmjs.com/package/oh-memos-mcp)
4
+ [![Node.js >= 20](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
+
7
+ MCP Server for **oh-memos** — Intelligent Persistent Memory for AI Assistants.
8
+
9
+ Pure Node.js. No Python required. Works with `npx` out of the box.
10
+
11
+ > **3.0:** requires Node.js 20+, serves legacy 2025-era and MCP `2026-07-28`
12
+ > clients from the same stdio package, and requires no data migration. Still on
13
+ > Node 18? Pin `oh-memos-mcp@2` until you can upgrade the runtime.
14
+
15
+ ---
16
+
17
+ ## Prerequisites
18
+
19
+ - **Node.js 20 or newer**
20
+
21
+ ```bash
22
+ npx -y oh-memos-mcp # 3.x, npm latest — needs Node.js 20+
23
+ npx -y oh-memos-mcp@2 # 2.x maintenance line — still runs on Node.js 18
24
+ ```
25
+
26
+ oh-memos backend API must be running before connecting this MCP server:
27
+
28
+ - **oh-memos API** on `http://localhost:18000`
29
+ - **Neo4j** on `localhost:7687` (Knowledge Graph)
30
+ - **Qdrant** on `localhost:6333` (Vector Search)
31
+
32
+ > Start all services: run `scripts\local\start.bat` from the [oh-memos repo](https://github.com/xigou/oh-memos).
33
+
34
+ ---
35
+
36
+ ## Quick Start
37
+
38
+ Add to your Claude Code `~/.claude/settings.json`:
39
+
40
+ ```json
41
+ {
42
+ "mcpServers": {
43
+ "oh-memos": {
44
+ "command": "npx",
45
+ "args": ["-y", "oh-memos-mcp"],
46
+ "env": {
47
+ "MEMOS_URL": "http://localhost:18000",
48
+ "MEMOS_USER": "dev_user",
49
+ "MEMOS_DEFAULT_CUBE": "dev_cube",
50
+ "MEMOS_CUBES_DIR": "G:/test/oh-memos/data/oh-memos_cubes"
51
+ }
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ Or use a `.env` file in your working directory (the server auto-discovers it):
58
+
59
+ ```bash
60
+ cp node_modules/oh-memos-mcp/.env.example .env
61
+ # Edit .env with your paths
62
+ npx -y oh-memos-mcp
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Configuration Examples
68
+
69
+ ### Linux / macOS
70
+
71
+ ```json
72
+ {
73
+ "mcpServers": {
74
+ "oh-memos": {
75
+ "command": "npx",
76
+ "args": ["-y", "oh-memos-mcp"],
77
+ "env": {
78
+ "MEMOS_URL": "http://localhost:18000",
79
+ "MEMOS_USER": "dev_user",
80
+ "MEMOS_DEFAULT_CUBE": "dev_cube",
81
+ "MEMOS_CUBES_DIR": "/home/user/oh-memos/data/oh-memos_cubes"
82
+ }
83
+ }
84
+ }
85
+ }
86
+ ```
87
+
88
+ ### Windows
89
+
90
+ ```json
91
+ {
92
+ "mcpServers": {
93
+ "oh-memos": {
94
+ "command": "npx",
95
+ "args": ["-y", "oh-memos-mcp"],
96
+ "env": {
97
+ "MEMOS_URL": "http://localhost:18000",
98
+ "MEMOS_USER": "dev_user",
99
+ "MEMOS_DEFAULT_CUBE": "dev_cube",
100
+ "MEMOS_CUBES_DIR": "G:/test/oh-memos/data/oh-memos_cubes"
101
+ }
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ ### WSL2
108
+
109
+ ```json
110
+ {
111
+ "mcpServers": {
112
+ "oh-memos": {
113
+ "command": "npx",
114
+ "args": ["-y", "oh-memos-mcp"],
115
+ "env": {
116
+ "MEMOS_URL": "http://localhost:18000",
117
+ "MEMOS_USER": "dev_user",
118
+ "MEMOS_DEFAULT_CUBE": "dev_cube",
119
+ "MEMOS_CUBES_DIR": "/mnt/g/test/oh-memos/data/oh-memos_cubes"
120
+ }
121
+ }
122
+ }
123
+ }
124
+ ```
125
+
126
+ ### With `alwaysAllow` (skip per-tool confirmation)
127
+
128
+ `alwaysAllow` matches **tool names**, so a call form like
129
+ `memos_admin(action=list_cubes)` matches nothing — list the bare name and every
130
+ action of that tool is auto-approved.
131
+
132
+ `memos_delete` is deliberately absent below. Auto-approving it means memories can
133
+ be deleted without a prompt; add it only if you have decided you want that.
134
+
135
+ ```json
136
+ {
137
+ "mcpServers": {
138
+ "oh-memos": {
139
+ "type": "stdio",
140
+ "command": "npx",
141
+ "args": ["-y", "oh-memos-mcp"],
142
+ "env": {
143
+ "MEMOS_URL": "http://localhost:18000",
144
+ "MEMOS_USER": "dev_user",
145
+ "MEMOS_DEFAULT_CUBE": "dev_cube",
146
+ "MEMOS_CUBES_DIR": "/path/to/oh-memos/data/oh-memos_cubes"
147
+ },
148
+ "alwaysAllow": [
149
+ "memos_context_resume",
150
+ "memos_search",
151
+ "memos_save",
152
+ "memos_list_v2",
153
+ "memos_get",
154
+ "memos_suggest",
155
+ "memos_think",
156
+ "memos_graph",
157
+ "memos_admin",
158
+ "memos_export_wiki",
159
+ "memos_canvas"
160
+ ]
161
+ }
162
+ }
163
+ }
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Environment Variables
169
+
170
+ | Variable | Required | Default | Description |
171
+ |----------|----------|---------|-------------|
172
+ | `MEMOS_URL` | Yes | — | oh-memos API base URL |
173
+ | `MEMOS_USER` | Yes | — | Default user ID |
174
+ | `MEMOS_DEFAULT_CUBE` | Yes | — | Default memory cube ID |
175
+ | `MEMOS_CUBES_DIR` | Yes | — | Absolute path to cubes storage directory |
176
+ | `MEMOS_TIMEOUT_TOOL` | No | `300` | Tool call timeout (seconds) |
177
+ | `MEMOS_TIMEOUT_STARTUP` | No | `30` | API startup wait timeout (seconds) |
178
+ | `MEMOS_TIMEOUT_HEALTH` | No | `5` | Health check timeout (seconds) |
179
+ | `MEMOS_API_WAIT_MAX` | No | `60` | Max time to wait for API on startup (seconds) |
180
+ | `MEMOS_ENABLE_DELETE` | No | `false` | Enable `memos_delete` tool |
181
+ | `NEO4J_HTTP_URL` | No | — | Neo4j HTTP endpoint (for direct graph queries) |
182
+ | `NEO4J_USER` | No | — | Neo4j username |
183
+ | `NEO4J_PASSWORD` | No | — | Neo4j password |
184
+ | `MEMOS_ENV_FILE` | No | — | Explicit path to a `.env` file. Highest priority — see below |
185
+
186
+ > **On locating `.env`**: without `MEMOS_ENV_FILE`, the file is found by guessing
187
+ > from position (working directory, two levels above the package, then dotenv's
188
+ > upward search). That works from a checkout and **never works under `npx`**,
189
+ > where the package root sits in the npm cache and every candidate misses — so no
190
+ > variable loads at all. Set `MEMOS_ENV_FILE` (or pass `--memos-env-file`) when the
191
+ > client's working directory and the install location are both outside the project.
192
+ > A path that does not exist warns on stderr rather than failing silently.
193
+ >
194
+ > Copy `.env.example` to get started.
195
+
196
+ ---
197
+
198
+ ## Tools (17)
199
+
200
+ The package defines 17 tool schemas. `memos_delete` is exposed by `tools/list`
201
+ only when `MEMOS_ENABLE_DELETE=true`; the other 16 are available by default.
202
+
203
+ <!-- mcp-tool-inventory:start -->
204
+ | Tool | Description |
205
+ |------|-------------|
206
+ | `memos_context_resume` | Recover project context after compaction (recent 24h + project state) |
207
+ | `memos_search` | Semantic search with keyword reranking. Pass `context` (recent turns) to enable LLM intent analysis and query expansion |
208
+ | `memos_save` | Save memories with explicit type (BUGFIX, DECISION, MILESTONE, SYNTHESIS…) |
209
+ | `memos_list_v2` | List memories with auto-compaction |
210
+ | `memos_get` | Get full memory details by ID |
211
+ | `memos_suggest` | Smart search query suggestions + `memory_type` decision tree |
212
+ | `memos_think` | Evidence pack for a question: retrieval + contradiction/staleness flags + gap analysis. The caller synthesizes the answer and may persist it as `SYNTHESIS` |
213
+ | `memos_graph` | Explainable graph queries plus strict Graphify node-link validation — `mode`: `related` / `path` / `impact` / `schema` / `import` |
214
+ | `memos_admin` | Maintenance — `action`: `list_cubes` / `register_cube` / `create_user` / `validate_cubes` / `stats` / `calendar` |
215
+ | `memos_export_wiki` | Export a cube as an interlinked markdown wiki (page per memory + index + mermaid graph) |
216
+ | `memos_import_wiki` | Import an exported wiki back into a cube; supports dry-run and versioning edited pages, never deletes memories |
217
+ | `memos_canvas` | Symbolic task canvas — short-term task state that survives context compaction. `action`: `open` / `update` / `show` / `list`. Nodes carry greppable ids (`000-N1`) and a `ref` anchoring them to evidence: `mem:<memory_id>` / `file:<path>` / `note:<text>` |
218
+ | `memos_distill_skill` | Create an inert, reviewable Skill candidate under `<project_path>/skill-candidates`; it never installs the candidate automatically |
219
+ | `memos_list_skill_candidates` | List generated Skill candidates without modifying or installing them |
220
+ | `memos_review_skill_candidate` | Approve or reject a candidate with reviewer audit metadata; approval does not install |
221
+ | `memos_install_skill_candidate` | Install an approved candidate only into `.claude/skills/<slug>/SKILL.md`, without overwrite or script execution |
222
+ | `memos_delete` | Delete selected or all memories. Disabled by default and requires explicit user confirmation when enabled |
223
+ <!-- mcp-tool-inventory:end -->
224
+
225
+ ### `memos_graph` modes
226
+
227
+ | Mode | Main input | Result |
228
+ |------|------------|--------|
229
+ | `related` | `query` | Related memories and edges, with provenance explanations when available |
230
+ | `path` | `source_id`, `target_id` | A bounded path between two graph nodes, including relationship evidence |
231
+ | `impact` | `memory_id`, optional `max_depth` | Forward blast radius from one memory |
232
+ | `schema` | Optional `sample_size` | Graph structure and statistics |
233
+ | `import` | `graph_json`, optional `project_key` | Deterministic validation and dry-run plan for Graphify NetworkX node-link JSON |
234
+
235
+ `import` accepts at most 5 MB of JSON and rejects duplicate node ids, dangling
236
+ edges, unsafe source paths, invalid confidence values, and oversized graphs. It
237
+ does **not** write Code Graph nodes to Neo4j, Qdrant, or a memory cube.
238
+
239
+ ---
240
+
241
+ ## How .env Loading Works
242
+
243
+ Priority order for configuration values (highest first):
244
+
245
+ 1. **CLI configuration flags** such as `--memos-url`
246
+ 2. **Explicit env file** selected by `--memos-env-file` or inherited `MEMOS_ENV_FILE`
247
+ 3. **Inherited process environment** — this is where MCP client `env` values belong
248
+ 4. **Auto-discovered `process.cwd()/.env`** — provides only missing defaults
249
+ 5. **Auto-discovered package-root `.env`** — provides only missing defaults
250
+ 6. **dotenv upward fallback**, then built-in defaults
251
+
252
+ The automatic file search never overrides explicit MCP/launcher environment values. Use `MEMOS_ENV_FILE` only when the selected file should deliberately be authoritative; this is also the reliable option for `npx` installs.
253
+
254
+ ---
255
+
256
+ ## Development
257
+
258
+ ```bash
259
+ git clone https://github.com/xigou/oh-memos.git
260
+ cd oh-memos/mcp-server-node
261
+ npm install
262
+ npm run dev # Run with tsx (no build needed)
263
+ npm run build # Compile to dist/
264
+ ```
265
+
266
+ ---
267
+
268
+ ## Requirements
269
+
270
+ - Node.js >= 20.0.0
271
+ - oh-memos backend API running (`scripts\local\start.bat`)
@@ -5,7 +5,7 @@
5
5
  * may apply the plan to Neo4j, but parsing and safety checks must be testable
6
6
  * without a database or a filesystem write.
7
7
  */
8
- import { normalizeProjectRelativePath, normalizeProvenance, stableCodeNodeId, } from "./graph-provenance.js";
8
+ import { EVIDENCE_KINDS, normalizeProjectRelativePath, normalizeProvenance, stableCodeNodeId, } from "./graph-provenance.js";
9
9
  function asRecord(value) {
10
10
  return value !== null && typeof value === "object" && !Array.isArray(value)
11
11
  ? value
@@ -23,6 +23,31 @@ function safeCount(value, fallback) {
23
23
  throw new Error("import limits must be positive integers");
24
24
  return value;
25
25
  }
26
+ function validateImportConfidence(record, label) {
27
+ const score = record.confidence_score;
28
+ if (score !== undefined) {
29
+ if (typeof score !== "number" || !Number.isFinite(score) || score < 0 || score > 1) {
30
+ throw new Error(`${label} confidence_score must be a number from 0 to 1`);
31
+ }
32
+ }
33
+ const confidence = record.confidence;
34
+ if (confidence === undefined)
35
+ return;
36
+ if (typeof confidence === "number") {
37
+ if (!Number.isFinite(confidence) || confidence < 0 || confidence > 1) {
38
+ throw new Error(`${label} confidence must be a number from 0 to 1`);
39
+ }
40
+ return;
41
+ }
42
+ if (typeof confidence === "string") {
43
+ const category = confidence.trim().toUpperCase();
44
+ if (!EVIDENCE_KINDS.includes(category)) {
45
+ throw new Error(`${label} confidence category must be one of ${EVIDENCE_KINDS.join(", ")}`);
46
+ }
47
+ return;
48
+ }
49
+ throw new Error(`${label} confidence must be a category or a number from 0 to 1`);
50
+ }
26
51
  function normalizeRelation(value) {
27
52
  const raw = typeof value === "string" && value.trim() ? value.trim() : "RELATED_TO";
28
53
  return raw.normalize("NFKC").toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "RELATED_TO";
@@ -76,6 +101,7 @@ export function buildGraphImportPlan(input, options = {}) {
76
101
  if (seenIds.has(externalId))
77
102
  throw new Error(`duplicate node id '${externalId}'`);
78
103
  seenIds.add(externalId);
104
+ validateImportConfidence(node, `node '${externalId}'`);
79
105
  const sourceFile = node.source_file === undefined
80
106
  ? undefined
81
107
  : normalizeProjectRelativePath(requiredString(node.source_file, `source_file for '${externalId}'`));
@@ -110,6 +136,7 @@ export function buildGraphImportPlan(input, options = {}) {
110
136
  const link = asRecord(rawLink);
111
137
  const source = requiredString(link.source ?? link._src, "edge source");
112
138
  const target = requiredString(link.target ?? link._tgt, "edge target");
139
+ validateImportConfidence(link, `edge '${source}' -> '${target}'`);
113
140
  if (!nodeByExternalId.has(source))
114
141
  throw new Error(`unknown source node '${source}'`);
115
142
  if (!nodeByExternalId.has(target))
@@ -20,7 +20,7 @@ export function handleMemosCapabilities() {
20
20
  "",
21
21
  `**Mode**: ${mode}`,
22
22
  mode === "lite"
23
- ? "Lite reuses the configured HTTP API and cube storage; it lowers search limits and filters auto-capture. It is a noise/resource policy, not an offline SQLite backend."
23
+ ? "Lite uses the Node JSONL provider with lexical search (optional local Ollama embeddings); it does not require the HTTP API, Qdrant, or Neo4j. Full-only graph, Wiki, and remote admin operations are unavailable."
24
24
  : "Full exposes API, graph, vector, BM25, Wiki round-trip, canvas, and skill lifecycle tools.",
25
25
  "",
26
26
  "**tree_text update**: in-place update is unsupported; the API now fails explicitly instead of silently succeeding. Use versioned writes.",
@@ -18,7 +18,9 @@ import { MEMOS_URL, MEMOS_PROVIDER } from "../config.js";
18
18
  import { errorResponse } from "./utils.js";
19
19
  export async function dispatchTool(name, arguments_) {
20
20
  if (MEMOS_PROVIDER === "local" && ["memos_think", "memos_graph", "memos_export_wiki", "memos_import_wiki", "memos_admin", "memos_delete"].includes(name)) {
21
- return errorResponse(`LOCAL_PROVIDER_UNSUPPORTED: ${name} requires the Full HTTP/graph provider`);
21
+ return errorResponse(`Lite mode: ${name} is unavailable because it requires the Full HTTP/graph provider. ` +
22
+ "Available Lite paths include memos_save, memos_list_v2, memos_get, memos_search, memos_suggest, memos_context_resume, and memos_canvas. " +
23
+ "Set MEMOS_MODE=full and start the backend for Full-only operations.");
22
24
  }
23
25
  switch (name) {
24
26
  // Memory tools