@syke1/mcp-server 1.3.6 → 1.3.8

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
@@ -10,30 +10,39 @@ Works with **Claude Code**, **Cursor**, **Windsurf**, and any MCP-compatible AI
10
10
 
11
11
  ![SYKE Node Detail](https://syke.cloud/images/node-detail.png)
12
12
 
13
+ ## How It Works
14
+
15
+ 1. **On startup**, SYKE scans your source directory and builds a complete dependency graph using static import analysis.
16
+ 2. **Your AI agent modifies files freely** — no interruptions during normal work.
17
+ 3. **Before build/deploy**, the AI calls `gate_build` to check if all changes are safe.
18
+ 4. **If dependencies break**, SYKE detects cascading failures and blocks the build with a `FAIL` verdict.
19
+ 5. **The dashboard** shows a real-time visualization of your dependency graph with risk indicators.
20
+
21
+ > **SYKE is a safety net, not a gatekeeper.** It doesn't block your AI while working — it catches what your AI missed before you ship.
22
+
13
23
  ## Quick Start
14
24
 
15
- ### 1. Add to your MCP config
25
+ ### 1. Create config file
16
26
 
17
- **Claude Code** (`~/.claude/mcp.json`):
27
+ Create `~/.syke/config.json`:
18
28
 
19
29
  ```json
20
30
  {
21
- "mcpServers": {
22
- "syke": {
23
- "command": "npx",
24
- "args": ["@syke1/mcp-server@latest"],
25
- "env": {
26
- "SYKE_LICENSE_KEY": "your-key-here",
27
- "SYKE_WEB_PORT": "3333",
28
- "GEMINI_KEY": "your-gemini-key",
29
- "OPENAI_KEY": "your-openai-key",
30
- "ANTHROPIC_KEY": "your-anthropic-key"
31
- }
32
- }
33
- }
31
+ "licenseKey": "SYKE-XXXX-XXXX-XXXX-XXXX",
32
+ "geminiKey": "your-gemini-api-key"
34
33
  }
35
34
  ```
36
35
 
36
+ > Get your license key at [syke.cloud/dashboard](https://syke.cloud/dashboard/). You only need ONE AI key. Supported: `geminiKey`, `openaiKey`, `anthropicKey`.
37
+
38
+ ### 2. Register MCP server
39
+
40
+ **Claude Code:**
41
+
42
+ ```bash
43
+ claude mcp add syke -- npx @syke1/mcp-server@latest
44
+ ```
45
+
37
46
  **Cursor** (`.cursor/mcp.json`):
38
47
 
39
48
  ```json
@@ -41,12 +50,7 @@ Works with **Claude Code**, **Cursor**, **Windsurf**, and any MCP-compatible AI
41
50
  "mcpServers": {
42
51
  "syke": {
43
52
  "command": "npx",
44
- "args": ["@syke1/mcp-server@latest"],
45
- "env": {
46
- "SYKE_LICENSE_KEY": "your-key-here",
47
- "SYKE_WEB_PORT": "3333",
48
- "GEMINI_KEY": "your-gemini-key"
49
- }
53
+ "args": ["@syke1/mcp-server@latest"]
50
54
  }
51
55
  }
52
56
  }
@@ -59,28 +63,27 @@ Works with **Claude Code**, **Cursor**, **Windsurf**, and any MCP-compatible AI
59
63
  "mcpServers": {
60
64
  "syke": {
61
65
  "command": "npx",
62
- "args": ["@syke1/mcp-server@latest"],
63
- "env": {
64
- "SYKE_LICENSE_KEY": "your-key-here",
65
- "SYKE_WEB_PORT": "3333",
66
- "GEMINI_KEY": "your-gemini-key"
67
- }
66
+ "args": ["@syke1/mcp-server@latest"]
68
67
  }
69
68
  }
70
69
  }
71
70
  ```
72
71
 
73
- > **Note:** You only need ONE AI key. SYKE auto-selects: Gemini > OpenAI > Anthropic. Set `SYKE_AI_PROVIDER` to force a specific one.
74
-
75
72
  > **Windows note:** If `npx` is not found, use the full path: `"command": "C:\\Program Files\\nodejs\\npx.cmd"`
76
73
 
77
- ### 2. Restart your AI agent
74
+ ### 3. Add build gate to your project
78
75
 
79
- SYKE auto-detects your project language and builds the dependency graph on startup.
76
+ Add this line to your project's `CLAUDE.md` (or equivalent AI instruction file):
80
77
 
81
- ### 3. Open the dashboard
78
+ ```
79
+ After completing code changes, always run the gate_build MCP tool before committing or deploying.
80
+ ```
81
+
82
+ This ensures your AI agent automatically runs SYKE's safety check after every task — no manual prompting needed.
82
83
 
83
- A web dashboard opens automatically at `http://localhost:3333` (configurable via `SYKE_WEB_PORT`) showing your live dependency graph.
84
+ ### 4. Restart your AI agent
85
+
86
+ SYKE auto-detects your project language and builds the dependency graph on startup. Open `http://localhost:3333` to see your live dashboard.
84
87
 
85
88
  ## Features
86
89
 
@@ -101,14 +104,14 @@ A web dashboard opens automatically at `http://localhost:3333` (configurable via
101
104
 
102
105
  SYKE supports three AI providers for semantic analysis. Bring your own key:
103
106
 
104
- | Provider | Model | Env Variable |
105
- |----------|-------|-------------|
106
- | Google Gemini | `gemini-2.5-flash` | `GEMINI_KEY` |
107
- | OpenAI | `gpt-4o-mini` | `OPENAI_KEY` |
108
- | Anthropic | `claude-sonnet-4-20250514` | `ANTHROPIC_KEY` |
107
+ | Provider | Model | Config Key | Env Variable |
108
+ |----------|-------|-----------|-------------|
109
+ | Google Gemini | `gemini-2.5-flash` | `geminiKey` | `GEMINI_KEY` |
110
+ | OpenAI | `gpt-4o-mini` | `openaiKey` | `OPENAI_KEY` |
111
+ | Anthropic | `claude-sonnet-4-20250514` | `anthropicKey` | `ANTHROPIC_KEY` |
109
112
 
110
113
  **Auto-selection:** SYKE uses the first available key (Gemini > OpenAI > Anthropic).
111
- **Force provider:** Set `SYKE_AI_PROVIDER=openai` (or `gemini`, `anthropic`) to override.
114
+ **Force provider:** Set `aiProvider` in config (or `SYKE_AI_PROVIDER` env var) to override.
112
115
 
113
116
  ### Language Support
114
117
 
@@ -116,10 +119,55 @@ Auto-detected, zero-config: **Dart/Flutter**, **TypeScript/JavaScript**, **Pytho
116
119
 
117
120
  ### Web Dashboard
118
121
 
119
- Live dependency graph visualization at `localhost:3333` (or your custom `SYKE_WEB_PORT`) with:
120
- - Interactive node graph (click any file to see its connections)
122
+ Live dependency graph visualization at `localhost:3333` with:
123
+ - Interactive 3D node graph (click any file to see its connections)
121
124
  - Real-time cascade monitoring
122
125
  - Risk level indicators
126
+ - Server offline detection with auto-reconnect
127
+
128
+ ## Configuration
129
+
130
+ SYKE reads from `~/.syke/config.json` (primary) with environment variable overrides:
131
+
132
+ | Config Key | Env Variable | Description | Required |
133
+ |-----------|-------------|-------------|----------|
134
+ | `licenseKey` | `SYKE_LICENSE_KEY` | Pro license key from dashboard | No (Free tier works without) |
135
+ | `geminiKey` | `GEMINI_KEY` | Google Gemini API key for `ai_analyze` | No (any one AI key) |
136
+ | `openaiKey` | `OPENAI_KEY` | OpenAI API key for `ai_analyze` | No (any one AI key) |
137
+ | `anthropicKey` | `ANTHROPIC_KEY` | Anthropic API key for `ai_analyze` | No (any one AI key) |
138
+ | `aiProvider` | `SYKE_AI_PROVIDER` | Force AI provider: `gemini`, `openai`, or `anthropic` | No (auto-selects) |
139
+ | `port` | `SYKE_WEB_PORT` | Dashboard port (default: 3333) | No |
140
+
141
+ **Full config example** (`~/.syke/config.json`):
142
+
143
+ ```json
144
+ {
145
+ "licenseKey": "SYKE-XXXX-XXXX-XXXX-XXXX",
146
+ "geminiKey": "AIza...",
147
+ "openaiKey": "",
148
+ "anthropicKey": "",
149
+ "port": 3333
150
+ }
151
+ ```
152
+
153
+ ## Recommended Workflow
154
+
155
+ ```
156
+ You (developer) AI Agent SYKE
157
+ | | |
158
+ |-- "Add feature X" -->| |
159
+ | |-- modifies files |
160
+ | |-- modifies files |
161
+ | |-- modifies files |
162
+ | | |
163
+ | |-- gate_build --->|
164
+ | | |-- scans graph
165
+ | | |-- checks impact
166
+ | |<-- PASS/FAIL ----|
167
+ | | |
168
+ |<-- "Done. Safe to | |
169
+ | build." ----------| |
170
+ ```
123
171
 
124
172
  ## Pricing
125
173
 
@@ -136,27 +184,7 @@ Live dependency graph visualization at `localhost:3333` (or your custom `SYKE_WE
136
184
  - AI semantic analysis (BYOK — Gemini, OpenAI, or Claude)
137
185
  - Priority support
138
186
 
139
- Get your license key at [syke.cloud/dashboard](https://syke.cloud/dashboard/).
140
-
141
- ## Configuration
142
-
143
- | Environment Variable | Description | Required |
144
- |---------------------|-------------|----------|
145
- | `SYKE_LICENSE_KEY` | Pro license key from dashboard | No (Free tier works without) |
146
- | `GEMINI_KEY` | Google Gemini API key for `ai_analyze` | No (any one AI key) |
147
- | `OPENAI_KEY` | OpenAI API key for `ai_analyze` | No (any one AI key) |
148
- | `ANTHROPIC_KEY` | Anthropic API key for `ai_analyze` | No (any one AI key) |
149
- | `SYKE_AI_PROVIDER` | Force AI provider: `gemini`, `openai`, or `anthropic` | No (auto-selects) |
150
- | `SYKE_WEB_PORT` | Dashboard port (default: 3333) | No |
151
- | `SYKE_NO_BROWSER` | Set to `1` to disable auto-open browser | No |
152
- | `SYKE_currentProjectRoot` | Override auto-detected project root | No |
153
-
154
- ## How It Works
155
-
156
- 1. **On startup**, SYKE scans your source directory and builds a complete dependency graph using static import analysis.
157
- 2. **When your AI modifies a file**, call `gate_build` to check if the change is safe before building.
158
- 3. **If dependencies break**, SYKE detects cascading failures and blocks the build with a `FAIL` verdict.
159
- 4. **The dashboard** shows a real-time visualization of your dependency graph with risk indicators.
187
+ Sign up at [syke.cloud](https://syke.cloud) — 3-day free trial included.
160
188
 
161
189
  ## License
162
190
 
package/dist/index.js CHANGED
@@ -522,6 +522,8 @@ async function main() {
522
522
  fileCache.initialize();
523
523
  fileCache.startWatching();
524
524
  }
525
+ // Web server handle (set after server starts)
526
+ let webServerHandle = null;
525
527
  // Switch project callback — reinitializes graph + file cache
526
528
  function switchProject(newRoot) {
527
529
  currentProjectRoot = newRoot;
@@ -533,6 +535,10 @@ async function main() {
533
535
  fileCache = new file_cache_1.FileCache(newRoot);
534
536
  fileCache.initialize();
535
537
  fileCache.startWatching();
538
+ // Re-wire SSE events to the new FileCache
539
+ if (webServerHandle) {
540
+ webServerHandle.setFileCache(fileCache);
541
+ }
536
542
  // Rebuild graph
537
543
  const graph = (0, graph_1.refreshGraph)(newRoot, currentPackageName);
538
544
  console.error(`[syke] Switched to project: ${newRoot}`);
@@ -552,7 +558,8 @@ async function main() {
552
558
  }
553
559
  // Start Express web server with file cache for SSE (only if project detected)
554
560
  if (currentProjectRoot) {
555
- const webApp = (0, server_1.createWebServer)(() => (0, graph_1.getGraph)(currentProjectRoot, currentPackageName), fileCache, switchProject, () => currentProjectRoot, () => currentPackageName, () => licenseStatus, () => !!(0, provider_1.getAIProvider)());
561
+ const { app: webApp, setFileCache: setWebFileCache } = (0, server_1.createWebServer)(() => (0, graph_1.getGraph)(currentProjectRoot, currentPackageName), fileCache, switchProject, () => currentProjectRoot, () => currentPackageName, () => licenseStatus, () => !!(0, provider_1.getAIProvider)());
562
+ webServerHandle = { setFileCache: setWebFileCache };
556
563
  webApp.listen(WEB_PORT, () => {
557
564
  const dashUrl = `http://localhost:${WEB_PORT}`;
558
565
  console.error(`[syke] Web dashboard: ${dashUrl}`);
@@ -1,3 +1,4 @@
1
+ import express from "express";
1
2
  import { DependencyGraph } from "../graph";
2
3
  import { FileCache } from "../watcher/file-cache";
3
4
  import { RealtimeAnalysis } from "../ai/realtime-analyzer";
@@ -24,9 +25,14 @@ export interface SwitchProjectResult {
24
25
  fileCount: number;
25
26
  edgeCount: number;
26
27
  }
27
- export declare function createWebServer(getGraphFn: () => DependencyGraph, fileCache?: FileCache, switchProjectFn?: (newRoot: string) => SwitchProjectResult, getProjectRoot?: () => string, getPackageName?: () => string, getLicenseStatus?: () => {
28
+ export interface WebServerHandle {
29
+ app: ReturnType<typeof express>;
30
+ /** Re-wire SSE events when FileCache is replaced (e.g. after switchProject) */
31
+ setFileCache(cache: FileCache): void;
32
+ }
33
+ export declare function createWebServer(getGraphFn: () => DependencyGraph, initialFileCache?: FileCache, switchProjectFn?: (newRoot: string) => SwitchProjectResult, getProjectRoot?: () => string, getPackageName?: () => string, getLicenseStatus?: () => {
28
34
  plan: string;
29
35
  expiresAt?: string;
30
36
  error?: string;
31
37
  source?: string;
32
- }, hasAIKeyFn?: () => boolean): import("express-serve-static-core").Express;
38
+ }, hasAIKeyFn?: () => boolean): WebServerHandle;
@@ -226,7 +226,7 @@ function acknowledgeWarnings() {
226
226
  function getAllWarnings() {
227
227
  return [...warningStore];
228
228
  }
229
- function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot, getPackageName, getLicenseStatus, hasAIKeyFn) {
229
+ function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProjectRoot, getPackageName, getLicenseStatus, hasAIKeyFn) {
230
230
  const app = (0, express_1.default)();
231
231
  app.use(express_1.default.json());
232
232
  // Serve static files from public/
@@ -234,6 +234,7 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
234
234
  app.use(express_1.default.static(publicDir));
235
235
  // ── SSE: Server-Sent Events for real-time updates ──
236
236
  const sseClients = new Set();
237
+ let currentFileCache = initialFileCache || null;
237
238
  function broadcastSSE(event, data) {
238
239
  const payload = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
239
240
  for (const client of sseClients) {
@@ -274,7 +275,7 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
274
275
  "Access-Control-Allow-Origin": "*",
275
276
  });
276
277
  // Send initial connection event
277
- res.write(`event: connected\ndata: ${JSON.stringify({ clients: sseClients.size + 1, cacheSize: fileCache?.size || 0 })}\n\n`);
278
+ res.write(`event: connected\ndata: ${JSON.stringify({ clients: sseClients.size + 1, cacheSize: currentFileCache?.size || 0 })}\n\n`);
278
279
  sseClients.add(res);
279
280
  console.error(`[syke:sse] Client connected (${sseClients.size} total)`);
280
281
  _req.on("close", () => {
@@ -283,8 +284,8 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
283
284
  });
284
285
  });
285
286
  // Wire FileCache change events → SSE broadcast + AI analysis
286
- if (fileCache) {
287
- fileCache.on("change", async (change) => {
287
+ function wireFileCacheEvents(cache) {
288
+ cache.on("change", async (change) => {
288
289
  const graph = getGraphFn();
289
290
  const absPath = path.normalize(path.join(graph.sourceDir, change.relativePath));
290
291
  // Compute affected nodes for visual pulse
@@ -317,7 +318,7 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
317
318
  if (license && license.plan === "pro") {
318
319
  broadcastSSE("analysis-start", { file: change.relativePath });
319
320
  try {
320
- const analysis = await (0, realtime_analyzer_1.analyzeChangeRealtime)(change, graph, (relPath) => fileCache.getFileByRelPath(relPath));
321
+ const analysis = await (0, realtime_analyzer_1.analyzeChangeRealtime)(change, graph, (relPath) => currentFileCache?.getFileByRelPath(relPath) ?? null);
321
322
  broadcastSSE("analysis-result", analysis);
322
323
  // Store warnings for MCP check_warnings tool
323
324
  addWarning(analysis);
@@ -341,15 +342,23 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
341
342
  }
342
343
  });
343
344
  }
345
+ if (currentFileCache)
346
+ wireFileCacheEvents(currentFileCache);
347
+ /** Replace the FileCache (called after switchProject) */
348
+ function setFileCache(cache) {
349
+ currentFileCache = cache;
350
+ wireFileCacheEvents(cache);
351
+ console.error(`[syke:sse] FileCache re-wired (${cache.size} files)`);
352
+ }
344
353
  // GET /api/cache-status — Memory cache stats
345
354
  app.get("/api/cache-status", (_req, res) => {
346
- if (!fileCache) {
355
+ if (!currentFileCache) {
347
356
  return res.json({ enabled: false });
348
357
  }
349
358
  res.json({
350
359
  enabled: true,
351
- fileCount: fileCache.size,
352
- totalLines: fileCache.totalLines,
360
+ fileCount: currentFileCache.size,
361
+ totalLines: currentFileCache.totalLines,
353
362
  sseClients: sseClients.size,
354
363
  });
355
364
  });
@@ -804,5 +813,5 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
804
813
  res.status(500).json({ error: err.message || "Failed to switch project" });
805
814
  }
806
815
  });
807
- return app;
816
+ return { app, setFileCache };
808
817
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syke1/mcp-server",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "mcpName": "io.github.khalomsky/syke",
5
5
  "description": "AI code impact analysis MCP server — dependency graphs, cascade detection, and a mandatory build gate for AI coding agents",
6
6
  "main": "dist/index.js",