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

128 lines (127 loc) 4.68 kB
import { api } from "./api-utils.js"; // Smart capability cache with field-level TTL export class SmartCapabilityCache { constructor() { this.cache = new Map(); // TTL configuration based on VME resource change patterns this.ttlConfig = { zones: 3600, // Zones rarely change (1 hour) clusters: 1800, // Cluster topology changes occasionally (30 min) service_plans: 1800, // Plans change occasionally (30 min) instance_types: 7200, // Instance types very stable (2 hours) virtual_images: 900, // Images updated more frequently (15 min) cluster_status: 300, // Node status changes often (5 min) resource_pools: 1800, // Pool config changes occasionally (30 min) networks: 3600, // Network config rarely changes (1 hour) groups: 3600, // Groups rarely change (1 hour) }; // Default TTL for unknown fields this.defaultTTL = 600; // 10 minutes } /** * Get data for a specific field, using cache if fresh or fetching if stale */ async getField(fieldName, forceRefresh = false) { const cached = this.cache.get(fieldName); const now = Math.floor(Date.now() / 1000); // Check if cache is fresh and not forcing refresh if (!forceRefresh && cached && this.isFresh(cached, now)) { return cached.data; } // Fetch fresh data from VME API const endpoint = this.getEndpointForField(fieldName); try { const response = await api.get(endpoint); // Store in cache with appropriate TTL const cacheEntry = { data: response.data, cached_at: now, ttl_seconds: this.ttlConfig[fieldName] || this.defaultTTL, endpoint: endpoint, field_name: fieldName }; this.cache.set(fieldName, cacheEntry); return response.data; } catch (error) { // If API fails and we have stale cache, return it with warning if (cached) { console.warn(`VME API failed for ${fieldName}, returning stale cache data`); return cached.data; } // No cache and API failed - propagate error throw new Error(`Failed to fetch ${fieldName}: ${error.message}`); } } /** * Get cache status for a specific field or all fields */ getCacheStatus(fieldName) { const now = Math.floor(Date.now() / 1000); const statuses = []; if (fieldName) { const cached = this.cache.get(fieldName); if (cached) { statuses.push(this.buildCacheStatus(cached, now)); } } else { // Return status for all cached fields for (const cached of this.cache.values()) { statuses.push(this.buildCacheStatus(cached, now)); } } return statuses; } /** * Invalidate cache for specific field or all fields */ invalidate(fieldName) { if (fieldName) { this.cache.delete(fieldName); } else { this.cache.clear(); } } /** * Get cache hit rate statistics */ getStatistics() { // This would need hit/miss tracking - placeholder for now return { hits: 0, misses: 0, hitRate: 0 }; } // Private helper methods isFresh(cached, now) { return (now - cached.cached_at) < cached.ttl_seconds; } buildCacheStatus(cached, now) { const age = now - cached.cached_at; const expiresIn = cached.ttl_seconds - age; return { field_name: cached.field_name, cached_at: cached.cached_at, ttl_seconds: cached.ttl_seconds, age_seconds: age, is_fresh: this.isFresh(cached, now), expires_in_seconds: Math.max(0, expiresIn), endpoint: cached.endpoint }; } getEndpointForField(fieldName) { // Map field names to VME API endpoints const endpointMap = { zones: "/zones", clusters: "/clusters", service_plans: "/service-plans", instance_types: "/instance-types", virtual_images: "/virtual-images", resource_pools: "/resource-pools", networks: "/networks", groups: "/groups" }; return endpointMap[fieldName] || `/${fieldName}`; } } // Global cache instance export const capabilityCache = new SmartCapabilityCache();