mcp-package-version
Version:
An MCP server to provide LLMs the latest (stable) version of packages in package.json and requirements.txt files
89 lines (88 loc) • 3.82 kB
JavaScript
import axios from 'axios';
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
export class NpmHandler {
registry = 'https://registry.npmjs.org';
async getPackageVersion(packageName, currentVersion, constraints) {
// Check if package should be excluded
if (constraints?.excludePackage) {
return {
name: packageName,
currentVersion: currentVersion?.replace(/^[\^~]/, ''),
latestVersion: currentVersion?.replace(/^[\^~]/, '') || 'unknown',
registry: 'npm',
skipped: true,
skipReason: 'Package excluded from updates'
};
}
try {
const response = await axios.get(`${this.registry}/${encodeURIComponent(packageName)}`);
let latestVersion = response.data['dist-tags']?.latest;
if (!latestVersion) {
throw new Error('Latest version not found');
}
// If major version constraint exists, find the latest version within that major
if (constraints?.majorVersion !== undefined) {
const versions = Object.keys(response.data.versions || {});
const constrainedVersions = versions.filter(v => {
const major = parseInt(v.split('.')[0]);
return major === constraints.majorVersion;
});
if (constrainedVersions.length > 0) {
// Sort versions and get the latest within the major version
latestVersion = constrainedVersions.sort((a, b) => {
const [aMajor, aMinor, aPatch] = a.split('.').map(Number);
const [bMajor, bMinor, bPatch] = b.split('.').map(Number);
if (aMajor !== bMajor)
return bMajor - aMajor;
if (aMinor !== bMinor)
return bMinor - aMinor;
return bPatch - aPatch;
})[0];
}
}
const result = {
name: packageName,
latestVersion,
registry: 'npm'
};
if (currentVersion) {
// Remove any leading ^ or ~ from the current version
const cleanCurrentVersion = currentVersion.replace(/^[\^~]/, '');
result.currentVersion = cleanCurrentVersion;
}
if (constraints?.majorVersion !== undefined) {
result.skipReason = `Limited to major version ${constraints.majorVersion}`;
}
return result;
}
catch (error) {
console.error(`Error fetching npm package ${packageName}:`, error);
throw new McpError(ErrorCode.InternalError, `Failed to fetch npm package ${packageName}`);
}
}
async getLatestVersion(args) {
if (!args.dependencies || typeof args.dependencies !== 'object') {
throw new McpError(ErrorCode.InvalidParams, 'Invalid dependencies object');
}
const results = [];
for (const [name, version] of Object.entries(args.dependencies)) {
if (typeof version !== 'string')
continue;
try {
const result = await this.getPackageVersion(name, version, args.constraints?.[name]);
results.push(result);
}
catch (error) {
console.error(`Error checking npm package ${name}:`, error);
}
}
return {
content: [
{
type: 'text',
text: JSON.stringify(results, null, 2),
},
],
};
}
}