Skip to main content
Glama
README.md17.2 kB
# VergeOS MCP Server A Model Context Protocol (MCP) server for interacting with [VergeOS](https://www.verge.io/) virtualization platform. This enables AI assistants like Claude, Windsurf/Cascade, and other MCP-compatible clients to manage VMs, networks, tenants, and monitor your VergeOS cluster through natural language. ## Architecture Overview This project provides two deployment options: ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ DEPLOYMENT OPTIONS │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ Option 1: Local (stdio) Option 2: Remote (HTTP + Local Proxy) │ │ ───────────────────────── ───────────────────────────────────── │ │ │ │ ┌──────────┐ stdio ┌─────────┐ ┌──────────┐ HTTP ┌─────────┐│ │ │ Windsurf │◄──────────►│ MCP │ │ Windsurf │◄────────►│ Local ││ │ │ /Claude │ │ Server │ │ /Claude │ stdio │ Proxy ││ │ └──────────┘ └────┬────┘ └──────────┘ └────┬────┘│ │ │ │ │ │ │ HTTPS HTTPS │ │ │ ▼ ▼ │ │ ┌─────────┐ ┌──────────┐ │ │ │VergeOS │ │ K8s MCP │ │ │ │ API │ │ Server │ │ │ └─────────┘ └────┬─────┘ │ │ │ │ │ HTTPS│ │ │ ▼ │ │ ┌──────────┐ │ │ │ VergeOS │ │ │ │ API │ │ │ └──────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` ### When to Use Each Option | Option | Use Case | |--------|----------| | **Local (stdio)** | AI client runs on the same machine that can reach VergeOS | | **Remote (HTTP)** | AI client is remote (e.g., laptop) and VergeOS is on a private network | ## Features ### MCP Tools #### VM Power Control | Tool | Description | |------|-------------| | `list_vms` | List all virtual machines (filter by running/name) | | `get_vm` | Get detailed VM information by ID | | `get_vm_status` | Get VM running status and power state | | `power_on_vm` | Power on a VM | | `power_off_vm` | Gracefully power off with optional wait and auto-force | | `force_off_vm` | Force power off (hard shutdown) | | `reset_vm` | Reset/reboot a VM | #### VM Configuration | Tool | Description | |------|-------------| | `modify_vm` | Change CPU cores and/or RAM (handles running VMs) | | `add_drive` | Add a new disk drive to a VM | | `resize_drive` | Expand an existing disk (increase only) | | `get_vm_nics` | Get VM network interfaces | | `get_vm_drives` | Get VM disk drives with sizes | #### Network Management | Tool | Description | |------|-------------| | `list_networks` | List all virtual networks | | `get_network` | Get network details | | `network_action` | Power on/off, reset, apply rules | #### Tenant Management | Tool | Description | |------|-------------| | `list_tenants` | List all tenants | | `get_tenant` | Get tenant details | | `tenant_action` | Power on/off, reset tenants | #### Cluster & Node Management | Tool | Description | |------|-------------| | `list_nodes` | List cluster nodes | | `get_node_stats` | Get node statistics | | `get_cluster_status` | Get cluster health status | | `get_cluster_stats` | Get storage tier statistics | #### Storage & Monitoring | Tool | Description | |------|-------------| | `list_volumes` | List storage volumes | | `get_logs` | Get system logs (filter by level/object type) | | `get_alarms` | Get active alarms | ### Smart Features - **Graceful shutdown with wait**: `power_off_vm` can wait for VM to shut down and auto-force if timeout expires - **Running VM handling**: `modify_vm` detects running VMs and can auto-shutdown to apply CPU/RAM changes - **Log filtering**: Filter logs by level (`error`, `warning`, `audit`) or object type (`vm`, `node`, `vnet`) ### MCP Resources - `vergeos://cluster/status` - Cluster status overview - `vergeos://vms/list` - All virtual machines - `vergeos://networks/list` - All virtual networks - `vergeos://alarms/active` - Active system alarms --- ## Option 1: Local Installation (stdio) Use this if your AI client runs on a machine that can directly reach your VergeOS instance. ### Installation ```bash git clone <repo-url> vergeos-mcp-server cd vergeos-mcp-server npm install ``` ### Configuration Create a `.env` file: ```bash VERGEOS_HOST=your-vergeos-host VERGEOS_USER=admin VERGEOS_PASS=your-password ``` Or use an API token (recommended): ```bash # Get a token curl -sk -X POST "https://your-vergeos-host/api/sys/tokens" \ -u "admin:password" \ -H "Content-Type: application/json" \ -d '{"login":"admin","password":"password"}' | jq -r '."$key"' # Set in .env VERGEOS_HOST=your-vergeos-host VERGEOS_TOKEN=your-token-here ``` ### Claude Desktop Configuration Add to `~/.config/claude/claude_desktop_config.json`: ```json { "mcpServers": { "vergeos": { "command": "node", "args": ["/path/to/vergeos-mcp-server/src/index.js"], "env": { "VERGEOS_HOST": "your-vergeos-host", "VERGEOS_USER": "admin", "VERGEOS_PASS": "your-password" } } } } ``` ### Windsurf Configuration Add to `~/.codeium/windsurf/mcp_config.json`: ```json { "mcpServers": { "vergeos": { "command": "node", "args": ["/path/to/vergeos-mcp-server/src/index.js"], "env": { "VERGEOS_HOST": "your-vergeos-host", "VERGEOS_USER": "admin", "VERGEOS_PASS": "your-password" } } } } ``` --- ## Option 2: Remote Installation (Kubernetes + Local Proxy) Use this if your AI client (e.g., Windsurf on your laptop) cannot directly reach VergeOS, but you have a Kubernetes cluster that can. ### Architecture ``` ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Windsurf │─────►│ Local Proxy │─────►│ K8s MCP │─────►│ VergeOS │ │ (Laptop) │stdio │ (Laptop) │HTTPS │ Server │HTTPS │ API │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ ┌─────┴─────┐ │ Traefik │ │ Ingress │ └───────────┘ ``` ### Step 1: Deploy to Kubernetes ```bash # Clone the repo on your K8s host cd vergeos-mcp-server # Edit credentials in deploy.sh or create ~/.vergeos-credentials cat > ~/.vergeos-credentials << EOF VERGEOS_USER=admin VERGEOS_PASS=your-password EOF # Deploy ./deploy.sh ``` This creates: - Namespace: `vergeos-mcp` - Deployment running the HTTP MCP server - Service exposing port 3002 - IngressRoute for external access (Traefik) ### Step 2: Configure DNS Add a DNS record pointing to your Traefik ingress: ``` vergeos-mcp.yourdomain.com → <traefik-ip> ``` ### Step 3: Test the Server ```bash # Health check curl https://vergeos-mcp.yourdomain.com/health # List VMs curl https://vergeos-mcp.yourdomain.com/vms # MCP protocol test curl -X POST https://vergeos-mcp.yourdomain.com/message \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' ``` ### Step 4: Install Local Proxy (on your laptop) Since Windsurf only supports stdio-based MCP servers, you need a local proxy: ```bash # Create directory mkdir -p ~/.mcp/vergeos cd ~/.mcp/vergeos # Create package.json cat > package.json << 'EOF' { "name": "vergeos-mcp-proxy", "version": "1.0.0", "type": "module", "dependencies": { "@modelcontextprotocol/sdk": "^0.5.0", "node-fetch": "^3.3.2" } } EOF # Create index.js cat > index.js << 'EOF' #!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js"; const SERVER_URL = process.env.VERGEOS_MCP_URL || "https://vergeos-mcp.yourdomain.com"; async function apiCall(path, options = {}) { const fetch = (await import("node-fetch")).default; const response = await fetch(`${SERVER_URL}${path}`, { ...options, headers: { "Content-Type": "application/json", ...options.headers }, }); if (!response.ok) throw new Error(`API Error: ${response.status}`); return response.json(); } const server = new Server({ name: "vergeos", version: "1.0.0" }, { capabilities: { tools: {} } }); const TOOLS = [ { name: "list_vms", description: "List all VMs in VergeOS", inputSchema: { type: "object", properties: {} } }, { name: "get_vm", description: "Get VM details by ID", inputSchema: { type: "object", properties: { id: { type: "number" } }, required: ["id"] } }, { name: "power_on_vm", description: "Power on a VM", inputSchema: { type: "object", properties: { id: { type: "number" } }, required: ["id"] } }, { name: "power_off_vm", description: "Power off a VM", inputSchema: { type: "object", properties: { id: { type: "number" } }, required: ["id"] } }, { name: "reset_vm", description: "Reset a VM", inputSchema: { type: "object", properties: { id: { type: "number" } }, required: ["id"] } }, { name: "list_networks", description: "List virtual networks", inputSchema: { type: "object", properties: {} } }, { name: "list_tenants", description: "List tenants", inputSchema: { type: "object", properties: {} } }, { name: "list_nodes", description: "List cluster nodes", inputSchema: { type: "object", properties: {} } }, { name: "get_cluster_status", description: "Get cluster status", inputSchema: { type: "object", properties: {} } }, { name: "get_alarms", description: "Get active alarms", inputSchema: { type: "object", properties: {} } }, { name: "get_logs", description: "Get system logs", inputSchema: { type: "object", properties: { limit: { type: "number" } } } }, ]; server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS })); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { const result = await apiCall(`/tools/${name}`, { method: "POST", body: JSON.stringify(args || {}) }); return { content: [{ type: "text", text: JSON.stringify(result.result, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true }; } }); const transport = new StdioServerTransport(); await server.connect(transport); EOF # Install dependencies npm install ``` ### Step 5: Configure Windsurf Add to `~/.codeium/windsurf/mcp_config.json`: ```json { "mcpServers": { "vergeos": { "command": "node", "args": ["/Users/yourusername/.mcp/vergeos/index.js"], "env": { "VERGEOS_MCP_URL": "https://vergeos-mcp.yourdomain.com" } } } } ``` Restart Windsurf to load the new MCP server. --- ## REST API Reference The HTTP server also exposes a REST API for direct access: | Endpoint | Method | Description | |----------|--------|-------------| | `/health` | GET | Health check | | `/tools` | GET | List available MCP tools | | `/tools/:name` | POST | Execute an MCP tool | | `/vms` | GET | List all VMs | | `/vms/:id` | GET | Get VM details | | `/vms/:id/:action` | POST | VM action (poweron/poweroff/reset) | | `/networks` | GET | List networks | | `/tenants` | GET | List tenants | | `/nodes` | GET | List nodes | | `/cluster/status` | GET | Cluster status | | `/alarms` | GET | Active alarms | | `/logs` | GET | System logs | ### MCP Protocol Endpoints | Endpoint | Method | Description | |----------|--------|-------------| | `/sse` | GET | Server-Sent Events connection | | `/message` | POST | MCP JSON-RPC messages | --- ## Example Interactions Once connected, you can ask your AI assistant: - "List all VMs in VergeOS" - "Power off the VM named 'test-vm'" - "Show me the cluster status" - "What alarms are active?" - "List all virtual networks" - "Get details for VM ID 34" - "How many nodes are in the cluster?" - "Show me the last 20 log entries" --- ## VergeOS API Notes ### Authentication VergeOS uses cookie-based authentication: 1. POST to `/api/sys/tokens` with Basic Auth 2. Response contains token in `$key` field 3. Use token as cookie: `Cookie: token=<value>` ```bash # Get token TOKEN=$(curl -sk -X POST "https://vergeos/api/sys/tokens" \ -u "admin:password" \ -H "Content-Type: application/json" \ -d '{"login":"admin","password":"password"}' | jq -r '."$key"') # Use token curl -sk "https://vergeos/api/v4/vms" -b "token=$TOKEN" ``` ### API Quirks - VMs with `is_snapshot: true` are templates, not running VMs - `/machine_nics?machine=<ID>` may return NICs from other machines; always filter by machine ID - Use `fields=most` for detailed responses, but be aware of large payloads --- ## Security Considerations - SSL verification is disabled for self-signed certificates (common in homelabs) - Store credentials in environment variables or Kubernetes secrets - Use API tokens instead of username/password when possible - The HTTP server should be behind TLS (handled by Traefik/Ingress) - Consider network policies to restrict access to the MCP server --- ## Troubleshooting ### Connection Issues ```bash # Test VergeOS API directly curl -sk https://your-vergeos-host/api/v4/vms -b "token=YOUR_TOKEN" # Test MCP server curl https://vergeos-mcp.yourdomain.com/health ``` ### Token Expiration Tokens may expire. The server automatically fetches new tokens using username/password if configured. ```bash # Manually refresh token curl -sk -X POST "https://your-vergeos-host/api/sys/tokens" \ -u "admin:password" \ -H "Content-Type: application/json" \ -d '{"login":"admin","password":"password"}' ``` ### Kubernetes Logs ```bash kubectl logs -n vergeos-mcp deployment/vergeos-mcp kubectl get pods -n vergeos-mcp ``` ### Local Proxy Issues ```bash # Test proxy directly echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node ~/.mcp/vergeos/index.js ``` --- ## File Structure ``` vergeos-mcp-server/ ├── src/ │ ├── index.js # Stdio MCP server (local use) │ ├── http-server.js # HTTP server (legacy) │ ├── mcp-http-server.js # HTTP+MCP server (K8s deployment) │ └── stdio-proxy.js # Stdio proxy for remote server ├── local-proxy/ │ ├── package.json # Local proxy dependencies │ └── index.js # Local proxy for Windsurf ├── deploy.sh # Kubernetes deployment script ├── k8s-deployment.yaml # Kubernetes manifests ├── package.json ├── .env.example └── README.md ``` --- ## License MIT

Latest Blog Posts

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/dvvincent/vergeos-mcp-server'

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