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
JavaScript
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();