@nekzus/mcp-server 1.11.8 → 1.12.33
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/dist/.tsbuildinfo +1 -1
- package/dist/index.d.ts +58 -1173
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +390 -302
- package/dist/index.js.map +1 -1
- package/package.json +10 -7
package/dist/index.js
CHANGED
|
@@ -48,7 +48,7 @@ export const NpmMaintainerSchema = z
|
|
|
48
48
|
email: z.string().optional(),
|
|
49
49
|
url: z.string().optional(),
|
|
50
50
|
})
|
|
51
|
-
.
|
|
51
|
+
.loose();
|
|
52
52
|
export const NpmPackageVersionSchema = z
|
|
53
53
|
.object({
|
|
54
54
|
name: z.string(),
|
|
@@ -63,7 +63,7 @@ export const NpmPackageVersionSchema = z
|
|
|
63
63
|
email: z.string().optional(),
|
|
64
64
|
url: z.string().optional(),
|
|
65
65
|
})
|
|
66
|
-
.
|
|
66
|
+
.loose(),
|
|
67
67
|
])
|
|
68
68
|
.optional(),
|
|
69
69
|
license: z.string().optional(),
|
|
@@ -72,60 +72,60 @@ export const NpmPackageVersionSchema = z
|
|
|
72
72
|
type: z.string().optional(),
|
|
73
73
|
url: z.string().optional(),
|
|
74
74
|
})
|
|
75
|
-
.
|
|
75
|
+
.loose()
|
|
76
76
|
.optional(),
|
|
77
77
|
bugs: z
|
|
78
78
|
.object({
|
|
79
79
|
url: z.string().optional(),
|
|
80
80
|
})
|
|
81
|
-
.
|
|
81
|
+
.loose()
|
|
82
82
|
.optional(),
|
|
83
83
|
homepage: z.string().optional(),
|
|
84
|
-
dependencies: z.record(z.string()).optional(),
|
|
85
|
-
devDependencies: z.record(z.string()).optional(),
|
|
86
|
-
peerDependencies: z.record(z.string()).optional(),
|
|
84
|
+
dependencies: z.record(z.string(), z.string()).optional(),
|
|
85
|
+
devDependencies: z.record(z.string(), z.string()).optional(),
|
|
86
|
+
peerDependencies: z.record(z.string(), z.string()).optional(),
|
|
87
87
|
types: z.string().optional(),
|
|
88
88
|
typings: z.string().optional(),
|
|
89
89
|
dist: z
|
|
90
90
|
.object({ shasum: z.string().optional(), tarball: z.string().optional() })
|
|
91
|
-
.
|
|
91
|
+
.loose()
|
|
92
92
|
.optional(),
|
|
93
93
|
})
|
|
94
|
-
.
|
|
94
|
+
.loose();
|
|
95
95
|
export const NpmPackageInfoSchema = z
|
|
96
96
|
.object({
|
|
97
97
|
name: z.string(),
|
|
98
|
-
'dist-tags': z.record(z.string()),
|
|
99
|
-
versions: z.record(NpmPackageVersionSchema),
|
|
100
|
-
time: z.record(z.string()).optional(),
|
|
98
|
+
'dist-tags': z.record(z.string(), z.string()),
|
|
99
|
+
versions: z.record(z.string(), NpmPackageVersionSchema),
|
|
100
|
+
time: z.record(z.string(), z.string()).optional(),
|
|
101
101
|
repository: z
|
|
102
102
|
.object({
|
|
103
103
|
type: z.string().optional(),
|
|
104
104
|
url: z.string().optional(),
|
|
105
105
|
})
|
|
106
|
-
.
|
|
106
|
+
.loose()
|
|
107
107
|
.optional(),
|
|
108
108
|
bugs: z
|
|
109
109
|
.object({
|
|
110
110
|
url: z.string().optional(),
|
|
111
111
|
})
|
|
112
|
-
.
|
|
112
|
+
.loose()
|
|
113
113
|
.optional(),
|
|
114
114
|
homepage: z.string().optional(),
|
|
115
115
|
maintainers: z.array(NpmMaintainerSchema).optional(),
|
|
116
116
|
})
|
|
117
|
-
.
|
|
117
|
+
.loose();
|
|
118
118
|
export const NpmPackageDataSchema = z.object({
|
|
119
119
|
name: z.string(),
|
|
120
120
|
version: z.string(),
|
|
121
121
|
description: z.string().optional(),
|
|
122
122
|
license: z.string().optional(),
|
|
123
|
-
dependencies: z.record(z.string()).optional(),
|
|
124
|
-
devDependencies: z.record(z.string()).optional(),
|
|
125
|
-
peerDependencies: z.record(z.string()).optional(),
|
|
123
|
+
dependencies: z.record(z.string(), z.string()).optional(),
|
|
124
|
+
devDependencies: z.record(z.string(), z.string()).optional(),
|
|
125
|
+
peerDependencies: z.record(z.string(), z.string()).optional(),
|
|
126
126
|
types: z.string().optional(),
|
|
127
127
|
typings: z.string().optional(),
|
|
128
|
-
});
|
|
128
|
+
}).loose();
|
|
129
129
|
export const BundlephobiaDataSchema = z.object({
|
|
130
130
|
size: z.number(),
|
|
131
131
|
gzip: z.number(),
|
|
@@ -231,7 +231,7 @@ export const NpmSearchResultSchema = z
|
|
|
231
231
|
})),
|
|
232
232
|
total: z.number(), // total is a sibling of objects
|
|
233
233
|
})
|
|
234
|
-
.
|
|
234
|
+
.loose();
|
|
235
235
|
// Logger function that uses stderr - only for critical errors
|
|
236
236
|
const log = (...args) => {
|
|
237
237
|
// Filter out server status messages
|
|
@@ -257,9 +257,15 @@ function isNpmPackageInfo(data) {
|
|
|
257
257
|
}
|
|
258
258
|
function isNpmPackageData(data) {
|
|
259
259
|
try {
|
|
260
|
-
|
|
260
|
+
// Use safeParse to get error details
|
|
261
|
+
const result = NpmPackageDataSchema.safeParse(data);
|
|
262
|
+
if (!result.success) {
|
|
263
|
+
console.error('isNpmPackageData validation failed:', JSON.stringify(result.error.issues, null, 2));
|
|
264
|
+
}
|
|
265
|
+
return result.success;
|
|
261
266
|
}
|
|
262
|
-
catch {
|
|
267
|
+
catch (e) {
|
|
268
|
+
console.error('isNpmPackageData threw exception:', e);
|
|
263
269
|
return false;
|
|
264
270
|
}
|
|
265
271
|
}
|
|
@@ -273,7 +279,11 @@ function isBundlephobiaData(data) {
|
|
|
273
279
|
}
|
|
274
280
|
function isNpmDownloadsData(data) {
|
|
275
281
|
try {
|
|
276
|
-
|
|
282
|
+
const result = NpmDownloadsDataSchema.safeParse(data);
|
|
283
|
+
if (!result.success) {
|
|
284
|
+
console.error('isNpmDownloadsData validation failed:', JSON.stringify(result.error.issues, null, 2));
|
|
285
|
+
}
|
|
286
|
+
return result.success;
|
|
277
287
|
}
|
|
278
288
|
catch {
|
|
279
289
|
return false;
|
|
@@ -909,15 +919,67 @@ export async function handleNpmSize(args) {
|
|
|
909
919
|
};
|
|
910
920
|
}
|
|
911
921
|
}
|
|
922
|
+
// Helper to detect dependencies
|
|
923
|
+
async function getPackageDependencies(pkgName, version) {
|
|
924
|
+
try {
|
|
925
|
+
const response = await fetch(`https://registry.npmjs.org/${pkgName}/${version}`, {
|
|
926
|
+
headers: { Accept: 'application/json', 'User-Agent': 'NPM-Sentinel-MCP' },
|
|
927
|
+
});
|
|
928
|
+
if (!response.ok)
|
|
929
|
+
return { dependencies: {}, devDependencies: {} };
|
|
930
|
+
const data = (await response.json());
|
|
931
|
+
return {
|
|
932
|
+
dependencies: data.dependencies || {},
|
|
933
|
+
devDependencies: data.devDependencies || {},
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
catch (error) {
|
|
937
|
+
console.error(`Error fetching dependencies for ${pkgName}:`, error);
|
|
938
|
+
return { dependencies: {}, devDependencies: {} };
|
|
939
|
+
}
|
|
940
|
+
}
|
|
912
941
|
export async function handleNpmVulnerabilities(args) {
|
|
913
942
|
try {
|
|
914
943
|
const packagesToProcess = args.packages || [];
|
|
915
944
|
if (packagesToProcess.length === 0) {
|
|
916
945
|
throw new Error('No package names provided');
|
|
917
946
|
}
|
|
918
|
-
|
|
947
|
+
// Prepare batch query, checking cache first
|
|
948
|
+
const finalBatchQueries = [];
|
|
949
|
+
const packageMap = new Map();
|
|
950
|
+
const cachedResultsMap = new Map();
|
|
951
|
+
const addToQuery = (name, releaseVersion, isDep) => {
|
|
952
|
+
const version = releaseVersion === 'latest' ? undefined : releaseVersion;
|
|
953
|
+
const key = `${name}@${version || 'latest'}`;
|
|
954
|
+
if (packageMap.has(key))
|
|
955
|
+
return; // Already requested/processed
|
|
956
|
+
// Check Cache
|
|
957
|
+
const cacheKey = generateCacheKey('handleNpmVulnerabilities', name, version || 'all');
|
|
958
|
+
const cachedData = cacheGet(cacheKey);
|
|
959
|
+
if (cachedData) {
|
|
960
|
+
// Store cached result directly using the same structure as we will build later
|
|
961
|
+
cachedResultsMap.set(key, {
|
|
962
|
+
package: `${name}${version ? `@${version}` : ''}`,
|
|
963
|
+
isDependency: isDep,
|
|
964
|
+
vulnerabilities: cachedData.vulnerabilities,
|
|
965
|
+
count: cachedData.vulnerabilities.length,
|
|
966
|
+
status: cachedData.vulnerabilities.length > 0 ? 'vulnerable' : 'secure',
|
|
967
|
+
source: 'cache'
|
|
968
|
+
});
|
|
969
|
+
packageMap.set(key, { name, version, isDependency: isDep });
|
|
970
|
+
}
|
|
971
|
+
else {
|
|
972
|
+
// Not in cache, add to API query
|
|
973
|
+
packageMap.set(key, { name, version, isDependency: isDep });
|
|
974
|
+
finalBatchQueries.push({
|
|
975
|
+
package: { name, ecosystem: 'npm' },
|
|
976
|
+
version: version === 'latest' ? undefined : version,
|
|
977
|
+
});
|
|
978
|
+
}
|
|
979
|
+
};
|
|
980
|
+
await Promise.all(packagesToProcess.map(async (pkgInput) => {
|
|
919
981
|
let name = '';
|
|
920
|
-
let version =
|
|
982
|
+
let version = 'latest';
|
|
921
983
|
if (typeof pkgInput === 'string') {
|
|
922
984
|
const atIdx = pkgInput.lastIndexOf('@');
|
|
923
985
|
if (atIdx > 0) {
|
|
@@ -928,142 +990,94 @@ export async function handleNpmVulnerabilities(args) {
|
|
|
928
990
|
name = pkgInput;
|
|
929
991
|
}
|
|
930
992
|
}
|
|
931
|
-
else
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
};
|
|
946
|
-
}
|
|
947
|
-
const osvBody = {
|
|
948
|
-
package: {
|
|
949
|
-
name,
|
|
950
|
-
ecosystem: 'npm',
|
|
951
|
-
},
|
|
952
|
-
};
|
|
953
|
-
if (version) {
|
|
954
|
-
osvBody.version = version;
|
|
993
|
+
else {
|
|
994
|
+
return; // Skip invalid
|
|
995
|
+
}
|
|
996
|
+
// Add main package
|
|
997
|
+
addToQuery(name, version, false);
|
|
998
|
+
// Add dependencies (only if version specified)
|
|
999
|
+
if (version !== 'latest') {
|
|
1000
|
+
const { dependencies } = await getPackageDependencies(name, version);
|
|
1001
|
+
for (const [depName, depVersion] of Object.entries(dependencies)) {
|
|
1002
|
+
const cleanVersion = depVersion.replace(/[\^~]/g, '');
|
|
1003
|
+
if (/^\d+\.\d+\.\d+/.test(cleanVersion)) {
|
|
1004
|
+
addToQuery(depName, cleanVersion, true);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
955
1007
|
}
|
|
956
|
-
|
|
1008
|
+
}));
|
|
1009
|
+
let apiResults = [];
|
|
1010
|
+
if (finalBatchQueries.length > 0) {
|
|
1011
|
+
// Perform Batch API call to OSV for non-cached items
|
|
1012
|
+
const response = await fetch('https://api.osv.dev/v1/querybatch', {
|
|
957
1013
|
method: 'POST',
|
|
958
|
-
headers: {
|
|
959
|
-
|
|
960
|
-
},
|
|
961
|
-
body: JSON.stringify(osvBody),
|
|
1014
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1015
|
+
body: JSON.stringify({ queries: finalBatchQueries }),
|
|
962
1016
|
});
|
|
963
|
-
const queryVersionSpecified = !!version;
|
|
964
1017
|
if (!response.ok) {
|
|
965
|
-
|
|
966
|
-
package: packageNameForOutput,
|
|
967
|
-
versionQueried: version || null,
|
|
968
|
-
status: 'error',
|
|
969
|
-
error: `OSV API Error: ${response.statusText}`,
|
|
970
|
-
vulnerabilities: [],
|
|
971
|
-
};
|
|
972
|
-
// Do not cache error responses from OSV API as they might be temporary
|
|
973
|
-
return errorResult;
|
|
974
|
-
}
|
|
975
|
-
const data = (await response.json());
|
|
976
|
-
const vulns = data.vulns || [];
|
|
977
|
-
let message;
|
|
978
|
-
if (vulns.length === 0) {
|
|
979
|
-
message = `No known vulnerabilities found${queryVersionSpecified ? ' for the specified version' : ''}.`;
|
|
980
|
-
}
|
|
981
|
-
else {
|
|
982
|
-
message = `${vulns.length} vulnerability(ies) found${queryVersionSpecified ? ' for the specified version' : ''}.`;
|
|
1018
|
+
throw new Error(`OSV Batch API Error: ${response.status} ${response.statusText}`);
|
|
983
1019
|
}
|
|
1020
|
+
const batchData = (await response.json());
|
|
1021
|
+
apiResults = batchData.results || [];
|
|
1022
|
+
}
|
|
1023
|
+
// Reconstruct all results (Cache + API)
|
|
1024
|
+
// We iterate over the packageMap to maintain order essentially, or we reconstruct based on what we see
|
|
1025
|
+
// Since map iteration order is insertion order, we can use that to return results generally in order of discovery
|
|
1026
|
+
// Map API results back to their query keys to merge easily
|
|
1027
|
+
const apiResultsMap = new Map();
|
|
1028
|
+
finalBatchQueries.forEach((query, index) => {
|
|
1029
|
+
const vulns = apiResults[index]?.vulns || [];
|
|
1030
|
+
const pkgName = query.package.name;
|
|
1031
|
+
const pkgVersion = query.version;
|
|
1032
|
+
const key = `${pkgName}@${pkgVersion || 'latest'}`;
|
|
1033
|
+
apiResultsMap.set(key, vulns);
|
|
1034
|
+
});
|
|
1035
|
+
const processedResults = [];
|
|
1036
|
+
for (const [key, info] of packageMap.entries()) {
|
|
1037
|
+
if (cachedResultsMap.has(key)) {
|
|
1038
|
+
processedResults.push(cachedResultsMap.get(key));
|
|
1039
|
+
continue;
|
|
1040
|
+
}
|
|
1041
|
+
// Process API result
|
|
1042
|
+
const vulns = apiResultsMap.get(key) || [];
|
|
984
1043
|
const processedVulns = vulns.map((vuln) => {
|
|
985
|
-
const sev = typeof vuln.severity === 'object'
|
|
986
|
-
? vuln.severity.type || 'Unknown'
|
|
987
|
-
: vuln.severity || 'Unknown';
|
|
1044
|
+
const sev = typeof vuln.severity === 'object' ? vuln.severity.type || 'Unknown' : vuln.severity || 'Unknown';
|
|
988
1045
|
const refs = vuln.references ? vuln.references.map((r) => r.url) : [];
|
|
989
|
-
const affectedRanges = [];
|
|
990
|
-
const affectedVersionsListed = [];
|
|
991
1046
|
const vulnerabilityDetails = {
|
|
992
|
-
|
|
1047
|
+
id: vuln.id,
|
|
1048
|
+
summary: vuln.summary || 'No summary available',
|
|
993
1049
|
severity: sev,
|
|
994
1050
|
references: refs,
|
|
1051
|
+
aliases: vuln.aliases || [],
|
|
1052
|
+
modified: vuln.modified,
|
|
1053
|
+
published: vuln.published,
|
|
995
1054
|
};
|
|
996
|
-
if (vuln.affected
|
|
997
|
-
|
|
998
|
-
const firstAffectedEvents = vuln.affected[0]?.ranges?.[0]?.events;
|
|
999
|
-
if (firstAffectedEvents) {
|
|
1000
|
-
const introducedEvent = firstAffectedEvents.find((e) => e.introduced);
|
|
1001
|
-
const fixedEvent = firstAffectedEvents.find((e) => e.fixed);
|
|
1002
|
-
if (introducedEvent?.introduced)
|
|
1003
|
-
lifecycle.introduced = introducedEvent.introduced;
|
|
1004
|
-
if (fixedEvent?.fixed)
|
|
1005
|
-
lifecycle.fixed = fixedEvent.fixed;
|
|
1006
|
-
}
|
|
1007
|
-
if (Object.keys(lifecycle).length > 0) {
|
|
1008
|
-
vulnerabilityDetails.lifecycle = lifecycle;
|
|
1009
|
-
if (queryVersionSpecified && version && lifecycle.fixed) {
|
|
1010
|
-
const queriedParts = version.split('.').map(Number);
|
|
1011
|
-
const fixedParts = lifecycle.fixed.split('.').map(Number);
|
|
1012
|
-
let isFixedDecision = false;
|
|
1013
|
-
const maxLength = Math.max(queriedParts.length, fixedParts.length);
|
|
1014
|
-
for (let i = 0; i < maxLength; i++) {
|
|
1015
|
-
const qp = queriedParts[i] || 0;
|
|
1016
|
-
const fp = fixedParts[i] || 0;
|
|
1017
|
-
if (fp < qp) {
|
|
1018
|
-
isFixedDecision = true;
|
|
1019
|
-
break;
|
|
1020
|
-
}
|
|
1021
|
-
if (fp > qp) {
|
|
1022
|
-
isFixedDecision = false;
|
|
1023
|
-
break;
|
|
1024
|
-
}
|
|
1025
|
-
if (i === maxLength - 1) {
|
|
1026
|
-
isFixedDecision = fixedParts.length <= queriedParts.length;
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
vulnerabilityDetails.isFixedInQueriedVersion = isFixedDecision;
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
if (!queryVersionSpecified && vuln.affected) {
|
|
1034
|
-
for (const aff of vuln.affected) {
|
|
1035
|
-
if (aff.ranges) {
|
|
1036
|
-
for (const range of aff.ranges) {
|
|
1037
|
-
affectedRanges.push({ type: range.type, events: range.events });
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
if (aff.versions && aff.versions.length > 0) {
|
|
1041
|
-
affectedVersionsListed.push(...aff.versions);
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
1044
|
-
if (affectedRanges.length > 0) {
|
|
1045
|
-
vulnerabilityDetails.affectedRanges = affectedRanges;
|
|
1046
|
-
}
|
|
1047
|
-
if (affectedVersionsListed.length > 0) {
|
|
1048
|
-
vulnerabilityDetails.affectedVersionsListed = affectedVersionsListed;
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1055
|
+
if (vuln.affected)
|
|
1056
|
+
vulnerabilityDetails.affected = vuln.affected;
|
|
1051
1057
|
return vulnerabilityDetails;
|
|
1052
1058
|
});
|
|
1053
|
-
const
|
|
1059
|
+
const resultEntry = {
|
|
1060
|
+
package: `${info.name}${info.version && info.version !== 'latest' && info.version !== undefined ? `@${info.version}` : ''}`,
|
|
1061
|
+
isDependency: info.isDependency,
|
|
1054
1062
|
vulnerabilities: processedVulns,
|
|
1055
|
-
|
|
1063
|
+
count: processedVulns.length,
|
|
1064
|
+
status: processedVulns.length > 0 ? 'vulnerable' : 'secure',
|
|
1065
|
+
message: processedVulns.length > 0 ? `${processedVulns.length} vulnerability(ies) found` : 'No known vulnerabilities found',
|
|
1056
1066
|
};
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
status: 'success',
|
|
1067
|
+
processedResults.push(resultEntry);
|
|
1068
|
+
// Cache this result for future
|
|
1069
|
+
const cacheKey = generateCacheKey('handleNpmVulnerabilities', info.name, info.version || 'all');
|
|
1070
|
+
cacheSet(cacheKey, {
|
|
1062
1071
|
vulnerabilities: processedVulns,
|
|
1063
|
-
message:
|
|
1064
|
-
};
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1072
|
+
message: `${processedVulns.length} vulnerabilities found`
|
|
1073
|
+
}, CACHE_TTL_MEDIUM);
|
|
1074
|
+
}
|
|
1075
|
+
// Filter final output
|
|
1076
|
+
const finalOutput = processedResults.filter(r => r.count > 0 || !r.isDependency);
|
|
1077
|
+
const responseJson = JSON.stringify({
|
|
1078
|
+
summary: `Scanned ${packageMap.size} packages (including dependencies). Found vulnerabilities in ${finalOutput.filter(r => r.count > 0).length} packages. (${cachedResultsMap.size} from cache, ${finalBatchQueries.length} from API)`,
|
|
1079
|
+
results: finalOutput
|
|
1080
|
+
}, null, 2);
|
|
1067
1081
|
return { content: [{ type: 'text', text: responseJson }], isError: false };
|
|
1068
1082
|
}
|
|
1069
1083
|
catch (error) {
|
|
@@ -3091,17 +3105,13 @@ export default function createServer({ config, }) {
|
|
|
3091
3105
|
// Create server instance
|
|
3092
3106
|
const server = new McpServer({
|
|
3093
3107
|
name: 'npm-sentinel-mcp',
|
|
3094
|
-
version: '1.
|
|
3095
|
-
capabilities: {
|
|
3096
|
-
resources: {},
|
|
3097
|
-
},
|
|
3108
|
+
version: '1.12.0',
|
|
3098
3109
|
});
|
|
3099
3110
|
// Update paths to be relative to the package
|
|
3100
3111
|
const README_PATH = path.join(packageRoot, 'README.md');
|
|
3101
3112
|
const LLMS_FULL_TEXT_PATH = path.join(packageRoot, 'llms-full.txt');
|
|
3102
3113
|
// Register README.md resource
|
|
3103
|
-
server.
|
|
3104
|
-
name: 'Server README',
|
|
3114
|
+
server.registerResource('serverReadme', 'doc://server/readme', {
|
|
3105
3115
|
description: 'Main documentation and usage guide for this NPM Info Server.',
|
|
3106
3116
|
mimeType: 'text/markdown',
|
|
3107
3117
|
}, async (uri) => {
|
|
@@ -3127,8 +3137,7 @@ export default function createServer({ config, }) {
|
|
|
3127
3137
|
}
|
|
3128
3138
|
});
|
|
3129
3139
|
// Register llms-full.txt resource (MCP Specification)
|
|
3130
|
-
server.
|
|
3131
|
-
name: 'MCP Full Specification',
|
|
3140
|
+
server.registerResource('mcpSpecification', 'doc://mcp/specification', {
|
|
3132
3141
|
description: 'The llms-full.txt content providing a comprehensive overview of the Model Context Protocol.',
|
|
3133
3142
|
mimeType: 'text/plain',
|
|
3134
3143
|
}, async (uri) => {
|
|
@@ -3154,207 +3163,283 @@ export default function createServer({ config, }) {
|
|
|
3154
3163
|
}
|
|
3155
3164
|
});
|
|
3156
3165
|
// Add NPM tools - Ensuring each tool registration is complete and correct
|
|
3157
|
-
server.
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3166
|
+
server.registerTool('npmVersions', {
|
|
3167
|
+
description: 'Get all available versions of an NPM package',
|
|
3168
|
+
inputSchema: {
|
|
3169
|
+
packages: z.array(z.string()).describe('List of package names to get versions for'),
|
|
3170
|
+
},
|
|
3171
|
+
annotations: {
|
|
3172
|
+
title: 'Get All Package Versions',
|
|
3173
|
+
readOnlyHint: true,
|
|
3174
|
+
openWorldHint: true,
|
|
3175
|
+
idempotentHint: true,
|
|
3176
|
+
},
|
|
3164
3177
|
}, async (args) => {
|
|
3165
3178
|
return await handleNpmVersions(args);
|
|
3166
3179
|
});
|
|
3167
|
-
server.
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3180
|
+
server.registerTool('npmLatest', {
|
|
3181
|
+
description: 'Get the latest version and changelog of an NPM package',
|
|
3182
|
+
inputSchema: {
|
|
3183
|
+
packages: z.array(z.string()).describe('List of package names to get latest versions for'),
|
|
3184
|
+
},
|
|
3185
|
+
annotations: {
|
|
3186
|
+
title: 'Get Latest Package Information',
|
|
3187
|
+
readOnlyHint: true,
|
|
3188
|
+
openWorldHint: true,
|
|
3189
|
+
idempotentHint: true, // Result for 'latest' tag can change, but call itself is idempotent
|
|
3190
|
+
},
|
|
3174
3191
|
}, async (args) => {
|
|
3175
3192
|
return await handleNpmLatest(args);
|
|
3176
3193
|
});
|
|
3177
|
-
server.
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3194
|
+
server.registerTool('npmDeps', {
|
|
3195
|
+
description: 'Analyze dependencies and devDependencies of an NPM package',
|
|
3196
|
+
inputSchema: {
|
|
3197
|
+
packages: z.array(z.string()).describe('List of package names to analyze dependencies for'),
|
|
3198
|
+
},
|
|
3199
|
+
annotations: {
|
|
3200
|
+
title: 'Get Package Dependencies',
|
|
3201
|
+
readOnlyHint: true,
|
|
3202
|
+
openWorldHint: true,
|
|
3203
|
+
idempotentHint: true,
|
|
3204
|
+
},
|
|
3184
3205
|
}, async (args) => {
|
|
3185
3206
|
return await handleNpmDeps(args);
|
|
3186
3207
|
});
|
|
3187
|
-
server.
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3208
|
+
server.registerTool('npmTypes', {
|
|
3209
|
+
description: 'Check TypeScript types availability and version for a package',
|
|
3210
|
+
inputSchema: {
|
|
3211
|
+
packages: z.array(z.string()).describe('List of package names to check types for'),
|
|
3212
|
+
},
|
|
3213
|
+
annotations: {
|
|
3214
|
+
title: 'Check TypeScript Type Availability',
|
|
3215
|
+
readOnlyHint: true,
|
|
3216
|
+
openWorldHint: true,
|
|
3217
|
+
idempotentHint: true,
|
|
3218
|
+
},
|
|
3194
3219
|
}, async (args) => {
|
|
3195
3220
|
return await handleNpmTypes(args);
|
|
3196
3221
|
});
|
|
3197
|
-
server.
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3222
|
+
server.registerTool('npmSize', {
|
|
3223
|
+
description: 'Get package size information including dependencies and bundle size',
|
|
3224
|
+
inputSchema: {
|
|
3225
|
+
packages: z.array(z.string()).describe('List of package names to get size information for'),
|
|
3226
|
+
},
|
|
3227
|
+
annotations: {
|
|
3228
|
+
title: 'Get Package Size (Bundlephobia)',
|
|
3229
|
+
readOnlyHint: true,
|
|
3230
|
+
openWorldHint: true,
|
|
3231
|
+
idempotentHint: true,
|
|
3232
|
+
},
|
|
3204
3233
|
}, async (args) => {
|
|
3205
3234
|
return await handleNpmSize(args);
|
|
3206
3235
|
});
|
|
3207
|
-
server.
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3236
|
+
server.registerTool('npmVulnerabilities', {
|
|
3237
|
+
description: 'Check for known vulnerabilities in packages',
|
|
3238
|
+
inputSchema: {
|
|
3239
|
+
packages: z.array(z.string()).describe('List of package names to check for vulnerabilities'),
|
|
3240
|
+
},
|
|
3241
|
+
annotations: {
|
|
3242
|
+
title: 'Check Package Vulnerabilities (OSV.dev)',
|
|
3243
|
+
readOnlyHint: true,
|
|
3244
|
+
openWorldHint: true,
|
|
3245
|
+
idempotentHint: false, // Vulnerability data can change frequently
|
|
3246
|
+
},
|
|
3214
3247
|
}, async (args) => {
|
|
3215
3248
|
return await handleNpmVulnerabilities(args);
|
|
3216
3249
|
});
|
|
3217
|
-
server.
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
.
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3250
|
+
server.registerTool('npmTrends', {
|
|
3251
|
+
description: 'Get download trends and popularity metrics for packages',
|
|
3252
|
+
inputSchema: {
|
|
3253
|
+
packages: z.array(z.string()).describe('List of package names to get trends for'),
|
|
3254
|
+
period: z
|
|
3255
|
+
.enum(['last-week', 'last-month', 'last-year'])
|
|
3256
|
+
.describe('Time period for trends. Options: "last-week", "last-month", "last-year"')
|
|
3257
|
+
.optional()
|
|
3258
|
+
.default('last-month'),
|
|
3259
|
+
},
|
|
3260
|
+
annotations: {
|
|
3261
|
+
title: 'Get NPM Package Download Trends',
|
|
3262
|
+
readOnlyHint: true,
|
|
3263
|
+
openWorldHint: true,
|
|
3264
|
+
idempotentHint: true, // Trends for a fixed past period are idempotent
|
|
3265
|
+
},
|
|
3229
3266
|
}, async (args) => {
|
|
3230
3267
|
return await handleNpmTrends(args);
|
|
3231
3268
|
});
|
|
3232
|
-
server.
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3269
|
+
server.registerTool('npmCompare', {
|
|
3270
|
+
description: 'Compare multiple NPM packages based on various metrics',
|
|
3271
|
+
inputSchema: {
|
|
3272
|
+
packages: z.array(z.string()).describe('List of package names to compare'),
|
|
3273
|
+
},
|
|
3274
|
+
annotations: {
|
|
3275
|
+
title: 'Compare NPM Packages',
|
|
3276
|
+
readOnlyHint: true,
|
|
3277
|
+
openWorldHint: true,
|
|
3278
|
+
idempotentHint: true,
|
|
3279
|
+
},
|
|
3239
3280
|
}, async (args) => {
|
|
3240
3281
|
return await handleNpmCompare(args);
|
|
3241
3282
|
});
|
|
3242
|
-
server.
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3283
|
+
server.registerTool('npmMaintainers', {
|
|
3284
|
+
description: 'Get maintainers information for NPM packages',
|
|
3285
|
+
inputSchema: {
|
|
3286
|
+
packages: z.array(z.string()).describe('List of package names to get maintainers for'),
|
|
3287
|
+
},
|
|
3288
|
+
annotations: {
|
|
3289
|
+
title: 'Get NPM Package Maintainers',
|
|
3290
|
+
readOnlyHint: true,
|
|
3291
|
+
openWorldHint: true,
|
|
3292
|
+
idempotentHint: true,
|
|
3293
|
+
},
|
|
3249
3294
|
}, async (args) => {
|
|
3250
3295
|
return await handleNpmMaintainers(args);
|
|
3251
3296
|
});
|
|
3252
|
-
server.
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3297
|
+
server.registerTool('npmScore', {
|
|
3298
|
+
description: 'Get consolidated package score based on quality, maintenance, and popularity metrics',
|
|
3299
|
+
inputSchema: {
|
|
3300
|
+
packages: z.array(z.string()).describe('List of package names to get scores for'),
|
|
3301
|
+
},
|
|
3302
|
+
annotations: {
|
|
3303
|
+
title: 'Get NPM Package Score (NPMS.io)',
|
|
3304
|
+
readOnlyHint: true,
|
|
3305
|
+
openWorldHint: true,
|
|
3306
|
+
idempotentHint: true, // Score for a version is stable, for 'latest' can change
|
|
3307
|
+
},
|
|
3259
3308
|
}, async (args) => {
|
|
3260
3309
|
return await handleNpmScore(args);
|
|
3261
3310
|
});
|
|
3262
|
-
server.
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3311
|
+
server.registerTool('npmPackageReadme', {
|
|
3312
|
+
description: 'Get the README content for NPM packages',
|
|
3313
|
+
inputSchema: {
|
|
3314
|
+
packages: z.array(z.string()).describe('List of package names to get READMEs for'),
|
|
3315
|
+
},
|
|
3316
|
+
annotations: {
|
|
3317
|
+
title: 'Get NPM Package README',
|
|
3318
|
+
readOnlyHint: true,
|
|
3319
|
+
openWorldHint: true,
|
|
3320
|
+
idempotentHint: true,
|
|
3321
|
+
},
|
|
3269
3322
|
}, async (args) => {
|
|
3270
3323
|
return await handleNpmPackageReadme(args);
|
|
3271
3324
|
});
|
|
3272
|
-
server.
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
.
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3325
|
+
server.registerTool('npmSearch', {
|
|
3326
|
+
description: 'Search for NPM packages with optional limit',
|
|
3327
|
+
inputSchema: {
|
|
3328
|
+
query: z.string().describe('Search query for packages'),
|
|
3329
|
+
limit: z
|
|
3330
|
+
.number()
|
|
3331
|
+
.min(1)
|
|
3332
|
+
.max(50)
|
|
3333
|
+
.optional()
|
|
3334
|
+
.describe('Maximum number of results to return (default: 10)'),
|
|
3335
|
+
},
|
|
3336
|
+
annotations: {
|
|
3337
|
+
title: 'Search NPM Packages',
|
|
3338
|
+
readOnlyHint: true,
|
|
3339
|
+
openWorldHint: true,
|
|
3340
|
+
idempotentHint: false, // Search results can change
|
|
3341
|
+
},
|
|
3285
3342
|
}, async (args) => {
|
|
3286
3343
|
return await handleNpmSearch(args);
|
|
3287
3344
|
});
|
|
3288
|
-
server.
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3345
|
+
server.registerTool('npmLicenseCompatibility', {
|
|
3346
|
+
description: 'Check license compatibility between multiple packages',
|
|
3347
|
+
inputSchema: {
|
|
3348
|
+
packages: z
|
|
3349
|
+
.array(z.string())
|
|
3350
|
+
.min(1)
|
|
3351
|
+
.describe('List of package names to check for license compatibility'),
|
|
3352
|
+
},
|
|
3353
|
+
annotations: {
|
|
3354
|
+
title: 'Check NPM License Compatibility',
|
|
3355
|
+
readOnlyHint: true,
|
|
3356
|
+
openWorldHint: true,
|
|
3357
|
+
idempotentHint: true,
|
|
3358
|
+
},
|
|
3298
3359
|
}, async (args) => {
|
|
3299
3360
|
return await handleNpmLicenseCompatibility(args);
|
|
3300
3361
|
});
|
|
3301
|
-
server.
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3362
|
+
server.registerTool('npmRepoStats', {
|
|
3363
|
+
description: 'Get repository statistics for NPM packages',
|
|
3364
|
+
inputSchema: {
|
|
3365
|
+
packages: z.array(z.string()).describe('List of package names to get repository stats for'),
|
|
3366
|
+
},
|
|
3367
|
+
annotations: {
|
|
3368
|
+
title: 'Get NPM Package Repository Stats (GitHub)',
|
|
3369
|
+
readOnlyHint: true,
|
|
3370
|
+
openWorldHint: true,
|
|
3371
|
+
idempotentHint: true, // Stats for a repo at a point in time, though they change over time
|
|
3372
|
+
},
|
|
3308
3373
|
}, async (args) => {
|
|
3309
3374
|
return await handleNpmRepoStats(args);
|
|
3310
3375
|
});
|
|
3311
|
-
server.
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3376
|
+
server.registerTool('npmDeprecated', {
|
|
3377
|
+
description: 'Check if packages are deprecated',
|
|
3378
|
+
inputSchema: {
|
|
3379
|
+
packages: z.array(z.string()).describe('List of package names to check for deprecation'),
|
|
3380
|
+
},
|
|
3381
|
+
annotations: {
|
|
3382
|
+
title: 'Check NPM Package Deprecation Status',
|
|
3383
|
+
readOnlyHint: true,
|
|
3384
|
+
openWorldHint: true,
|
|
3385
|
+
idempotentHint: true, // Deprecation status is generally stable for a version
|
|
3386
|
+
},
|
|
3318
3387
|
}, async (args) => {
|
|
3319
3388
|
return await handleNpmDeprecated(args);
|
|
3320
3389
|
});
|
|
3321
|
-
server.
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3390
|
+
server.registerTool('npmChangelogAnalysis', {
|
|
3391
|
+
description: 'Analyze changelog and release history of packages',
|
|
3392
|
+
inputSchema: {
|
|
3393
|
+
packages: z.array(z.string()).describe('List of package names to analyze changelogs for'),
|
|
3394
|
+
},
|
|
3395
|
+
annotations: {
|
|
3396
|
+
title: 'Analyze NPM Package Changelog (GitHub)',
|
|
3397
|
+
readOnlyHint: true,
|
|
3398
|
+
openWorldHint: true,
|
|
3399
|
+
idempotentHint: true,
|
|
3400
|
+
},
|
|
3328
3401
|
}, async (args) => {
|
|
3329
3402
|
return await handleNpmChangelogAnalysis(args);
|
|
3330
3403
|
});
|
|
3331
|
-
server.
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3404
|
+
server.registerTool('npmAlternatives', {
|
|
3405
|
+
description: 'Find alternative packages with similar functionality',
|
|
3406
|
+
inputSchema: {
|
|
3407
|
+
packages: z.array(z.string()).describe('List of package names to find alternatives for'),
|
|
3408
|
+
},
|
|
3409
|
+
annotations: {
|
|
3410
|
+
title: 'Find NPM Package Alternatives',
|
|
3411
|
+
readOnlyHint: true,
|
|
3412
|
+
openWorldHint: true,
|
|
3413
|
+
idempotentHint: false, // Search-based, results can change
|
|
3414
|
+
},
|
|
3338
3415
|
}, async (args) => {
|
|
3339
3416
|
return await handleNpmAlternatives(args);
|
|
3340
3417
|
});
|
|
3341
|
-
server.
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3418
|
+
server.registerTool('npmQuality', {
|
|
3419
|
+
description: 'Analyze package quality metrics',
|
|
3420
|
+
inputSchema: {
|
|
3421
|
+
packages: z.array(z.string()).describe('List of package names to analyze'),
|
|
3422
|
+
},
|
|
3423
|
+
annotations: {
|
|
3424
|
+
title: 'Analyze NPM Package Quality (NPMS.io)',
|
|
3425
|
+
readOnlyHint: true,
|
|
3426
|
+
openWorldHint: true,
|
|
3427
|
+
idempotentHint: true, // Score for a version is stable, for 'latest' can change
|
|
3428
|
+
},
|
|
3348
3429
|
}, async (args) => {
|
|
3349
3430
|
return await handleNpmQuality(args);
|
|
3350
3431
|
});
|
|
3351
|
-
server.
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3432
|
+
server.registerTool('npmMaintenance', {
|
|
3433
|
+
description: 'Analyze package maintenance metrics',
|
|
3434
|
+
inputSchema: {
|
|
3435
|
+
packages: z.array(z.string()).describe('List of package names to analyze'),
|
|
3436
|
+
},
|
|
3437
|
+
annotations: {
|
|
3438
|
+
title: 'Analyze NPM Package Maintenance (NPMS.io)',
|
|
3439
|
+
readOnlyHint: true,
|
|
3440
|
+
openWorldHint: true,
|
|
3441
|
+
idempotentHint: true, // Score for a version is stable, for 'latest' can change
|
|
3442
|
+
},
|
|
3358
3443
|
}, async (args) => {
|
|
3359
3444
|
return await handleNpmMaintenance(args);
|
|
3360
3445
|
});
|
|
@@ -3387,8 +3472,11 @@ async function main() {
|
|
|
3387
3472
|
// Type guard for NpmPackageVersionSchema
|
|
3388
3473
|
function isNpmPackageVersionData(data) {
|
|
3389
3474
|
try {
|
|
3390
|
-
|
|
3391
|
-
|
|
3475
|
+
const result = NpmPackageVersionSchema.safeParse(data);
|
|
3476
|
+
if (!result.success) {
|
|
3477
|
+
console.error('isNpmPackageVersionData validation failed:', JSON.stringify(result.error.issues, null, 2));
|
|
3478
|
+
}
|
|
3479
|
+
return result.success;
|
|
3392
3480
|
}
|
|
3393
3481
|
catch (e) {
|
|
3394
3482
|
// This catch block might not be strictly necessary with safeParse but kept for safety
|