UNPKG

vme-mcp-server

Version:

An intelligent Model Context Protocol (MCP) server that transforms HPE VM Essentials (VME) infrastructure management into natural language conversations. Provision VMs, manage resources, and control your infrastructure through simple English commands with

237 lines (236 loc) 10.6 kB
import { capabilityCache } from "./capability-cache.js"; // Capability discovery engine export class CapabilityDiscoveryEngine { /** * Discover capabilities for specified domains */ async discoverCapabilities(domains = ["all"], forceRefresh = false) { const result = { discovered_at: new Date().toISOString(), cache_status: [] }; // Determine which domains to discover const shouldDiscover = (domain) => domains.includes("all") || domains.includes(domain); try { // Discover capabilities in parallel for efficiency const discoveries = await Promise.allSettled([ shouldDiscover("compute") ? this.discoverComputeCapabilities(forceRefresh) : Promise.resolve(null), shouldDiscover("networking") ? this.discoverNetworkingCapabilities(forceRefresh) : Promise.resolve(null), shouldDiscover("storage") ? this.discoverStorageCapabilities(forceRefresh) : Promise.resolve(null), shouldDiscover("platform") ? this.discoverPlatformCapabilities(forceRefresh) : Promise.resolve(null), ]); // Process results if (discoveries[0]?.status === "fulfilled" && discoveries[0].value) { result.compute = discoveries[0].value; } if (discoveries[1]?.status === "fulfilled" && discoveries[1].value) { result.networking = discoveries[1].value; } if (discoveries[2]?.status === "fulfilled" && discoveries[2].value) { result.storage = discoveries[2].value; } if (discoveries[3]?.status === "fulfilled" && discoveries[3].value) { result.platform = discoveries[3].value; } // Add cache status summary result.cache_status = this.getCacheStatusSummary(); return result; } catch (error) { throw new Error(`Capability discovery failed: ${error.message}`); } } /** * Check if a specific capability is available */ async checkCapability(question, capabilityType) { // Simple natural language processing for capability questions const questionLower = question.toLowerCase(); try { // GPU support check if (questionLower.includes("gpu") || capabilityType === "gpu_support") { const compute = await this.discoverComputeCapabilities(); return { answer: compute.gpu_support, details: compute.gpu_support ? "GPU support is available in this VME environment" : "No GPU support detected in cluster nodes", confidence: 0.95 }; } // Hypervisor checks if (questionLower.includes("vmware") || questionLower.includes("kvm") || questionLower.includes("hypervisor")) { const compute = await this.discoverComputeCapabilities(); const hypervisor = questionLower.includes("vmware") ? "VMware" : questionLower.includes("kvm") ? "KVM" : null; if (hypervisor) { const available = compute.hypervisors.includes(hypervisor); return { answer: available, details: available ? `${hypervisor} hypervisor is available` : `${hypervisor} hypervisor not found. Available: ${compute.hypervisors.join(", ")}`, confidence: 0.9 }; } } // CPU/Memory limit checks if (questionLower.match(/\b(\d+)\s*(cpu|core|vcpu)/)) { const compute = await this.discoverComputeCapabilities(); const requestedCPU = parseInt(questionLower.match(/\b(\d+)\s*(cpu|core|vcpu)/)?.[1] || "0"); const canSupport = requestedCPU <= compute.max_cpu_per_vm; return { answer: canSupport, details: canSupport ? `${requestedCPU} CPU configuration is supported (max: ${compute.max_cpu_per_vm})` : `${requestedCPU} CPU exceeds maximum of ${compute.max_cpu_per_vm} per VM`, confidence: 0.85 }; } // Generic fallback return { answer: false, details: "Unable to determine capability from question. Try being more specific.", confidence: 0.1 }; } catch (error) { return { answer: false, details: `Error checking capability: ${error.message}`, confidence: 0.0 }; } } // Private discovery methods for each domain async discoverComputeCapabilities(forceRefresh = false) { const [clusters, servicePlans, instanceTypes, virtualImages] = await Promise.all([ capabilityCache.getField("clusters", forceRefresh), capabilityCache.getField("service_plans", forceRefresh), capabilityCache.getField("instance_types", forceRefresh), capabilityCache.getField("virtual_images", forceRefresh), ]); // Derive hypervisors from cluster data const hypervisors = new Set(); let maxCPU = 0; let maxMemoryGB = 0; let hasGPU = false; if (clusters?.clusters) { for (const cluster of clusters.clusters) { if (cluster.servers) { for (const server of cluster.servers) { if (server.serverType) { hypervisors.add(server.serverType); } if (server.maxCpu && server.maxCpu > maxCPU) { maxCPU = server.maxCpu; } if (server.maxMemory && server.maxMemory > maxMemoryGB) { maxMemoryGB = Math.floor(server.maxMemory / (1024 * 1024 * 1024)); // Convert to GB } if (server.gpuCount && server.gpuCount > 0) { hasGPU = true; } } } } } // Process service plans for limits const plans = servicePlans?.servicePlans?.map((plan) => ({ id: plan.id, name: plan.name, max_cpu: plan.maxCpu, max_memory: plan.maxMemory, max_storage: plan.maxStorage })) || []; // Process instance types const instances = instanceTypes?.instanceTypes?.map((type) => ({ id: type.id, name: type.name, code: type.code })) || []; // Process virtual images const images = virtualImages?.virtualImages?.map((img) => ({ id: img.id, name: img.name, os_type: img.osType?.name || "Unknown", category: img.osType?.category || "unknown", version: img.osType?.osVersion })) || []; return { hypervisors: Array.from(hypervisors), instance_types: instances, service_plans: plans, max_cpu_per_vm: maxCPU, max_memory_per_vm: `${maxMemoryGB}GB`, gpu_support: hasGPU, available_images: images.slice(0, 10) // Limit to prevent token bloat }; } async discoverNetworkingCapabilities(forceRefresh = false) { const [zones, networks] = await Promise.all([ capabilityCache.getField("zones", forceRefresh), capabilityCache.getField("networks", forceRefresh).catch(() => null), // Optional ]); const zoneList = zones?.zones?.map((zone) => ({ id: zone.id, name: zone.name, description: zone.description })) || []; return { zones: zoneList, network_types: ["VLAN"], // Default for VME load_balancer_support: false, // Would need to check features firewall_support: false, // Would need to check features }; } async discoverStorageCapabilities(forceRefresh = false) { // Get real data from VME API const servicePlans = await capabilityCache.getField("service_plans", forceRefresh); // Derive storage capabilities from actual service plans and other data const storageTypes = new Set(); let maxVolumeSize = "1TB"; // Default if (servicePlans?.servicePlans) { for (const plan of servicePlans.servicePlans) { // Look for storage-related info in service plans if (plan.maxStorage) { const sizeGB = Math.floor(plan.maxStorage / (1024 * 1024 * 1024)); if (sizeGB > parseInt(maxVolumeSize)) { maxVolumeSize = `${sizeGB}GB`; } } } } // Basic storage types - would need more VME API endpoints to get real storage info storageTypes.add("Local"); // VME always has local storage return { storage_types: Array.from(storageTypes), max_volume_size: maxVolumeSize, snapshot_support: true, // VME typically supports snapshots encryption_support: false, // Would need to check actual VME features }; } async discoverPlatformCapabilities(forceRefresh = false) { const groups = await capabilityCache.getField("groups", forceRefresh); const groupList = groups?.groups?.map((group) => ({ id: group.id, name: group.name, description: group.description })) || []; return { api_version: "6.2.x", // Would get from API info endpoint groups: groupList, enabled_features: ["VM Provisioning", "Resource Management"], // Would derive from license/features }; } getCacheStatusSummary() { const statuses = capabilityCache.getCacheStatus(); return statuses.map(status => ({ field: status.field_name, fresh: status.is_fresh, age_seconds: status.age_seconds })); } } // Global discovery engine instance export const capabilityDiscovery = new CapabilityDiscoveryEngine();