@musashishao/agent-kit 1.2.2 → 1.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.
Files changed (40) hide show
  1. package/.agent/mcp-gateway/README.md +121 -0
  2. package/.agent/mcp-gateway/dist/index.d.ts +11 -0
  3. package/.agent/mcp-gateway/dist/index.js +504 -0
  4. package/.agent/mcp-gateway/dist/sync/debouncer.d.ts +56 -0
  5. package/.agent/mcp-gateway/dist/sync/debouncer.js +112 -0
  6. package/.agent/mcp-gateway/dist/sync/incremental_syncer.d.ts +58 -0
  7. package/.agent/mcp-gateway/dist/sync/incremental_syncer.js +172 -0
  8. package/.agent/mcp-gateway/dist/sync/index.d.ts +6 -0
  9. package/.agent/mcp-gateway/dist/sync/index.js +6 -0
  10. package/.agent/mcp-gateway/dist/sync/timestamp_checker.d.ts +69 -0
  11. package/.agent/mcp-gateway/dist/sync/timestamp_checker.js +169 -0
  12. package/.agent/mcp-gateway/package.json +28 -0
  13. package/.agent/mcp-gateway/src/index.ts +608 -0
  14. package/.agent/mcp-gateway/src/sync/debouncer.ts +129 -0
  15. package/.agent/mcp-gateway/src/sync/incremental_syncer.ts +237 -0
  16. package/.agent/mcp-gateway/src/sync/index.ts +7 -0
  17. package/.agent/mcp-gateway/src/sync/timestamp_checker.ts +194 -0
  18. package/.agent/scripts/ak_cli.py +549 -0
  19. package/.agent/scripts/setup_host.py +557 -0
  20. package/.agent/scripts/verify_install.py +174 -0
  21. package/.agent/skills/app-builder/SKILL.md +51 -1
  22. package/.agent/skills/app-builder/scripts/generate_ai_infra.py +510 -0
  23. package/.agent/skills/documentation-templates/SKILL.md +9 -1
  24. package/.agent/skills/documentation-templates/agents-template.md +202 -0
  25. package/.agent/skills/graph-mapper/SKILL.md +211 -0
  26. package/.agent/skills/graph-mapper/scripts/generate_graph.py +705 -0
  27. package/.agent/skills/rag-engineering/SKILL.md +342 -0
  28. package/.agent/skills/rag-engineering/chunking-strategies.md +229 -0
  29. package/.agent/skills/rag-engineering/contextual-retrieval.md +261 -0
  30. package/.agent/skills/rag-engineering/hybrid-search.md +356 -0
  31. package/.agent/skills/rag-engineering/scripts/chunk_code.py +916 -0
  32. package/.agent/templates/mcp_configs/claude_desktop.json +14 -0
  33. package/.agent/templates/mcp_configs/cursor.json +13 -0
  34. package/.agent/templates/mcp_configs/vscode.json +13 -0
  35. package/.agent/workflows/create.md +70 -2
  36. package/bin/cli.js +91 -0
  37. package/docs/AI_DATA_INFRASTRUCTURE.md +288 -0
  38. package/docs/CHANGELOG_AI_INFRA.md +111 -0
  39. package/docs/PLAN-universal-intelligence.md +48 -0
  40. package/package.json +7 -2
@@ -0,0 +1,121 @@
1
+ # Agent Kit MCP Gateway
2
+
3
+ > Live Project Cortex - MCP Server providing real-time project context to AI agents.
4
+
5
+ ## Features
6
+
7
+ - **get_project_context** - Read AGENTS.md sections
8
+ - **analyze_dependencies** - Query dependency graph
9
+ - **search_code_logic** - Semantic code search
10
+ - **get_impact_zone** - Impact analysis for changes
11
+ - **force_sync** - Refresh all AI data
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ cd .agent/mcp-gateway
17
+ npm install
18
+ npm run build
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ### With Claude Desktop
24
+
25
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
26
+
27
+ ```json
28
+ {
29
+ "mcpServers": {
30
+ "agent-kit": {
31
+ "command": "node",
32
+ "args": ["/path/to/.agent/mcp-gateway/dist/index.js"],
33
+ "env": {
34
+ "PROJECT_ROOT": "/path/to/your/project"
35
+ }
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ ### With Cursor
42
+
43
+ Add to `.cursor/mcp.json`:
44
+
45
+ ```json
46
+ {
47
+ "mcpServers": {
48
+ "agent-kit": {
49
+ "command": "node",
50
+ "args": [".agent/mcp-gateway/dist/index.js"],
51
+ "env": {
52
+ "PROJECT_ROOT": "."
53
+ }
54
+ }
55
+ }
56
+ }
57
+ ```
58
+
59
+ ### Development
60
+
61
+ ```bash
62
+ # Run in dev mode
63
+ npm run dev
64
+
65
+ # Build for production
66
+ npm run build
67
+ ```
68
+
69
+ ## Environment Variables
70
+
71
+ | Variable | Description | Default |
72
+ |----------|-------------|---------|
73
+ | `PROJECT_ROOT` | Path to project root | Current directory |
74
+ | `AGENT_KIT_PATH` | Path to Agent Kit installation | Auto-detected |
75
+
76
+ ## Tools Reference
77
+
78
+ ### get_project_context
79
+
80
+ ```json
81
+ {
82
+ "section": "tech_stack" // or "structure", "conventions", "commands", "all"
83
+ }
84
+ ```
85
+
86
+ ### analyze_dependencies
87
+
88
+ ```json
89
+ {
90
+ "file_path": "src/components/Button.tsx",
91
+ "direction": "both", // "imports", "imported_by", "both"
92
+ "depth": 2
93
+ }
94
+ ```
95
+
96
+ ### search_code_logic
97
+
98
+ ```json
99
+ {
100
+ "query": "authentication login",
101
+ "file_filter": "*.ts",
102
+ "top_k": 10
103
+ }
104
+ ```
105
+
106
+ ### get_impact_zone
107
+
108
+ ```json
109
+ {
110
+ "file_path": "src/utils/auth.ts",
111
+ "depth": 3
112
+ }
113
+ ```
114
+
115
+ ### force_sync
116
+
117
+ ```json
118
+ {
119
+ "target": "all" // or "graph", "rag", "agents_md"
120
+ }
121
+ ```
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Agent Kit MCP Gateway Server
4
+ *
5
+ * Provides AI agents with live access to project context, dependency graphs,
6
+ * and semantic code search with automatic sync capabilities.
7
+ *
8
+ * Usage:
9
+ * node dist/index.js [--project-root /path/to/project]
10
+ */
11
+ export {};
@@ -0,0 +1,504 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Agent Kit MCP Gateway Server
4
+ *
5
+ * Provides AI agents with live access to project context, dependency graphs,
6
+ * and semantic code search with automatic sync capabilities.
7
+ *
8
+ * Usage:
9
+ * node dist/index.js [--project-root /path/to/project]
10
+ */
11
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
12
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
13
+ import { z } from "zod";
14
+ import * as fs from "fs";
15
+ import * as path from "path";
16
+ // Import sync modules
17
+ import { IncrementalSyncer, getGlobalDebouncer, TimestampChecker } from "./sync/index.js";
18
+ // Get project root from environment or command line
19
+ const PROJECT_ROOT = process.env.PROJECT_ROOT || process.cwd();
20
+ // Initialize sync components
21
+ const syncer = new IncrementalSyncer(PROJECT_ROOT);
22
+ const debouncer = getGlobalDebouncer(30000); // 30 second cooldown
23
+ const timestampChecker = new TimestampChecker(PROJECT_ROOT);
24
+ // ============================================================================
25
+ // Auto-Sync Helper
26
+ // ============================================================================
27
+ async function autoSyncIfNeeded() {
28
+ // Check if data is stale
29
+ const status = timestampChecker.getSyncStatus();
30
+ if (!status.needsSync) {
31
+ return { synced: false, message: "Data is fresh" };
32
+ }
33
+ // Try to sync with debouncing
34
+ const result = await debouncer.executeWithDebounce(async () => {
35
+ return await syncer.syncAll();
36
+ });
37
+ if (result.executed) {
38
+ return { synced: true, message: `Auto-synced ${status.changedFiles} changed files` };
39
+ }
40
+ else {
41
+ return { synced: false, message: result.reason || "Sync skipped" };
42
+ }
43
+ }
44
+ // ============================================================================
45
+ // Utility Functions
46
+ // ============================================================================
47
+ function readJsonFile(filePath) {
48
+ try {
49
+ const fullPath = path.resolve(PROJECT_ROOT, filePath);
50
+ if (!fs.existsSync(fullPath)) {
51
+ return null;
52
+ }
53
+ return JSON.parse(fs.readFileSync(fullPath, "utf-8"));
54
+ }
55
+ catch (error) {
56
+ return null;
57
+ }
58
+ }
59
+ function readTextFile(filePath) {
60
+ try {
61
+ const fullPath = path.resolve(PROJECT_ROOT, filePath);
62
+ if (!fs.existsSync(fullPath)) {
63
+ return null;
64
+ }
65
+ return fs.readFileSync(fullPath, "utf-8");
66
+ }
67
+ catch (error) {
68
+ return null;
69
+ }
70
+ }
71
+ function getFileModTime(filePath) {
72
+ try {
73
+ const fullPath = path.resolve(PROJECT_ROOT, filePath);
74
+ const stats = fs.statSync(fullPath);
75
+ return stats.mtimeMs;
76
+ }
77
+ catch {
78
+ return 0;
79
+ }
80
+ }
81
+ // ============================================================================
82
+ // Create MCP Server
83
+ // ============================================================================
84
+ const server = new McpServer({
85
+ name: "agent-kit-gateway",
86
+ version: "1.0.0",
87
+ });
88
+ // ============================================================================
89
+ // Tool 1: get_project_context
90
+ // ============================================================================
91
+ server.tool("get_project_context", "Get project overview including tech stack, structure, and conventions from AGENTS.md", {
92
+ section: z
93
+ .enum(["all", "tech_stack", "structure", "conventions", "commands"])
94
+ .optional()
95
+ .default("all")
96
+ .describe("Specific section to retrieve"),
97
+ }, async ({ section }) => {
98
+ const agentsMd = readTextFile("AGENTS.md");
99
+ if (!agentsMd) {
100
+ return {
101
+ content: [
102
+ {
103
+ type: "text",
104
+ text: JSON.stringify({
105
+ error: "AGENTS.md not found",
106
+ suggestion: "Run 'ak init' to generate AI infrastructure",
107
+ project_root: PROJECT_ROOT,
108
+ }),
109
+ },
110
+ ],
111
+ };
112
+ }
113
+ // Parse sections from AGENTS.md
114
+ const sections = {};
115
+ const sectionRegex = /^## (.+)$/gm;
116
+ let matches;
117
+ let lastIndex = 0;
118
+ let lastSection = "";
119
+ const lines = agentsMd.split("\n");
120
+ let currentSection = "";
121
+ let currentContent = [];
122
+ for (const line of lines) {
123
+ if (line.startsWith("## ")) {
124
+ if (currentSection) {
125
+ sections[currentSection] = currentContent.join("\n").trim();
126
+ }
127
+ currentSection = line.replace("## ", "").trim();
128
+ currentContent = [];
129
+ }
130
+ else {
131
+ currentContent.push(line);
132
+ }
133
+ }
134
+ if (currentSection) {
135
+ sections[currentSection] = currentContent.join("\n").trim();
136
+ }
137
+ // Map section names to content
138
+ const sectionMap = {
139
+ tech_stack: sections["🛠️ Tech Stack"] || sections["Tech Stack"],
140
+ structure: sections["📁 Directory Map"] || sections["Directory Map"],
141
+ conventions: sections["📜 Rules & Conventions"] || sections["Rules & Conventions"],
142
+ commands: sections["🔧 Commands Reference"] || sections["Commands Reference"],
143
+ all: agentsMd,
144
+ };
145
+ const result = sectionMap[section] || agentsMd;
146
+ return {
147
+ content: [
148
+ {
149
+ type: "text",
150
+ text: result,
151
+ },
152
+ ],
153
+ };
154
+ });
155
+ // ============================================================================
156
+ // Tool 2: analyze_dependencies
157
+ // ============================================================================
158
+ server.tool("analyze_dependencies", "Get dependency graph for a file or module. Shows imports and files that import this file. Auto-syncs if data is stale.", {
159
+ file_path: z.string().describe("File path to analyze (relative to project root)"),
160
+ direction: z
161
+ .enum(["imports", "imported_by", "both"])
162
+ .optional()
163
+ .default("both")
164
+ .describe("Direction of dependencies to show"),
165
+ depth: z.number().optional().default(2).describe("Depth of traversal"),
166
+ }, async ({ file_path, direction, depth }) => {
167
+ // Auto-sync if data is stale
168
+ const syncStatus = await autoSyncIfNeeded();
169
+ const graph = readJsonFile(".agent/graph.json");
170
+ if (!graph) {
171
+ return {
172
+ content: [
173
+ {
174
+ type: "text",
175
+ text: JSON.stringify({
176
+ error: "Dependency graph not found",
177
+ suggestion: "Run 'ak sync' to generate dependency graph",
178
+ }),
179
+ },
180
+ ],
181
+ };
182
+ }
183
+ // Normalize file path
184
+ const normalizedPath = file_path.replace(/^\.\//, "");
185
+ // Find the node
186
+ const node = graph.nodes?.find((n) => n.id === normalizedPath || n.path === normalizedPath);
187
+ if (!node) {
188
+ return {
189
+ content: [
190
+ {
191
+ type: "text",
192
+ text: JSON.stringify({
193
+ error: `File not found in graph: ${file_path}`,
194
+ available_files: graph.nodes?.slice(0, 10).map((n) => n.id),
195
+ }),
196
+ },
197
+ ],
198
+ };
199
+ }
200
+ // Build result based on direction
201
+ const result = {
202
+ file: normalizedPath,
203
+ type: node.type,
204
+ };
205
+ if (direction === "imports" || direction === "both") {
206
+ result.imports = node.imports || [];
207
+ }
208
+ if (direction === "imported_by" || direction === "both") {
209
+ // Find files that import this file
210
+ const importedBy = graph.edges
211
+ ?.filter((e) => e.target === normalizedPath)
212
+ .map((e) => e.source) || [];
213
+ result.imported_by = importedBy;
214
+ }
215
+ // Calculate impact score
216
+ result.impact_score = (result.imported_by?.length || 0);
217
+ return {
218
+ content: [
219
+ {
220
+ type: "text",
221
+ text: JSON.stringify(result, null, 2),
222
+ },
223
+ ],
224
+ };
225
+ });
226
+ // ============================================================================
227
+ // Tool 3: search_code_logic
228
+ // ============================================================================
229
+ server.tool("search_code_logic", "Semantic search through code chunks with context. Auto-syncs if data is stale.", {
230
+ query: z.string().describe("Search query describing what you're looking for"),
231
+ file_filter: z.string().optional().describe("Glob pattern to filter files (e.g., '*.ts')"),
232
+ top_k: z.number().optional().default(10).describe("Number of results to return"),
233
+ }, async ({ query, file_filter, top_k }) => {
234
+ // Auto-sync if data is stale
235
+ const syncStatus = await autoSyncIfNeeded();
236
+ const chunks = readJsonFile(".agent/rag/chunks.json");
237
+ if (!chunks || !chunks.chunks) {
238
+ return {
239
+ content: [
240
+ {
241
+ type: "text",
242
+ text: JSON.stringify({
243
+ error: "RAG chunks not found",
244
+ suggestion: "Run 'ak sync' to generate code chunks",
245
+ }),
246
+ },
247
+ ],
248
+ };
249
+ }
250
+ // Simple keyword-based search (in production, use embeddings)
251
+ const queryWords = query.toLowerCase().split(/\s+/);
252
+ const scored = chunks.chunks.map((chunk) => {
253
+ const content = (chunk.content || "").toLowerCase();
254
+ const metadata = chunk.metadata || {};
255
+ // Apply file filter
256
+ if (file_filter) {
257
+ const pattern = file_filter.replace("*", ".*");
258
+ if (!new RegExp(pattern).test(metadata.file_path || "")) {
259
+ return { chunk, score: -1 };
260
+ }
261
+ }
262
+ // Score based on keyword matches
263
+ let score = 0;
264
+ for (const word of queryWords) {
265
+ if (content.includes(word)) {
266
+ score += 1;
267
+ }
268
+ if ((metadata.name || "").toLowerCase().includes(word)) {
269
+ score += 2; // Boost for name matches
270
+ }
271
+ }
272
+ return { chunk, score };
273
+ });
274
+ // Sort and take top k
275
+ const results = scored
276
+ .filter((s) => s.score > 0)
277
+ .sort((a, b) => b.score - a.score)
278
+ .slice(0, top_k)
279
+ .map((s) => ({
280
+ file: s.chunk.metadata?.file_path,
281
+ type: s.chunk.metadata?.chunk_type,
282
+ name: s.chunk.metadata?.name,
283
+ lines: `${s.chunk.metadata?.start_line}-${s.chunk.metadata?.end_line}`,
284
+ preview: s.chunk.content?.substring(0, 200) + "...",
285
+ relevance_score: s.score,
286
+ }));
287
+ return {
288
+ content: [
289
+ {
290
+ type: "text",
291
+ text: JSON.stringify({
292
+ query,
293
+ total_results: results.length,
294
+ results,
295
+ }, null, 2),
296
+ },
297
+ ],
298
+ };
299
+ });
300
+ // ============================================================================
301
+ // Tool 4: get_impact_zone
302
+ // ============================================================================
303
+ server.tool("get_impact_zone", "Get all files that would be affected if a specific file is modified. Auto-syncs if data is stale.", {
304
+ file_path: z.string().describe("File path to analyze impact for"),
305
+ depth: z.number().optional().default(3).describe("How many levels of dependencies to traverse"),
306
+ }, async ({ file_path, depth }) => {
307
+ // Auto-sync if data is stale
308
+ const syncStatus = await autoSyncIfNeeded();
309
+ const graph = readJsonFile(".agent/graph.json");
310
+ if (!graph) {
311
+ return {
312
+ content: [
313
+ {
314
+ type: "text",
315
+ text: JSON.stringify({
316
+ error: "Dependency graph not found",
317
+ suggestion: "Run 'ak sync' to generate dependency graph",
318
+ }),
319
+ },
320
+ ],
321
+ };
322
+ }
323
+ const normalizedPath = file_path.replace(/^\.\//, "");
324
+ // Build adjacency list for reverse dependencies (who imports this?)
325
+ const reverseGraph = {};
326
+ for (const edge of graph.edges || []) {
327
+ if (!reverseGraph[edge.target]) {
328
+ reverseGraph[edge.target] = [];
329
+ }
330
+ reverseGraph[edge.target].push(edge.source);
331
+ }
332
+ // BFS to find all affected files
333
+ const visited = new Set();
334
+ const queue = [{ file: normalizedPath, level: 0 }];
335
+ const impactByLevel = {};
336
+ while (queue.length > 0) {
337
+ const { file, level } = queue.shift();
338
+ if (visited.has(file) || level > depth) {
339
+ continue;
340
+ }
341
+ visited.add(file);
342
+ if (level > 0) {
343
+ if (!impactByLevel[level]) {
344
+ impactByLevel[level] = [];
345
+ }
346
+ impactByLevel[level].push(file);
347
+ }
348
+ // Add files that import this file
349
+ const dependents = reverseGraph[file] || [];
350
+ for (const dep of dependents) {
351
+ if (!visited.has(dep)) {
352
+ queue.push({ file: dep, level: level + 1 });
353
+ }
354
+ }
355
+ }
356
+ // Flatten results
357
+ const allAffected = Object.values(impactByLevel).flat();
358
+ return {
359
+ content: [
360
+ {
361
+ type: "text",
362
+ text: JSON.stringify({
363
+ source_file: normalizedPath,
364
+ total_affected: allAffected.length,
365
+ impact_by_level: impactByLevel,
366
+ all_affected_files: allAffected,
367
+ warning: allAffected.length > 10
368
+ ? "High impact change! Review carefully."
369
+ : null,
370
+ }, null, 2),
371
+ },
372
+ ],
373
+ };
374
+ });
375
+ // ============================================================================
376
+ // Tool 5: force_sync
377
+ // ============================================================================
378
+ server.tool("force_sync", "Force refresh all AI infrastructure data (AGENTS.md, graph, RAG chunks)", {
379
+ target: z
380
+ .enum(["all", "graph", "rag", "agents_md"])
381
+ .optional()
382
+ .default("all")
383
+ .describe("What to sync"),
384
+ }, async ({ target }) => {
385
+ const { spawn } = await import("child_process");
386
+ const results = {};
387
+ const runScript = (scriptPath, args) => {
388
+ return new Promise((resolve, reject) => {
389
+ const proc = spawn("python", [scriptPath, ...args], {
390
+ cwd: PROJECT_ROOT,
391
+ });
392
+ let output = "";
393
+ let error = "";
394
+ proc.stdout.on("data", (data) => {
395
+ output += data.toString();
396
+ });
397
+ proc.stderr.on("data", (data) => {
398
+ error += data.toString();
399
+ });
400
+ proc.on("close", (code) => {
401
+ if (code === 0) {
402
+ resolve(output);
403
+ }
404
+ else {
405
+ resolve(`Error: ${error || output}`);
406
+ }
407
+ });
408
+ proc.on("error", (err) => {
409
+ resolve(`Failed to run: ${err.message}`);
410
+ });
411
+ });
412
+ };
413
+ // Determine script paths (relative to kit installation)
414
+ const kitPath = process.env.AGENT_KIT_PATH || path.join(__dirname, "..", "..");
415
+ if (target === "all" || target === "graph") {
416
+ const graphScript = path.join(kitPath, "skills/graph-mapper/scripts/generate_graph.py");
417
+ if (fs.existsSync(graphScript)) {
418
+ results.graph = await runScript(graphScript, [
419
+ "--src", path.join(PROJECT_ROOT, "src"),
420
+ "--output", path.join(PROJECT_ROOT, ".agent/graph.json"),
421
+ "--format", "both"
422
+ ]);
423
+ }
424
+ else {
425
+ results.graph = "Graph script not found";
426
+ }
427
+ }
428
+ if (target === "all" || target === "rag") {
429
+ const ragScript = path.join(kitPath, "skills/rag-engineering/scripts/chunk_code.py");
430
+ if (fs.existsSync(ragScript)) {
431
+ results.rag = await runScript(ragScript, [
432
+ "--src", path.join(PROJECT_ROOT, "src"),
433
+ "--output", path.join(PROJECT_ROOT, ".agent/rag/chunks.json")
434
+ ]);
435
+ }
436
+ else {
437
+ results.rag = "RAG script not found";
438
+ }
439
+ }
440
+ if (target === "all" || target === "agents_md") {
441
+ const infraScript = path.join(kitPath, "skills/app-builder/scripts/generate_ai_infra.py");
442
+ if (fs.existsSync(infraScript)) {
443
+ results.agents_md = await runScript(infraScript, [
444
+ "--project-root", PROJECT_ROOT
445
+ ]);
446
+ }
447
+ else {
448
+ results.agents_md = "AI infra script not found";
449
+ }
450
+ }
451
+ return {
452
+ content: [
453
+ {
454
+ type: "text",
455
+ text: JSON.stringify({
456
+ status: "Sync completed",
457
+ target,
458
+ results,
459
+ timestamp: new Date().toISOString(),
460
+ }, null, 2),
461
+ },
462
+ ],
463
+ };
464
+ });
465
+ // ============================================================================
466
+ // Resource: Project Status
467
+ // ============================================================================
468
+ server.resource("project-status", "status://project", async (uri) => {
469
+ const agentsMd = fs.existsSync(path.join(PROJECT_ROOT, "AGENTS.md"));
470
+ const graphJson = fs.existsSync(path.join(PROJECT_ROOT, ".agent/graph.json"));
471
+ const ragChunks = fs.existsSync(path.join(PROJECT_ROOT, ".agent/rag/chunks.json"));
472
+ const status = {
473
+ project_root: PROJECT_ROOT,
474
+ infrastructure: {
475
+ agents_md: agentsMd ? "✅ Present" : "❌ Missing",
476
+ graph: graphJson ? "✅ Present" : "❌ Missing",
477
+ rag: ragChunks ? "✅ Present" : "❌ Missing",
478
+ },
479
+ last_checked: new Date().toISOString(),
480
+ };
481
+ return {
482
+ contents: [
483
+ {
484
+ uri: uri.href,
485
+ mimeType: "application/json",
486
+ text: JSON.stringify(status, null, 2),
487
+ },
488
+ ],
489
+ };
490
+ });
491
+ // ============================================================================
492
+ // Start Server
493
+ // ============================================================================
494
+ async function main() {
495
+ console.error(`Agent Kit MCP Gateway starting...`);
496
+ console.error(`Project root: ${PROJECT_ROOT}`);
497
+ const transport = new StdioServerTransport();
498
+ await server.connect(transport);
499
+ console.error("MCP Gateway ready and listening on stdio");
500
+ }
501
+ main().catch((error) => {
502
+ console.error("Fatal error:", error);
503
+ process.exit(1);
504
+ });
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Debouncer
3
+ *
4
+ * Prevents excessive syncing by enforcing a cooldown period
5
+ * between sync operations. Essential for performance when
6
+ * AI makes many rapid queries.
7
+ */
8
+ export declare class Debouncer {
9
+ private lastSync;
10
+ private cooldownMs;
11
+ private pendingSync;
12
+ /**
13
+ * @param cooldownMs Minimum time between syncs (default: 30 seconds)
14
+ */
15
+ constructor(cooldownMs?: number);
16
+ /**
17
+ * Check if enough time has passed since last sync
18
+ */
19
+ canSync(): boolean;
20
+ /**
21
+ * Get remaining cooldown time in milliseconds
22
+ */
23
+ getRemainingCooldown(): number;
24
+ /**
25
+ * Get remaining cooldown time in human-readable format
26
+ */
27
+ getRemainingCooldownFormatted(): string;
28
+ /**
29
+ * Mark that a sync has occurred
30
+ */
31
+ markSynced(): void;
32
+ /**
33
+ * Execute a sync operation with debouncing
34
+ *
35
+ * @param syncFn The sync function to execute
36
+ * @returns Result of sync or null if debounced
37
+ */
38
+ executeWithDebounce<T>(syncFn: () => Promise<T>): Promise<{
39
+ executed: boolean;
40
+ result?: T;
41
+ reason?: string;
42
+ }>;
43
+ /**
44
+ * Force reset the debouncer (for manual sync commands)
45
+ */
46
+ reset(): void;
47
+ /**
48
+ * Get debouncer status
49
+ */
50
+ getStatus(): {
51
+ lastSync: string;
52
+ canSync: boolean;
53
+ cooldownRemaining: string;
54
+ };
55
+ }
56
+ export declare function getGlobalDebouncer(cooldownMs?: number): Debouncer;