@danielblomma/cortex-mcp 0.6.5 → 1.0.1
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 +87 -0
- package/bin/cortex.mjs +4 -3
- package/bin/wsl.mjs +30 -0
- package/package.json +1 -1
- package/scaffold/mcp/package-lock.json +10 -6
- package/scaffold/mcp/src/paths.ts +16 -1
- package/scaffold/scripts/memory-compile.mjs +10 -1
- package/scaffold/scripts/memory-lint.mjs +10 -1
- package/scaffold/scripts/watch.sh +9 -1
package/README.md
CHANGED
|
@@ -131,6 +131,59 @@ Codex (`~/.config/codex/mcp-config.json`):
|
|
|
131
131
|
}
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
+
## WSL Mode (Windows)
|
|
135
|
+
|
|
136
|
+
If you run Node.js inside WSL but use Claude Desktop or another MCP client on Windows:
|
|
137
|
+
|
|
138
|
+
1. Install Cortex inside WSL:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# In a WSL terminal
|
|
142
|
+
npm i -g @danielblomma/cortex-mcp
|
|
143
|
+
cd /mnt/c/Users/yourname/your-project
|
|
144
|
+
cortex init --bootstrap
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
2. Configure Claude Desktop (`%APPDATA%\Claude\claude_desktop_config.json`):
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"mcpServers": {
|
|
152
|
+
"cortex": {
|
|
153
|
+
"command": "wsl.exe",
|
|
154
|
+
"args": ["--distribution", "Ubuntu", "--exec", "cortex", "mcp"],
|
|
155
|
+
"env": {
|
|
156
|
+
"CORTEX_PROJECT_ROOT": "C:\\Users\\yourname\\your-project",
|
|
157
|
+
"CORTEX_AUTO_BOOTSTRAP_ON_MCP": "1"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Cortex automatically converts Windows paths (e.g. `C:\Users\...`) to WSL paths (`/mnt/c/Users/...`).
|
|
165
|
+
|
|
166
|
+
For projects on the WSL filesystem (e.g. `~/projects/myapp`), use the WSL path directly:
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"mcpServers": {
|
|
171
|
+
"cortex": {
|
|
172
|
+
"command": "wsl.exe",
|
|
173
|
+
"args": ["--distribution", "Ubuntu", "--exec", "cortex", "mcp"],
|
|
174
|
+
"env": {
|
|
175
|
+
"CORTEX_PROJECT_ROOT": "/home/yourname/projects/myapp",
|
|
176
|
+
"CORTEX_AUTO_BOOTSTRAP_ON_MCP": "1"
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Notes:**
|
|
184
|
+
- File watching on `/mnt/` paths (Windows filesystem) automatically uses poll mode since `inotify` is unreliable across filesystem boundaries.
|
|
185
|
+
- For best performance, keep projects on the WSL filesystem (`~/...`) rather than `/mnt/c/...`.
|
|
186
|
+
|
|
134
187
|
## MCP Tools
|
|
135
188
|
|
|
136
189
|
### `context.search`
|
|
@@ -154,6 +207,40 @@ Input:
|
|
|
154
207
|
- `depth` (int, 1-3, default `1`)
|
|
155
208
|
- `include_edges` (bool, default `true`)
|
|
156
209
|
|
|
210
|
+
### `context.find_callers`
|
|
211
|
+
|
|
212
|
+
Return chunk callers for a chunk or file entity using the indexed call graph.
|
|
213
|
+
|
|
214
|
+
Input:
|
|
215
|
+
|
|
216
|
+
- `entity_id` (string, required)
|
|
217
|
+
- `depth` (int, 1-4, default `1`)
|
|
218
|
+
- `include_edges` (bool, default `true`)
|
|
219
|
+
|
|
220
|
+
### `context.trace_calls`
|
|
221
|
+
|
|
222
|
+
Trace call graph neighbors from a chunk or file entity in the requested direction.
|
|
223
|
+
|
|
224
|
+
Input:
|
|
225
|
+
|
|
226
|
+
- `entity_id` (string, required)
|
|
227
|
+
- `depth` (int, 1-4, default `2`)
|
|
228
|
+
- `direction` (`"outgoing"` | `"incoming"` | `"both"`, default `"outgoing"`)
|
|
229
|
+
- `include_edges` (bool, default `true`)
|
|
230
|
+
|
|
231
|
+
### `context.impact_analysis`
|
|
232
|
+
|
|
233
|
+
Analyze likely impacted call-graph entities starting from an entity id or search query.
|
|
234
|
+
|
|
235
|
+
Input:
|
|
236
|
+
|
|
237
|
+
- `entity_id` (string, optional) — either `entity_id` or `query` is required
|
|
238
|
+
- `query` (string, optional)
|
|
239
|
+
- `depth` (int, 1-4, default `2`)
|
|
240
|
+
- `top_k` (int, 1-20, default `8`)
|
|
241
|
+
- `direction` (`"incoming"` | `"outgoing"` | `"both"`, default `"incoming"`)
|
|
242
|
+
- `include_edges` (bool, default `true`)
|
|
243
|
+
|
|
157
244
|
### `context.get_rules`
|
|
158
245
|
|
|
159
246
|
List indexed rules and optionally include inactive rules.
|
package/bin/cortex.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import fs from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
|
+
import { normalizeProjectRoot } from "./wsl.mjs";
|
|
6
7
|
|
|
7
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
9
|
const __dirname = path.dirname(__filename);
|
|
@@ -599,9 +600,9 @@ async function run() {
|
|
|
599
600
|
}
|
|
600
601
|
|
|
601
602
|
if (command === "mcp") {
|
|
602
|
-
const
|
|
603
|
-
|
|
604
|
-
|
|
603
|
+
const rawTarget = process.env.CORTEX_PROJECT_ROOT || process.cwd();
|
|
604
|
+
const target = path.resolve(normalizeProjectRoot(rawTarget));
|
|
605
|
+
process.env.CORTEX_PROJECT_ROOT = target;
|
|
605
606
|
await ensureProjectInitializedForMcp(target);
|
|
606
607
|
ensureProjectInitialized(target);
|
|
607
608
|
const serverEntry = path.join(target, "mcp", "dist", "server.js");
|
package/bin/wsl.mjs
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
|
|
3
|
+
let _isWSL = null;
|
|
4
|
+
|
|
5
|
+
export function isWSL() {
|
|
6
|
+
if (_isWSL !== null) return _isWSL;
|
|
7
|
+
try {
|
|
8
|
+
const version = fs.readFileSync("/proc/version", "utf8");
|
|
9
|
+
_isWSL = /microsoft|wsl/i.test(version);
|
|
10
|
+
} catch {
|
|
11
|
+
_isWSL = false;
|
|
12
|
+
}
|
|
13
|
+
return _isWSL;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function windowsToWslPath(winPath) {
|
|
17
|
+
const match = winPath.match(/^([A-Za-z]):[/\\](.*)/);
|
|
18
|
+
if (!match) return winPath;
|
|
19
|
+
const drive = match[1].toLowerCase();
|
|
20
|
+
const rest = match[2].replace(/\\/g, "/").replace(/\/+$/, "");
|
|
21
|
+
return `/mnt/${drive}/${rest}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function normalizeProjectRoot(rawPath) {
|
|
25
|
+
if (!isWSL()) return rawPath;
|
|
26
|
+
if (/^[A-Za-z]:[/\\]/.test(rawPath)) {
|
|
27
|
+
return windowsToWslPath(rawPath);
|
|
28
|
+
}
|
|
29
|
+
return rawPath;
|
|
30
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danielblomma/cortex-mcp",
|
|
3
3
|
"mcpName": "io.github.DanielBlomma/cortex",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "1.0.1",
|
|
5
5
|
"description": "Local, repo-scoped context platform for coding assistants. Semantic search, graph relationships, and architectural rule context.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"author": "Daniel Blomma",
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"node_modules/@hono/node-server": {
|
|
36
|
-
"version": "1.19.
|
|
37
|
-
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.
|
|
38
|
-
"integrity": "sha512-
|
|
36
|
+
"version": "1.19.13",
|
|
37
|
+
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.13.tgz",
|
|
38
|
+
"integrity": "sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ==",
|
|
39
39
|
"license": "MIT",
|
|
40
40
|
"engines": {
|
|
41
41
|
"node": ">=18.14.1"
|
|
@@ -236,6 +236,7 @@
|
|
|
236
236
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.13.tgz",
|
|
237
237
|
"integrity": "sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==",
|
|
238
238
|
"license": "MIT",
|
|
239
|
+
"peer": true,
|
|
239
240
|
"dependencies": {
|
|
240
241
|
"undici-types": "~6.21.0"
|
|
241
242
|
}
|
|
@@ -1284,10 +1285,11 @@
|
|
|
1284
1285
|
}
|
|
1285
1286
|
},
|
|
1286
1287
|
"node_modules/hono": {
|
|
1287
|
-
"version": "4.12.
|
|
1288
|
-
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.
|
|
1289
|
-
"integrity": "sha512-
|
|
1288
|
+
"version": "4.12.12",
|
|
1289
|
+
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.12.tgz",
|
|
1290
|
+
"integrity": "sha512-p1JfQMKaceuCbpJKAPKVqyqviZdS0eUxH9v82oWo1kb9xjQ5wA6iP3FNVAPDFlz5/p7d45lO+BpSk1tuSZMF4Q==",
|
|
1290
1291
|
"license": "MIT",
|
|
1292
|
+
"peer": true,
|
|
1291
1293
|
"engines": {
|
|
1292
1294
|
"node": ">=16.9.0"
|
|
1293
1295
|
}
|
|
@@ -2444,6 +2446,7 @@
|
|
|
2444
2446
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
|
2445
2447
|
"dev": true,
|
|
2446
2448
|
"license": "Apache-2.0",
|
|
2449
|
+
"peer": true,
|
|
2447
2450
|
"bin": {
|
|
2448
2451
|
"tsc": "bin/tsc",
|
|
2449
2452
|
"tsserver": "bin/tsserver"
|
|
@@ -2602,6 +2605,7 @@
|
|
|
2602
2605
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
|
2603
2606
|
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
|
2604
2607
|
"license": "MIT",
|
|
2608
|
+
"peer": true,
|
|
2605
2609
|
"funding": {
|
|
2606
2610
|
"url": "https://github.com/sponsors/colinhacks"
|
|
2607
2611
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
1
2
|
import path from "node:path";
|
|
2
3
|
import { fileURLToPath } from "node:url";
|
|
3
4
|
import type { RankingWeights } from "./types.js";
|
|
@@ -5,9 +6,23 @@ import type { RankingWeights } from "./types.js";
|
|
|
5
6
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
7
|
const __dirname = path.dirname(__filename);
|
|
7
8
|
|
|
9
|
+
function normalizeForWsl(rawPath: string): string {
|
|
10
|
+
const winMatch = rawPath.match(/^([A-Za-z]):[/\\](.*)/);
|
|
11
|
+
if (!winMatch) return rawPath;
|
|
12
|
+
try {
|
|
13
|
+
const version = fs.readFileSync("/proc/version", "utf8");
|
|
14
|
+
if (!/microsoft|wsl/i.test(version)) return rawPath;
|
|
15
|
+
} catch {
|
|
16
|
+
return rawPath;
|
|
17
|
+
}
|
|
18
|
+
const drive = winMatch[1].toLowerCase();
|
|
19
|
+
const rest = winMatch[2].replace(/\\/g, "/").replace(/\/+$/, "");
|
|
20
|
+
return `/mnt/${drive}/${rest}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
8
23
|
const PROJECT_ROOT_OVERRIDE = process.env.CORTEX_PROJECT_ROOT?.trim();
|
|
9
24
|
export const REPO_ROOT = PROJECT_ROOT_OVERRIDE
|
|
10
|
-
? path.resolve(PROJECT_ROOT_OVERRIDE)
|
|
25
|
+
? path.resolve(normalizeForWsl(PROJECT_ROOT_OVERRIDE))
|
|
11
26
|
: path.resolve(__dirname, "../..");
|
|
12
27
|
export const CONTEXT_DIR = path.join(REPO_ROOT, ".context");
|
|
13
28
|
export const CACHE_DIR = path.join(CONTEXT_DIR, "cache");
|
|
@@ -6,8 +6,17 @@ import { parseFrontmatter, parseStringList } from "../mcp/dist/frontmatter.js";
|
|
|
6
6
|
|
|
7
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
8
|
const __dirname = path.dirname(__filename);
|
|
9
|
+
|
|
10
|
+
function normalizeForWsl(rawPath) {
|
|
11
|
+
const m = rawPath.match(/^([A-Za-z]):[/\\](.*)/);
|
|
12
|
+
if (!m) return rawPath;
|
|
13
|
+
try { if (!/microsoft|wsl/i.test(fs.readFileSync("/proc/version", "utf8"))) return rawPath; }
|
|
14
|
+
catch { return rawPath; }
|
|
15
|
+
return `/mnt/${m[1].toLowerCase()}/${m[2].replace(/\\/g, "/").replace(/\/+$/, "")}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
9
18
|
const REPO_ROOT = process.env.CORTEX_PROJECT_ROOT
|
|
10
|
-
? path.resolve(process.env.CORTEX_PROJECT_ROOT)
|
|
19
|
+
? path.resolve(normalizeForWsl(process.env.CORTEX_PROJECT_ROOT))
|
|
11
20
|
: path.resolve(__dirname, "..");
|
|
12
21
|
const CONTEXT_DIR = path.join(REPO_ROOT, ".context");
|
|
13
22
|
const MEMORY_DIR = path.join(CONTEXT_DIR, "memory");
|
|
@@ -6,8 +6,17 @@ import { parseFrontmatter, parseStringList } from "../mcp/dist/frontmatter.js";
|
|
|
6
6
|
|
|
7
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
8
|
const __dirname = path.dirname(__filename);
|
|
9
|
+
|
|
10
|
+
function normalizeForWsl(rawPath) {
|
|
11
|
+
const m = rawPath.match(/^([A-Za-z]):[/\\](.*)/);
|
|
12
|
+
if (!m) return rawPath;
|
|
13
|
+
try { if (!/microsoft|wsl/i.test(fs.readFileSync("/proc/version", "utf8"))) return rawPath; }
|
|
14
|
+
catch { return rawPath; }
|
|
15
|
+
return `/mnt/${m[1].toLowerCase()}/${m[2].replace(/\\/g, "/").replace(/\/+$/, "")}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
9
18
|
const REPO_ROOT = process.env.CORTEX_PROJECT_ROOT
|
|
10
|
-
? path.resolve(process.env.CORTEX_PROJECT_ROOT)
|
|
19
|
+
? path.resolve(normalizeForWsl(process.env.CORTEX_PROJECT_ROOT))
|
|
11
20
|
: path.resolve(__dirname, "..");
|
|
12
21
|
const CONTEXT_DIR = path.join(REPO_ROOT, ".context");
|
|
13
22
|
const MEMORY_DIR = path.join(CONTEXT_DIR, "memory");
|
|
@@ -84,10 +84,18 @@ detect_event_backend() {
|
|
|
84
84
|
return 1
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
is_wsl_mnt_path() {
|
|
88
|
+
grep -qi microsoft /proc/version 2>/dev/null && [[ "$REPO_ROOT" == /mnt/* ]]
|
|
89
|
+
}
|
|
90
|
+
|
|
87
91
|
resolve_mode() {
|
|
88
92
|
case "$WATCH_MODE" in
|
|
89
93
|
auto)
|
|
90
|
-
if
|
|
94
|
+
if is_wsl_mnt_path; then
|
|
95
|
+
echo "[watch] WSL detected with /mnt/ path, using poll mode (inotify unreliable on Windows mounts)"
|
|
96
|
+
WATCH_MODE="poll"
|
|
97
|
+
EVENT_BACKEND=""
|
|
98
|
+
elif EVENT_BACKEND="$(detect_event_backend)"; then
|
|
91
99
|
WATCH_MODE="event"
|
|
92
100
|
else
|
|
93
101
|
WATCH_MODE="poll"
|