Skip to main content
Glama

CloudStack MCP Server

by phantosmax
server.ts•9.51 kB
// Add AbortController polyfill for older Node.js versions if (!globalThis.AbortController) { try { const polyfill = await import('node-abort-controller'); globalThis.AbortController = polyfill.AbortController as any; globalThis.AbortSignal = polyfill.AbortSignal as any; } catch (error) { console.error('Failed to load AbortController polyfill:', error); } } import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, McpError, ErrorCode, } from '@modelcontextprotocol/sdk/types.js'; import { CloudStackClient } from './cloudstack-client.js'; import { allToolDefinitions } from './tool-definitions/index.js'; import { VirtualMachineHandlers, StorageHandlers, NetworkHandlers, MonitoringHandlers, AdminHandlers, SecurityHandlers, } from './handlers/index.js'; import dotenv from 'dotenv'; // Ensure environment variables are loaded dotenv.config(); interface CloudStackConfig { apiUrl: string; apiKey: string; secretKey: string; timeout?: number; } class CloudStackMcpServer { private server: Server; private cloudStackClient: CloudStackClient; private vmHandlers!: VirtualMachineHandlers; private storageHandlers!: StorageHandlers; private networkHandlers!: NetworkHandlers; private monitoringHandlers!: MonitoringHandlers; private adminHandlers!: AdminHandlers; private securityHandlers!: SecurityHandlers; constructor() { this.server = new Server( { name: 'cloudstack-mcp-server', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); this.cloudStackClient = new CloudStackClient(this.getConfig()); this.initializeHandlers(); this.setupToolHandlers(); this.setupErrorHandling(); } private initializeHandlers(): void { this.vmHandlers = new VirtualMachineHandlers(this.cloudStackClient); this.storageHandlers = new StorageHandlers(this.cloudStackClient); this.networkHandlers = new NetworkHandlers(this.cloudStackClient); this.monitoringHandlers = new MonitoringHandlers(this.cloudStackClient); this.adminHandlers = new AdminHandlers(this.cloudStackClient); this.securityHandlers = new SecurityHandlers(this.cloudStackClient); } private getConfig(): CloudStackConfig { const config: CloudStackConfig = { apiUrl: process.env.CLOUDSTACK_API_URL || '', apiKey: process.env.CLOUDSTACK_API_KEY || '', secretKey: process.env.CLOUDSTACK_SECRET_KEY || '', timeout: parseInt(process.env.CLOUDSTACK_TIMEOUT || '30000'), }; if (!config.apiUrl || !config.apiKey || !config.secretKey) { throw new Error('Missing required CloudStack configuration. Please set CLOUDSTACK_API_URL, CLOUDSTACK_API_KEY, and CLOUDSTACK_SECRET_KEY environment variables.'); } return config; } private setupToolHandlers(): void { this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: allToolDefinitions, }; }); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { // Virtual Machine Operations case 'list_virtual_machines': return await this.vmHandlers.handleListVirtualMachines(args); case 'get_virtual_machine': return await this.vmHandlers.handleGetVirtualMachine(args); case 'start_virtual_machine': return await this.vmHandlers.handleStartVirtualMachine(args); case 'stop_virtual_machine': return await this.vmHandlers.handleStopVirtualMachine(args); case 'reboot_virtual_machine': return await this.vmHandlers.handleRebootVirtualMachine(args); case 'destroy_virtual_machine': return await this.vmHandlers.handleDestroyVirtualMachine(args); case 'deploy_virtual_machine': return await this.vmHandlers.handleDeployVirtualMachine(args); case 'scale_virtual_machine': return await this.vmHandlers.handleScaleVirtualMachine(args); case 'migrate_virtual_machine': return await this.vmHandlers.handleMigrateVirtualMachine(args); case 'reset_password_virtual_machine': return await this.vmHandlers.handleResetPasswordVirtualMachine(args); case 'change_service_offering_virtual_machine': return await this.vmHandlers.handleChangeServiceOfferingVirtualMachine(args); case 'list_virtual_machine_metrics': return await this.vmHandlers.handleListVirtualMachineMetrics(args); // Storage Management case 'list_volumes': return await this.storageHandlers.handleListVolumes(args); case 'create_volume': return await this.storageHandlers.handleCreateVolume(args); case 'attach_volume': return await this.storageHandlers.handleAttachVolume(args); case 'detach_volume': return await this.storageHandlers.handleDetachVolume(args); case 'resize_volume': return await this.storageHandlers.handleResizeVolume(args); case 'create_snapshot': return await this.storageHandlers.handleCreateSnapshot(args); case 'list_snapshots': return await this.storageHandlers.handleListSnapshots(args); // Networking case 'list_networks': return await this.networkHandlers.handleListNetworks(args); case 'create_network': return await this.networkHandlers.handleCreateNetwork(args); case 'list_public_ip_addresses': return await this.networkHandlers.handleListPublicIpAddresses(args); case 'associate_ip_address': return await this.networkHandlers.handleAssociateIpAddress(args); case 'enable_static_nat': return await this.networkHandlers.handleEnableStaticNat(args); case 'create_firewall_rule': return await this.networkHandlers.handleCreateFirewallRule(args); case 'list_load_balancer_rules': return await this.networkHandlers.handleListLoadBalancerRules(args); // Monitoring & Analytics case 'list_events': return await this.monitoringHandlers.handleListEvents(args); case 'list_alerts': return await this.monitoringHandlers.handleListAlerts(args); case 'list_capacity': return await this.monitoringHandlers.handleListCapacity(args); case 'list_async_jobs': return await this.monitoringHandlers.handleListAsyncJobs(args); case 'list_usage_records': return await this.monitoringHandlers.handleListUsageRecords(args); // Admin & System Management case 'list_zones': return await this.adminHandlers.handleListZones(args); case 'list_templates': return await this.adminHandlers.handleListTemplates(args); case 'list_accounts': return await this.adminHandlers.handleListAccounts(args); case 'list_users': return await this.adminHandlers.handleListUsers(args); case 'list_domains': return await this.adminHandlers.handleListDomains(args); case 'list_hosts': return await this.adminHandlers.handleListHosts(args); case 'list_clusters': return await this.adminHandlers.handleListClusters(args); case 'list_storage_pools': return await this.adminHandlers.handleListStoragePools(args); case 'list_system_vms': return await this.adminHandlers.handleListSystemVms(args); case 'list_service_offerings': return await this.adminHandlers.handleListServiceOfferings(args); // Security & Compliance case 'list_ssh_key_pairs': return await this.securityHandlers.handleListSSHKeyPairs(args); case 'create_ssh_key_pair': return await this.securityHandlers.handleCreateSSHKeyPair(args); case 'list_security_groups': return await this.securityHandlers.handleListSecurityGroups(args); case 'create_security_group_rule': return await this.securityHandlers.handleCreateSecurityGroupRule(args); default: throw new McpError( ErrorCode.MethodNotFound, `Unknown tool: ${name}` ); } } catch (error) { if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, `Error executing tool ${request.params.name}: ${error instanceof Error ? error.message : String(error)}` ); } }); } private setupErrorHandling(): void { this.server.onerror = (error) => { console.error('[MCP Error]', error); }; process.on('SIGINT', async () => { await this.server.close(); process.exit(0); }); } async run(): Promise<void> { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('CloudStack MCP server running on stdio'); } } const server = new CloudStackMcpServer(); server.run().catch(console.error);

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/phantosmax/cloudstack-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server