mnemon-mcp 1.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 +34 -0
- package/CONTRIBUTING.md +59 -0
- package/LICENSE +21 -0
- package/README.md +434 -0
- package/SECURITY.md +29 -0
- package/config.example.json +52 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/db.d.ts +16 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +360 -0
- package/dist/db.js.map +1 -0
- package/dist/embedder.d.ts +22 -0
- package/dist/embedder.d.ts.map +1 -0
- package/dist/embedder.js +109 -0
- package/dist/embedder.js.map +1 -0
- package/dist/import/cli.d.ts +12 -0
- package/dist/import/cli.d.ts.map +1 -0
- package/dist/import/cli.js +105 -0
- package/dist/import/cli.js.map +1 -0
- package/dist/import/config-loader.d.ts +29 -0
- package/dist/import/config-loader.d.ts.map +1 -0
- package/dist/import/config-loader.js +140 -0
- package/dist/import/config-loader.js.map +1 -0
- package/dist/import/kb-config.d.ts +27 -0
- package/dist/import/kb-config.d.ts.map +1 -0
- package/dist/import/kb-config.js +10 -0
- package/dist/import/kb-config.js.map +1 -0
- package/dist/import/kb-import.d.ts +45 -0
- package/dist/import/kb-import.d.ts.map +1 -0
- package/dist/import/kb-import.js +285 -0
- package/dist/import/kb-import.js.map +1 -0
- package/dist/import/md-parser.d.ts +35 -0
- package/dist/import/md-parser.d.ts.map +1 -0
- package/dist/import/md-parser.js +104 -0
- package/dist/import/md-parser.js.map +1 -0
- package/dist/index-http.d.ts +12 -0
- package/dist/index-http.d.ts.map +1 -0
- package/dist/index-http.js +202 -0
- package/dist/index-http.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +16 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +341 -0
- package/dist/server.js.map +1 -0
- package/dist/stemmer.d.ts +29 -0
- package/dist/stemmer.d.ts.map +1 -0
- package/dist/stemmer.js +68 -0
- package/dist/stemmer.js.map +1 -0
- package/dist/stop-words.d.ts +12 -0
- package/dist/stop-words.d.ts.map +1 -0
- package/dist/stop-words.js +112 -0
- package/dist/stop-words.js.map +1 -0
- package/dist/tools/memory-add.d.ts +15 -0
- package/dist/tools/memory-add.d.ts.map +1 -0
- package/dist/tools/memory-add.js +120 -0
- package/dist/tools/memory-add.js.map +1 -0
- package/dist/tools/memory-delete.d.ts +10 -0
- package/dist/tools/memory-delete.d.ts.map +1 -0
- package/dist/tools/memory-delete.js +39 -0
- package/dist/tools/memory-delete.js.map +1 -0
- package/dist/tools/memory-export.d.ts +10 -0
- package/dist/tools/memory-export.d.ts.map +1 -0
- package/dist/tools/memory-export.js +102 -0
- package/dist/tools/memory-export.js.map +1 -0
- package/dist/tools/memory-health.d.ts +11 -0
- package/dist/tools/memory-health.d.ts.map +1 -0
- package/dist/tools/memory-health.js +79 -0
- package/dist/tools/memory-health.js.map +1 -0
- package/dist/tools/memory-inspect.d.ts +10 -0
- package/dist/tools/memory-inspect.d.ts.map +1 -0
- package/dist/tools/memory-inspect.js +139 -0
- package/dist/tools/memory-inspect.js.map +1 -0
- package/dist/tools/memory-search.d.ts +16 -0
- package/dist/tools/memory-search.d.ts.map +1 -0
- package/dist/tools/memory-search.js +459 -0
- package/dist/tools/memory-search.js.map +1 -0
- package/dist/tools/memory-update.d.ts +11 -0
- package/dist/tools/memory-update.d.ts.map +1 -0
- package/dist/tools/memory-update.js +142 -0
- package/dist/tools/memory-update.js.map +1 -0
- package/dist/tools/style-extract.d.ts +40 -0
- package/dist/tools/style-extract.d.ts.map +1 -0
- package/dist/tools/style-extract.js +43 -0
- package/dist/tools/style-extract.js.map +1 -0
- package/dist/tools/utils.d.ts +28 -0
- package/dist/tools/utils.d.ts.map +1 -0
- package/dist/tools/utils.js +33 -0
- package/dist/tools/utils.js.map +1 -0
- package/dist/types.d.ts +216 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +122 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +96 -0
- package/dist/validation.js.map +1 -0
- package/dist/vector.d.ts +30 -0
- package/dist/vector.d.ts.map +1 -0
- package/dist/vector.js +90 -0
- package/dist/vector.js.map +1 -0
- package/package.json +75 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to mnemon-mcp will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [1.0.0] - 2026-03-16
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- 4-layer memory model: episodic, semantic, procedural, resource
|
|
14
|
+
- 7 MCP tools: `memory_add`, `memory_search`, `memory_update`, `memory_delete`, `memory_inspect`, `memory_export`, `memory_health`
|
|
15
|
+
- FTS5 full-text search with BM25 ranking and AND→OR fallback
|
|
16
|
+
- Snowball stemming for English and Russian at index and query time
|
|
17
|
+
- Progressive AND relaxation for complex multi-token queries
|
|
18
|
+
- Fact versioning via superseding chains
|
|
19
|
+
- Markdown knowledge base import pipeline with configurable routing
|
|
20
|
+
- Temporal fact windows (valid_from / valid_until) and entity aliases
|
|
21
|
+
- Memory decay scoring (episodic: 30-day, resource: 90-day half-life)
|
|
22
|
+
- Contradiction detection on memory_add
|
|
23
|
+
- `memory_health` tool: diagnostic report with expired entries, orphaned chains, stale memories, and optional GC
|
|
24
|
+
- MCP Resources (stats, recent, layer, entity) and Prompts (recall, context-load, journal)
|
|
25
|
+
- HTTP transport with Bearer auth, CORS, rate limiting, body size limits, graceful shutdown
|
|
26
|
+
- Optional vector search with BYOK embeddings (OpenAI, Ollama) via sqlite-vec
|
|
27
|
+
- Hybrid search mode combining FTS5 + vector via Reciprocal Rank Fusion (RRF)
|
|
28
|
+
- Tool input schemas generated from Zod via `z.toJSONSchema()` — single source of truth
|
|
29
|
+
- Import config with Zod validation
|
|
30
|
+
- 182 tests (unit + integration + validation)
|
|
31
|
+
- CI pipeline with build, test, and smoke tests
|
|
32
|
+
|
|
33
|
+
[Unreleased]: https://github.com/nikitacometa/mnemon-mcp/compare/v1.0.0...HEAD
|
|
34
|
+
[1.0.0]: https://github.com/nikitacometa/mnemon-mcp/releases/tag/v1.0.0
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Contributing to mnemon-mcp
|
|
2
|
+
|
|
3
|
+
## Philosophy
|
|
4
|
+
|
|
5
|
+
**Air-gapped by design.** mnemon-mcp makes zero network calls. No telemetry, no analytics, no crash reporting, no pings to any external service. All data stays on the user's machine in `~/.mnemon-mcp/memory.db`.
|
|
6
|
+
|
|
7
|
+
PRs adding telemetry, analytics, or any external network call will be rejected without review.
|
|
8
|
+
|
|
9
|
+
## Development Setup
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
git clone https://github.com/nikitacometa/mnemon-mcp.git
|
|
13
|
+
cd mnemon-mcp
|
|
14
|
+
npm install
|
|
15
|
+
npm run build
|
|
16
|
+
npm test
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Requires Node.js 22+ and TypeScript 5.9.
|
|
20
|
+
|
|
21
|
+
## Running Locally
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm run dev
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Smoke test — verify the server responds to JSON-RPC over stdio:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node dist/index.js
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Code Guidelines
|
|
34
|
+
|
|
35
|
+
- **TypeScript strict mode** — no `any`, no unsafe casts, return types on all exported functions.
|
|
36
|
+
- **Never use `console.log()` in `src/tools/` or `src/import/`** — stdout is the MCP JSON-RPC transport. Any stray output will corrupt the protocol. Use `console.error()` for debugging.
|
|
37
|
+
- **Run `npm test` and `npm run build` before opening a PR.** Both must pass.
|
|
38
|
+
- **Keep dependencies minimal.** Before adding a package, consider whether the standard library or an existing dep covers the use case.
|
|
39
|
+
- **No `any`** — prefer `unknown` with a type guard, or a generic with a constraint.
|
|
40
|
+
|
|
41
|
+
## PR Guidelines
|
|
42
|
+
|
|
43
|
+
- One feature per PR. Split unrelated changes into separate PRs.
|
|
44
|
+
- Include tests for all new functionality. The test runner is Vitest (`npm test`).
|
|
45
|
+
- Update `README.md` if adding new MCP tools or changing observable behavior.
|
|
46
|
+
- Reference the task board ID (e.g. `T-123`) in the PR description if applicable.
|
|
47
|
+
|
|
48
|
+
## Security Policy
|
|
49
|
+
|
|
50
|
+
- Never include memory content in error messages or log output.
|
|
51
|
+
- Sanitize all user-supplied strings before embedding them in error responses.
|
|
52
|
+
- No external API calls — not in tools, not in the import pipeline, not in tests.
|
|
53
|
+
- Report security issues privately via GitHub Security Advisories, not in public issues.
|
|
54
|
+
|
|
55
|
+
## Architecture Notes
|
|
56
|
+
|
|
57
|
+
The server uses `better-sqlite3` (synchronous) because MCP stdio transport is inherently synchronous — async DB would add complexity with no benefit. Do not replace it with an async driver.
|
|
58
|
+
|
|
59
|
+
FTS5 search lives in `src/tools/memory-search.ts`. The tokenizer is `unicode61` (Cyrillic + Latin). Stemming improvements belong in a pre-processing layer, not in the tokenizer config.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nikita Gorokhov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
# mnemon-mcp
|
|
2
|
+
|
|
3
|
+
[](https://github.com/nikitacometa/mnemon-mcp/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/mnemon-mcp)
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
**Persistent layered memory for AI agents.**
|
|
9
|
+
Local-first. Zero-cloud. Single SQLite file.
|
|
10
|
+
|
|
11
|
+
Your AI agent forgets everything after each session. Mnemon fixes that.
|
|
12
|
+
|
|
13
|
+
It gives any [MCP](https://modelcontextprotocol.io)-compatible client — [OpenClaw](https://openclaw.ai), Claude Code, Cursor, Windsurf, or your own — a structured long-term memory backed by a single SQLite database on your machine. No API keys, no cloud, no telemetry. Just `npm install` and your agent remembers.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Why Layered Memory?
|
|
18
|
+
|
|
19
|
+
Flat key-value stores treat "what happened yesterday" the same as "never commit without tests." That's wrong — different kinds of knowledge have different lifetimes and access patterns.
|
|
20
|
+
|
|
21
|
+
Mnemon organizes memories into **four layers**:
|
|
22
|
+
|
|
23
|
+
| Layer | What it stores | How it's accessed | Lifetime |
|
|
24
|
+
|-------|---------------|-------------------|----------|
|
|
25
|
+
| **Episodic** | Events, sessions, journal entries | By date or period | Decays (30-day half-life) |
|
|
26
|
+
| **Semantic** | Facts, preferences, relationships | By topic or entity | Stable |
|
|
27
|
+
| **Procedural** | Rules, workflows, conventions | Loaded at startup | Rarely changes |
|
|
28
|
+
| **Resource** | Reference material, book notes | On demand | Decays slowly (90 days) |
|
|
29
|
+
|
|
30
|
+
A journal entry from last Tuesday and a coding rule that never changes live in different layers — because they should.
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
### Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install -g mnemon-mcp
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Or from source:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
git clone https://github.com/nikitacometa/mnemon-mcp.git
|
|
44
|
+
cd mnemon-mcp && npm install && npm run build
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Configure Your MCP Client
|
|
48
|
+
|
|
49
|
+
<details open>
|
|
50
|
+
<summary><strong>OpenClaw</strong></summary>
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
openclaw mcp register mnemon-mcp --command="mnemon-mcp"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Or add to `~/.openclaw/mcp_config.json`:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mnemon-mcp": {
|
|
61
|
+
"command": "mnemon-mcp"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
</details>
|
|
67
|
+
|
|
68
|
+
<details>
|
|
69
|
+
<summary><strong>Claude Code</strong></summary>
|
|
70
|
+
|
|
71
|
+
Add to `~/.claude/mcp.json`:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"mcpServers": {
|
|
76
|
+
"mnemon-mcp": {
|
|
77
|
+
"command": "mnemon-mcp"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
</details>
|
|
84
|
+
|
|
85
|
+
<details>
|
|
86
|
+
<summary><strong>Cursor / Windsurf / Other MCP clients</strong></summary>
|
|
87
|
+
|
|
88
|
+
Add to your client's MCP config:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"mcpServers": {
|
|
93
|
+
"mnemon-mcp": {
|
|
94
|
+
"command": "mnemon-mcp"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
</details>
|
|
101
|
+
|
|
102
|
+
<details>
|
|
103
|
+
<summary><strong>Running from source?</strong></summary>
|
|
104
|
+
|
|
105
|
+
Use the full path to the compiled entry point:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"mnemon-mcp": {
|
|
110
|
+
"command": "node",
|
|
111
|
+
"args": ["/absolute/path/to/mnemon-mcp/dist/index.js"]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
</details>
|
|
117
|
+
|
|
118
|
+
### Verify
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | mnemon-mcp
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
You should see 7 tools in the response. The database (`~/.mnemon-mcp/memory.db`) is created automatically on first run.
|
|
125
|
+
|
|
126
|
+
That's it. Your agent now has persistent memory.
|
|
127
|
+
|
|
128
|
+
## What It Can Do
|
|
129
|
+
|
|
130
|
+
### 7 MCP Tools
|
|
131
|
+
|
|
132
|
+
| Tool | What it does |
|
|
133
|
+
|------|-------------|
|
|
134
|
+
| **`memory_add`** | Store a memory with layer, entity, confidence, importance, and optional TTL |
|
|
135
|
+
| **`memory_search`** | Full-text or exact search with filters by layer, entity, date, scope, confidence |
|
|
136
|
+
| **`memory_update`** | Update in-place or create a versioned replacement (superseding chain) |
|
|
137
|
+
| **`memory_delete`** | Delete a memory; re-activates its predecessor if any |
|
|
138
|
+
| **`memory_inspect`** | Get layer statistics or trace a single memory's version history |
|
|
139
|
+
| **`memory_export`** | Export to JSON, Markdown, or Claude-md format with filters |
|
|
140
|
+
| **`memory_health`** | Run diagnostics: expired entries, orphaned chains, stale memories; optionally GC |
|
|
141
|
+
|
|
142
|
+
### MCP Resources & Prompts
|
|
143
|
+
|
|
144
|
+
**Resources** — live data your agent can read:
|
|
145
|
+
|
|
146
|
+
| URI | Returns |
|
|
147
|
+
|-----|---------|
|
|
148
|
+
| `memory://stats` | Aggregate stats per layer |
|
|
149
|
+
| `memory://recent` | Memories created/updated in last 24h |
|
|
150
|
+
| `memory://layer/{layer}` | All active memories in a layer |
|
|
151
|
+
| `memory://entity/{name}` | All active memories about an entity |
|
|
152
|
+
|
|
153
|
+
**Prompts** — pre-built workflows:
|
|
154
|
+
|
|
155
|
+
| Prompt | Purpose |
|
|
156
|
+
|--------|---------|
|
|
157
|
+
| `recall` | "Tell me everything you know about X" |
|
|
158
|
+
| `context-load` | Load relevant context before starting a task |
|
|
159
|
+
| `journal` | Create a structured journal entry |
|
|
160
|
+
|
|
161
|
+
## Search
|
|
162
|
+
|
|
163
|
+
Two modes, both supporting layer / entity / scope / date / confidence filters:
|
|
164
|
+
|
|
165
|
+
**FTS mode** (default) — tokenized full-text search with BM25 ranking. Multi-word queries use AND; if too few results, OR supplements with a score penalty. Progressive AND relaxation tries top-3 most specific terms before falling back to full OR.
|
|
166
|
+
|
|
167
|
+
Scores: `bm25 × (0.3 + 0.7 × importance) × decay(layer)`
|
|
168
|
+
|
|
169
|
+
**Exact mode** — `LIKE` substring match for precise phrase lookups.
|
|
170
|
+
|
|
171
|
+
### Stemming
|
|
172
|
+
|
|
173
|
+
Snowball stemmer applied at both **index time** and **query time** for English and Russian. This means `"running"` matches `"runs"`, and `"книги"` matches `"книга"`. Stop words are filtered from queries to improve precision.
|
|
174
|
+
|
|
175
|
+
## Fact Versioning
|
|
176
|
+
|
|
177
|
+
Knowledge evolves. Mnemon doesn't delete old facts — it chains them:
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
v1: "Team uses React 17" → superseded_by: v2
|
|
181
|
+
v2: "Team uses React 19" → supersedes: v1 (active)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Search returns only the latest version. `memory_inspect` with `include_history: true` reveals the full chain. `memory_delete` re-activates the predecessor — nothing is lost.
|
|
185
|
+
|
|
186
|
+
## Vector Search (Optional, BYOK)
|
|
187
|
+
|
|
188
|
+
Enable semantic similarity search by providing your own embedding API:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# OpenAI
|
|
192
|
+
MNEMON_EMBEDDING_PROVIDER=openai MNEMON_EMBEDDING_API_KEY=sk-... mnemon-mcp
|
|
193
|
+
|
|
194
|
+
# Ollama (local, free)
|
|
195
|
+
MNEMON_EMBEDDING_PROVIDER=ollama mnemon-mcp
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
This unlocks two additional search modes:
|
|
199
|
+
- **`mode: "vector"`** — pure cosine similarity search
|
|
200
|
+
- **`mode: "hybrid"`** — FTS5 + vector combined via [Reciprocal Rank Fusion](https://www.singlestore.com/blog/hybrid-search-using-reciprocal-rank-fusion-in-sql/)
|
|
201
|
+
|
|
202
|
+
Requires `sqlite-vec` (installed as optional dependency). New memories are embedded on add; existing ones can be backfilled.
|
|
203
|
+
|
|
204
|
+
<details>
|
|
205
|
+
<summary>Embedding configuration</summary>
|
|
206
|
+
|
|
207
|
+
| Variable | Default | Description |
|
|
208
|
+
|----------|---------|-------------|
|
|
209
|
+
| `MNEMON_EMBEDDING_PROVIDER` | — | `openai` or `ollama` (unset = disabled) |
|
|
210
|
+
| `MNEMON_EMBEDDING_API_KEY` | — | API key (required for OpenAI) |
|
|
211
|
+
| `MNEMON_EMBEDDING_MODEL` | `text-embedding-3-small` / `nomic-embed-text` | Model name |
|
|
212
|
+
| `MNEMON_EMBEDDING_DIMENSIONS` | `1024` / `768` | Vector dimensions |
|
|
213
|
+
| `MNEMON_OLLAMA_URL` | `http://localhost:11434` | Ollama endpoint |
|
|
214
|
+
|
|
215
|
+
</details>
|
|
216
|
+
|
|
217
|
+
## Importing a Knowledge Base
|
|
218
|
+
|
|
219
|
+
Got a folder of Markdown files? Import them in bulk:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
cp config.example.json ~/.mnemon-mcp/config.json # edit this first
|
|
223
|
+
npm run import:kb -- --kb-path /path/to/your/kb # incremental (skips unchanged files)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The config maps glob patterns to memory layers:
|
|
227
|
+
|
|
228
|
+
```json
|
|
229
|
+
{
|
|
230
|
+
"owner_name": "your-name",
|
|
231
|
+
"extra_stop_words": [],
|
|
232
|
+
"mappings": [
|
|
233
|
+
{
|
|
234
|
+
"glob": "journal/*.md",
|
|
235
|
+
"layer": "episodic",
|
|
236
|
+
"entity_type": "user",
|
|
237
|
+
"entity_name": "$owner",
|
|
238
|
+
"importance": 0.6,
|
|
239
|
+
"split": "h2"
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"glob": "people/*.md",
|
|
243
|
+
"layer": "semantic",
|
|
244
|
+
"entity_type": "person",
|
|
245
|
+
"entity_name": "from-heading",
|
|
246
|
+
"importance": 0.8,
|
|
247
|
+
"split": "h3"
|
|
248
|
+
}
|
|
249
|
+
]
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Config Fields
|
|
254
|
+
|
|
255
|
+
| Field | Type | Description |
|
|
256
|
+
|-------|------|-------------|
|
|
257
|
+
| `owner_name` | string | Your name — used for `$owner` substitution in `entity_name` |
|
|
258
|
+
| `extra_stop_words` | string[] | Words to filter from FTS queries (e.g., your name forms) |
|
|
259
|
+
| `glob` | string | File pattern to match |
|
|
260
|
+
| `layer` | string | Target memory layer |
|
|
261
|
+
| `entity_type` | string | `user` / `person` / `project` / `concept` / `file` / `rule` / `tool` |
|
|
262
|
+
| `entity_name` | string | Literal name, `"$owner"`, or `"from-heading"` (extract from H2/H3) |
|
|
263
|
+
| `split` | string | `"whole"` (one memory per file), `"h2"`, or `"h3"` (split on headings) |
|
|
264
|
+
| `importance` | number | 0.0–1.0, affects search ranking |
|
|
265
|
+
| `confidence` | number | 0.0–1.0, filterable in search |
|
|
266
|
+
| `scope` | string | Optional namespace |
|
|
267
|
+
|
|
268
|
+
## HTTP Transport
|
|
269
|
+
|
|
270
|
+
For remote or multi-client setups:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
MNEMON_AUTH_TOKEN=your-secret MNEMON_PORT=3000 npm run start:http
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
| Endpoint | Description |
|
|
277
|
+
|----------|-------------|
|
|
278
|
+
| `POST /mcp` | MCP JSON-RPC (Bearer auth if token set) |
|
|
279
|
+
| `GET /health` | `{"status":"ok","version":"..."}` |
|
|
280
|
+
|
|
281
|
+
Rate limiting (100 req/min/IP by default), CORS headers, 1MB body limit, timing-safe auth, graceful shutdown on SIGTERM.
|
|
282
|
+
|
|
283
|
+
## Configuration Reference
|
|
284
|
+
|
|
285
|
+
| Variable | Default | Description |
|
|
286
|
+
|----------|---------|-------------|
|
|
287
|
+
| `MNEMON_DB_PATH` | `~/.mnemon-mcp/memory.db` | Database path |
|
|
288
|
+
| `MNEMON_KB_PATH` | `.` | Knowledge base root for import |
|
|
289
|
+
| `MNEMON_CONFIG_PATH` | `~/.mnemon-mcp/config.json` | Import config path |
|
|
290
|
+
| `MNEMON_AUTH_TOKEN` | — | Bearer token for HTTP transport |
|
|
291
|
+
| `MNEMON_PORT` | `3000` | HTTP transport port |
|
|
292
|
+
| `MNEMON_CORS_ORIGIN` | `*` | CORS `Access-Control-Allow-Origin` |
|
|
293
|
+
| `MNEMON_RATE_LIMIT` | `100` | Max requests per minute per IP (0 = off) |
|
|
294
|
+
|
|
295
|
+
## Tool Reference
|
|
296
|
+
|
|
297
|
+
<details>
|
|
298
|
+
<summary><code>memory_add</code> — full parameter list</summary>
|
|
299
|
+
|
|
300
|
+
| Parameter | Type | Required | Description |
|
|
301
|
+
|-----------|------|----------|-------------|
|
|
302
|
+
| `content` | string | Yes | Memory text (max 100K chars) |
|
|
303
|
+
| `layer` | string | Yes | `episodic` / `semantic` / `procedural` / `resource` |
|
|
304
|
+
| `title` | string | No | Short title (max 500 chars) |
|
|
305
|
+
| `entity_type` | string | No | `user` / `project` / `person` / `concept` / `file` / `rule` / `tool` |
|
|
306
|
+
| `entity_name` | string | No | Entity name for filtering |
|
|
307
|
+
| `confidence` | number | No | 0.0–1.0 (default 0.8) |
|
|
308
|
+
| `importance` | number | No | 0.0–1.0 (default 0.5) |
|
|
309
|
+
| `scope` | string | No | Namespace (default `global`) |
|
|
310
|
+
| `source_file` | string | No | Source file path — triggers auto-supersede of matching entries |
|
|
311
|
+
| `ttl_days` | number | No | Auto-expire after N days |
|
|
312
|
+
| `valid_from` / `valid_until` | string | No | Temporal fact window (ISO 8601) |
|
|
313
|
+
|
|
314
|
+
</details>
|
|
315
|
+
|
|
316
|
+
<details>
|
|
317
|
+
<summary><code>memory_search</code> — full parameter list</summary>
|
|
318
|
+
|
|
319
|
+
| Parameter | Type | Required | Description |
|
|
320
|
+
|-----------|------|----------|-------------|
|
|
321
|
+
| `query` | string | Yes | Search text |
|
|
322
|
+
| `mode` | string | No | `fts` (default), `exact`, `vector`, `hybrid` |
|
|
323
|
+
| `layers` | string[] | No | Filter by layers |
|
|
324
|
+
| `entity_name` | string | No | Filter by entity (supports aliases) |
|
|
325
|
+
| `scope` | string | No | Filter by scope |
|
|
326
|
+
| `date_from` / `date_to` | string | No | Date range (ISO 8601) |
|
|
327
|
+
| `as_of` | string | No | Temporal fact filter — facts valid at this date |
|
|
328
|
+
| `min_confidence` | number | No | Minimum confidence |
|
|
329
|
+
| `min_importance` | number | No | Minimum importance |
|
|
330
|
+
| `limit` | number | No | Max results (default 10, max 100) |
|
|
331
|
+
| `offset` | number | No | Pagination offset |
|
|
332
|
+
|
|
333
|
+
</details>
|
|
334
|
+
|
|
335
|
+
<details>
|
|
336
|
+
<summary><code>memory_update</code> — full parameter list</summary>
|
|
337
|
+
|
|
338
|
+
| Parameter | Type | Required | Description |
|
|
339
|
+
|-----------|------|----------|-------------|
|
|
340
|
+
| `id` | string | Yes | Memory ID |
|
|
341
|
+
| `content` | string | No | New content |
|
|
342
|
+
| `title` | string | No | New title |
|
|
343
|
+
| `confidence` | number | No | New confidence |
|
|
344
|
+
| `importance` | number | No | New importance |
|
|
345
|
+
| `supersede` | boolean | No | `true` = versioned replacement; `false` (default) = in-place |
|
|
346
|
+
| `new_content` | string | No | Content for superseding entry |
|
|
347
|
+
|
|
348
|
+
</details>
|
|
349
|
+
|
|
350
|
+
<details>
|
|
351
|
+
<summary><code>memory_delete</code></summary>
|
|
352
|
+
|
|
353
|
+
| Parameter | Type | Required | Description |
|
|
354
|
+
|-----------|------|----------|-------------|
|
|
355
|
+
| `id` | string | Yes | Memory ID. Re-activates predecessor if part of a superseding chain |
|
|
356
|
+
|
|
357
|
+
</details>
|
|
358
|
+
|
|
359
|
+
<details>
|
|
360
|
+
<summary><code>memory_inspect</code></summary>
|
|
361
|
+
|
|
362
|
+
| Parameter | Type | Required | Description |
|
|
363
|
+
|-----------|------|----------|-------------|
|
|
364
|
+
| `id` | string | No | Memory ID (omit for aggregate stats) |
|
|
365
|
+
| `layer` | string | No | Filter stats by layer |
|
|
366
|
+
| `entity_name` | string | No | Filter stats by entity |
|
|
367
|
+
| `include_history` | boolean | No | Show superseding chain |
|
|
368
|
+
|
|
369
|
+
</details>
|
|
370
|
+
|
|
371
|
+
<details>
|
|
372
|
+
<summary><code>memory_export</code></summary>
|
|
373
|
+
|
|
374
|
+
| Parameter | Type | Required | Description |
|
|
375
|
+
|-----------|------|----------|-------------|
|
|
376
|
+
| `format` | string | Yes | `json` / `markdown` / `claude-md` |
|
|
377
|
+
| `layers` | string[] | No | Filter by layers |
|
|
378
|
+
| `scope` | string | No | Filter by scope |
|
|
379
|
+
| `date_from` / `date_to` | string | No | Date range |
|
|
380
|
+
| `limit` | number | No | Max entries (default all, max 10K) |
|
|
381
|
+
|
|
382
|
+
</details>
|
|
383
|
+
|
|
384
|
+
<details>
|
|
385
|
+
<summary><code>memory_health</code></summary>
|
|
386
|
+
|
|
387
|
+
| Parameter | Type | Required | Description |
|
|
388
|
+
|-----------|------|----------|-------------|
|
|
389
|
+
| `cleanup` | boolean | No | `true` = garbage-collect expired entries (default: report only) |
|
|
390
|
+
|
|
391
|
+
Returns: status (`healthy` / `warning` / `degraded`), per-layer stats, expired entries, orphaned chains, stale/low-confidence counts, cleaned count when `cleanup=true`.
|
|
392
|
+
|
|
393
|
+
</details>
|
|
394
|
+
|
|
395
|
+
## How It Compares
|
|
396
|
+
|
|
397
|
+
| | **mnemon-mcp** | mem0 | basic-memory | Anthropic KG |
|
|
398
|
+
|---|---|---|---|---|
|
|
399
|
+
| **Architecture** | SQLite FTS5 | Cloud API + Qdrant | Markdown + vector | JSON file |
|
|
400
|
+
| **Memory structure** | 4 typed layers | Flat | Flat | Graph |
|
|
401
|
+
| **Fact versioning** | Superseding chains | Partial | No | No |
|
|
402
|
+
| **Stemming** | EN + RU (Snowball) | EN only | EN only | None |
|
|
403
|
+
| **OpenClaw support** | Native MCP | No | No | No |
|
|
404
|
+
| **Dependencies** | 0 required | Qdrant, Neo4j, Ollama | FastEmbed, Python 3.12 | None |
|
|
405
|
+
| **Cloud required** | No | Yes | No (SaaS optional) | No |
|
|
406
|
+
| **Cost** | Free | $19–249/mo | Free + SaaS | Free |
|
|
407
|
+
| **Setup** | `npm install -g` | Docker + API keys | pip + deps | Built-in |
|
|
408
|
+
| **License** | MIT | Apache 2.0 | AGPL | MIT |
|
|
409
|
+
|
|
410
|
+
## Development
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
npm run dev # run via tsx (no build step)
|
|
414
|
+
npm run build # TypeScript → dist/
|
|
415
|
+
npm test # vitest (182 tests)
|
|
416
|
+
npm run bench # performance benchmarks
|
|
417
|
+
npm run db:backup # backup database
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Stack:** TypeScript 5.9 (strict mode), better-sqlite3, @modelcontextprotocol/sdk, Snowball stemmer, Zod, vitest.
|
|
421
|
+
|
|
422
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for code guidelines.
|
|
423
|
+
|
|
424
|
+
## Design Principles
|
|
425
|
+
|
|
426
|
+
- **Air-gapped** — zero network calls, zero telemetry. Your memories stay on your machine.
|
|
427
|
+
- **Single file** — one SQLite database, zero ops, instant backup via file copy.
|
|
428
|
+
- **Deterministic search** — FTS5, not embeddings, is the default. Interpretable, reproducible, no GPU needed.
|
|
429
|
+
- **Structured over flat** — layers encode access patterns; superseding chains encode time.
|
|
430
|
+
- **Minimal** — 4 production dependencies. Works everywhere Node runs.
|
|
431
|
+
|
|
432
|
+
## License
|
|
433
|
+
|
|
434
|
+
[MIT](LICENSE)
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
| Version | Supported |
|
|
6
|
+
|---------|-----------|
|
|
7
|
+
| 1.x | Yes |
|
|
8
|
+
|
|
9
|
+
## Reporting a Vulnerability
|
|
10
|
+
|
|
11
|
+
**Do not open a public issue for security vulnerabilities.**
|
|
12
|
+
|
|
13
|
+
Report security issues via [GitHub Security Advisories](https://github.com/nikitacometa/mnemon-mcp/security/advisories/new).
|
|
14
|
+
|
|
15
|
+
Expected response time: 48 hours for acknowledgment, 7 days for initial assessment.
|
|
16
|
+
|
|
17
|
+
## Scope
|
|
18
|
+
|
|
19
|
+
mnemon-mcp is a local-first tool — it makes zero network calls by design (unless HTTP transport is explicitly enabled). Security-relevant areas:
|
|
20
|
+
|
|
21
|
+
- **SQL injection** — all queries use parameterized statements; FTS5 MATCH input is sanitized
|
|
22
|
+
- **Path traversal** — import pipeline validates paths within the configured KB root
|
|
23
|
+
- **HTTP transport** — Bearer token auth with timing-safe comparison; 1MB body size limit
|
|
24
|
+
- **Data at rest** — SQLite database stored at `~/.mnemon-mcp/memory.db` with user-only permissions
|
|
25
|
+
|
|
26
|
+
## Out of Scope
|
|
27
|
+
|
|
28
|
+
- Denial of service via large imports (local tool, single user)
|
|
29
|
+
- Memory content in error messages (intentionally excluded per CONTRIBUTING.md)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"owner_name": "your-name",
|
|
3
|
+
"extra_stop_words": [],
|
|
4
|
+
"mappings": [
|
|
5
|
+
{
|
|
6
|
+
"glob": "journal/*.md",
|
|
7
|
+
"layer": "episodic",
|
|
8
|
+
"entity_type": "user",
|
|
9
|
+
"entity_name": "$owner",
|
|
10
|
+
"importance": 0.6,
|
|
11
|
+
"confidence": 0.9,
|
|
12
|
+
"split": "h2"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"glob": "people/*.md",
|
|
16
|
+
"layer": "semantic",
|
|
17
|
+
"entity_type": "person",
|
|
18
|
+
"entity_name": "from-heading",
|
|
19
|
+
"importance": 0.8,
|
|
20
|
+
"confidence": 0.8,
|
|
21
|
+
"split": "h3"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"glob": "projects/*.md",
|
|
25
|
+
"layer": "semantic",
|
|
26
|
+
"entity_type": "project",
|
|
27
|
+
"entity_name": "from-heading",
|
|
28
|
+
"importance": 0.7,
|
|
29
|
+
"confidence": 0.8,
|
|
30
|
+
"split": "h2"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"glob": "knowledge/*.md",
|
|
34
|
+
"layer": "semantic",
|
|
35
|
+
"entity_type": "concept",
|
|
36
|
+
"entity_name": "from-heading",
|
|
37
|
+
"importance": 0.6,
|
|
38
|
+
"confidence": 0.8,
|
|
39
|
+
"split": "h2"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"glob": "notes/*.md",
|
|
43
|
+
"layer": "resource",
|
|
44
|
+
"entity_type": "concept",
|
|
45
|
+
"entity_name": "from-heading",
|
|
46
|
+
"importance": 0.5,
|
|
47
|
+
"confidence": 0.8,
|
|
48
|
+
"split": "h2"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"external_files": []
|
|
52
|
+
}
|