mcp-package-version
Version:
An MCP server to provide LLMs the latest (stable) version of packages in package.json and requirements.txt files
116 lines (115 loc) • 5.39 kB
JavaScript
import axios from 'axios';
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
export class SwiftHandler {
async getPackageVersion(packageUrl, currentVersion, versionRequirement, constraints) {
// Extract package name from URL
const packageName = packageUrl.split('/').pop()?.replace('.git', '') || packageUrl;
// Check if package should be excluded
if (constraints?.excludePackage) {
return {
name: packageName,
currentVersion: currentVersion,
latestVersion: currentVersion || 'unknown',
registry: 'swift',
skipped: true,
skipReason: 'Package excluded from updates'
};
}
try {
// For GitHub repositories, we can use the GitHub API to get the latest release
if (packageUrl.includes('github.com')) {
// Convert GitHub URL to API URL
// Example: https://github.com/apple/swift-argument-parser -> https://api.github.com/repos/apple/swift-argument-parser/releases
const apiUrl = packageUrl
.replace('https://github.com/', 'https://api.github.com/repos/')
.replace('.git', '') + '/releases';
const response = await axios.get(apiUrl);
if (!response.data || response.data.length === 0) {
throw new Error('No releases found');
}
// Find the latest release that's not a pre-release
let latestRelease = response.data.find((release) => !release.prerelease);
// If no stable release is found, use the latest release
if (!latestRelease) {
latestRelease = response.data[0];
}
let latestVersion = latestRelease.tag_name;
// Remove 'v' prefix if present
if (latestVersion.startsWith('v')) {
latestVersion = latestVersion.substring(1);
}
// If major version constraint exists, check if the latest version complies
if (constraints?.majorVersion !== undefined) {
const major = parseInt(latestVersion.split('.')[0]);
if (major !== constraints.majorVersion) {
// Find the latest release within the specified major version
const constrainedRelease = response.data.find((release) => {
let version = release.tag_name;
if (version.startsWith('v')) {
version = version.substring(1);
}
return parseInt(version.split('.')[0]) === constraints.majorVersion;
});
if (constrainedRelease) {
latestVersion = constrainedRelease.tag_name;
if (latestVersion.startsWith('v')) {
latestVersion = latestVersion.substring(1);
}
}
}
}
const result = {
name: packageName,
latestVersion,
registry: 'swift'
};
if (currentVersion) {
result.currentVersion = currentVersion;
}
if (constraints?.majorVersion !== undefined) {
result.skipReason = `Limited to major version ${constraints.majorVersion}`;
}
return result;
}
else {
// For non-GitHub repositories, we can't easily determine the latest version
// Return the current version as the latest version
return {
name: packageName,
currentVersion: currentVersion,
latestVersion: currentVersion || 'unknown',
registry: 'swift',
skipped: true,
skipReason: 'Non-GitHub repository, cannot determine latest version'
};
}
}
catch (error) {
console.error(`Error fetching Swift package ${packageName}:`, error);
throw new McpError(ErrorCode.InternalError, `Failed to fetch Swift package ${packageName}`);
}
}
async getLatestVersion(args) {
if (!args.dependencies || !Array.isArray(args.dependencies)) {
throw new McpError(ErrorCode.InvalidParams, 'Invalid dependencies array');
}
const results = [];
for (const dependency of args.dependencies) {
try {
const result = await this.getPackageVersion(dependency.url, dependency.version, dependency.requirement, args.constraints?.[dependency.url]);
results.push(result);
}
catch (error) {
console.error(`Error checking Swift package ${dependency.url}:`, error);
}
}
return {
content: [
{
type: 'text',
text: JSON.stringify(results, null, 2),
},
],
};
}
}