context-vault 2.2.0 → 2.4.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/bin/cli.js +393 -63
- package/node_modules/@context-vault/core/LICENSE +21 -0
- package/node_modules/@context-vault/core/package.json +36 -0
- package/{src → node_modules/@context-vault/core/src}/capture/index.js +3 -2
- package/{src → node_modules/@context-vault/core/src}/core/categories.js +1 -0
- package/{src → node_modules/@context-vault/core/src}/core/config.js +5 -0
- package/{src → node_modules/@context-vault/core/src}/core/files.js +1 -0
- package/{src → node_modules/@context-vault/core/src}/core/status.js +32 -8
- package/node_modules/@context-vault/core/src/index/db.js +245 -0
- package/node_modules/@context-vault/core/src/index/embed.js +87 -0
- package/{src → node_modules/@context-vault/core/src}/index/index.js +51 -12
- package/node_modules/@context-vault/core/src/index.js +29 -0
- package/{src → node_modules/@context-vault/core/src}/retrieve/index.js +52 -43
- package/{src → node_modules/@context-vault/core/src}/server/tools.js +195 -31
- package/package.json +15 -15
- package/scripts/postinstall.js +45 -0
- package/scripts/prepack.js +31 -0
- package/src/server/index.js +127 -68
- package/ui/serve.js +7 -6
- package/README.md +0 -431
- package/smithery.yaml +0 -10
- package/src/capture/README.md +0 -23
- package/src/core/README.md +0 -20
- package/src/index/README.md +0 -28
- package/src/index/db.js +0 -139
- package/src/index/embed.js +0 -57
- package/src/retrieve/README.md +0 -19
- package/src/server/README.md +0 -44
- /package/{src → node_modules/@context-vault/core/src}/capture/file-ops.js +0 -0
- /package/{src → node_modules/@context-vault/core/src}/capture/formatters.js +0 -0
- /package/{src → node_modules/@context-vault/core/src}/core/frontmatter.js +0 -0
- /package/{src → node_modules/@context-vault/core/src}/server/helpers.js +0 -0
package/src/server/index.js
CHANGED
|
@@ -9,74 +9,133 @@ import { fileURLToPath } from "node:url";
|
|
|
9
9
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
10
|
const pkg = JSON.parse(readFileSync(join(__dirname, "..", "..", "package.json"), "utf-8"));
|
|
11
11
|
|
|
12
|
-
import { resolveConfig } from "
|
|
13
|
-
import { embed } from "
|
|
14
|
-
import { initDatabase, prepareStatements, insertVec, deleteVec } from "
|
|
15
|
-
import { registerTools } from "
|
|
16
|
-
|
|
17
|
-
// ───
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
12
|
+
import { resolveConfig } from "@context-vault/core/core/config";
|
|
13
|
+
import { embed } from "@context-vault/core/index/embed";
|
|
14
|
+
import { initDatabase, NativeModuleError, prepareStatements, insertVec, deleteVec } from "@context-vault/core/index/db";
|
|
15
|
+
import { registerTools } from "@context-vault/core/server/tools";
|
|
16
|
+
|
|
17
|
+
// ─── Phased Startup ─────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
async function main() {
|
|
20
|
+
let phase = "CONFIG";
|
|
21
|
+
let db;
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
// ── Phase: CONFIG ────────────────────────────────────────────────────────
|
|
25
|
+
const config = resolveConfig();
|
|
26
|
+
|
|
27
|
+
// ── Phase: DIRS ──────────────────────────────────────────────────────────
|
|
28
|
+
phase = "DIRS";
|
|
29
|
+
mkdirSync(config.dataDir, { recursive: true });
|
|
30
|
+
mkdirSync(config.vaultDir, { recursive: true });
|
|
31
|
+
|
|
32
|
+
// Write .context-mcp marker (non-fatal)
|
|
33
|
+
try {
|
|
34
|
+
const markerPath = join(config.vaultDir, ".context-mcp");
|
|
35
|
+
const markerData = existsSync(markerPath) ? JSON.parse(readFileSync(markerPath, "utf-8")) : {};
|
|
36
|
+
writeFileSync(markerPath, JSON.stringify({ created: markerData.created || new Date().toISOString(), version: pkg.version }, null, 2) + "\n");
|
|
37
|
+
} catch (markerErr) {
|
|
38
|
+
console.error(`[context-mcp] Warning: could not write marker file: ${markerErr.message}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
config.vaultDirExists = existsSync(config.vaultDir);
|
|
42
|
+
|
|
43
|
+
// Startup diagnostics
|
|
44
|
+
console.error(`[context-mcp] Vault: ${config.vaultDir}`);
|
|
45
|
+
console.error(`[context-mcp] Database: ${config.dbPath}`);
|
|
46
|
+
console.error(`[context-mcp] Dev dir: ${config.devDir}`);
|
|
47
|
+
if (!config.vaultDirExists) {
|
|
48
|
+
console.error(`[context-mcp] WARNING: Vault directory not found!`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ── Phase: DB ────────────────────────────────────────────────────────────
|
|
52
|
+
phase = "DB";
|
|
53
|
+
db = await initDatabase(config.dbPath);
|
|
54
|
+
const stmts = prepareStatements(db);
|
|
55
|
+
|
|
56
|
+
const ctx = {
|
|
57
|
+
db,
|
|
58
|
+
config,
|
|
59
|
+
stmts,
|
|
60
|
+
embed,
|
|
61
|
+
insertVec: (rowid, embedding) => insertVec(stmts, rowid, embedding),
|
|
62
|
+
deleteVec: (rowid) => deleteVec(stmts, rowid),
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// ── Phase: SERVER ────────────────────────────────────────────────────────
|
|
66
|
+
phase = "SERVER";
|
|
67
|
+
const server = new McpServer(
|
|
68
|
+
{ name: "context-mcp", version: pkg.version },
|
|
69
|
+
{ capabilities: { tools: {} } }
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
registerTools(server, ctx);
|
|
73
|
+
|
|
74
|
+
// ── Graceful Shutdown ────────────────────────────────────────────────────
|
|
75
|
+
function shutdown(signal) {
|
|
76
|
+
console.error(`[context-mcp] Received ${signal}, shutting down...`);
|
|
77
|
+
try {
|
|
78
|
+
if (db.inTransaction) {
|
|
79
|
+
console.error("[context-mcp] Rolling back active transaction...");
|
|
80
|
+
db.exec("ROLLBACK");
|
|
81
|
+
}
|
|
82
|
+
db.pragma("wal_checkpoint(TRUNCATE)");
|
|
83
|
+
db.close();
|
|
84
|
+
console.error("[context-mcp] Database closed cleanly.");
|
|
85
|
+
} catch (shutdownErr) {
|
|
86
|
+
console.error(`[context-mcp] Shutdown error: ${shutdownErr.message}`);
|
|
87
|
+
}
|
|
88
|
+
process.exit(0);
|
|
89
|
+
}
|
|
90
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
91
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
92
|
+
|
|
93
|
+
// ── Phase: CONNECTED ─────────────────────────────────────────────────────
|
|
94
|
+
phase = "CONNECTED";
|
|
95
|
+
const transport = new StdioServerTransport();
|
|
96
|
+
await server.connect(transport);
|
|
97
|
+
|
|
98
|
+
// ── Non-blocking Update Check ────────────────────────────────────────────
|
|
99
|
+
setTimeout(() => {
|
|
100
|
+
import("node:child_process").then(({ execSync }) => {
|
|
101
|
+
try {
|
|
102
|
+
const latest = execSync("npm view context-vault version", {
|
|
103
|
+
encoding: "utf-8",
|
|
104
|
+
timeout: 5000,
|
|
105
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
106
|
+
}).trim();
|
|
107
|
+
if (latest && latest !== pkg.version) {
|
|
108
|
+
console.error(`[context-mcp] Update available: v${pkg.version} → v${latest}. Run: context-mcp update`);
|
|
109
|
+
}
|
|
110
|
+
} catch {}
|
|
111
|
+
}).catch(() => {});
|
|
112
|
+
}, 3000);
|
|
113
|
+
|
|
114
|
+
} catch (err) {
|
|
115
|
+
if (err instanceof NativeModuleError) {
|
|
116
|
+
// Boxed diagnostic for native module mismatch
|
|
117
|
+
console.error("");
|
|
118
|
+
console.error("╔══════════════════════════════════════════════════════════════╗");
|
|
119
|
+
console.error("║ context-mcp: Native Module Error ║");
|
|
120
|
+
console.error("╚══════════════════════════════════════════════════════════════╝");
|
|
121
|
+
console.error("");
|
|
122
|
+
console.error(err.message);
|
|
123
|
+
console.error("");
|
|
124
|
+
console.error(` Node.js path: ${process.execPath}`);
|
|
125
|
+
console.error(` Node.js version: ${process.version}`);
|
|
126
|
+
console.error("");
|
|
127
|
+
process.exit(78); // EX_CONFIG
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
console.error(`[context-mcp] Fatal error during ${phase} phase: ${err.message}`);
|
|
131
|
+
if (phase === "DB") {
|
|
132
|
+
console.error(`[context-mcp] Try deleting the DB file and restarting: rm "${err.dbPath || "vault.db"}"`);
|
|
133
|
+
}
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
39
136
|
}
|
|
40
137
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
let db, stmts;
|
|
44
|
-
try {
|
|
45
|
-
db = initDatabase(config.dbPath);
|
|
46
|
-
stmts = prepareStatements(db);
|
|
47
|
-
} catch (e) {
|
|
48
|
-
console.error(`[context-mcp] Database init failed: ${e.message}`);
|
|
49
|
-
console.error(`[context-mcp] DB path: ${config.dbPath}`);
|
|
50
|
-
console.error(`[context-mcp] Try deleting the DB file and restarting: rm "${config.dbPath}"`);
|
|
138
|
+
main().catch((err) => {
|
|
139
|
+
console.error(`[context-mcp] Unexpected fatal error: ${err.message}`);
|
|
51
140
|
process.exit(1);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const ctx = {
|
|
55
|
-
db,
|
|
56
|
-
config,
|
|
57
|
-
stmts,
|
|
58
|
-
embed,
|
|
59
|
-
insertVec: (rowid, embedding) => insertVec(stmts, rowid, embedding),
|
|
60
|
-
deleteVec: (rowid) => deleteVec(stmts, rowid),
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
// ─── MCP Server ──────────────────────────────────────────────────────────────
|
|
64
|
-
|
|
65
|
-
const server = new McpServer(
|
|
66
|
-
{ name: "context-mcp", version: pkg.version },
|
|
67
|
-
{ capabilities: { tools: {} } }
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
registerTools(server, ctx);
|
|
71
|
-
|
|
72
|
-
// ─── Graceful Shutdown ───────────────────────────────────────────────────────
|
|
73
|
-
|
|
74
|
-
function shutdown() {
|
|
75
|
-
try { db.close(); } catch {}
|
|
76
|
-
process.exit(0);
|
|
77
|
-
}
|
|
78
|
-
process.on("SIGINT", shutdown);
|
|
79
|
-
process.on("SIGTERM", shutdown);
|
|
80
|
-
|
|
81
|
-
const transport = new StdioServerTransport();
|
|
82
|
-
await server.connect(transport);
|
|
141
|
+
});
|
package/ui/serve.js
CHANGED
|
@@ -12,10 +12,10 @@ import { createServer } from "node:http";
|
|
|
12
12
|
import { readFileSync, writeFileSync, existsSync, statSync, readdirSync } from "node:fs";
|
|
13
13
|
import { resolve, dirname, join, basename } from "node:path";
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
|
-
import { resolveConfig } from "
|
|
16
|
-
import { initDatabase } from "
|
|
17
|
-
import { embed } from "
|
|
18
|
-
import { hybridSearch } from "
|
|
15
|
+
import { resolveConfig } from "@context-vault/core/core/config";
|
|
16
|
+
import { initDatabase } from "@context-vault/core/index/db";
|
|
17
|
+
import { embed } from "@context-vault/core/index/embed";
|
|
18
|
+
import { hybridSearch } from "@context-vault/core/retrieve";
|
|
19
19
|
|
|
20
20
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
21
21
|
|
|
@@ -348,8 +348,9 @@ async function handleSearch(res, url) {
|
|
|
348
348
|
|
|
349
349
|
if (!query) return jsonResponse(res, { results: [] });
|
|
350
350
|
|
|
351
|
-
const
|
|
352
|
-
|
|
351
|
+
const searchCtx = { db, config, embed };
|
|
352
|
+
const results = await hybridSearch(searchCtx, query, { kindFilter });
|
|
353
|
+
jsonResponse(res, { query, results });
|
|
353
354
|
}
|
|
354
355
|
|
|
355
356
|
// ─── Config Handlers ─────────────────────────────────────────────────────────
|
package/README.md
DELETED
|
@@ -1,431 +0,0 @@
|
|
|
1
|
-
# context-mcp
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/context-vault)
|
|
4
|
-
[](https://www.npmjs.com/package/context-vault)
|
|
5
|
-
[](./LICENSE)
|
|
6
|
-
[](https://nodejs.org)
|
|
7
|
-
|
|
8
|
-
Persistent memory for AI agents — saves and searches knowledge across sessions.
|
|
9
|
-
|
|
10
|
-
<p align="center">
|
|
11
|
-
<img src="assets/demo.gif" alt="context-vault demo — Claude Code and Cursor using the knowledge vault" width="800">
|
|
12
|
-
</p>
|
|
13
|
-
|
|
14
|
-
## Quick Start
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npm install -g context-vault
|
|
18
|
-
context-mcp setup
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Setup auto-detects your tools (Claude Code, Claude Desktop, Cursor, Windsurf, Cline), downloads the embedding model, seeds your vault with a starter entry, and verifies everything works. Then open your AI tool and try:
|
|
22
|
-
|
|
23
|
-
> "Search my vault for getting started"
|
|
24
|
-
|
|
25
|
-
## What It Does
|
|
26
|
-
|
|
27
|
-
- **Save** insights, decisions, patterns, and any custom knowledge kind from AI sessions
|
|
28
|
-
- **Search** with hybrid full-text + semantic similarity, ranked by relevance and recency
|
|
29
|
-
- **Own your data** — plain markdown files in folders you control, git-versioned, human-editable
|
|
30
|
-
|
|
31
|
-
## Tools
|
|
32
|
-
|
|
33
|
-
The server exposes five tools. Your AI agent calls them automatically — you don't invoke them directly.
|
|
34
|
-
|
|
35
|
-
| Tool | Type | Description |
|
|
36
|
-
|------|------|-------------|
|
|
37
|
-
| `get_context` | Read | Hybrid FTS5 + vector search across all knowledge |
|
|
38
|
-
| `save_context` | Write | Save new knowledge or update existing entries by ID |
|
|
39
|
-
| `list_context` | Browse | List vault entries with filtering and pagination |
|
|
40
|
-
| `delete_context` | Delete | Remove an entry by ID (file + index) |
|
|
41
|
-
| `context_status` | Diag | Show resolved config, health, and per-kind file counts |
|
|
42
|
-
|
|
43
|
-
### `get_context` — Search your vault
|
|
44
|
-
|
|
45
|
-
```js
|
|
46
|
-
get_context({
|
|
47
|
-
query: "react query caching", // Natural language or keywords
|
|
48
|
-
kind: "insight", // Optional: filter by kind
|
|
49
|
-
tags: ["react"], // Optional: filter by tags
|
|
50
|
-
limit: 5 // Optional: max results (default 10)
|
|
51
|
-
})
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Returns entries ranked by combined full-text and semantic similarity, with recency weighting.
|
|
55
|
-
|
|
56
|
-
### `save_context` — Save or update knowledge
|
|
57
|
-
|
|
58
|
-
```js
|
|
59
|
-
// Create new entry
|
|
60
|
-
save_context({
|
|
61
|
-
kind: "insight", // Determines folder: insights/
|
|
62
|
-
body: "React Query staleTime defaults to 0",
|
|
63
|
-
tags: ["react", "performance"],
|
|
64
|
-
title: "staleTime gotcha", // Optional
|
|
65
|
-
meta: { type: "gotcha" }, // Optional: any structured data
|
|
66
|
-
folder: "react/hooks", // Optional: subfolder organization
|
|
67
|
-
source: "debugging-session" // Optional: provenance
|
|
68
|
-
})
|
|
69
|
-
// → ~/vault/knowledge/insights/react/hooks/staletime-gotcha.md
|
|
70
|
-
|
|
71
|
-
// Update existing entry by ID
|
|
72
|
-
save_context({
|
|
73
|
-
id: "01HXYZ...", // ULID from a previous save
|
|
74
|
-
body: "Updated content here", // Only provide fields you want to change
|
|
75
|
-
tags: ["react", "updated"] // Omitted fields are preserved
|
|
76
|
-
})
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
The `kind` field accepts any string — `"insight"`, `"decision"`, `"pattern"`, `"reference"`, or any custom kind. The folder is auto-created from the pluralized kind name.
|
|
80
|
-
|
|
81
|
-
When updating (`id` provided), omitted fields are preserved from the original. You cannot change `kind` or `identity_key` — delete and re-create instead.
|
|
82
|
-
|
|
83
|
-
### `list_context` — Browse entries
|
|
84
|
-
|
|
85
|
-
```js
|
|
86
|
-
list_context({
|
|
87
|
-
kind: "insight", // Optional: filter by kind
|
|
88
|
-
category: "knowledge", // Optional: knowledge, entity, or event
|
|
89
|
-
tags: ["react"], // Optional: filter by tags
|
|
90
|
-
limit: 10, // Optional: max results (default 20, max 100)
|
|
91
|
-
offset: 0 // Optional: pagination offset
|
|
92
|
-
})
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Returns entry metadata (id, title, kind, category, tags, created_at) without body content. Use `get_context` with a search query to retrieve full entries.
|
|
96
|
-
|
|
97
|
-
### `delete_context` — Remove an entry
|
|
98
|
-
|
|
99
|
-
```js
|
|
100
|
-
delete_context({
|
|
101
|
-
id: "01HXYZ..." // ULID of the entry to delete
|
|
102
|
-
})
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Removes the markdown file from disk and cleans up the database and vector index.
|
|
106
|
-
|
|
107
|
-
### `context_status` — Diagnostics
|
|
108
|
-
|
|
109
|
-
Shows vault path, database size, file counts per kind, embedding coverage, and any issues.
|
|
110
|
-
|
|
111
|
-
## Knowledge Organization
|
|
112
|
-
|
|
113
|
-
### Folders and Kinds
|
|
114
|
-
|
|
115
|
-
Each top-level subdirectory in the vault maps to a `kind` value. The directory name is depluralized:
|
|
116
|
-
|
|
117
|
-
```
|
|
118
|
-
knowledge/insights/ → kind: "insight"
|
|
119
|
-
knowledge/decisions/ → kind: "decision"
|
|
120
|
-
knowledge/patterns/ → kind: "pattern"
|
|
121
|
-
knowledge/references/ → kind: "reference"
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
Within each kind directory, nested subfolders provide human-browsable organization. The subfolder path is stored in `meta.folder`:
|
|
125
|
-
|
|
126
|
-
```
|
|
127
|
-
ON DISK IN DB (vault table)
|
|
128
|
-
knowledge/insights/ kind: "insight", meta.folder: null
|
|
129
|
-
flat-file.md
|
|
130
|
-
knowledge/insights/react/hooks/ kind: "insight", meta.folder: "react/hooks"
|
|
131
|
-
use-query-gotcha.md
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
Tags are semantic (what the content is about). Folder structure is organizational (where it lives). These are separate concerns.
|
|
135
|
-
|
|
136
|
-
### File Format
|
|
137
|
-
|
|
138
|
-
All knowledge files use YAML frontmatter:
|
|
139
|
-
|
|
140
|
-
```markdown
|
|
141
|
-
---
|
|
142
|
-
id: 01HXYZ...
|
|
143
|
-
tags: ["react", "performance"]
|
|
144
|
-
source: claude-code
|
|
145
|
-
created: 2026-02-17T12:00:00Z
|
|
146
|
-
---
|
|
147
|
-
React Query's staleTime defaults to 0 — set it explicitly or every mount triggers a refetch.
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
Standard keys: `id`, `tags`, `source`, `created`. Any extra frontmatter keys (`type`, `status`, `language`, `folder`, etc.) are stored in a `meta` JSON column automatically.
|
|
151
|
-
|
|
152
|
-
### Custom Kinds
|
|
153
|
-
|
|
154
|
-
No code changes required:
|
|
155
|
-
|
|
156
|
-
1. `mkdir ~/vault/knowledge/references/`
|
|
157
|
-
2. Add `.md` files with YAML frontmatter
|
|
158
|
-
3. The next session auto-indexes them
|
|
159
|
-
|
|
160
|
-
The kind name comes from the directory: `references/` → kind `reference`.
|
|
161
|
-
|
|
162
|
-
## Configuration
|
|
163
|
-
|
|
164
|
-
Works out of the box with zero config. All paths are overridable:
|
|
165
|
-
|
|
166
|
-
```
|
|
167
|
-
CLI args > env vars > config file > convention defaults
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### Defaults
|
|
171
|
-
|
|
172
|
-
| Setting | Default |
|
|
173
|
-
|---------|---------|
|
|
174
|
-
| Vault dir | `~/vault/` |
|
|
175
|
-
| Data dir | `~/.context-mcp/` |
|
|
176
|
-
| Database | `~/.context-mcp/vault.db` |
|
|
177
|
-
| Dev dir | `~/dev/` |
|
|
178
|
-
|
|
179
|
-
### Config File (`~/.context-mcp/config.json`)
|
|
180
|
-
|
|
181
|
-
Lives in the data directory alongside the database. Created by `setup`, or create it manually:
|
|
182
|
-
|
|
183
|
-
```json
|
|
184
|
-
{
|
|
185
|
-
"vaultDir": "/Users/you/vault/",
|
|
186
|
-
"dataDir": "/Users/you/.context-mcp",
|
|
187
|
-
"dbPath": "/Users/you/.context-mcp/vault.db",
|
|
188
|
-
"devDir": "/Users/you/dev"
|
|
189
|
-
}
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
### Environment Variables
|
|
193
|
-
|
|
194
|
-
| Variable | Overrides |
|
|
195
|
-
|----------|-----------|
|
|
196
|
-
| `CONTEXT_MCP_VAULT_DIR` | Vault directory (knowledge files) |
|
|
197
|
-
| `CONTEXT_MCP_DB_PATH` | Database path |
|
|
198
|
-
| `CONTEXT_MCP_DEV_DIR` | Dev directory |
|
|
199
|
-
| `CONTEXT_MCP_DATA_DIR` | Data directory (DB + config storage) |
|
|
200
|
-
|
|
201
|
-
### CLI Arguments
|
|
202
|
-
|
|
203
|
-
```bash
|
|
204
|
-
context-mcp serve --vault-dir /custom/vault --dev-dir /custom/dev
|
|
205
|
-
context-mcp serve --data-dir /custom/data --db-path /custom/data/vault.db
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
## CLI
|
|
209
|
-
|
|
210
|
-
```bash
|
|
211
|
-
context-mcp <command> [options]
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
| Command | Description |
|
|
215
|
-
|---------|-------------|
|
|
216
|
-
| `setup` | Interactive MCP installer — detects tools, writes configs |
|
|
217
|
-
| `serve` | Start the MCP server (used by AI clients in MCP configs) |
|
|
218
|
-
| `ui [--port 3141]` | Launch the web dashboard |
|
|
219
|
-
| `reindex` | Rebuild search index from knowledge files |
|
|
220
|
-
| `status` | Show vault diagnostics (paths, counts, health) |
|
|
221
|
-
|
|
222
|
-
If running from source without a global install, use `node bin/cli.js` instead of `context-mcp`.
|
|
223
|
-
|
|
224
|
-
## Install
|
|
225
|
-
|
|
226
|
-
### npm (Recommended)
|
|
227
|
-
|
|
228
|
-
```bash
|
|
229
|
-
npm install -g context-vault
|
|
230
|
-
context-mcp setup
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
The `setup` command auto-detects installed tools (Claude Code, Claude Desktop, Cursor, Windsurf, Cline), lets you pick which to configure, and writes the correct MCP config for each. Existing configs are preserved — only the `context-mcp` entry is added or updated.
|
|
234
|
-
|
|
235
|
-
### Local Development
|
|
236
|
-
|
|
237
|
-
```bash
|
|
238
|
-
git clone https://github.com/fellanH/context-mcp.git
|
|
239
|
-
cd context-mcp
|
|
240
|
-
npm install
|
|
241
|
-
|
|
242
|
-
# Interactive setup — detects your tools and configures them
|
|
243
|
-
node bin/cli.js setup
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
For non-interactive environments (CI, scripts):
|
|
247
|
-
|
|
248
|
-
```bash
|
|
249
|
-
context-mcp setup --yes
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### Manual Configuration
|
|
253
|
-
|
|
254
|
-
If you prefer manual setup, add to your tool's MCP config. Pass `--vault-dir` to point at your vault folder (omit it to use the default `~/vault/`).
|
|
255
|
-
|
|
256
|
-
**npm install** (portable — survives upgrades):
|
|
257
|
-
|
|
258
|
-
```json
|
|
259
|
-
{
|
|
260
|
-
"mcpServers": {
|
|
261
|
-
"context-mcp": {
|
|
262
|
-
"command": "context-mcp",
|
|
263
|
-
"args": ["serve", "--vault-dir", "/path/to/vault"]
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
**Local dev clone** (absolute path to source):
|
|
270
|
-
|
|
271
|
-
```json
|
|
272
|
-
{
|
|
273
|
-
"mcpServers": {
|
|
274
|
-
"context-mcp": {
|
|
275
|
-
"command": "node",
|
|
276
|
-
"args": ["/path/to/context-mcp/src/server/index.js", "--vault-dir", "/path/to/vault"]
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
You can also pass config via environment variables in the MCP config block:
|
|
283
|
-
|
|
284
|
-
```json
|
|
285
|
-
{
|
|
286
|
-
"mcpServers": {
|
|
287
|
-
"context-mcp": {
|
|
288
|
-
"command": "context-mcp",
|
|
289
|
-
"args": ["serve"],
|
|
290
|
-
"env": {
|
|
291
|
-
"CONTEXT_MCP_VAULT_DIR": "/path/to/vault"
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
### How the Server Runs
|
|
299
|
-
|
|
300
|
-
The server is an MCP (Model Context Protocol) process — you don't start or stop it manually. Your AI client (Claude Code, Cursor, Cline, etc.) spawns it automatically as a child process when a session begins, based on the `mcpServers` config above. The server communicates over stdio and lives for the duration of the session. When the session ends, the client terminates the process and SQLite cleans up its WAL files.
|
|
301
|
-
|
|
302
|
-
This means:
|
|
303
|
-
- **No daemon, no port, no background service.** The server only runs while your AI client is active.
|
|
304
|
-
- **Multiple sessions** can run separate server instances concurrently — SQLite WAL mode handles concurrent access safely.
|
|
305
|
-
- **Embedding model** is downloaded during `setup` (~22MB, all-MiniLM-L6-v2). If setup was skipped, it downloads on first use.
|
|
306
|
-
- **Auto-reindex** on first tool call per session ensures the search index is always in sync with your files on disk. No manual reindex needed.
|
|
307
|
-
|
|
308
|
-
## Desktop App (macOS)
|
|
309
|
-
|
|
310
|
-
A macOS dock application that starts the UI server and opens the dashboard in your browser.
|
|
311
|
-
|
|
312
|
-
```bash
|
|
313
|
-
osacompile -o "/Applications/Context.app" ui/Context.applescript
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
The app checks if port 3141 is already in use, starts the server if not, and opens `http://localhost:3141`. Server logs are written to `/tmp/context-mcp.log`.
|
|
317
|
-
|
|
318
|
-
## How It Works
|
|
319
|
-
|
|
320
|
-
```
|
|
321
|
-
YOUR FILES (source of truth) SEARCH INDEX (derived)
|
|
322
|
-
~/vault/ ~/.context-mcp/vault.db
|
|
323
|
-
├── knowledge/ ┌───────────────────────────────┐
|
|
324
|
-
│ ├── insights/ │ vault table │
|
|
325
|
-
│ │ ├── react-query-caching.md │ kind: insight │
|
|
326
|
-
│ │ └── react/hooks/ │ meta.folder: "react/hooks" │
|
|
327
|
-
│ │ └── use-query-gotcha.md │ kind: decision │
|
|
328
|
-
│ ├── decisions/ │ kind: pattern │
|
|
329
|
-
│ │ └── use-sqlite-over-pg.md │ kind: <any custom> │
|
|
330
|
-
│ └── patterns/ │ + FTS5 full-text │
|
|
331
|
-
│ └── api-error-handler.md │ + vec0 embeddings │
|
|
332
|
-
├── entities/ └───────────────────────────────┘
|
|
333
|
-
└── events/
|
|
334
|
-
Human-editable, git-versioned Fast hybrid search, RAG-ready
|
|
335
|
-
You own these files Rebuilt from files anytime
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
The SQLite database is stored at `~/.context-mcp/vault.db` by default (configurable via `--db-path`, `CONTEXT_MCP_DB_PATH`, or `config.json`). It contains FTS5 full-text indexes and sqlite-vec embeddings (384-dim float32, all-MiniLM-L6-v2). The database is a derived index — delete it and the server rebuilds it automatically on next session.
|
|
339
|
-
|
|
340
|
-
Requires **Node.js 20** or later.
|
|
341
|
-
|
|
342
|
-
### Architecture
|
|
343
|
-
|
|
344
|
-
```
|
|
345
|
-
src/
|
|
346
|
-
├── core/ Shared utilities (config, frontmatter, files, status)
|
|
347
|
-
├── capture/ Write path — creates .md files in the vault
|
|
348
|
-
├── index/ Sync layer — SQLite schema, embeddings, reindex
|
|
349
|
-
├── retrieve/ Read path — hybrid FTS5 + vector search
|
|
350
|
-
└── server/ MCP server — wires layers into tool handlers
|
|
351
|
-
|
|
352
|
-
bin/
|
|
353
|
-
└── cli.js CLI entry point (setup, serve, ui, reindex, status)
|
|
354
|
-
|
|
355
|
-
ui/
|
|
356
|
-
├── serve.js HTTP server for web dashboard
|
|
357
|
-
├── index.html Single-page dashboard UI
|
|
358
|
-
└── Context.applescript macOS dock app launcher
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
Each layer has a single responsibility and can be understood independently. The server is the only module that imports across layer boundaries.
|
|
362
|
-
|
|
363
|
-
### Module Dependency Graph
|
|
364
|
-
|
|
365
|
-
```
|
|
366
|
-
core/files.js, core/frontmatter.js ← capture/
|
|
367
|
-
↑
|
|
368
|
-
core/config.js server/ ← bin/cli.js
|
|
369
|
-
↑
|
|
370
|
-
index/embed.js ← retrieve/ ← ui/serve.js
|
|
371
|
-
↑
|
|
372
|
-
index/db.js ←────────────────── (all consumers)
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
## Troubleshooting
|
|
376
|
-
|
|
377
|
-
### Native module build failures
|
|
378
|
-
|
|
379
|
-
`better-sqlite3` and `sqlite-vec` include native C code compiled for your platform. If install fails:
|
|
380
|
-
|
|
381
|
-
```bash
|
|
382
|
-
npm rebuild better-sqlite3 sqlite-vec
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
On Apple Silicon Macs, ensure you're running a native ARM Node.js (not Rosetta). Check with `node -p process.arch` — it should say `arm64`.
|
|
386
|
-
|
|
387
|
-
### Vault directory not found
|
|
388
|
-
|
|
389
|
-
If `context_status` or `get_context` reports the vault directory doesn't exist:
|
|
390
|
-
|
|
391
|
-
```bash
|
|
392
|
-
context-mcp status # Shows resolved paths
|
|
393
|
-
mkdir -p ~/vault # Create the default vault directory
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
Or re-run `context-mcp setup` to reconfigure.
|
|
397
|
-
|
|
398
|
-
### Embedding model download
|
|
399
|
-
|
|
400
|
-
The embedding model (all-MiniLM-L6-v2, ~22MB) is normally downloaded during `context-mcp setup`. If setup was skipped or the cache was cleared, it downloads automatically on first use. If it hangs, check your network or proxy settings.
|
|
401
|
-
|
|
402
|
-
### Stale search index
|
|
403
|
-
|
|
404
|
-
If search results seem outdated or missing:
|
|
405
|
-
|
|
406
|
-
```bash
|
|
407
|
-
context-mcp reindex
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
This rebuilds the entire index from your vault files. Auto-reindex runs on every session start, but manual reindex can help diagnose issues.
|
|
411
|
-
|
|
412
|
-
### Config path debugging
|
|
413
|
-
|
|
414
|
-
```bash
|
|
415
|
-
context-mcp status
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
Shows all resolved paths (vault dir, data dir, DB path, config file) and where each was resolved from (defaults, config file, env, or CLI args).
|
|
419
|
-
|
|
420
|
-
## Dependencies
|
|
421
|
-
|
|
422
|
-
| Package | Purpose |
|
|
423
|
-
|---------|---------|
|
|
424
|
-
| `@modelcontextprotocol/sdk` | MCP protocol (McpServer, StdioServerTransport) |
|
|
425
|
-
| `better-sqlite3` | SQLite driver |
|
|
426
|
-
| `sqlite-vec` | Vector search (384-dim float32) |
|
|
427
|
-
| `@huggingface/transformers` | Local embeddings (all-MiniLM-L6-v2, ~22MB) |
|
|
428
|
-
|
|
429
|
-
## License
|
|
430
|
-
|
|
431
|
-
MIT
|
package/smithery.yaml
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
startCommand:
|
|
2
|
-
type: stdio
|
|
3
|
-
configSchema:
|
|
4
|
-
type: object
|
|
5
|
-
properties:
|
|
6
|
-
vaultDir:
|
|
7
|
-
type: string
|
|
8
|
-
description: "Path to the vault directory containing your knowledge files. Defaults to ~/vault/"
|
|
9
|
-
commandFunction: |-
|
|
10
|
-
(config) => ({ command: 'npx', args: ['-y', 'context-vault', 'serve', ...(config.vaultDir ? ['--vault-dir', config.vaultDir] : [])] })
|