@cocaxcode/ai-context-inspector 0.3.3 → 0.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.
- package/README.md +124 -9
- package/dist/{chunk-CAQUPN6F.js → chunk-3NLUFQSB.js} +940 -1
- package/dist/index.js +657 -8
- package/dist/server-22Y7DPSM.js +395 -0
- package/package.json +7 -3
- package/dist/server-HS77RFVF.js +0 -179
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
detectTargetTools,
|
|
4
|
+
executeImport,
|
|
5
|
+
exportEcosystem,
|
|
6
|
+
generateHtml,
|
|
7
|
+
introspectServers,
|
|
8
|
+
loadBundle,
|
|
9
|
+
planImport,
|
|
10
|
+
runAllScanners,
|
|
11
|
+
scanMcpConfigs
|
|
12
|
+
} from "./chunk-3NLUFQSB.js";
|
|
13
|
+
|
|
14
|
+
// src/server.ts
|
|
15
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
16
|
+
|
|
17
|
+
// src/tools/scan.ts
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
function registerScanTool(server) {
|
|
20
|
+
server.tool(
|
|
21
|
+
"scan",
|
|
22
|
+
"Escanea un proyecto y descubre todo su ecosistema AI: MCP servers, archivos de contexto, skills y memorias",
|
|
23
|
+
{
|
|
24
|
+
dir: z.string().optional().describe("Directorio a escanear (default: cwd)"),
|
|
25
|
+
include_user: z.boolean().optional().describe("Incluir configuraci\xF3n del usuario"),
|
|
26
|
+
no_introspect: z.boolean().optional().describe("No conectar a MCP servers"),
|
|
27
|
+
timeout: z.number().optional().describe("Timeout de introspecci\xF3n en ms (default: 10000)")
|
|
28
|
+
},
|
|
29
|
+
async ({ dir, include_user, no_introspect, timeout }) => {
|
|
30
|
+
try {
|
|
31
|
+
const result = await runAllScanners({
|
|
32
|
+
dir: dir ?? process.cwd(),
|
|
33
|
+
includeUser: include_user ?? false,
|
|
34
|
+
introspect: !(no_introspect ?? false),
|
|
35
|
+
timeout: timeout ?? 1e4
|
|
36
|
+
});
|
|
37
|
+
return {
|
|
38
|
+
content: [
|
|
39
|
+
{
|
|
40
|
+
type: "text",
|
|
41
|
+
text: JSON.stringify(result, null, 2)
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
};
|
|
45
|
+
} catch (err) {
|
|
46
|
+
return {
|
|
47
|
+
isError: true,
|
|
48
|
+
content: [
|
|
49
|
+
{
|
|
50
|
+
type: "text",
|
|
51
|
+
text: `Error escaneando: ${err.message}`
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/tools/introspect.ts
|
|
61
|
+
import { z as z2 } from "zod";
|
|
62
|
+
function registerIntrospectTool(server) {
|
|
63
|
+
server.tool(
|
|
64
|
+
"introspect_mcp",
|
|
65
|
+
"Introspecciona un MCP server espec\xEDfico: lista sus tools, resources y prompts",
|
|
66
|
+
{
|
|
67
|
+
server_name: z2.string().describe("Nombre del server MCP a introspeccionar"),
|
|
68
|
+
dir: z2.string().optional().describe("Directorio del proyecto (default: cwd)"),
|
|
69
|
+
timeout: z2.number().optional().describe("Timeout en ms (default: 10000)")
|
|
70
|
+
},
|
|
71
|
+
async ({ server_name, dir, timeout }) => {
|
|
72
|
+
try {
|
|
73
|
+
const { servers } = await scanMcpConfigs({
|
|
74
|
+
dir: dir ?? process.cwd(),
|
|
75
|
+
includeUser: true
|
|
76
|
+
});
|
|
77
|
+
const target = servers.find((s) => s.name === server_name);
|
|
78
|
+
if (!target) {
|
|
79
|
+
return {
|
|
80
|
+
isError: true,
|
|
81
|
+
content: [
|
|
82
|
+
{
|
|
83
|
+
type: "text",
|
|
84
|
+
text: `Server '${server_name}' no encontrado en la configuraci\xF3n. Servers disponibles: ${servers.map((s) => s.name).join(", ") || "(ninguno)"}`
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
await introspectServers([target], timeout ?? 1e4);
|
|
90
|
+
return {
|
|
91
|
+
content: [
|
|
92
|
+
{
|
|
93
|
+
type: "text",
|
|
94
|
+
text: JSON.stringify(target, null, 2)
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
};
|
|
98
|
+
} catch (err) {
|
|
99
|
+
return {
|
|
100
|
+
isError: true,
|
|
101
|
+
content: [
|
|
102
|
+
{
|
|
103
|
+
type: "text",
|
|
104
|
+
text: `Error introspectando: ${err.message}`
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/tools/report.ts
|
|
114
|
+
import { z as z3 } from "zod";
|
|
115
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
116
|
+
import { dirname, resolve } from "path";
|
|
117
|
+
function registerReportTool(server) {
|
|
118
|
+
server.tool(
|
|
119
|
+
"generate_report",
|
|
120
|
+
"Genera un dashboard HTML interactivo con el ecosistema AI del proyecto",
|
|
121
|
+
{
|
|
122
|
+
dir: z3.string().optional().describe("Directorio a escanear (default: cwd)"),
|
|
123
|
+
output: z3.string().optional().describe("Ruta del archivo HTML (default: ai-context-report.html)"),
|
|
124
|
+
include_user: z3.boolean().optional().describe("Incluir configuraci\xF3n del usuario (~/.claude, skills, memorias, agentes)"),
|
|
125
|
+
no_introspect: z3.boolean().optional().describe("No conectar a MCP servers"),
|
|
126
|
+
timeout: z3.number().optional().describe("Timeout de introspecci\xF3n en ms (default: 10000)")
|
|
127
|
+
},
|
|
128
|
+
async ({ dir, output, include_user, no_introspect, timeout }) => {
|
|
129
|
+
try {
|
|
130
|
+
const result = await runAllScanners({
|
|
131
|
+
dir: dir ?? process.cwd(),
|
|
132
|
+
includeUser: include_user ?? false,
|
|
133
|
+
introspect: !(no_introspect ?? false),
|
|
134
|
+
timeout: timeout ?? 1e4
|
|
135
|
+
});
|
|
136
|
+
const html = generateHtml(result);
|
|
137
|
+
const outputPath = resolve(output ?? "ai-context-report.html");
|
|
138
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
139
|
+
await writeFile(outputPath, html, "utf-8");
|
|
140
|
+
return {
|
|
141
|
+
content: [
|
|
142
|
+
{
|
|
143
|
+
type: "text",
|
|
144
|
+
text: `Reporte generado: ${outputPath}
|
|
145
|
+
|
|
146
|
+
Resumen:
|
|
147
|
+
- MCP Servers: ${result.mcpServers.length}
|
|
148
|
+
- Tools: ${result.mcpServers.reduce((s, m) => s + (m.introspection?.tools.length ?? 0), 0)}
|
|
149
|
+
- Archivos: ${result.contextFiles.length}
|
|
150
|
+
- Skills: ${result.skills.length}
|
|
151
|
+
- Memorias: ${result.memories.length}`
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
};
|
|
155
|
+
} catch (err) {
|
|
156
|
+
return {
|
|
157
|
+
isError: true,
|
|
158
|
+
content: [
|
|
159
|
+
{
|
|
160
|
+
type: "text",
|
|
161
|
+
text: `Error generando reporte: ${err.message}`
|
|
162
|
+
}
|
|
163
|
+
]
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// src/tools/export.ts
|
|
171
|
+
import { z as z4 } from "zod";
|
|
172
|
+
function registerExportTool(server) {
|
|
173
|
+
server.tool(
|
|
174
|
+
"export_ecosystem",
|
|
175
|
+
"Exporta el ecosistema AI completo de un proyecto a un bundle JSON portable en .aci/ (MCP servers, skills, agentes, memorias, archivos de contexto)",
|
|
176
|
+
{
|
|
177
|
+
dir: z4.string().optional().describe("Directorio a escanear (default: directorio actual)"),
|
|
178
|
+
include_user: z4.boolean().optional().describe("Incluir recursos a nivel de usuario (~/.claude/skills, memorias, etc.)"),
|
|
179
|
+
only: z4.array(z4.enum(["mcp", "skills", "agents", "memories", "context"])).optional().describe("Exportar solo categorias especificas"),
|
|
180
|
+
secrets: z4.union([z4.enum(["none", "all"]), z4.array(z4.string())]).optional().default("none").describe(
|
|
181
|
+
'Manejo de secretos: "none" redacta todo (default), "all" incluye todo, array de nombres incluye solo esos'
|
|
182
|
+
)
|
|
183
|
+
},
|
|
184
|
+
async ({ dir, include_user, only, secrets }) => {
|
|
185
|
+
try {
|
|
186
|
+
let secretsMode = "none";
|
|
187
|
+
let secretDecisions;
|
|
188
|
+
if (secrets === "all") {
|
|
189
|
+
secretsMode = "all";
|
|
190
|
+
} else if (Array.isArray(secrets)) {
|
|
191
|
+
secretsMode = "custom";
|
|
192
|
+
secretDecisions = {};
|
|
193
|
+
for (const varName of secrets) {
|
|
194
|
+
secretDecisions[varName] = true;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const bundle = await exportEcosystem({
|
|
198
|
+
dir: dir ?? process.cwd(),
|
|
199
|
+
includeUser: include_user ?? false,
|
|
200
|
+
only,
|
|
201
|
+
secrets: secretsMode,
|
|
202
|
+
secretDecisions
|
|
203
|
+
});
|
|
204
|
+
const mcpCount = bundle.resources.mcpServers.length;
|
|
205
|
+
const skillsCount = bundle.resources.skills.length;
|
|
206
|
+
const agentsCount = bundle.resources.agents.length;
|
|
207
|
+
const memoriesCount = bundle.resources.memories.length;
|
|
208
|
+
const contextCount = bundle.resources.contextFiles.length;
|
|
209
|
+
const allRedacted = bundle.resources.mcpServers.flatMap((s) => s.envVarsRedacted);
|
|
210
|
+
const allIncluded = bundle.resources.mcpServers.flatMap((s) => s.envVarsIncluded);
|
|
211
|
+
let summary = `Bundle exportado en .aci/bundle.json
|
|
212
|
+
|
|
213
|
+
`;
|
|
214
|
+
summary += `MCP Servers: ${mcpCount}
|
|
215
|
+
`;
|
|
216
|
+
summary += `Skills: ${skillsCount}
|
|
217
|
+
`;
|
|
218
|
+
summary += `Agents: ${agentsCount}
|
|
219
|
+
`;
|
|
220
|
+
summary += `Memorias: ${memoriesCount}
|
|
221
|
+
`;
|
|
222
|
+
summary += `Context Files: ${contextCount}
|
|
223
|
+
`;
|
|
224
|
+
if (allRedacted.length > 0) {
|
|
225
|
+
summary += `
|
|
226
|
+
Variables redactadas: ${allRedacted.join(", ")}`;
|
|
227
|
+
}
|
|
228
|
+
if (allIncluded.length > 0) {
|
|
229
|
+
summary += `
|
|
230
|
+
Variables incluidas: ${allIncluded.join(", ")}`;
|
|
231
|
+
}
|
|
232
|
+
if (bundle.warnings.length > 0) {
|
|
233
|
+
summary += `
|
|
234
|
+
|
|
235
|
+
\u26A0\uFE0F ${bundle.warnings.join("\n")}`;
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
content: [{ type: "text", text: summary }]
|
|
239
|
+
};
|
|
240
|
+
} catch (err) {
|
|
241
|
+
return {
|
|
242
|
+
isError: true,
|
|
243
|
+
content: [
|
|
244
|
+
{
|
|
245
|
+
type: "text",
|
|
246
|
+
text: `Error exportando ecosistema: ${err.message}`
|
|
247
|
+
}
|
|
248
|
+
]
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// src/tools/import.ts
|
|
256
|
+
import { z as z5 } from "zod";
|
|
257
|
+
function registerImportTool(server) {
|
|
258
|
+
server.tool(
|
|
259
|
+
"import_ecosystem",
|
|
260
|
+
"Importa un bundle de ecosistema AI (.aci/) a un proyecto, adaptando la configuracion a la herramienta destino",
|
|
261
|
+
{
|
|
262
|
+
file: z5.string().optional().describe("Ruta al archivo JSON del bundle (auto-detecta .aci/bundle.json si no se especifica)"),
|
|
263
|
+
dir: z5.string().optional().describe("Directorio destino del proyecto (default: directorio actual)"),
|
|
264
|
+
target: z5.enum(["claude", "cursor", "windsurf", "copilot", "gemini", "codex", "opencode"]).optional().describe("Herramienta AI destino (auto-detecta si no se especifica)"),
|
|
265
|
+
scope: z5.enum(["project", "user"]).optional().describe("Forzar scope para recursos flexibles (skills, agents)"),
|
|
266
|
+
force: z5.boolean().optional().describe("Sobrescribir recursos existentes sin preguntar"),
|
|
267
|
+
confirm: z5.boolean().optional().default(true).describe("Ejecutar la importacion (false = solo mostrar plan/dry-run)"),
|
|
268
|
+
only: z5.array(z5.enum(["mcp", "skills", "agents", "memories", "context"])).optional().describe("Importar solo categorias especificas"),
|
|
269
|
+
secrets: z5.union([z5.enum(["none", "all"]), z5.array(z5.string()), z5.record(z5.string(), z5.string())]).optional().default("none").describe(
|
|
270
|
+
'Secretos: "none" redacta, "all" usa valores del bundle, array incluye solo esos, objeto {nombre: valor} asigna valores custom'
|
|
271
|
+
)
|
|
272
|
+
},
|
|
273
|
+
async ({ file, dir, target, scope, force, confirm, only, secrets }) => {
|
|
274
|
+
try {
|
|
275
|
+
const resolvedDir = dir ?? process.cwd();
|
|
276
|
+
const bundle = await loadBundle(file ?? void 0, resolvedDir);
|
|
277
|
+
let resolvedTarget;
|
|
278
|
+
if (target) {
|
|
279
|
+
resolvedTarget = target;
|
|
280
|
+
} else {
|
|
281
|
+
const detected = await detectTargetTools(resolvedDir);
|
|
282
|
+
if (detected.length === 0) {
|
|
283
|
+
return {
|
|
284
|
+
isError: true,
|
|
285
|
+
content: [
|
|
286
|
+
{
|
|
287
|
+
type: "text",
|
|
288
|
+
text: 'No se detecto herramienta AI en el directorio. Especifica el parametro "target".'
|
|
289
|
+
}
|
|
290
|
+
]
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
resolvedTarget = detected[0];
|
|
294
|
+
}
|
|
295
|
+
let secretsMode = "none";
|
|
296
|
+
let secretValues;
|
|
297
|
+
if (secrets === "all") {
|
|
298
|
+
secretsMode = "all";
|
|
299
|
+
} else if (Array.isArray(secrets)) {
|
|
300
|
+
secretsMode = "custom";
|
|
301
|
+
secretValues = {};
|
|
302
|
+
for (const name of secrets) {
|
|
303
|
+
secretValues[name] = null;
|
|
304
|
+
}
|
|
305
|
+
} else if (typeof secrets === "object" && secrets !== null && !Array.isArray(secrets)) {
|
|
306
|
+
secretsMode = "custom";
|
|
307
|
+
secretValues = secrets;
|
|
308
|
+
}
|
|
309
|
+
const options = {
|
|
310
|
+
file: file ?? void 0,
|
|
311
|
+
dir: resolvedDir,
|
|
312
|
+
target: resolvedTarget,
|
|
313
|
+
scope: scope ?? void 0,
|
|
314
|
+
force: force ?? false,
|
|
315
|
+
confirm: confirm ?? true,
|
|
316
|
+
only,
|
|
317
|
+
secrets: secretsMode,
|
|
318
|
+
secretValues
|
|
319
|
+
};
|
|
320
|
+
const plan = await planImport(bundle, options);
|
|
321
|
+
if (!confirm) {
|
|
322
|
+
let planText = `Plan de importacion (${resolvedTarget}):
|
|
323
|
+
|
|
324
|
+
`;
|
|
325
|
+
for (const action of plan.actions) {
|
|
326
|
+
const icon = action.action === "install" ? "\u2705" : action.action === "skip" ? "\u23ED\uFE0F" : action.action === "overwrite" ? "\u{1F504}" : "\u274C";
|
|
327
|
+
const label = action.action === "install" ? "Instalar" : action.action === "skip" ? "Omitir" : action.action === "overwrite" ? "Sobrescribir" : "No soportado";
|
|
328
|
+
planText += ` ${icon} ${label} ${action.category}: ${action.name} \u2192 ${action.targetPath}`;
|
|
329
|
+
if (action.reason) planText += ` (${action.reason})`;
|
|
330
|
+
planText += "\n";
|
|
331
|
+
}
|
|
332
|
+
planText += `
|
|
333
|
+
Resumen: ${plan.summary.install} instalar, ${plan.summary.skip} omitir, ${plan.summary.unsupported} no soportado`;
|
|
334
|
+
if (plan.pendingEnvVars.length > 0) {
|
|
335
|
+
planText += `
|
|
336
|
+
\u26A0\uFE0F ${plan.pendingEnvVars.length} env vars pendientes: ${plan.pendingEnvVars.join(", ")}`;
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
content: [{ type: "text", text: planText }]
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
const result = await executeImport(plan, bundle, options);
|
|
343
|
+
let resultText = `Importacion completada (${resolvedTarget}):
|
|
344
|
+
|
|
345
|
+
`;
|
|
346
|
+
resultText += ` \u2705 ${result.installed.length} instalados
|
|
347
|
+
`;
|
|
348
|
+
resultText += ` \u23ED\uFE0F ${result.skipped.length} omitidos
|
|
349
|
+
`;
|
|
350
|
+
resultText += ` \u274C ${result.unsupported.length} no soportados
|
|
351
|
+
`;
|
|
352
|
+
if (result.pendingEnvVars.length > 0) {
|
|
353
|
+
resultText += `
|
|
354
|
+
\u26A0\uFE0F Variables de entorno pendientes:
|
|
355
|
+
`;
|
|
356
|
+
for (const varName of result.pendingEnvVars) {
|
|
357
|
+
resultText += ` ${varName}
|
|
358
|
+
`;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
content: [{ type: "text", text: resultText }]
|
|
363
|
+
};
|
|
364
|
+
} catch (err) {
|
|
365
|
+
return {
|
|
366
|
+
isError: true,
|
|
367
|
+
content: [
|
|
368
|
+
{
|
|
369
|
+
type: "text",
|
|
370
|
+
text: `Error importando ecosistema: ${err.message}`
|
|
371
|
+
}
|
|
372
|
+
]
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// src/server.ts
|
|
380
|
+
var VERSION = "0.1.0";
|
|
381
|
+
function createServer() {
|
|
382
|
+
const server = new McpServer({
|
|
383
|
+
name: "ai-context-inspector",
|
|
384
|
+
version: VERSION
|
|
385
|
+
});
|
|
386
|
+
registerScanTool(server);
|
|
387
|
+
registerIntrospectTool(server);
|
|
388
|
+
registerReportTool(server);
|
|
389
|
+
registerExportTool(server);
|
|
390
|
+
registerImportTool(server);
|
|
391
|
+
return server;
|
|
392
|
+
}
|
|
393
|
+
export {
|
|
394
|
+
createServer
|
|
395
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cocaxcode/ai-context-inspector",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Scan
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Scan, export, and import your AI ecosystem across tools. Discover MCP servers, context files, skills, memories. Export/import between Claude, Cursor, Windsurf, Copilot, Gemini, Codex, OpenCode. CLI + MCP server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"ai-context-inspector": "dist/index.js"
|
|
@@ -46,7 +46,11 @@
|
|
|
46
46
|
"html-report",
|
|
47
47
|
"context-files",
|
|
48
48
|
"skills",
|
|
49
|
-
"ai-ecosystem"
|
|
49
|
+
"ai-ecosystem",
|
|
50
|
+
"export",
|
|
51
|
+
"import",
|
|
52
|
+
"opencode",
|
|
53
|
+
"ai-config-migration"
|
|
50
54
|
],
|
|
51
55
|
"author": "cocaxcode",
|
|
52
56
|
"license": "MIT",
|
package/dist/server-HS77RFVF.js
DELETED
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
generateHtml,
|
|
4
|
-
introspectServers,
|
|
5
|
-
runAllScanners,
|
|
6
|
-
scanMcpConfigs
|
|
7
|
-
} from "./chunk-CAQUPN6F.js";
|
|
8
|
-
|
|
9
|
-
// src/server.ts
|
|
10
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
11
|
-
|
|
12
|
-
// src/tools/scan.ts
|
|
13
|
-
import { z } from "zod";
|
|
14
|
-
function registerScanTool(server) {
|
|
15
|
-
server.tool(
|
|
16
|
-
"scan",
|
|
17
|
-
"Escanea un proyecto y descubre todo su ecosistema AI: MCP servers, archivos de contexto, skills y memorias",
|
|
18
|
-
{
|
|
19
|
-
dir: z.string().optional().describe("Directorio a escanear (default: cwd)"),
|
|
20
|
-
include_user: z.boolean().optional().describe("Incluir configuraci\xF3n del usuario"),
|
|
21
|
-
no_introspect: z.boolean().optional().describe("No conectar a MCP servers"),
|
|
22
|
-
timeout: z.number().optional().describe("Timeout de introspecci\xF3n en ms (default: 10000)")
|
|
23
|
-
},
|
|
24
|
-
async ({ dir, include_user, no_introspect, timeout }) => {
|
|
25
|
-
try {
|
|
26
|
-
const result = await runAllScanners({
|
|
27
|
-
dir: dir ?? process.cwd(),
|
|
28
|
-
includeUser: include_user ?? false,
|
|
29
|
-
introspect: !(no_introspect ?? false),
|
|
30
|
-
timeout: timeout ?? 1e4
|
|
31
|
-
});
|
|
32
|
-
return {
|
|
33
|
-
content: [
|
|
34
|
-
{
|
|
35
|
-
type: "text",
|
|
36
|
-
text: JSON.stringify(result, null, 2)
|
|
37
|
-
}
|
|
38
|
-
]
|
|
39
|
-
};
|
|
40
|
-
} catch (err) {
|
|
41
|
-
return {
|
|
42
|
-
isError: true,
|
|
43
|
-
content: [
|
|
44
|
-
{
|
|
45
|
-
type: "text",
|
|
46
|
-
text: `Error escaneando: ${err.message}`
|
|
47
|
-
}
|
|
48
|
-
]
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// src/tools/introspect.ts
|
|
56
|
-
import { z as z2 } from "zod";
|
|
57
|
-
function registerIntrospectTool(server) {
|
|
58
|
-
server.tool(
|
|
59
|
-
"introspect_mcp",
|
|
60
|
-
"Introspecciona un MCP server espec\xEDfico: lista sus tools, resources y prompts",
|
|
61
|
-
{
|
|
62
|
-
server_name: z2.string().describe("Nombre del server MCP a introspeccionar"),
|
|
63
|
-
dir: z2.string().optional().describe("Directorio del proyecto (default: cwd)"),
|
|
64
|
-
timeout: z2.number().optional().describe("Timeout en ms (default: 10000)")
|
|
65
|
-
},
|
|
66
|
-
async ({ server_name, dir, timeout }) => {
|
|
67
|
-
try {
|
|
68
|
-
const { servers } = await scanMcpConfigs({
|
|
69
|
-
dir: dir ?? process.cwd(),
|
|
70
|
-
includeUser: true
|
|
71
|
-
});
|
|
72
|
-
const target = servers.find((s) => s.name === server_name);
|
|
73
|
-
if (!target) {
|
|
74
|
-
return {
|
|
75
|
-
isError: true,
|
|
76
|
-
content: [
|
|
77
|
-
{
|
|
78
|
-
type: "text",
|
|
79
|
-
text: `Server '${server_name}' no encontrado en la configuraci\xF3n. Servers disponibles: ${servers.map((s) => s.name).join(", ") || "(ninguno)"}`
|
|
80
|
-
}
|
|
81
|
-
]
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
await introspectServers([target], timeout ?? 1e4);
|
|
85
|
-
return {
|
|
86
|
-
content: [
|
|
87
|
-
{
|
|
88
|
-
type: "text",
|
|
89
|
-
text: JSON.stringify(target, null, 2)
|
|
90
|
-
}
|
|
91
|
-
]
|
|
92
|
-
};
|
|
93
|
-
} catch (err) {
|
|
94
|
-
return {
|
|
95
|
-
isError: true,
|
|
96
|
-
content: [
|
|
97
|
-
{
|
|
98
|
-
type: "text",
|
|
99
|
-
text: `Error introspectando: ${err.message}`
|
|
100
|
-
}
|
|
101
|
-
]
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// src/tools/report.ts
|
|
109
|
-
import { z as z3 } from "zod";
|
|
110
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
111
|
-
import { dirname, resolve } from "path";
|
|
112
|
-
function registerReportTool(server) {
|
|
113
|
-
server.tool(
|
|
114
|
-
"generate_report",
|
|
115
|
-
"Genera un dashboard HTML interactivo con el ecosistema AI del proyecto",
|
|
116
|
-
{
|
|
117
|
-
dir: z3.string().optional().describe("Directorio a escanear (default: cwd)"),
|
|
118
|
-
output: z3.string().optional().describe("Ruta del archivo HTML (default: ai-context-report.html)"),
|
|
119
|
-
include_user: z3.boolean().optional().describe("Incluir configuraci\xF3n del usuario (~/.claude, skills, memorias, agentes)"),
|
|
120
|
-
no_introspect: z3.boolean().optional().describe("No conectar a MCP servers"),
|
|
121
|
-
timeout: z3.number().optional().describe("Timeout de introspecci\xF3n en ms (default: 10000)")
|
|
122
|
-
},
|
|
123
|
-
async ({ dir, output, include_user, no_introspect, timeout }) => {
|
|
124
|
-
try {
|
|
125
|
-
const result = await runAllScanners({
|
|
126
|
-
dir: dir ?? process.cwd(),
|
|
127
|
-
includeUser: include_user ?? false,
|
|
128
|
-
introspect: !(no_introspect ?? false),
|
|
129
|
-
timeout: timeout ?? 1e4
|
|
130
|
-
});
|
|
131
|
-
const html = generateHtml(result);
|
|
132
|
-
const outputPath = resolve(output ?? "ai-context-report.html");
|
|
133
|
-
await mkdir(dirname(outputPath), { recursive: true });
|
|
134
|
-
await writeFile(outputPath, html, "utf-8");
|
|
135
|
-
return {
|
|
136
|
-
content: [
|
|
137
|
-
{
|
|
138
|
-
type: "text",
|
|
139
|
-
text: `Reporte generado: ${outputPath}
|
|
140
|
-
|
|
141
|
-
Resumen:
|
|
142
|
-
- MCP Servers: ${result.mcpServers.length}
|
|
143
|
-
- Tools: ${result.mcpServers.reduce((s, m) => s + (m.introspection?.tools.length ?? 0), 0)}
|
|
144
|
-
- Archivos: ${result.contextFiles.length}
|
|
145
|
-
- Skills: ${result.skills.length}
|
|
146
|
-
- Memorias: ${result.memories.length}`
|
|
147
|
-
}
|
|
148
|
-
]
|
|
149
|
-
};
|
|
150
|
-
} catch (err) {
|
|
151
|
-
return {
|
|
152
|
-
isError: true,
|
|
153
|
-
content: [
|
|
154
|
-
{
|
|
155
|
-
type: "text",
|
|
156
|
-
text: `Error generando reporte: ${err.message}`
|
|
157
|
-
}
|
|
158
|
-
]
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// src/server.ts
|
|
166
|
-
var VERSION = "0.1.0";
|
|
167
|
-
function createServer() {
|
|
168
|
-
const server = new McpServer({
|
|
169
|
-
name: "ai-context-inspector",
|
|
170
|
-
version: VERSION
|
|
171
|
-
});
|
|
172
|
-
registerScanTool(server);
|
|
173
|
-
registerIntrospectTool(server);
|
|
174
|
-
registerReportTool(server);
|
|
175
|
-
return server;
|
|
176
|
-
}
|
|
177
|
-
export {
|
|
178
|
-
createServer
|
|
179
|
-
};
|