@deplens/mcp 0.1.6 → 0.1.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/bin/deplens-mcp.js +0 -0
- package/package.json +6 -3
- package/src/core/changelog-parser.mjs +313 -0
- package/src/core/diff-analyzer.mjs +590 -0
- package/src/core/diff.mjs +145 -0
- package/src/core/inspect.mjs +950 -482
- package/src/core/parse-dts.mjs +198 -172
- package/src/core/parse-source.mjs +524 -0
- package/src/core/version-resolver.mjs +317 -0
- package/src/server.mjs +579 -40
package/src/server.mjs
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
CallToolRequestSchema,
|
|
6
|
+
ListToolsRequestSchema,
|
|
7
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
5
8
|
let corePromise = null;
|
|
9
|
+
let diffPromise = null;
|
|
6
10
|
|
|
7
11
|
async function loadCore() {
|
|
8
12
|
if (!corePromise) {
|
|
@@ -11,8 +15,13 @@ async function loadCore() {
|
|
|
11
15
|
const fallbackUrl = new URL("./core/inspect.mjs", import.meta.url);
|
|
12
16
|
return await import(fallbackUrl.href);
|
|
13
17
|
} catch (fallbackError) {
|
|
14
|
-
const message =
|
|
15
|
-
|
|
18
|
+
const message =
|
|
19
|
+
fallbackError instanceof Error
|
|
20
|
+
? fallbackError.message
|
|
21
|
+
: String(fallbackError);
|
|
22
|
+
const err = new Error(
|
|
23
|
+
`Failed to load @deplens/core. Fallback also failed: ${message}`,
|
|
24
|
+
);
|
|
16
25
|
err.cause = error;
|
|
17
26
|
throw err;
|
|
18
27
|
}
|
|
@@ -21,22 +30,116 @@ async function loadCore() {
|
|
|
21
30
|
return corePromise;
|
|
22
31
|
}
|
|
23
32
|
|
|
33
|
+
async function loadDiff() {
|
|
34
|
+
if (!diffPromise) {
|
|
35
|
+
diffPromise = (async () => {
|
|
36
|
+
// Try @deplens/core first
|
|
37
|
+
try {
|
|
38
|
+
const core = await import("@deplens/core");
|
|
39
|
+
if (core.runDiff) return core.runDiff;
|
|
40
|
+
if (core.default?.runDiff) return core.default.runDiff;
|
|
41
|
+
} catch {
|
|
42
|
+
// @deplens/core not available, try fallback
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Fallback to local module
|
|
46
|
+
try {
|
|
47
|
+
const fallbackUrl = new URL("./core/diff.mjs", import.meta.url);
|
|
48
|
+
const mod = await import(fallbackUrl.href);
|
|
49
|
+
return mod.runDiff || mod.default?.runDiff;
|
|
50
|
+
} catch (e) {
|
|
51
|
+
console.error("Failed to load diff module:", e);
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
})();
|
|
55
|
+
}
|
|
56
|
+
return diffPromise;
|
|
57
|
+
}
|
|
58
|
+
|
|
24
59
|
const inspectToolSchema = {
|
|
25
60
|
type: "object",
|
|
26
61
|
properties: {
|
|
27
|
-
target: {
|
|
28
|
-
|
|
62
|
+
target: {
|
|
63
|
+
type: "string",
|
|
64
|
+
description: "Package name or import path (e.g. react, next/server)",
|
|
65
|
+
},
|
|
66
|
+
subpath: {
|
|
67
|
+
type: "string",
|
|
68
|
+
description: "Optional subpath (e.g. server for next/server)",
|
|
69
|
+
},
|
|
29
70
|
filter: { type: "string", description: "Substring filter for exports" },
|
|
30
71
|
kind: {
|
|
31
72
|
type: "array",
|
|
32
|
-
items: {
|
|
73
|
+
items: {
|
|
74
|
+
type: "string",
|
|
75
|
+
enum: ["function", "class", "object", "constant", "interface", "type"],
|
|
76
|
+
},
|
|
33
77
|
description: "Filter by export kind",
|
|
34
78
|
},
|
|
35
|
-
showTypes: {
|
|
79
|
+
showTypes: {
|
|
80
|
+
type: "boolean",
|
|
81
|
+
description: "Show type signatures from .d.ts",
|
|
82
|
+
},
|
|
83
|
+
includeDocs: {
|
|
84
|
+
type: "boolean",
|
|
85
|
+
description: "Include README preview (docs)",
|
|
86
|
+
},
|
|
87
|
+
includeExamples: {
|
|
88
|
+
type: "boolean",
|
|
89
|
+
description: "Include README/examples/@example snippets",
|
|
90
|
+
},
|
|
91
|
+
remote: {
|
|
92
|
+
type: "boolean",
|
|
93
|
+
description: "Download package to cache and inspect that version",
|
|
94
|
+
},
|
|
95
|
+
remoteVersion: {
|
|
96
|
+
type: "string",
|
|
97
|
+
description: "Version for remote download (default: latest)",
|
|
98
|
+
},
|
|
99
|
+
format: {
|
|
100
|
+
type: "string",
|
|
101
|
+
enum: ["text", "json", "object"],
|
|
102
|
+
description: "Output format (default: text)",
|
|
103
|
+
},
|
|
104
|
+
listSections: {
|
|
105
|
+
type: "boolean",
|
|
106
|
+
description: "List available README sections",
|
|
107
|
+
},
|
|
108
|
+
docsSections: {
|
|
109
|
+
type: "array",
|
|
110
|
+
items: { type: "string" },
|
|
111
|
+
description: "Extract specific README sections by name",
|
|
112
|
+
},
|
|
113
|
+
search: {
|
|
114
|
+
type: "string",
|
|
115
|
+
description: "Semantic search query (token matching + JSDoc)",
|
|
116
|
+
},
|
|
117
|
+
maxExports: {
|
|
118
|
+
type: "number",
|
|
119
|
+
description: "Max exports to show (default: 100)",
|
|
120
|
+
},
|
|
121
|
+
maxProps: {
|
|
122
|
+
type: "number",
|
|
123
|
+
description: "Max props per object (default: 10)",
|
|
124
|
+
},
|
|
125
|
+
maxExamples: {
|
|
126
|
+
type: "number",
|
|
127
|
+
description: "Max examples to show (default: 10)",
|
|
128
|
+
},
|
|
36
129
|
depth: { type: "number", description: "Depth for object inspection (0-5)" },
|
|
37
|
-
resolveFrom: {
|
|
38
|
-
|
|
39
|
-
|
|
130
|
+
resolveFrom: {
|
|
131
|
+
type: "string",
|
|
132
|
+
description: "Base directory for module resolution",
|
|
133
|
+
},
|
|
134
|
+
rootDir: {
|
|
135
|
+
type: "string",
|
|
136
|
+
description: "Working directory for the inspection (default: cwd)",
|
|
137
|
+
},
|
|
138
|
+
jsdoc: {
|
|
139
|
+
type: "string",
|
|
140
|
+
enum: ["off", "compact", "full"],
|
|
141
|
+
description: "JSDoc mode",
|
|
142
|
+
},
|
|
40
143
|
jsdocOutput: {
|
|
41
144
|
type: "string",
|
|
42
145
|
enum: ["off", "section", "inline", "only"],
|
|
@@ -46,11 +149,17 @@ const inspectToolSchema = {
|
|
|
46
149
|
type: "object",
|
|
47
150
|
properties: {
|
|
48
151
|
symbols: {
|
|
49
|
-
oneOf: [
|
|
152
|
+
oneOf: [
|
|
153
|
+
{ type: "string" },
|
|
154
|
+
{ type: "array", items: { type: "string" } },
|
|
155
|
+
],
|
|
50
156
|
},
|
|
51
157
|
sections: {
|
|
52
158
|
type: "array",
|
|
53
|
-
items: {
|
|
159
|
+
items: {
|
|
160
|
+
type: "string",
|
|
161
|
+
enum: ["summary", "params", "returns", "tags"],
|
|
162
|
+
},
|
|
54
163
|
},
|
|
55
164
|
tags: {
|
|
56
165
|
type: "object",
|
|
@@ -64,26 +173,256 @@ const inspectToolSchema = {
|
|
|
64
173
|
truncate: { type: "string", enum: ["none", "sentence", "word"] },
|
|
65
174
|
},
|
|
66
175
|
},
|
|
176
|
+
analyzeSource: {
|
|
177
|
+
type: "boolean",
|
|
178
|
+
description:
|
|
179
|
+
"Analyze source code (.ts/.js) for implementation details, complexity, patterns",
|
|
180
|
+
},
|
|
181
|
+
sourceMaxFiles: {
|
|
182
|
+
type: "number",
|
|
183
|
+
description: "Max source files to analyze (default: 5)",
|
|
184
|
+
},
|
|
185
|
+
sourceIncludeBody: {
|
|
186
|
+
type: "boolean",
|
|
187
|
+
description: "Include function body snippets in output",
|
|
188
|
+
},
|
|
67
189
|
},
|
|
68
190
|
required: ["target"],
|
|
69
191
|
};
|
|
70
192
|
|
|
193
|
+
const diffToolSchema = {
|
|
194
|
+
type: "object",
|
|
195
|
+
properties: {
|
|
196
|
+
package: {
|
|
197
|
+
type: "string",
|
|
198
|
+
description: "Package name to compare (e.g. react, zod)",
|
|
199
|
+
},
|
|
200
|
+
from: {
|
|
201
|
+
type: "string",
|
|
202
|
+
description:
|
|
203
|
+
"Source version (e.g. '3.22.0', 'installed'). Default: 'installed'",
|
|
204
|
+
},
|
|
205
|
+
to: {
|
|
206
|
+
type: "string",
|
|
207
|
+
description:
|
|
208
|
+
"Target version (e.g. '3.24.0', 'latest'). Default: 'latest'",
|
|
209
|
+
},
|
|
210
|
+
includeSource: {
|
|
211
|
+
type: "boolean",
|
|
212
|
+
description: "Include source code complexity analysis",
|
|
213
|
+
},
|
|
214
|
+
includeChangelog: {
|
|
215
|
+
type: "boolean",
|
|
216
|
+
description: "Parse and include CHANGELOG.md entries (default: true)",
|
|
217
|
+
},
|
|
218
|
+
filter: {
|
|
219
|
+
type: "string",
|
|
220
|
+
description: "Filter exports by name",
|
|
221
|
+
},
|
|
222
|
+
format: {
|
|
223
|
+
type: "string",
|
|
224
|
+
enum: ["text", "json", "object"],
|
|
225
|
+
description: "Output format: 'text' (default) or 'json'",
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
verbose: {
|
|
229
|
+
type: "boolean",
|
|
230
|
+
description: "Show detailed changes",
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
required: ["package"],
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const inspectToolOutputSchema = {
|
|
237
|
+
type: "object",
|
|
238
|
+
additionalProperties: false,
|
|
239
|
+
properties: {
|
|
240
|
+
schemaVersion: { type: "number" },
|
|
241
|
+
package: { type: ["string", "null"] },
|
|
242
|
+
version: { type: ["string", "null"] },
|
|
243
|
+
description: { type: ["string", "null"] },
|
|
244
|
+
resolution: {
|
|
245
|
+
type: ["object", "null"],
|
|
246
|
+
additionalProperties: false,
|
|
247
|
+
properties: {
|
|
248
|
+
target: { type: ["string", "null"] },
|
|
249
|
+
resolveFrom: { type: ["string", "null"] },
|
|
250
|
+
resolveCwd: { type: ["string", "null"] },
|
|
251
|
+
resolved: { type: ["string", "null"] },
|
|
252
|
+
entrypointPath: { type: ["string", "null"] },
|
|
253
|
+
entrypointExists: { type: "boolean" },
|
|
254
|
+
},
|
|
255
|
+
required: [
|
|
256
|
+
"target",
|
|
257
|
+
"resolveFrom",
|
|
258
|
+
"resolveCwd",
|
|
259
|
+
"resolved",
|
|
260
|
+
"entrypointPath",
|
|
261
|
+
"entrypointExists",
|
|
262
|
+
],
|
|
263
|
+
},
|
|
264
|
+
exports: {
|
|
265
|
+
type: ["object", "null"],
|
|
266
|
+
additionalProperties: false,
|
|
267
|
+
properties: {
|
|
268
|
+
total: { type: "number" },
|
|
269
|
+
functions: { type: "array", items: { type: "string" } },
|
|
270
|
+
classes: { type: "array", items: { type: "string" } },
|
|
271
|
+
objects: { type: "array", items: { type: "string" } },
|
|
272
|
+
constants: { type: "array", items: { type: "string" } },
|
|
273
|
+
},
|
|
274
|
+
required: ["total", "functions", "classes", "objects", "constants"],
|
|
275
|
+
},
|
|
276
|
+
types: {
|
|
277
|
+
type: ["object", "null"],
|
|
278
|
+
additionalProperties: true,
|
|
279
|
+
},
|
|
280
|
+
docs: {
|
|
281
|
+
type: ["object", "null"],
|
|
282
|
+
additionalProperties: true,
|
|
283
|
+
},
|
|
284
|
+
sections: {
|
|
285
|
+
type: ["array", "null"],
|
|
286
|
+
items: { type: "object" },
|
|
287
|
+
},
|
|
288
|
+
examples: {
|
|
289
|
+
type: ["object", "null"],
|
|
290
|
+
additionalProperties: true,
|
|
291
|
+
},
|
|
292
|
+
meta: {
|
|
293
|
+
type: ["object", "null"],
|
|
294
|
+
additionalProperties: true,
|
|
295
|
+
},
|
|
296
|
+
warnings: { type: "array", items: { type: "string" } },
|
|
297
|
+
},
|
|
298
|
+
required: [
|
|
299
|
+
"schemaVersion",
|
|
300
|
+
"package",
|
|
301
|
+
"version",
|
|
302
|
+
"description",
|
|
303
|
+
"exports",
|
|
304
|
+
"types",
|
|
305
|
+
"docs",
|
|
306
|
+
"sections",
|
|
307
|
+
"examples",
|
|
308
|
+
"resolution",
|
|
309
|
+
"meta",
|
|
310
|
+
"warnings",
|
|
311
|
+
],
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const diffToolOutputSchema = {
|
|
315
|
+
type: "object",
|
|
316
|
+
additionalProperties: false,
|
|
317
|
+
properties: {
|
|
318
|
+
schemaVersion: { type: "number" },
|
|
319
|
+
package: { type: "string" },
|
|
320
|
+
from: { type: "string" },
|
|
321
|
+
to: { type: "string" },
|
|
322
|
+
output: { type: ["string", "null"] },
|
|
323
|
+
summary: { type: ["object", "null"], additionalProperties: true },
|
|
324
|
+
changes: { type: ["array", "null"], items: { type: "object" } },
|
|
325
|
+
},
|
|
326
|
+
required: [
|
|
327
|
+
"schemaVersion",
|
|
328
|
+
"package",
|
|
329
|
+
"from",
|
|
330
|
+
"to",
|
|
331
|
+
"output",
|
|
332
|
+
"summary",
|
|
333
|
+
"changes",
|
|
334
|
+
],
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
function formatInspectSummary(result) {
|
|
338
|
+
if (!result) return "No results";
|
|
339
|
+
|
|
340
|
+
const lines = [];
|
|
341
|
+
|
|
342
|
+
if (result.package) {
|
|
343
|
+
lines.push(
|
|
344
|
+
`📦 ${result.package}${result.version ? ` v${result.version}` : ""}`,
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (result.description) {
|
|
349
|
+
lines.push(` ${result.description}`);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (result.exports) {
|
|
353
|
+
const parts = [];
|
|
354
|
+
if (result.exports.functions?.length)
|
|
355
|
+
parts.push(`${result.exports.functions.length} functions`);
|
|
356
|
+
if (result.exports.classes?.length)
|
|
357
|
+
parts.push(`${result.exports.classes.length} classes`);
|
|
358
|
+
if (result.exports.objects?.length)
|
|
359
|
+
parts.push(`${result.exports.objects.length} objects`);
|
|
360
|
+
if (result.exports.constants?.length)
|
|
361
|
+
parts.push(`${result.exports.constants.length} constants`);
|
|
362
|
+
if (parts.length) {
|
|
363
|
+
lines.push(` 🔑 ${result.exports.total} exports: ${parts.join(", ")}`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (result.types) {
|
|
368
|
+
const hasTypes = Object.values(result.types).some(
|
|
369
|
+
(v) => v && Object.keys(v).length > 0,
|
|
370
|
+
);
|
|
371
|
+
if (hasTypes) {
|
|
372
|
+
lines.push(` 🔬 Type definitions available`);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (result.warnings?.length) {
|
|
377
|
+
lines.push(` ⚠️ ${result.warnings.length} warning(s)`);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return lines.join("\n") || "Inspection complete";
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function formatDiffSummary(summary, packageName) {
|
|
384
|
+
const lines = [];
|
|
385
|
+
|
|
386
|
+
if (packageName) {
|
|
387
|
+
lines.push(`📦 ${packageName}`);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (summary) {
|
|
391
|
+
const parts = [];
|
|
392
|
+
if (summary.breaking) parts.push(`${summary.breaking} breaking`);
|
|
393
|
+
if (summary.warnings) parts.push(`${summary.warnings} warnings`);
|
|
394
|
+
if (summary.additions) parts.push(`${summary.additions} additions`);
|
|
395
|
+
if (summary.removals) parts.push(`${summary.removals} removals`);
|
|
396
|
+
if (parts.length) {
|
|
397
|
+
lines.push(` 📊 ${parts.join(", ")}`);
|
|
398
|
+
} else {
|
|
399
|
+
lines.push(` 📊 No changes detected`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return lines.join("\n") || "Diff complete";
|
|
404
|
+
}
|
|
405
|
+
|
|
71
406
|
const tools = [
|
|
72
407
|
{
|
|
73
408
|
name: "deplens.inspect",
|
|
74
|
-
description:
|
|
409
|
+
description:
|
|
410
|
+
"Inspect a package to get types, exports, docs, examples, and resolution info.",
|
|
75
411
|
inputSchema: inspectToolSchema,
|
|
412
|
+
outputSchema: inspectToolOutputSchema,
|
|
76
413
|
},
|
|
77
414
|
{
|
|
78
|
-
name: "
|
|
79
|
-
description:
|
|
80
|
-
|
|
415
|
+
name: "deplens.diff",
|
|
416
|
+
description:
|
|
417
|
+
"Compare two versions of an npm package. Detects breaking changes, additions, and modifications. Parses CHANGELOG.md when available.",
|
|
418
|
+
inputSchema: diffToolSchema,
|
|
419
|
+
outputSchema: diffToolOutputSchema,
|
|
81
420
|
},
|
|
82
421
|
];
|
|
83
422
|
|
|
84
423
|
const server = new Server(
|
|
85
424
|
{ name: "deplens", version: "0.1.6" },
|
|
86
|
-
{ capabilities: { tools: {} } }
|
|
425
|
+
{ capabilities: { tools: {} } },
|
|
87
426
|
);
|
|
88
427
|
|
|
89
428
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
@@ -93,36 +432,236 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
93
432
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
94
433
|
const { name, arguments: args } = request.params;
|
|
95
434
|
try {
|
|
96
|
-
|
|
97
|
-
|
|
435
|
+
// Handle inspect tool
|
|
436
|
+
if (name === "deplens.inspect" || name === "deplens_inspect") {
|
|
437
|
+
const DEBUG = process.env.DEPLENS_DEBUG === "true";
|
|
438
|
+
if (DEBUG) {
|
|
439
|
+
console.error("[DEPLENS DEBUG] inspect args:", JSON.stringify(args, null, 2));
|
|
440
|
+
}
|
|
441
|
+
const rootDir =
|
|
442
|
+
args?.rootDir || process.env.DEPLENS_ROOT || process.cwd();
|
|
443
|
+
const target = args?.subpath
|
|
444
|
+
? `${args.target}/${args.subpath}`
|
|
445
|
+
: args?.target;
|
|
446
|
+
if (!target) throw new Error("Missing required field: target");
|
|
447
|
+
|
|
448
|
+
const core = await loadCore();
|
|
449
|
+
const runInspect = core.runInspect || core.default?.runInspect;
|
|
450
|
+
if (!runInspect) {
|
|
451
|
+
throw new Error("Failed to load runInspect from @deplens/core");
|
|
452
|
+
}
|
|
453
|
+
// Always get structured output first
|
|
454
|
+
const structuredOutput = await runInspect({
|
|
455
|
+
target,
|
|
456
|
+
filter: args?.filter,
|
|
457
|
+
showTypes: args?.showTypes,
|
|
458
|
+
includeDocs: args?.includeDocs,
|
|
459
|
+
includeExamples: args?.includeExamples,
|
|
460
|
+
remote: args?.remote,
|
|
461
|
+
remoteVersion: args?.remoteVersion,
|
|
462
|
+
jsdoc: args?.jsdoc,
|
|
463
|
+
jsdocOutput: args?.jsdocOutput,
|
|
464
|
+
jsdocQuery: args?.jsdocQuery,
|
|
465
|
+
kind: args?.kind,
|
|
466
|
+
depth: args?.depth,
|
|
467
|
+
resolveFrom: args?.resolveFrom,
|
|
468
|
+
cwd: rootDir,
|
|
469
|
+
analyzeSource: args?.analyzeSource,
|
|
470
|
+
sourceMaxFiles: args?.sourceMaxFiles,
|
|
471
|
+
sourceIncludeBody: args?.sourceIncludeBody,
|
|
472
|
+
// It's always safe to return object in MCP
|
|
473
|
+
format: "object",
|
|
474
|
+
listSections: args?.listSections,
|
|
475
|
+
docsSections: args?.docsSections,
|
|
476
|
+
search: args?.search,
|
|
477
|
+
maxExports: args?.maxExports,
|
|
478
|
+
maxProps: args?.maxProps,
|
|
479
|
+
maxExamples: args?.maxExamples,
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
// Generate text output based on requested format
|
|
483
|
+
let text;
|
|
484
|
+
if (args?.format === "json") {
|
|
485
|
+
// Return JSON string
|
|
486
|
+
text = JSON.stringify(structuredOutput, null, 2);
|
|
487
|
+
} else if (args?.format === "text" || !args?.format) {
|
|
488
|
+
// Return pretty formatted text
|
|
489
|
+
text = await runInspect({
|
|
490
|
+
target,
|
|
491
|
+
filter: args?.filter,
|
|
492
|
+
showTypes: args?.showTypes,
|
|
493
|
+
includeDocs: args?.includeDocs,
|
|
494
|
+
includeExamples: args?.includeExamples,
|
|
495
|
+
remote: args?.remote,
|
|
496
|
+
remoteVersion: args?.remoteVersion,
|
|
497
|
+
jsdoc: args?.jsdoc,
|
|
498
|
+
jsdocOutput: args?.jsdocOutput,
|
|
499
|
+
jsdocQuery: args?.jsdocQuery,
|
|
500
|
+
kind: args?.kind,
|
|
501
|
+
depth: args?.depth,
|
|
502
|
+
resolveFrom: args?.resolveFrom,
|
|
503
|
+
cwd: rootDir,
|
|
504
|
+
analyzeSource: args?.analyzeSource,
|
|
505
|
+
sourceMaxFiles: args?.sourceMaxFiles,
|
|
506
|
+
sourceIncludeBody: args?.sourceIncludeBody,
|
|
507
|
+
format: "text",
|
|
508
|
+
listSections: args?.listSections,
|
|
509
|
+
docsSections: args?.docsSections,
|
|
510
|
+
search: args?.search,
|
|
511
|
+
maxExports: args?.maxExports,
|
|
512
|
+
maxProps: args?.maxProps,
|
|
513
|
+
maxExamples: args?.maxExamples,
|
|
514
|
+
});
|
|
515
|
+
} else {
|
|
516
|
+
// Default: summary
|
|
517
|
+
text = formatInspectSummary(structuredOutput);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// MCP best practice: ensure text is always a valid string
|
|
521
|
+
const validText = typeof text === "string" ? text : String(text || "");
|
|
522
|
+
|
|
523
|
+
// MCP best practice: ensure structuredContent is always an object, never a string
|
|
524
|
+
const validStructured =
|
|
525
|
+
typeof structuredOutput === "object" && structuredOutput !== null
|
|
526
|
+
? structuredOutput
|
|
527
|
+
: {
|
|
528
|
+
schemaVersion: 1,
|
|
529
|
+
package: null,
|
|
530
|
+
version: null,
|
|
531
|
+
description: null,
|
|
532
|
+
exports: null,
|
|
533
|
+
types: null,
|
|
534
|
+
docs: null,
|
|
535
|
+
sections: null,
|
|
536
|
+
examples: null,
|
|
537
|
+
resolution: null,
|
|
538
|
+
meta: { target: target || null },
|
|
539
|
+
warnings: [
|
|
540
|
+
"Invalid output format received from runInspect",
|
|
541
|
+
],
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
// Final validation before returning (critical for MCP spec compliance)
|
|
545
|
+
if (typeof validStructured !== "object" || validStructured === null) {
|
|
546
|
+
throw new Error(
|
|
547
|
+
`CRITICAL: structuredContent is not an object (type: ${typeof validStructured})`
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (DEBUG) {
|
|
552
|
+
console.error("[DEPLENS DEBUG] Response:", {
|
|
553
|
+
textType: typeof validText,
|
|
554
|
+
textLength: validText.length,
|
|
555
|
+
structuredType: typeof validStructured,
|
|
556
|
+
structuredKeys: Object.keys(validStructured),
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
return {
|
|
561
|
+
content: [{ type: "text", text: validText }],
|
|
562
|
+
structuredContent: validStructured,
|
|
563
|
+
isError: false,
|
|
564
|
+
};
|
|
98
565
|
}
|
|
99
566
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
567
|
+
// Handle diff tool
|
|
568
|
+
if (name === "deplens.diff" || name === "deplens_diff") {
|
|
569
|
+
const packageName = args?.package;
|
|
570
|
+
if (!packageName) throw new Error("Missing required field: package");
|
|
571
|
+
|
|
572
|
+
const runDiff = await loadDiff();
|
|
573
|
+
if (!runDiff) {
|
|
574
|
+
throw new Error(
|
|
575
|
+
"Diff functionality not available. Missing diff.mjs module.",
|
|
576
|
+
);
|
|
577
|
+
}
|
|
103
578
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
579
|
+
const rootDir =
|
|
580
|
+
args?.rootDir || process.env.DEPLENS_ROOT || process.cwd();
|
|
581
|
+
const result = await runDiff({
|
|
582
|
+
package: packageName,
|
|
583
|
+
from: args?.from || "installed",
|
|
584
|
+
to: args?.to || "latest",
|
|
585
|
+
projectDir: rootDir,
|
|
586
|
+
includeSource: args?.includeSource || false,
|
|
587
|
+
includeChangelog: args?.includeChangelog !== false,
|
|
588
|
+
filter: args?.filter,
|
|
589
|
+
format: args?.format || "text",
|
|
590
|
+
verbose: args?.verbose || false,
|
|
591
|
+
colors: false, // No ANSI colors in MCP output
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
const diffSummary = result?.diff?.summary ?? result?.summary ?? null;
|
|
595
|
+
const diffChanges = result?.changes
|
|
596
|
+
? result.changes
|
|
597
|
+
: result?.diff
|
|
598
|
+
? [
|
|
599
|
+
...(result.diff.breaking || []),
|
|
600
|
+
...(result.diff.warnings || []),
|
|
601
|
+
...(result.diff.additions || []),
|
|
602
|
+
...(result.diff.info || []),
|
|
603
|
+
]
|
|
604
|
+
: null;
|
|
605
|
+
|
|
606
|
+
const textOutput =
|
|
607
|
+
args?.format === "text" || !args?.format
|
|
608
|
+
? result?.output || ""
|
|
609
|
+
: formatDiffSummary(diffSummary, packageName);
|
|
610
|
+
|
|
611
|
+
const structured =
|
|
612
|
+
typeof result === "object" && result
|
|
613
|
+
? {
|
|
614
|
+
schemaVersion: 1,
|
|
615
|
+
package: result.package || packageName,
|
|
616
|
+
from: result.from || args?.from || "installed",
|
|
617
|
+
to: result.to || args?.to || "latest",
|
|
618
|
+
output: result.output || null,
|
|
619
|
+
summary: diffSummary,
|
|
620
|
+
changes: diffChanges,
|
|
621
|
+
}
|
|
622
|
+
: {
|
|
623
|
+
schemaVersion: 1,
|
|
624
|
+
package: packageName,
|
|
625
|
+
from: args?.from || "installed",
|
|
626
|
+
to: args?.to || "latest",
|
|
627
|
+
output: result?.output || String(result),
|
|
628
|
+
summary: null,
|
|
629
|
+
changes: null,
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
return {
|
|
633
|
+
content: [{ type: "text", text: textOutput }],
|
|
634
|
+
structuredContent: structured,
|
|
635
|
+
isError: false,
|
|
636
|
+
};
|
|
108
637
|
}
|
|
109
|
-
const output = await runInspect({
|
|
110
|
-
target,
|
|
111
|
-
filter: args?.filter,
|
|
112
|
-
showTypes: args?.showTypes,
|
|
113
|
-
jsdoc: args?.jsdoc,
|
|
114
|
-
jsdocOutput: args?.jsdocOutput,
|
|
115
|
-
jsdocQuery: args?.jsdocQuery,
|
|
116
|
-
kind: args?.kind,
|
|
117
|
-
depth: args?.depth,
|
|
118
|
-
resolveFrom: args?.resolveFrom,
|
|
119
|
-
cwd: rootDir,
|
|
120
|
-
});
|
|
121
638
|
|
|
122
|
-
|
|
639
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
123
640
|
} catch (error) {
|
|
124
641
|
const message = error instanceof Error ? error.message : String(error);
|
|
125
|
-
|
|
642
|
+
|
|
643
|
+
// MCP best practice: always return structuredContent as an object
|
|
644
|
+
const errorStructured = {
|
|
645
|
+
schemaVersion: 1,
|
|
646
|
+
error: message,
|
|
647
|
+
package: null,
|
|
648
|
+
version: null,
|
|
649
|
+
description: null,
|
|
650
|
+
exports: null,
|
|
651
|
+
types: null,
|
|
652
|
+
docs: null,
|
|
653
|
+
sections: null,
|
|
654
|
+
examples: null,
|
|
655
|
+
resolution: null,
|
|
656
|
+
meta: null,
|
|
657
|
+
warnings: [message],
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
return {
|
|
661
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
662
|
+
structuredContent: errorStructured,
|
|
663
|
+
isError: true,
|
|
664
|
+
};
|
|
126
665
|
}
|
|
127
666
|
});
|
|
128
667
|
|