@musashishao/agent-kit 1.4.0 → 1.5.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.
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
* Agent Kit MCP Gateway Server
|
|
4
4
|
*
|
|
5
5
|
* Provides AI agents with live access to project context, dependency graphs,
|
|
6
|
-
* and semantic
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* node dist/index.js [--project-root /path/to/project]
|
|
6
|
+
* and semantic search with automatic sync capabilities.
|
|
10
7
|
*/
|
|
11
8
|
export {};
|
|
@@ -3,10 +3,7 @@
|
|
|
3
3
|
* Agent Kit MCP Gateway Server
|
|
4
4
|
*
|
|
5
5
|
* Provides AI agents with live access to project context, dependency graphs,
|
|
6
|
-
* and semantic
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* node dist/index.js [--project-root /path/to/project]
|
|
6
|
+
* and semantic search with automatic sync capabilities.
|
|
10
7
|
*/
|
|
11
8
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
12
9
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -25,12 +22,10 @@ const timestampChecker = new TimestampChecker(PROJECT_ROOT);
|
|
|
25
22
|
// Auto-Sync Helper
|
|
26
23
|
// ============================================================================
|
|
27
24
|
async function autoSyncIfNeeded() {
|
|
28
|
-
// Check if data is stale
|
|
29
25
|
const status = timestampChecker.getSyncStatus();
|
|
30
26
|
if (!status.needsSync) {
|
|
31
27
|
return { synced: false, message: "Data is fresh" };
|
|
32
28
|
}
|
|
33
|
-
// Try to sync with debouncing
|
|
34
29
|
const result = await debouncer.executeWithDebounce(async () => {
|
|
35
30
|
return await syncer.syncAll();
|
|
36
31
|
});
|
|
@@ -47,35 +42,23 @@ async function autoSyncIfNeeded() {
|
|
|
47
42
|
function readJsonFile(filePath) {
|
|
48
43
|
try {
|
|
49
44
|
const fullPath = path.resolve(PROJECT_ROOT, filePath);
|
|
50
|
-
if (!fs.existsSync(fullPath))
|
|
45
|
+
if (!fs.existsSync(fullPath))
|
|
51
46
|
return null;
|
|
52
|
-
}
|
|
53
47
|
return JSON.parse(fs.readFileSync(fullPath, "utf-8"));
|
|
54
48
|
}
|
|
55
|
-
catch
|
|
49
|
+
catch {
|
|
56
50
|
return null;
|
|
57
51
|
}
|
|
58
52
|
}
|
|
59
53
|
function readTextFile(filePath) {
|
|
60
54
|
try {
|
|
61
55
|
const fullPath = path.resolve(PROJECT_ROOT, filePath);
|
|
62
|
-
if (!fs.existsSync(fullPath))
|
|
56
|
+
if (!fs.existsSync(fullPath))
|
|
63
57
|
return null;
|
|
64
|
-
}
|
|
65
58
|
return fs.readFileSync(fullPath, "utf-8");
|
|
66
59
|
}
|
|
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
60
|
catch {
|
|
78
|
-
return
|
|
61
|
+
return null;
|
|
79
62
|
}
|
|
80
63
|
}
|
|
81
64
|
// ============================================================================
|
|
@@ -83,47 +66,28 @@ function getFileModTime(filePath) {
|
|
|
83
66
|
// ============================================================================
|
|
84
67
|
const server = new McpServer({
|
|
85
68
|
name: "agent-kit-gateway",
|
|
86
|
-
version: "1.
|
|
69
|
+
version: "1.1.0", // Universal Intelligence Version
|
|
87
70
|
});
|
|
88
71
|
// ============================================================================
|
|
89
|
-
// Tool
|
|
72
|
+
// Tool: get_project_context
|
|
90
73
|
// ============================================================================
|
|
91
74
|
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"),
|
|
75
|
+
section: z.enum(["all", "tech_stack", "structure", "conventions", "commands"]).optional().default("all")
|
|
97
76
|
}, async ({ section }) => {
|
|
98
77
|
const agentsMd = readTextFile("AGENTS.md");
|
|
99
78
|
if (!agentsMd) {
|
|
100
79
|
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
|
-
],
|
|
80
|
+
content: [{ type: "text", text: "AGENTS.md not found. Run 'ak init' first." }]
|
|
111
81
|
};
|
|
112
82
|
}
|
|
113
|
-
// Parse sections from AGENTS.md
|
|
114
83
|
const sections = {};
|
|
115
|
-
const sectionRegex = /^## (.+)$/gm;
|
|
116
|
-
let matches;
|
|
117
|
-
let lastIndex = 0;
|
|
118
|
-
let lastSection = "";
|
|
119
84
|
const lines = agentsMd.split("\n");
|
|
120
85
|
let currentSection = "";
|
|
121
86
|
let currentContent = [];
|
|
122
87
|
for (const line of lines) {
|
|
123
88
|
if (line.startsWith("## ")) {
|
|
124
|
-
if (currentSection)
|
|
89
|
+
if (currentSection)
|
|
125
90
|
sections[currentSection] = currentContent.join("\n").trim();
|
|
126
|
-
}
|
|
127
91
|
currentSection = line.replace("## ", "").trim();
|
|
128
92
|
currentContent = [];
|
|
129
93
|
}
|
|
@@ -131,10 +95,8 @@ server.tool("get_project_context", "Get project overview including tech stack, s
|
|
|
131
95
|
currentContent.push(line);
|
|
132
96
|
}
|
|
133
97
|
}
|
|
134
|
-
if (currentSection)
|
|
98
|
+
if (currentSection)
|
|
135
99
|
sections[currentSection] = currentContent.join("\n").trim();
|
|
136
|
-
}
|
|
137
|
-
// Map section names to content
|
|
138
100
|
const sectionMap = {
|
|
139
101
|
tech_stack: sections["🛠️ Tech Stack"] || sections["Tech Stack"],
|
|
140
102
|
structure: sections["📁 Directory Map"] || sections["Directory Map"],
|
|
@@ -142,363 +104,114 @@ server.tool("get_project_context", "Get project overview including tech stack, s
|
|
|
142
104
|
commands: sections["🔧 Commands Reference"] || sections["Commands Reference"],
|
|
143
105
|
all: agentsMd,
|
|
144
106
|
};
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
107
|
+
return { content: [{ type: "text", text: sectionMap[section] || agentsMd }] };
|
|
108
|
+
});
|
|
109
|
+
// ============================================================================
|
|
110
|
+
// Tool: get_project_intelligence
|
|
111
|
+
// ============================================================================
|
|
112
|
+
server.tool("get_project_intelligence", "Get high-level project summary: Code vs Docs distribution, primary types, and impact analysis.", {}, async () => {
|
|
113
|
+
const graph = readJsonFile(".agent/graph.json");
|
|
114
|
+
if (!graph)
|
|
115
|
+
return { content: [{ type: "text", text: "Project data not generated." }] };
|
|
116
|
+
const stats = graph.metadata?.file_types || {};
|
|
117
|
+
const total = graph.metadata?.total_files || 1;
|
|
118
|
+
const docCount = (stats.documentation || 0) + (stats.document || 0) + (stats.readme || 0);
|
|
119
|
+
const codeCount = (stats.component || 0) + (stats.module || 0) + (stats.utility || 0);
|
|
120
|
+
const intelligence = {
|
|
121
|
+
project_name: path.basename(PROJECT_ROOT),
|
|
122
|
+
project_type: docCount > codeCount ? "Documentation-Heavy" : "Code-Centric",
|
|
123
|
+
distribution: { docs: `${Math.round((docCount / total) * 100)}%`, code: `${Math.round((codeCount / total) * 100)}%` },
|
|
124
|
+
top_files: graph.nodes?.slice(0, 5).map((n) => n.id)
|
|
153
125
|
};
|
|
126
|
+
return { content: [{ type: "text", text: JSON.stringify(intelligence, null, 2) }] };
|
|
154
127
|
});
|
|
155
128
|
// ============================================================================
|
|
156
|
-
// Tool
|
|
129
|
+
// Tool: analyze_dependencies
|
|
157
130
|
// ============================================================================
|
|
158
|
-
server.tool("analyze_dependencies", "
|
|
159
|
-
file_path: z.string()
|
|
160
|
-
direction: z
|
|
161
|
-
|
|
162
|
-
|
|
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();
|
|
131
|
+
server.tool("analyze_dependencies", "Analyze imports/references for a file.", {
|
|
132
|
+
file_path: z.string(),
|
|
133
|
+
direction: z.enum(["imports", "imported_by", "both"]).optional().default("both")
|
|
134
|
+
}, async ({ file_path, direction }) => {
|
|
135
|
+
await autoSyncIfNeeded();
|
|
169
136
|
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
|
|
137
|
+
if (!graph)
|
|
138
|
+
return { content: [{ type: "text", text: "Graph not found." }] };
|
|
184
139
|
const normalizedPath = file_path.replace(/^\.\//, "");
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
};
|
|
140
|
+
const node = graph.nodes?.find((n) => n.id === normalizedPath);
|
|
141
|
+
if (!node)
|
|
142
|
+
return { content: [{ type: "text", text: "File not found in graph." }] };
|
|
143
|
+
const isDoc = ["documentation", "readme", "document"].includes(node.type);
|
|
144
|
+
const outLabel = isDoc ? "references" : "imports";
|
|
145
|
+
const inLabel = isDoc ? "referenced_by" : "imported_by";
|
|
146
|
+
const result = { file: normalizedPath, type: node.type };
|
|
147
|
+
if (direction !== "imported_by")
|
|
148
|
+
result[outLabel] = node.imports || [];
|
|
149
|
+
if (direction !== "imports") {
|
|
150
|
+
result[inLabel] = graph.edges?.filter((e) => e.target === normalizedPath).map((e) => e.source) || [];
|
|
151
|
+
}
|
|
152
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
225
153
|
});
|
|
226
154
|
// ============================================================================
|
|
227
|
-
// Tool
|
|
155
|
+
// Tool: search_knowledge (Search Engine)
|
|
228
156
|
// ============================================================================
|
|
229
|
-
|
|
230
|
-
|
|
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();
|
|
157
|
+
async function handleSearch(args) {
|
|
158
|
+
await autoSyncIfNeeded();
|
|
236
159
|
const chunks = readJsonFile(".agent/rag/chunks.json");
|
|
237
|
-
if (!chunks
|
|
238
|
-
return {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
|
160
|
+
if (!chunks?.chunks)
|
|
161
|
+
return { content: [{ type: "text", text: "No chunks found." }] };
|
|
162
|
+
const query = args.query.toLowerCase();
|
|
163
|
+
const results = chunks.chunks
|
|
164
|
+
.map((chunk) => {
|
|
263
165
|
let score = 0;
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
score += 2; // Boost for name matches
|
|
270
|
-
}
|
|
271
|
-
}
|
|
166
|
+
const content = chunk.content.toLowerCase();
|
|
167
|
+
if (content.includes(query))
|
|
168
|
+
score += 5;
|
|
169
|
+
if (chunk.metadata.name?.toLowerCase().includes(query))
|
|
170
|
+
score += 10;
|
|
272
171
|
return { chunk, score };
|
|
273
|
-
})
|
|
274
|
-
// Sort and take top k
|
|
275
|
-
const results = scored
|
|
172
|
+
})
|
|
276
173
|
.filter((s) => s.score > 0)
|
|
277
174
|
.sort((a, b) => b.score - a.score)
|
|
278
|
-
.slice(0, top_k)
|
|
175
|
+
.slice(0, args.top_k)
|
|
279
176
|
.map((s) => ({
|
|
280
|
-
file: s.chunk.metadata
|
|
281
|
-
|
|
282
|
-
|
|
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,
|
|
177
|
+
file: s.chunk.metadata.file_path,
|
|
178
|
+
context: s.chunk.metadata.context_path || s.chunk.metadata.name,
|
|
179
|
+
preview: s.chunk.content.substring(0, 250) + "..."
|
|
286
180
|
}));
|
|
287
|
-
return {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
//
|
|
301
|
-
//
|
|
302
|
-
|
|
303
|
-
|
|
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();
|
|
181
|
+
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
|
|
182
|
+
}
|
|
183
|
+
server.tool("search_knowledge", "Universal search through project knowledge (Code + Docs).", {
|
|
184
|
+
query: z.string(),
|
|
185
|
+
file_filter: z.string().optional(),
|
|
186
|
+
top_k: z.number().optional().default(10)
|
|
187
|
+
}, async (args) => await handleSearch(args));
|
|
188
|
+
server.tool("search_code_logic", "Alias for search_knowledge.", {
|
|
189
|
+
query: z.string(),
|
|
190
|
+
file_filter: z.string().optional(),
|
|
191
|
+
top_k: z.number().optional().default(10)
|
|
192
|
+
}, async (args) => await handleSearch(args));
|
|
193
|
+
// ============================================================================
|
|
194
|
+
// Tool: get_impact_zone
|
|
195
|
+
// ============================================================================
|
|
196
|
+
server.tool("get_impact_zone", "Find files affected by changing a file.", { file_path: z.string() }, async ({ file_path }) => {
|
|
197
|
+
await autoSyncIfNeeded();
|
|
309
198
|
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
|
-
}
|
|
199
|
+
if (!graph)
|
|
200
|
+
return { content: [{ type: "text", text: "Graph not found." }] };
|
|
323
201
|
const normalizedPath = file_path.replace(/^\.\//, "");
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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
|
-
};
|
|
202
|
+
const affected = graph.edges
|
|
203
|
+
?.filter((e) => e.target === normalizedPath)
|
|
204
|
+
.map((e) => e.source) || [];
|
|
205
|
+
return { content: [{ type: "text", text: JSON.stringify({ file: normalizedPath, affected }, null, 2) }] };
|
|
490
206
|
});
|
|
491
207
|
// ============================================================================
|
|
492
208
|
// Start Server
|
|
493
209
|
// ============================================================================
|
|
494
210
|
async function main() {
|
|
495
|
-
console.error(`Agent Kit MCP Gateway starting...`);
|
|
496
|
-
console.error(`Project root: ${PROJECT_ROOT}`);
|
|
497
211
|
const transport = new StdioServerTransport();
|
|
498
212
|
await server.connect(transport);
|
|
499
|
-
console.error("MCP Gateway ready and listening on stdio");
|
|
500
213
|
}
|
|
501
|
-
main().catch(
|
|
502
|
-
console.error(
|
|
214
|
+
main().catch(err => {
|
|
215
|
+
console.error(err);
|
|
503
216
|
process.exit(1);
|
|
504
217
|
});
|