@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 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 target = process.env.CORTEX_PROJECT_ROOT
603
- ? path.resolve(process.env.CORTEX_PROJECT_ROOT)
604
- : process.cwd();
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.6.5",
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.10",
37
- "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.10.tgz",
38
- "integrity": "sha512-hZ7nOssGqRgyV3FVVQdfi+U4q02uB23bpnYpdvNXkYTRRyWx84b7yf1ans+dnJ/7h41sGL3CeQTfO+ZGxuO+Iw==",
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.7",
1288
- "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.7.tgz",
1289
- "integrity": "sha512-jq9l1DM0zVIvsm3lv9Nw9nlJnMNPOcAtsbsgiUhWcFzPE99Gvo6yRTlszSLLYacMeQ6quHD6hMfId8crVHvexw==",
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 EVENT_BACKEND="$(detect_event_backend)"; then
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"