VPS_startVirtualMachineV1
Start a stopped VPS instance by providing its virtual machine ID.
Instructions
Start a specified virtual machine.
If the virtual machine is already running, the request will still be processed without any effect.
Use this endpoint to power on stopped VPS instances.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| virtualMachineId | Yes | Virtual Machine ID |
Implementation Reference
- src/core/tools/vps.js:1768-1791 (schema)Schema definition for VPS_startVirtualMachineV1 tool. It is a POST request to /api/vps/v1/virtual-machines/{virtualMachineId}/start, requiring only the virtualMachineId (integer) parameter.
{ "name": "VPS_startVirtualMachineV1", "description": "Start a specified virtual machine.\n\nIf the virtual machine is already running, the request will still be processed without any effect.\n\nUse this endpoint to power on stopped VPS instances.", "method": "POST", "path": "/api/vps/v1/virtual-machines/{virtualMachineId}/start", "inputSchema": { "type": "object", "properties": { "virtualMachineId": { "type": "integer", "description": "Virtual Machine ID" } }, "required": [ "virtualMachineId" ] }, "security": [ { "apiToken": [] } ], "group": "vps" }, - src/core/runtime.js:86-95 (registration)Tools are registered in the MCPServer class by iterating over the tool list and adding them to the tools Map. VPS_startVirtualMachineV1 is included from the vps.js tool definition file.
initializeTools() { // Initialize each tool in the tools map for (const tool of this.toolList) { this.tools.set(tool.name, { name: tool.name, description: tool.description, inputSchema: tool.inputSchema, // Don't include security at the tool level }); } - src/core/runtime.js:1879-2105 (registration)The runtime's executeApiCall is the generic handler that processes VPS_startVirtualMachineV1. It substitutes path parameters (like {virtualMachineId}) from user input and makes a POST request to the API.
async executeApiCall(tool, params) { // Get method and path from tool const method = tool.method; let path = tool.path; // Clone params to avoid modifying the original const requestParams = { ...params }; // Replace path parameters with values from params Object.entries(requestParams).forEach(([key, value]) => { const placeholder = `{${key}}`; if (path.includes(placeholder)) { path = path.replace(placeholder, encodeURIComponent(String(value))); delete requestParams[key]; // Remove used parameter } }); // Build the full URL const baseUrl = this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`; const cleanPath = path.startsWith("/") ? path.slice(1) : path; const url = new URL(cleanPath, baseUrl).toString(); this.log('debug', `API Request: ${method} ${url}`); try { // Configure the request const config = { method: method.toLowerCase(), url, headers: { ...this.headers }, timeout: 60000, // 60s validateStatus: function (status) { return status < 500; // Resolve only if the status code is less than 500 } }; const bearerToken = process.env['API_TOKEN'] || process.env['APITOKEN']; // APITOKEN for backwards compatibility if (bearerToken) { config.headers['Authorization'] = `Bearer ${bearerToken}`; } else { this.log('error', `Bearer Token environment variable not found: API_TOKEN`); } // Add parameters based on request method if (["GET", "DELETE"].includes(method)) { // For GET/DELETE, send params as query string config.params = { ...(config.params || {}), ...requestParams }; } else { // For POST/PUT/PATCH, send params as JSON body config.data = requestParams; config.headers["Content-Type"] = "application/json"; } this.log('debug', "Request config:", { url: config.url, method: config.method, params: config.params, headers: Object.keys(config.headers) }); // Execute the request const response = await axios(config); this.log('debug', `Response status: ${response.status}`); return response.data; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); this.log('error', `API request failed: ${errorMessage}`); if (axios.isAxiosError(error)) { const responseData = error.response?.data; const responseStatus = error.response?.status; this.log('error', 'API Error Details:', { status: responseStatus, data: typeof responseData === 'object' ? JSON.stringify(responseData) : responseData }); // Rethrow with more context for better error handling const detailedError = new Error(`API request failed with status ${responseStatus}: ${errorMessage}`); detailedError.response = error.response; throw detailedError; } throw error; } } /** * Log messages with appropriate level * Only sends to MCP if we're connected */ log(level, message, data) { // Always log to stderr for visibility console.error(`[${level.toUpperCase()}] ${message}${data ? ': ' + JSON.stringify(data) : ''}`); // Only try to send via MCP if we're in debug mode or it's important if (this.debug || level !== 'debug') { try { // Only send if server exists and is connected if (this.server && this.server.isConnected) { this.server.sendLoggingMessage({ level, data: `[MCP Server] ${message}${data ? ': ' + JSON.stringify(data) : ''}` }); } } catch (e) { // If logging fails, log to stderr console.error('Failed to send log via MCP:', e.message); } } } /** * Create and configure Express app with shared middleware */ createApp() { const app = express(); app.use(express.json()); app.use(cors()); return app; } /** * Start the server with HTTP streaming transport */ async startHttp(host, port) { try { const app = this.createApp(); // Create HTTP transport with session management const httpTransport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => { // Generate a simple session ID return `session-${Date.now()}-${Math.random().toString(36).substring(7)}`; }, }); // Set up CORS for all routes app.options("*", (req, res) => { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, x-session-id"); res.sendStatus(200); }); // Health check endpoint app.get("/health", (req, res) => { res.status(200).json({ status: "ok", transport: "http" }); }); // Set up the HTTP transport endpoint app.post("/", async (req, res) => { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, x-session-id"); await httpTransport.handleRequest(req, res, req.body); }); // Start the server const server = app.listen(port, host, () => { this.log('info', `MCP Server with HTTP streaming transport started successfully with ${this.tools.size} tools`); this.log('info', `Listening on http://${host}:${port}`); }); // Connect the MCP server to the transport await this.server.connect(httpTransport); } catch (error) { console.error("Failed to start MCP server:", error); process.exit(1); } } /** * Start the server */ async startStdio() { try { // Create stdio transport const transport = new StdioServerTransport(); console.error("MCP Server starting on stdio transport"); // Connect to the transport await this.server.connect(transport); // Now we can safely log via MCP console.error(`Registered ${this.tools.size} tools`); this.log('info', `MCP Server with stdio transport started successfully with ${this.tools.size} tools`); } catch (error) { console.error("Failed to start MCP server:", error); process.exit(1); } } } export async function startServer({ name, version, tools }) { const argv = minimist(process.argv.slice(2), { string: ['host'], boolean: ['stdio', 'http', 'help'], default: { host: '127.0.0.1', port: 8100, stdio: true } }); if (argv.help) { console.log(` ${name} Usage: ${name} [options] Options: --http Use HTTP streaming transport --stdio Use standard input/output transport (default) --host <host> Host to bind to (default: 127.0.0.1) --port <port> Port to bind to (default: 8100) --help Show this help message Environment Variables: API_TOKEN Your Hostinger API token (required) DEBUG Enable debug logging (true/false) `); process.exit(0); } const server = new MCPServer({ name, version, tools }); if (argv.http) { await server.startHttp(argv.host, argv.port); } else { await server.startStdio(); } - src/core/tools/vps.ts:1778-1791 (registration)TypeScript schema definition for VPS_startVirtualMachineV1 with typed interface (OpenApiTool). Same configuration as the JS version.
{ "name": "VPS_startVirtualMachineV1", "description": "Start a specified virtual machine.\n\nIf the virtual machine is already running, the request will still be processed without any effect.\n\nUse this endpoint to power on stopped VPS instances.", "method": "POST", "path": "/api/vps/v1/virtual-machines/{virtualMachineId}/start", "inputSchema": { "type": "object", "properties": { "virtualMachineId": { "type": "integer", "description": "Virtual Machine ID" } }, "required": [ - src/servers/vps.ts:1-6 (registration)The VPS server entry point imports the tools array (which includes VPS_startVirtualMachineV1) and passes them to startServer for registration with the MCP framework.
#!/usr/bin/env node // Auto-generated entry for group: vps import { startServer } from '../core/runtime.js'; import tools from '../core/tools/vps.js'; startServer({ name: 'hostinger-vps-mcp', version: '0.1.41', tools });