@nekzus/mcp-server 1.2.0 → 1.3.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 +123 -152
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +616 -260
- package/dist/index.js.map +1 -0
- package/package.json +49 -14
package/dist/index.js
CHANGED
|
@@ -1,8 +1,96 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import fetch from 'node-fetch';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
// Zod schemas for npm package data
|
|
5
|
+
const NpmPackageVersionSchema = z
|
|
6
|
+
.object({
|
|
7
|
+
name: z.string(),
|
|
8
|
+
version: z.string(),
|
|
9
|
+
description: z.string().optional(),
|
|
10
|
+
author: z.union([z.string(), z.object({}).passthrough()]).optional(),
|
|
11
|
+
license: z.string().optional(),
|
|
12
|
+
repository: z
|
|
13
|
+
.object({
|
|
14
|
+
type: z.string().optional(),
|
|
15
|
+
url: z.string().optional(),
|
|
16
|
+
})
|
|
17
|
+
.passthrough()
|
|
18
|
+
.optional(),
|
|
19
|
+
bugs: z
|
|
20
|
+
.object({
|
|
21
|
+
url: z.string().optional(),
|
|
22
|
+
})
|
|
23
|
+
.passthrough()
|
|
24
|
+
.optional(),
|
|
25
|
+
homepage: z.string().optional(),
|
|
26
|
+
})
|
|
27
|
+
.passthrough();
|
|
28
|
+
const NpmPackageInfoSchema = z
|
|
29
|
+
.object({
|
|
30
|
+
name: z.string(),
|
|
31
|
+
'dist-tags': z.record(z.string()),
|
|
32
|
+
versions: z.record(NpmPackageVersionSchema),
|
|
33
|
+
time: z.record(z.string()).optional(),
|
|
34
|
+
repository: z
|
|
35
|
+
.object({
|
|
36
|
+
type: z.string().optional(),
|
|
37
|
+
url: z.string().optional(),
|
|
38
|
+
})
|
|
39
|
+
.passthrough()
|
|
40
|
+
.optional(),
|
|
41
|
+
bugs: z
|
|
42
|
+
.object({
|
|
43
|
+
url: z.string().optional(),
|
|
44
|
+
})
|
|
45
|
+
.passthrough()
|
|
46
|
+
.optional(),
|
|
47
|
+
homepage: z.string().optional(),
|
|
48
|
+
})
|
|
49
|
+
.passthrough();
|
|
50
|
+
const NpmPackageDataSchema = z.object({
|
|
51
|
+
name: z.string(),
|
|
52
|
+
version: z.string(),
|
|
53
|
+
description: z.string().optional(),
|
|
54
|
+
license: z.string().optional(),
|
|
55
|
+
dependencies: z.record(z.string()).optional(),
|
|
56
|
+
devDependencies: z.record(z.string()).optional(),
|
|
57
|
+
peerDependencies: z.record(z.string()).optional(),
|
|
58
|
+
types: z.string().optional(),
|
|
59
|
+
typings: z.string().optional(),
|
|
60
|
+
});
|
|
61
|
+
const BundlephobiaDataSchema = z.object({
|
|
62
|
+
size: z.number(),
|
|
63
|
+
gzip: z.number(),
|
|
64
|
+
dependencyCount: z.number(),
|
|
65
|
+
});
|
|
66
|
+
const NpmDownloadsDataSchema = z.object({
|
|
67
|
+
downloads: z.number(),
|
|
68
|
+
start: z.string(),
|
|
69
|
+
end: z.string(),
|
|
70
|
+
package: z.string(),
|
|
71
|
+
});
|
|
72
|
+
// Schemas for NPM quality, maintenance and popularity metrics
|
|
73
|
+
const NpmQualitySchema = z.object({
|
|
74
|
+
score: z.number(),
|
|
75
|
+
tests: z.number(),
|
|
76
|
+
coverage: z.number(),
|
|
77
|
+
linting: z.number(),
|
|
78
|
+
types: z.number(),
|
|
79
|
+
});
|
|
80
|
+
const NpmMaintenanceSchema = z.object({
|
|
81
|
+
score: z.number(),
|
|
82
|
+
issuesResolutionTime: z.number(),
|
|
83
|
+
commitsFrequency: z.number(),
|
|
84
|
+
releaseFrequency: z.number(),
|
|
85
|
+
lastUpdate: z.string(),
|
|
86
|
+
});
|
|
87
|
+
const NpmPopularitySchema = z.object({
|
|
88
|
+
score: z.number(),
|
|
89
|
+
stars: z.number(),
|
|
90
|
+
downloads: z.number(),
|
|
91
|
+
dependents: z.number(),
|
|
92
|
+
communityInterest: z.number(),
|
|
93
|
+
});
|
|
6
94
|
// Logger function that uses stderr - only for critical errors
|
|
7
95
|
const log = (...args) => {
|
|
8
96
|
// Filter out server status messages
|
|
@@ -14,198 +102,185 @@ const log = (...args) => {
|
|
|
14
102
|
};
|
|
15
103
|
// Define tools
|
|
16
104
|
const TOOLS = [
|
|
105
|
+
// NPM Package Analysis Tools
|
|
17
106
|
{
|
|
18
|
-
name: '
|
|
19
|
-
description: '
|
|
107
|
+
name: 'npmVersions',
|
|
108
|
+
description: 'Get all available versions of an NPM package',
|
|
109
|
+
parameters: z.object({
|
|
110
|
+
packageName: z.string().describe('The name of the package'),
|
|
111
|
+
}),
|
|
20
112
|
inputSchema: {
|
|
21
113
|
type: 'object',
|
|
22
114
|
properties: {
|
|
23
|
-
|
|
24
|
-
type: 'string',
|
|
25
|
-
description: 'Name of the recipient for the greeting',
|
|
26
|
-
},
|
|
115
|
+
packageName: { type: 'string' },
|
|
27
116
|
},
|
|
28
|
-
required: ['
|
|
117
|
+
required: ['packageName'],
|
|
29
118
|
},
|
|
30
119
|
},
|
|
31
120
|
{
|
|
32
|
-
name: '
|
|
33
|
-
description: '
|
|
121
|
+
name: 'npmLatest',
|
|
122
|
+
description: 'Get the latest version and changelog of an NPM package',
|
|
123
|
+
parameters: z.object({
|
|
124
|
+
packageName: z.string().describe('The name of the package'),
|
|
125
|
+
}),
|
|
34
126
|
inputSchema: {
|
|
35
127
|
type: 'object',
|
|
36
|
-
properties: {
|
|
128
|
+
properties: {
|
|
129
|
+
packageName: { type: 'string' },
|
|
130
|
+
},
|
|
131
|
+
required: ['packageName'],
|
|
37
132
|
},
|
|
38
133
|
},
|
|
39
134
|
{
|
|
40
|
-
name: '
|
|
41
|
-
description: '
|
|
135
|
+
name: 'npmDeps',
|
|
136
|
+
description: 'Analyze dependencies and devDependencies of an NPM package',
|
|
137
|
+
parameters: z.object({
|
|
138
|
+
packageName: z.string().describe('The name of the package'),
|
|
139
|
+
}),
|
|
42
140
|
inputSchema: {
|
|
43
141
|
type: 'object',
|
|
44
142
|
properties: {
|
|
45
|
-
|
|
46
|
-
type: 'string',
|
|
47
|
-
description: 'Timezone identifier (e.g., "America/New_York")',
|
|
48
|
-
},
|
|
49
|
-
locale: {
|
|
50
|
-
type: 'string',
|
|
51
|
-
description: 'Locale identifier (e.g., "en-US")',
|
|
52
|
-
},
|
|
143
|
+
packageName: { type: 'string' },
|
|
53
144
|
},
|
|
145
|
+
required: ['packageName'],
|
|
54
146
|
},
|
|
55
147
|
},
|
|
56
148
|
{
|
|
57
|
-
name: '
|
|
58
|
-
description: '
|
|
149
|
+
name: 'npmTypes',
|
|
150
|
+
description: 'Check TypeScript types availability and version for a package',
|
|
151
|
+
parameters: z.object({
|
|
152
|
+
packageName: z.string().describe('The name of the package'),
|
|
153
|
+
}),
|
|
59
154
|
inputSchema: {
|
|
60
155
|
type: 'object',
|
|
61
156
|
properties: {
|
|
62
|
-
|
|
63
|
-
type: 'string',
|
|
64
|
-
description: 'Mathematical expression to evaluate (e.g., "2 + 2 * 3")',
|
|
65
|
-
},
|
|
66
|
-
precision: {
|
|
67
|
-
type: 'number',
|
|
68
|
-
description: 'Number of decimal places for the result (default: 2)',
|
|
69
|
-
},
|
|
157
|
+
packageName: { type: 'string' },
|
|
70
158
|
},
|
|
71
|
-
required: ['
|
|
159
|
+
required: ['packageName'],
|
|
72
160
|
},
|
|
73
161
|
},
|
|
74
162
|
{
|
|
75
|
-
name: '
|
|
76
|
-
description: '
|
|
163
|
+
name: 'npmSize',
|
|
164
|
+
description: 'Get package size information including dependencies and bundle size',
|
|
165
|
+
parameters: z.object({
|
|
166
|
+
packageName: z.string().describe('The name of the package'),
|
|
167
|
+
}),
|
|
77
168
|
inputSchema: {
|
|
78
169
|
type: 'object',
|
|
79
170
|
properties: {
|
|
80
|
-
|
|
81
|
-
type: 'number',
|
|
82
|
-
description: 'Length of the password (default: 16)',
|
|
83
|
-
},
|
|
84
|
-
includeNumbers: {
|
|
85
|
-
type: 'boolean',
|
|
86
|
-
description: 'Include numbers in the password (default: true)',
|
|
87
|
-
},
|
|
88
|
-
includeSymbols: {
|
|
89
|
-
type: 'boolean',
|
|
90
|
-
description: 'Include special symbols in the password (default: true)',
|
|
91
|
-
},
|
|
92
|
-
includeUppercase: {
|
|
93
|
-
type: 'boolean',
|
|
94
|
-
description: 'Include uppercase letters in the password (default: true)',
|
|
95
|
-
},
|
|
171
|
+
packageName: { type: 'string' },
|
|
96
172
|
},
|
|
173
|
+
required: ['packageName'],
|
|
97
174
|
},
|
|
98
175
|
},
|
|
99
176
|
{
|
|
100
|
-
name: '
|
|
101
|
-
description: '
|
|
177
|
+
name: 'npmVulnerabilities',
|
|
178
|
+
description: 'Check for known vulnerabilities in a package',
|
|
179
|
+
parameters: z.object({
|
|
180
|
+
packageName: z.string().describe('The name of the package'),
|
|
181
|
+
}),
|
|
102
182
|
inputSchema: {
|
|
103
183
|
type: 'object',
|
|
104
184
|
properties: {
|
|
105
|
-
|
|
106
|
-
type: 'string',
|
|
107
|
-
description: 'Text or URL to encode in the QR code',
|
|
108
|
-
},
|
|
109
|
-
size: {
|
|
110
|
-
type: 'number',
|
|
111
|
-
description: 'Size of the QR code in pixels (default: 200)',
|
|
112
|
-
},
|
|
113
|
-
dark: {
|
|
114
|
-
type: 'string',
|
|
115
|
-
description: 'Color for dark modules (default: "#000000")',
|
|
116
|
-
},
|
|
117
|
-
light: {
|
|
118
|
-
type: 'string',
|
|
119
|
-
description: 'Color for light modules (default: "#ffffff")',
|
|
120
|
-
},
|
|
185
|
+
packageName: { type: 'string' },
|
|
121
186
|
},
|
|
122
|
-
required: ['
|
|
187
|
+
required: ['packageName'],
|
|
123
188
|
},
|
|
124
189
|
},
|
|
125
190
|
{
|
|
126
|
-
name: '
|
|
127
|
-
description: '
|
|
191
|
+
name: 'npmTrends',
|
|
192
|
+
description: 'Get download trends and popularity metrics for a package',
|
|
193
|
+
parameters: z.object({
|
|
194
|
+
packageName: z.string().describe('The name of the package'),
|
|
195
|
+
period: z.enum(['last-week', 'last-month', 'last-year']).describe('Time period for trends'),
|
|
196
|
+
}),
|
|
128
197
|
inputSchema: {
|
|
129
198
|
type: 'object',
|
|
130
199
|
properties: {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
description: 'Value to convert',
|
|
134
|
-
},
|
|
135
|
-
from: {
|
|
136
|
-
type: 'string',
|
|
137
|
-
description: 'Source unit (e.g., "cup", "tbsp", "g", "oz", "ml")',
|
|
138
|
-
},
|
|
139
|
-
to: {
|
|
200
|
+
packageName: { type: 'string' },
|
|
201
|
+
period: {
|
|
140
202
|
type: 'string',
|
|
141
|
-
|
|
203
|
+
enum: ['last-week', 'last-month', 'last-year'],
|
|
142
204
|
},
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
205
|
+
},
|
|
206
|
+
required: ['packageName', 'period'],
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
name: 'npmCompare',
|
|
211
|
+
description: 'Compare multiple NPM packages based on various metrics',
|
|
212
|
+
parameters: z.object({
|
|
213
|
+
packages: z.array(z.string()).describe('List of package names to compare'),
|
|
214
|
+
}),
|
|
215
|
+
inputSchema: {
|
|
216
|
+
type: 'object',
|
|
217
|
+
properties: {
|
|
218
|
+
packages: {
|
|
219
|
+
type: 'array',
|
|
220
|
+
items: { type: 'string' },
|
|
146
221
|
},
|
|
147
222
|
},
|
|
148
|
-
required: ['
|
|
223
|
+
required: ['packages'],
|
|
149
224
|
},
|
|
150
225
|
},
|
|
151
226
|
];
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
],
|
|
161
|
-
isError: false,
|
|
162
|
-
};
|
|
227
|
+
// Type guards for API responses
|
|
228
|
+
function isNpmPackageInfo(data) {
|
|
229
|
+
try {
|
|
230
|
+
return NpmPackageInfoSchema.parse(data) !== null;
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
163
235
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
{
|
|
172
|
-
type: 'text',
|
|
173
|
-
text: `🎴 Drew card: ${value}${suit}`,
|
|
174
|
-
},
|
|
175
|
-
],
|
|
176
|
-
isError: false,
|
|
177
|
-
};
|
|
236
|
+
function isNpmPackageData(data) {
|
|
237
|
+
try {
|
|
238
|
+
return NpmPackageDataSchema.parse(data) !== null;
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
178
243
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}).format(date);
|
|
187
|
-
return {
|
|
188
|
-
content: [
|
|
189
|
-
{
|
|
190
|
-
type: 'text',
|
|
191
|
-
text: `🕒 Current date and time in ${timeZone}: ${formattedDate}`,
|
|
192
|
-
},
|
|
193
|
-
],
|
|
194
|
-
isError: false,
|
|
195
|
-
};
|
|
244
|
+
function isBundlephobiaData(data) {
|
|
245
|
+
try {
|
|
246
|
+
return BundlephobiaDataSchema.parse(data) !== null;
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
196
251
|
}
|
|
197
|
-
|
|
252
|
+
function isNpmDownloadsData(data) {
|
|
198
253
|
try {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
254
|
+
return NpmDownloadsDataSchema.parse(data) !== null;
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
async function handleNpmVersions(args) {
|
|
261
|
+
try {
|
|
262
|
+
const response = await fetch(`https://registry.npmjs.org/${args.packageName}`);
|
|
263
|
+
if (!response.ok) {
|
|
264
|
+
throw new Error(`Failed to fetch package info: ${response.statusText}`);
|
|
265
|
+
}
|
|
266
|
+
const rawData = await response.json();
|
|
267
|
+
if (!isNpmPackageInfo(rawData)) {
|
|
268
|
+
throw new Error('Invalid package info data received');
|
|
269
|
+
}
|
|
270
|
+
const versions = Object.keys(rawData.versions ?? {}).sort((a, b) => {
|
|
271
|
+
const [aMajor = 0, aMinor = 0, aPatch = 0] = a.split('.').map(Number);
|
|
272
|
+
const [bMajor = 0, bMinor = 0, bPatch = 0] = b.split('.').map(Number);
|
|
273
|
+
if (aMajor !== bMajor)
|
|
274
|
+
return aMajor - bMajor;
|
|
275
|
+
if (aMinor !== bMinor)
|
|
276
|
+
return aMinor - bMinor;
|
|
277
|
+
return aPatch - bPatch;
|
|
278
|
+
});
|
|
204
279
|
return {
|
|
205
280
|
content: [
|
|
206
281
|
{
|
|
207
282
|
type: 'text',
|
|
208
|
-
text:
|
|
283
|
+
text: `📦 Available versions for ${args.packageName}:\n${versions.join('\n')}`,
|
|
209
284
|
},
|
|
210
285
|
],
|
|
211
286
|
isError: false,
|
|
@@ -216,56 +291,175 @@ async function handleCalculator(args) {
|
|
|
216
291
|
content: [
|
|
217
292
|
{
|
|
218
293
|
type: 'text',
|
|
219
|
-
text: `Error
|
|
294
|
+
text: `Error fetching package versions: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
220
295
|
},
|
|
221
296
|
],
|
|
222
297
|
isError: true,
|
|
223
298
|
};
|
|
224
299
|
}
|
|
225
300
|
}
|
|
226
|
-
async function
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
301
|
+
async function handleNpmLatest(args) {
|
|
302
|
+
try {
|
|
303
|
+
const response = await fetch(`https://registry.npmjs.org/${args.packageName}`);
|
|
304
|
+
if (!response.ok) {
|
|
305
|
+
throw new Error(`Failed to fetch package info: ${response.statusText}`);
|
|
306
|
+
}
|
|
307
|
+
const rawData = await response.json();
|
|
308
|
+
if (!isNpmPackageInfo(rawData)) {
|
|
309
|
+
throw new Error('Invalid package info data received');
|
|
310
|
+
}
|
|
311
|
+
const latestVersion = rawData['dist-tags']?.latest;
|
|
312
|
+
if (!latestVersion || !rawData.versions) {
|
|
313
|
+
throw new Error('No latest version or versions data found');
|
|
314
|
+
}
|
|
315
|
+
const latestVersionInfo = rawData.versions[latestVersion];
|
|
316
|
+
const description = latestVersionInfo.description ?? '';
|
|
317
|
+
const repository = latestVersionInfo.repository ?? rawData.repository;
|
|
318
|
+
const homepage = latestVersionInfo.homepage ?? rawData.homepage;
|
|
319
|
+
const bugs = latestVersionInfo.bugs ?? rawData.bugs;
|
|
320
|
+
const text = [
|
|
321
|
+
`📦 Latest version of ${args.packageName}: ${latestVersion}`,
|
|
322
|
+
'',
|
|
323
|
+
description && `Description:\n${description}`,
|
|
324
|
+
'',
|
|
325
|
+
'Links:',
|
|
326
|
+
homepage && `• Homepage: ${homepage}`,
|
|
327
|
+
repository?.url && `• Repository: ${repository.url.replace('git+', '').replace('.git', '')}`,
|
|
328
|
+
bugs?.url && `• Issues: ${bugs.url}`,
|
|
329
|
+
'',
|
|
330
|
+
repository?.url?.includes('github.com') &&
|
|
331
|
+
`You can check for updates at:\n${repository.url
|
|
332
|
+
.replace('git+', '')
|
|
333
|
+
.replace('git:', 'https:')
|
|
334
|
+
.replace('.git', '')}/releases`,
|
|
335
|
+
]
|
|
336
|
+
.filter(Boolean)
|
|
337
|
+
.join('\n');
|
|
338
|
+
return {
|
|
339
|
+
content: [{ type: 'text', text }],
|
|
340
|
+
isError: false,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
catch (error) {
|
|
344
|
+
return {
|
|
345
|
+
content: [
|
|
346
|
+
{
|
|
347
|
+
type: 'text',
|
|
348
|
+
text: `Error fetching package information: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
349
|
+
},
|
|
350
|
+
],
|
|
351
|
+
isError: true,
|
|
352
|
+
};
|
|
241
353
|
}
|
|
242
|
-
return {
|
|
243
|
-
content: [
|
|
244
|
-
{
|
|
245
|
-
type: 'text',
|
|
246
|
-
text: `🔐 Generated password: ${password}`,
|
|
247
|
-
},
|
|
248
|
-
],
|
|
249
|
-
isError: false,
|
|
250
|
-
};
|
|
251
354
|
}
|
|
252
|
-
async function
|
|
355
|
+
async function handleNpmDeps(args) {
|
|
253
356
|
try {
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
}
|
|
357
|
+
const response = await fetch(`https://registry.npmjs.org/${args.packageName}/latest`);
|
|
358
|
+
if (!response.ok) {
|
|
359
|
+
throw new Error(`Failed to fetch package info: ${response.statusText}`);
|
|
360
|
+
}
|
|
361
|
+
const rawData = await response.json();
|
|
362
|
+
if (!isNpmPackageData(rawData)) {
|
|
363
|
+
throw new Error('Invalid package data received');
|
|
364
|
+
}
|
|
365
|
+
const dependencies = rawData.dependencies ?? {};
|
|
366
|
+
const devDependencies = rawData.devDependencies ?? {};
|
|
367
|
+
const peerDependencies = rawData.peerDependencies ?? {};
|
|
368
|
+
const text = [
|
|
369
|
+
`📦 Dependencies for ${args.packageName}@${rawData.version}`,
|
|
370
|
+
'',
|
|
371
|
+
Object.keys(dependencies).length > 0 && [
|
|
372
|
+
'Dependencies:',
|
|
373
|
+
...Object.entries(dependencies).map(([dep, version]) => `• ${dep}: ${version}`),
|
|
374
|
+
'',
|
|
375
|
+
],
|
|
376
|
+
Object.keys(devDependencies).length > 0 && [
|
|
377
|
+
'Dev Dependencies:',
|
|
378
|
+
...Object.entries(devDependencies).map(([dep, version]) => `• ${dep}: ${version}`),
|
|
379
|
+
'',
|
|
380
|
+
],
|
|
381
|
+
Object.keys(peerDependencies).length > 0 && [
|
|
382
|
+
'Peer Dependencies:',
|
|
383
|
+
...Object.entries(peerDependencies).map(([dep, version]) => `• ${dep}: ${version}`),
|
|
384
|
+
],
|
|
385
|
+
]
|
|
386
|
+
.filter(Boolean)
|
|
387
|
+
.flat()
|
|
388
|
+
.join('\n');
|
|
389
|
+
return {
|
|
390
|
+
content: [{ type: 'text', text }],
|
|
391
|
+
isError: false,
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
catch (error) {
|
|
264
395
|
return {
|
|
265
396
|
content: [
|
|
266
397
|
{
|
|
267
398
|
type: 'text',
|
|
268
|
-
text:
|
|
399
|
+
text: `Error fetching dependencies: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
400
|
+
},
|
|
401
|
+
],
|
|
402
|
+
isError: true,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
async function handleNpmTypes(args) {
|
|
407
|
+
try {
|
|
408
|
+
const response = await fetch(`https://registry.npmjs.org/${args.packageName}/latest`);
|
|
409
|
+
if (!response.ok) {
|
|
410
|
+
throw new Error(`Failed to fetch package info: ${response.statusText}`);
|
|
411
|
+
}
|
|
412
|
+
const data = (await response.json());
|
|
413
|
+
let text = `📦 TypeScript support for ${args.packageName}@${data.version}\n\n`;
|
|
414
|
+
const hasTypes = Boolean(data.types || data.typings);
|
|
415
|
+
if (hasTypes) {
|
|
416
|
+
text += `✅ Package includes built-in TypeScript types\nTypes path: ${data.types || data.typings}\n\n`;
|
|
417
|
+
}
|
|
418
|
+
const typesPackage = `@types/${args.packageName.replace('@', '').replace('/', '__')}`;
|
|
419
|
+
const typesResponse = await fetch(`https://registry.npmjs.org/${typesPackage}/latest`).catch(() => null);
|
|
420
|
+
if (typesResponse?.ok) {
|
|
421
|
+
const typesData = (await typesResponse.json());
|
|
422
|
+
text += `📦 DefinitelyTyped package available: ${typesPackage}@${typesData.version}\n`;
|
|
423
|
+
text += `Install with: npm install -D ${typesPackage}\n`;
|
|
424
|
+
}
|
|
425
|
+
else if (!hasTypes) {
|
|
426
|
+
text += '❌ No TypeScript type definitions found\n';
|
|
427
|
+
}
|
|
428
|
+
return {
|
|
429
|
+
content: [{ type: 'text', text }],
|
|
430
|
+
isError: false,
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
catch (error) {
|
|
434
|
+
return {
|
|
435
|
+
content: [
|
|
436
|
+
{ type: 'text', text: `Error checking TypeScript types: ${error.message}` },
|
|
437
|
+
],
|
|
438
|
+
isError: true,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
async function handleNpmSize(args) {
|
|
443
|
+
try {
|
|
444
|
+
const response = await fetch(`https://bundlephobia.com/api/size?package=${args.packageName}`);
|
|
445
|
+
if (!response.ok) {
|
|
446
|
+
throw new Error(`Failed to fetch package size: ${response.statusText}`);
|
|
447
|
+
}
|
|
448
|
+
const rawData = await response.json();
|
|
449
|
+
if (!isBundlephobiaData(rawData)) {
|
|
450
|
+
throw new Error('Invalid response from bundlephobia');
|
|
451
|
+
}
|
|
452
|
+
const sizeInKb = Number((rawData.size / 1024).toFixed(2));
|
|
453
|
+
const gzipInKb = Number((rawData.gzip / 1024).toFixed(2));
|
|
454
|
+
return {
|
|
455
|
+
content: [
|
|
456
|
+
{
|
|
457
|
+
type: 'text',
|
|
458
|
+
text: `Package size: ${sizeInKb}KB (gzipped: ${gzipInKb}KB)`,
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
type: 'text',
|
|
462
|
+
text: `Dependencies: ${rawData.dependencyCount}`,
|
|
269
463
|
},
|
|
270
464
|
],
|
|
271
465
|
isError: false,
|
|
@@ -276,104 +470,266 @@ async function handleQRGen(args) {
|
|
|
276
470
|
content: [
|
|
277
471
|
{
|
|
278
472
|
type: 'text',
|
|
279
|
-
text: `Error
|
|
473
|
+
text: `Error fetching package size: ${error instanceof Error ? error.message : String(error)}`,
|
|
280
474
|
},
|
|
281
475
|
],
|
|
282
476
|
isError: true,
|
|
283
477
|
};
|
|
284
478
|
}
|
|
285
479
|
}
|
|
286
|
-
async function
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
type: 'text',
|
|
293
|
-
text: `⚖️ Converted ${args.value} ${args.from} to ${result} ${args.to}${args.ingredient ? ` of ${args.ingredient}` : ''}`,
|
|
480
|
+
async function handleNpmVulnerabilities(args) {
|
|
481
|
+
try {
|
|
482
|
+
const response = await fetch('https://api.osv.dev/v1/query', {
|
|
483
|
+
method: 'POST',
|
|
484
|
+
headers: {
|
|
485
|
+
'Content-Type': 'application/json',
|
|
294
486
|
},
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
487
|
+
body: JSON.stringify({
|
|
488
|
+
package: {
|
|
489
|
+
name: args.packageName,
|
|
490
|
+
ecosystem: 'npm',
|
|
491
|
+
},
|
|
492
|
+
}),
|
|
493
|
+
});
|
|
494
|
+
if (!response.ok) {
|
|
495
|
+
throw new Error(`Failed to fetch vulnerability info: ${response.statusText}`);
|
|
496
|
+
}
|
|
497
|
+
const data = (await response.json());
|
|
498
|
+
const vulns = data.vulns || [];
|
|
499
|
+
let text = `🔒 Security info for ${args.packageName}\n\n`;
|
|
500
|
+
if (vulns.length === 0) {
|
|
501
|
+
text += '✅ No known vulnerabilities\n';
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
text += `⚠️ Found ${vulns.length} vulnerabilities:\n\n`;
|
|
505
|
+
for (const vuln of vulns) {
|
|
506
|
+
text += `- ${vuln.summary}\n`;
|
|
507
|
+
const severity = typeof vuln.severity === 'object'
|
|
508
|
+
? vuln.severity.type || 'Unknown'
|
|
509
|
+
: vuln.severity || 'Unknown';
|
|
510
|
+
text += ` Severity: ${severity}\n`;
|
|
511
|
+
if (vuln.references && vuln.references.length > 0) {
|
|
512
|
+
text += ` More info: ${vuln.references[0].url}\n`;
|
|
513
|
+
}
|
|
514
|
+
text += '\n';
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return {
|
|
518
|
+
content: [{ type: 'text', text }],
|
|
519
|
+
isError: false,
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
catch (error) {
|
|
523
|
+
return {
|
|
524
|
+
content: [
|
|
525
|
+
{ type: 'text', text: `Error checking vulnerabilities: ${error.message}` },
|
|
526
|
+
],
|
|
527
|
+
isError: true,
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
async function handleNpmTrends(args) {
|
|
532
|
+
try {
|
|
533
|
+
const period = args.period || 'last-month';
|
|
534
|
+
const response = await fetch(`https://api.npmjs.org/downloads/point/${period}/${args.packageName}`);
|
|
535
|
+
if (!response.ok) {
|
|
536
|
+
throw new Error(`Failed to fetch download trends: ${response.statusText}`);
|
|
537
|
+
}
|
|
538
|
+
const data = await response.json();
|
|
539
|
+
if (!isNpmDownloadsData(data)) {
|
|
540
|
+
throw new Error('Invalid response format from npm downloads API');
|
|
541
|
+
}
|
|
542
|
+
let text = `📈 Download trends for ${args.packageName}\n\n`;
|
|
543
|
+
text += `Period: ${period}\n`;
|
|
544
|
+
text += `Total downloads: ${data.downloads.toLocaleString()}\n`;
|
|
545
|
+
text += `Average daily downloads: ${Math.round(data.downloads / (period === 'last-week' ? 7 : period === 'last-month' ? 30 : 365)).toLocaleString()}\n`;
|
|
546
|
+
return {
|
|
547
|
+
content: [{ type: 'text', text }],
|
|
548
|
+
isError: false,
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
catch (error) {
|
|
552
|
+
return {
|
|
553
|
+
content: [
|
|
554
|
+
{ type: 'text', text: `Error fetching download trends: ${error.message}` },
|
|
555
|
+
],
|
|
556
|
+
isError: true,
|
|
557
|
+
};
|
|
558
|
+
}
|
|
298
559
|
}
|
|
299
|
-
async function
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
return handleKitchenConvert(args);
|
|
315
|
-
default:
|
|
560
|
+
async function handleNpmCompare(args) {
|
|
561
|
+
try {
|
|
562
|
+
const results = await Promise.all(args.packages.map(async (pkg) => {
|
|
563
|
+
const [infoRes, downloadsRes] = await Promise.all([
|
|
564
|
+
fetch(`https://registry.npmjs.org/${pkg}/latest`),
|
|
565
|
+
fetch(`https://api.npmjs.org/downloads/point/last-month/${pkg}`),
|
|
566
|
+
]);
|
|
567
|
+
if (!infoRes.ok || !downloadsRes.ok) {
|
|
568
|
+
throw new Error(`Failed to fetch data for ${pkg}`);
|
|
569
|
+
}
|
|
570
|
+
const info = await infoRes.json();
|
|
571
|
+
const downloads = await downloadsRes.json();
|
|
572
|
+
if (!isNpmPackageData(info) || !isNpmDownloadsData(downloads)) {
|
|
573
|
+
throw new Error(`Invalid response format for ${pkg}`);
|
|
574
|
+
}
|
|
316
575
|
return {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
isError: true,
|
|
576
|
+
name: pkg,
|
|
577
|
+
version: info.version,
|
|
578
|
+
description: info.description,
|
|
579
|
+
downloads: downloads.downloads,
|
|
580
|
+
license: info.license,
|
|
581
|
+
dependencies: Object.keys(info.dependencies || {}).length,
|
|
324
582
|
};
|
|
583
|
+
}));
|
|
584
|
+
let text = '📊 Package Comparison\n\n';
|
|
585
|
+
// Table header
|
|
586
|
+
text += 'Package | Version | Monthly Downloads | Dependencies | License\n';
|
|
587
|
+
text += '--------|---------|------------------|--------------|--------\n';
|
|
588
|
+
// Table rows
|
|
589
|
+
for (const pkg of results) {
|
|
590
|
+
text += `${pkg.name} | ${pkg.version} | ${pkg.downloads.toLocaleString()} | ${pkg.dependencies} | ${pkg.license || 'N/A'}\n`;
|
|
591
|
+
}
|
|
592
|
+
return {
|
|
593
|
+
content: [{ type: 'text', text }],
|
|
594
|
+
isError: false,
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
catch (error) {
|
|
598
|
+
return {
|
|
599
|
+
content: [{ type: 'text', text: `Error comparing packages: ${error.message}` }],
|
|
600
|
+
isError: true,
|
|
601
|
+
};
|
|
325
602
|
}
|
|
326
603
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
tools: {},
|
|
334
|
-
},
|
|
335
|
-
});
|
|
336
|
-
// Setup request handlers
|
|
337
|
-
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
338
|
-
resources: [],
|
|
339
|
-
}));
|
|
340
|
-
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
341
|
-
throw new Error(`Resource not found: ${request.params.uri}`);
|
|
342
|
-
});
|
|
343
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
344
|
-
tools: TOOLS,
|
|
345
|
-
}));
|
|
346
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => handleToolCall(request.params.name, request.params.arguments ?? {}));
|
|
347
|
-
async function runServer() {
|
|
348
|
-
const transport = new StdioServerTransport();
|
|
349
|
-
// Handle direct messages
|
|
350
|
-
process.stdin.on('data', async (data) => {
|
|
351
|
-
try {
|
|
352
|
-
const message = JSON.parse(data.toString());
|
|
353
|
-
if (message.method === 'tools/call') {
|
|
354
|
-
const result = await handleToolCall(message.params.name, message.params.arguments ?? {});
|
|
355
|
-
process.stdout.write(`${JSON.stringify({
|
|
356
|
-
jsonrpc: '2.0',
|
|
357
|
-
result,
|
|
358
|
-
id: message.id,
|
|
359
|
-
})}\n`);
|
|
360
|
-
}
|
|
604
|
+
// Function to get package quality metrics
|
|
605
|
+
async function handleNpmQuality(args) {
|
|
606
|
+
try {
|
|
607
|
+
const response = await fetch(`https://api.npms.io/v2/package/${encodeURIComponent(args.packageName)}`);
|
|
608
|
+
if (!response.ok) {
|
|
609
|
+
throw new Error(`Failed to fetch quality data: ${response.statusText}`);
|
|
361
610
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
611
|
+
const data = (await response.json());
|
|
612
|
+
const quality = data.score.quality;
|
|
613
|
+
const result = NpmQualitySchema.parse({
|
|
614
|
+
score: Math.round(quality.score * 100) / 100,
|
|
615
|
+
tests: Math.round(quality.tests * 100) / 100,
|
|
616
|
+
coverage: Math.round(quality.coverage * 100) / 100,
|
|
617
|
+
linting: Math.round(quality.linting * 100) / 100,
|
|
618
|
+
types: Math.round(quality.types * 100) / 100,
|
|
619
|
+
});
|
|
620
|
+
return {
|
|
621
|
+
content: [
|
|
622
|
+
{
|
|
623
|
+
type: 'text',
|
|
624
|
+
text: `Quality metrics for ${args.packageName}:
|
|
625
|
+
- Overall Score: ${result.score}
|
|
626
|
+
- Tests: ${result.tests}
|
|
627
|
+
- Coverage: ${result.coverage}
|
|
628
|
+
- Linting: ${result.linting}
|
|
629
|
+
- Types: ${result.types}`,
|
|
630
|
+
},
|
|
631
|
+
],
|
|
632
|
+
isError: false,
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
catch (error) {
|
|
636
|
+
return {
|
|
637
|
+
content: [
|
|
638
|
+
{
|
|
639
|
+
type: 'text',
|
|
640
|
+
text: `Error fetching quality metrics: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
641
|
+
},
|
|
642
|
+
],
|
|
643
|
+
isError: true,
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
// Function to get package maintenance metrics
|
|
648
|
+
async function handleNpmMaintenance(args) {
|
|
649
|
+
try {
|
|
650
|
+
const response = await fetch(`https://api.npms.io/v2/package/${encodeURIComponent(args.packageName)}`);
|
|
651
|
+
if (!response.ok) {
|
|
652
|
+
throw new Error(`Failed to fetch maintenance data: ${response.statusText}`);
|
|
372
653
|
}
|
|
373
|
-
|
|
374
|
-
|
|
654
|
+
const data = (await response.json());
|
|
655
|
+
const maintenance = data.score.maintenance;
|
|
656
|
+
const result = NpmMaintenanceSchema.parse({
|
|
657
|
+
score: Math.round(maintenance.score * 100) / 100,
|
|
658
|
+
issuesResolutionTime: Math.round(maintenance.issuesResolutionTime * 100) / 100,
|
|
659
|
+
commitsFrequency: Math.round(maintenance.commitsFrequency * 100) / 100,
|
|
660
|
+
releaseFrequency: Math.round(maintenance.releaseFrequency * 100) / 100,
|
|
661
|
+
lastUpdate: new Date(maintenance.lastUpdate).toISOString(),
|
|
662
|
+
});
|
|
663
|
+
return {
|
|
664
|
+
content: [
|
|
665
|
+
{
|
|
666
|
+
type: 'text',
|
|
667
|
+
text: `Maintenance metrics for ${args.packageName}:
|
|
668
|
+
- Overall Score: ${result.score}
|
|
669
|
+
- Issues Resolution Time: ${result.issuesResolutionTime}
|
|
670
|
+
- Commits Frequency: ${result.commitsFrequency}
|
|
671
|
+
- Release Frequency: ${result.releaseFrequency}
|
|
672
|
+
- Last Update: ${new Date(result.lastUpdate).toLocaleDateString()}`,
|
|
673
|
+
},
|
|
674
|
+
],
|
|
675
|
+
isError: false,
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
catch (error) {
|
|
679
|
+
return {
|
|
680
|
+
content: [
|
|
681
|
+
{
|
|
682
|
+
type: 'text',
|
|
683
|
+
text: `Error fetching maintenance metrics: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
684
|
+
},
|
|
685
|
+
],
|
|
686
|
+
isError: true,
|
|
687
|
+
};
|
|
688
|
+
}
|
|
375
689
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
});
|
|
690
|
+
// Function to get package popularity metrics
|
|
691
|
+
async function handleNpmPopularity(args) {
|
|
692
|
+
try {
|
|
693
|
+
const response = await fetch(`https://api.npms.io/v2/package/${encodeURIComponent(args.packageName)}`);
|
|
694
|
+
if (!response.ok) {
|
|
695
|
+
throw new Error(`Failed to fetch popularity data: ${response.statusText}`);
|
|
696
|
+
}
|
|
697
|
+
const data = (await response.json());
|
|
698
|
+
const popularity = data.score.popularity;
|
|
699
|
+
const result = NpmPopularitySchema.parse({
|
|
700
|
+
score: Math.round(popularity.score * 100) / 100,
|
|
701
|
+
stars: Math.round(popularity.stars),
|
|
702
|
+
downloads: Math.round(popularity.downloads),
|
|
703
|
+
dependents: Math.round(popularity.dependents),
|
|
704
|
+
communityInterest: Math.round(popularity.communityInterest * 100) / 100,
|
|
705
|
+
});
|
|
706
|
+
return {
|
|
707
|
+
content: [
|
|
708
|
+
{
|
|
709
|
+
type: 'text',
|
|
710
|
+
text: `Popularity metrics for ${args.packageName}:
|
|
711
|
+
- Overall Score: ${result.score}
|
|
712
|
+
- GitHub Stars: ${result.stars}
|
|
713
|
+
- Downloads: ${result.downloads}
|
|
714
|
+
- Dependent Packages: ${result.dependents}
|
|
715
|
+
- Community Interest: ${result.communityInterest}`,
|
|
716
|
+
},
|
|
717
|
+
],
|
|
718
|
+
isError: false,
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
catch (error) {
|
|
722
|
+
return {
|
|
723
|
+
content: [
|
|
724
|
+
{
|
|
725
|
+
type: 'text',
|
|
726
|
+
text: `Error fetching popularity metrics: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
727
|
+
},
|
|
728
|
+
],
|
|
729
|
+
isError: true,
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
// Export functions
|
|
734
|
+
export { handleNpmCompare, handleNpmDeps, handleNpmLatest, handleNpmMaintenance, handleNpmPopularity, handleNpmQuality, handleNpmSize, handleNpmTrends, handleNpmTypes, handleNpmVersions, handleNpmVulnerabilities, };
|
|
735
|
+
//# sourceMappingURL=index.js.map
|