UNPKG

claude-flow-tbowman01

Version:

Enterprise-grade AI agent orchestration with ruv-swarm integration (Alpha Release)

347 lines 14.7 kB
/** * MCP Protocol Version Management and Compatibility Checking */ import { MCPError } from '../utils/errors.js'; /** * MCP Protocol Manager * Handles protocol version negotiation, compatibility checking, and feature management */ export class MCPProtocolManager { logger; supportedVersions = new Map(); currentVersion; serverCapabilities; knownVersions = [ { version: { major: 2024, minor: 11, patch: 5 }, name: 'MCP 2024.11.5', releaseDate: new Date('2024-11-01'), supportedFeatures: [ 'tools', 'prompts', 'resources', 'logging', 'sampling', 'notifications', 'tool_list_changed', 'resource_list_changed', 'prompt_list_changed', ], }, { version: { major: 2024, minor: 11, patch: 4 }, name: 'MCP 2024.11.4', releaseDate: new Date('2024-10-15'), supportedFeatures: [ 'tools', 'prompts', 'resources', 'logging', 'notifications', 'tool_list_changed', 'resource_list_changed', ], }, { version: { major: 2024, minor: 11, patch: 3 }, name: 'MCP 2024.11.3', releaseDate: new Date('2024-10-01'), supportedFeatures: ['tools', 'prompts', 'resources', 'logging', 'notifications'], }, { version: { major: 2024, minor: 10, patch: 0 }, name: 'MCP 2024.10.0', releaseDate: new Date('2024-09-01'), deprecated: true, deprecationDate: new Date('2024-11-01'), supportedFeatures: ['tools', 'prompts', 'resources', 'logging'], breakingChanges: ['Changed tool response format', 'Modified error codes'], migrationGuide: 'https://docs.mcp.io/migration/2024.10-to-2024.11', }, ]; constructor(logger, preferredVersion, serverCapabilities) { this.logger = logger; // Initialize supported versions for (const versionInfo of this.knownVersions) { const key = this.versionToString(versionInfo.version); this.supportedVersions.set(key, versionInfo); } // Set current version (latest supported or preferred) this.currentVersion = preferredVersion || this.getLatestSupportedVersion(); // Set server capabilities this.serverCapabilities = serverCapabilities || this.getDefaultCapabilities(); this.logger.info('Protocol manager initialized', { currentVersion: this.versionToString(this.currentVersion), supportedVersions: this.getSupportedVersionStrings(), }); } /** * Negotiate protocol version and capabilities with client */ async negotiateProtocol(clientParams) { this.logger.debug('Starting protocol negotiation', { clientVersion: this.versionToString(clientParams.protocolVersion), clientCapabilities: clientParams.capabilities, clientInfo: clientParams.clientInfo, }); const result = { agreedVersion: this.currentVersion, agreedCapabilities: { ...this.serverCapabilities }, clientCapabilities: clientParams.capabilities, serverCapabilities: this.serverCapabilities, warnings: [], limitations: [], }; try { // Check version compatibility const compatibility = this.checkCompatibility(clientParams.protocolVersion); if (!compatibility.compatible) { throw new MCPError(`Protocol version ${this.versionToString(clientParams.protocolVersion)} is not compatible. ${compatibility.errors.join(', ')}`); } // Use client's version if it's supported and newer if (this.isVersionSupported(clientParams.protocolVersion)) { const clientVersionInfo = this.getVersionInfo(clientParams.protocolVersion); const currentVersionInfo = this.getVersionInfo(this.currentVersion); if (clientVersionInfo && currentVersionInfo) { if (this.compareVersions(clientParams.protocolVersion, this.currentVersion) <= 0) { result.agreedVersion = clientParams.protocolVersion; } } } // Negotiate capabilities result.agreedCapabilities = this.negotiateCapabilities(clientParams.capabilities, this.serverCapabilities, result.agreedVersion); // Add warnings from compatibility check result.warnings.push(...compatibility.warnings); // Check for deprecated features const versionInfo = this.getVersionInfo(result.agreedVersion); if (versionInfo?.deprecated) { result.warnings.push(`Protocol version ${this.versionToString(result.agreedVersion)} is deprecated. ` + `Please upgrade to a newer version.`); } // Check for missing features const missingFeatures = this.getMissingFeatures(result.agreedVersion, result.agreedCapabilities); if (missingFeatures.length > 0) { result.limitations.push(`Some features may not be available: ${missingFeatures.join(', ')}`); } this.logger.info('Protocol negotiation completed', { agreedVersion: this.versionToString(result.agreedVersion), warnings: result.warnings.length, limitations: result.limitations.length, }); return result; } catch (error) { this.logger.error('Protocol negotiation failed', { clientVersion: this.versionToString(clientParams.protocolVersion), error, }); throw error; } } /** * Check compatibility between client and server versions */ checkCompatibility(clientVersion) { const result = { compatible: false, warnings: [], errors: [], }; const clientVersionInfo = this.getVersionInfo(clientVersion); const serverVersionInfo = this.getVersionInfo(this.currentVersion); // Check if version is known if (!clientVersionInfo) { result.errors.push(`Unknown protocol version: ${this.versionToString(clientVersion)}`); result.recommendedVersion = this.getLatestSupportedVersion(); return result; } // Check major version compatibility if (clientVersion.major !== this.currentVersion.major) { result.errors.push(`Major version mismatch: client ${clientVersion.major}, server ${this.currentVersion.major}`); return result; } // Check if client version is too new if (this.compareVersions(clientVersion, this.currentVersion) > 0) { result.errors.push(`Client version ${this.versionToString(clientVersion)} is newer than supported server version ${this.versionToString(this.currentVersion)}`); result.recommendedVersion = this.currentVersion; return result; } // Check for deprecated versions if (clientVersionInfo.deprecated) { result.warnings.push(`Client is using deprecated version ${this.versionToString(clientVersion)}. ` + `Support will be removed after ${clientVersionInfo.deprecationDate?.toISOString().split('T')[0]}`); result.recommendedVersion = this.getLatestSupportedVersion(); } // Check for missing features const serverFeatures = serverVersionInfo?.supportedFeatures || []; const clientFeatures = clientVersionInfo.supportedFeatures; const missingFeatures = serverFeatures.filter((feature) => !clientFeatures.includes(feature)); if (missingFeatures.length > 0) { result.missingFeatures = missingFeatures; result.warnings.push(`Client version lacks some server features: ${missingFeatures.join(', ')}`); } // Check for deprecated features being used const deprecatedFeatures = this.getDeprecatedFeatures(clientVersion); if (deprecatedFeatures.length > 0) { result.deprecatedFeatures = deprecatedFeatures; result.warnings.push(`Client version uses deprecated features: ${deprecatedFeatures.join(', ')}`); } result.compatible = true; return result; } /** * Get information about a specific protocol version */ getVersionInfo(version) { return this.supportedVersions.get(this.versionToString(version)); } /** * Check if a version is supported */ isVersionSupported(version) { return this.supportedVersions.has(this.versionToString(version)); } /** * Get the latest supported version */ getLatestSupportedVersion() { const versions = Array.from(this.supportedVersions.values()) .filter((v) => !v.deprecated) .sort((a, b) => this.compareVersions(b.version, a.version)); return versions[0]?.version || { major: 2024, minor: 11, patch: 5 }; } /** * Get all supported version strings */ getSupportedVersionStrings() { return Array.from(this.supportedVersions.keys()); } /** * Get current server capabilities */ getServerCapabilities() { return { ...this.serverCapabilities }; } /** * Update server capabilities */ updateServerCapabilities(capabilities) { this.serverCapabilities = { ...this.serverCapabilities, ...capabilities }; this.logger.info('Server capabilities updated', { capabilities: this.serverCapabilities }); } /** * Check if a feature is supported in a specific version */ isFeatureSupported(version, feature) { const versionInfo = this.getVersionInfo(version); return versionInfo?.supportedFeatures.includes(feature) || false; } versionToString(version) { return `${version.major}.${version.minor}.${version.patch}`; } compareVersions(a, b) { if (a.major !== b.major) return a.major - b.major; if (a.minor !== b.minor) return a.minor - b.minor; return a.patch - b.patch; } getDefaultCapabilities() { return { logging: { level: 'info', }, tools: { listChanged: true, }, resources: { listChanged: true, subscribe: false, }, prompts: { listChanged: true, }, }; } negotiateCapabilities(clientCapabilities, serverCapabilities, agreedVersion) { const result = {}; // Negotiate logging capabilities if (clientCapabilities.logging && serverCapabilities.logging) { result.logging = { level: this.negotiateLogLevel(clientCapabilities.logging.level, serverCapabilities.logging.level), }; } // Negotiate tools capabilities if (clientCapabilities.tools && serverCapabilities.tools) { result.tools = { listChanged: clientCapabilities.tools.listChanged && serverCapabilities.tools.listChanged, }; } // Negotiate resources capabilities if (clientCapabilities.resources && serverCapabilities.resources) { result.resources = { listChanged: clientCapabilities.resources.listChanged && serverCapabilities.resources.listChanged, subscribe: clientCapabilities.resources.subscribe && serverCapabilities.resources.subscribe, }; } // Negotiate prompts capabilities if (clientCapabilities.prompts && serverCapabilities.prompts) { result.prompts = { listChanged: clientCapabilities.prompts.listChanged && serverCapabilities.prompts.listChanged, }; } // Only include capabilities supported by the agreed version return this.filterCapabilitiesByVersion(result, agreedVersion); } negotiateLogLevel(clientLevel, serverLevel) { const levels = ['debug', 'info', 'warn', 'error']; const clientIndex = clientLevel ? levels.indexOf(clientLevel) : 1; const serverIndex = serverLevel ? levels.indexOf(serverLevel) : 1; // Use the more restrictive (higher) level const chosenIndex = Math.max(clientIndex, serverIndex); return levels[chosenIndex]; } filterCapabilitiesByVersion(capabilities, version) { const versionInfo = this.getVersionInfo(version); if (!versionInfo) return capabilities; const result = {}; // Only include capabilities supported by this version if (versionInfo.supportedFeatures.includes('logging') && capabilities.logging) { result.logging = capabilities.logging; } if (versionInfo.supportedFeatures.includes('tools') && capabilities.tools) { result.tools = capabilities.tools; } if (versionInfo.supportedFeatures.includes('resources') && capabilities.resources) { result.resources = capabilities.resources; } if (versionInfo.supportedFeatures.includes('prompts') && capabilities.prompts) { result.prompts = capabilities.prompts; } return result; } getMissingFeatures(version, capabilities) { const versionInfo = this.getVersionInfo(version); if (!versionInfo) return []; const missing = []; const availableFeatures = versionInfo.supportedFeatures; // Check what's missing compared to latest version const latestVersion = this.getLatestSupportedVersion(); const latestVersionInfo = this.getVersionInfo(latestVersion); if (latestVersionInfo) { for (const feature of latestVersionInfo.supportedFeatures) { if (!availableFeatures.includes(feature)) { missing.push(feature); } } } return missing; } getDeprecatedFeatures(version) { const versionInfo = this.getVersionInfo(version); return versionInfo?.breakingChanges || []; } } //# sourceMappingURL=protocol-manager.js.map