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/CHANGELOG.md +266 -228
- package/README.md +271 -260
- package/dist/graphify-import.js +28 -1
- package/dist/handlers/admin.js +1 -1
- package/dist/handlers/index.js +3 -1
- package/dist/index.js +27 -6
- package/dist/runtime-version.d.ts +2 -0
- package/dist/runtime-version.js +10 -0
- package/dist/server-lifecycle.d.ts +10 -0
- package/dist/server-lifecycle.js +30 -0
- package/dist/server.d.ts +5 -2
- package/dist/server.js +37 -47
- package/dist/stdio-compat-transport.d.ts +24 -0
- package/dist/stdio-compat-transport.js +75 -0
- package/dist/tools-registry.d.ts +93 -245
- package/package.json +15 -6
package/README.md
CHANGED
|
@@ -1,260 +1,271 @@
|
|
|
1
|
-
# oh-memos-mcp
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/oh-memos-mcp)
|
|
4
|
-
[](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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- **
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
"
|
|
144
|
-
"
|
|
145
|
-
"
|
|
146
|
-
"
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
|
171
|
-
|
|
172
|
-
| `
|
|
173
|
-
| `
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
|
205
|
-
|
|
206
|
-
| `
|
|
207
|
-
| `
|
|
208
|
-
| `
|
|
209
|
-
| `
|
|
210
|
-
| `
|
|
211
|
-
| `
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
|
217
|
-
|
|
218
|
-
| `
|
|
219
|
-
| `
|
|
220
|
-
| `
|
|
221
|
-
| `
|
|
222
|
-
| `
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
1
|
+
# oh-memos-mcp
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/oh-memos-mcp)
|
|
4
|
+
[](https://nodejs.org)
|
|
5
|
+
[](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`)
|
package/dist/graphify-import.js
CHANGED
|
@@ -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))
|
package/dist/handlers/admin.js
CHANGED
|
@@ -20,7 +20,7 @@ export function handleMemosCapabilities() {
|
|
|
20
20
|
"",
|
|
21
21
|
`**Mode**: ${mode}`,
|
|
22
22
|
mode === "lite"
|
|
23
|
-
? "Lite
|
|
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.",
|
package/dist/handlers/index.js
CHANGED
|
@@ -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(`
|
|
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
|