server_provision
Provision cloud servers on Hetzner, DigitalOcean, Vultr, or Linode with optional Coolify/Dokploy installation or bare VPS setup. Automates server creation and initial configuration.
Instructions
Provision a new server on a cloud provider. Default: Coolify auto-install via cloud-init. Pass mode:'bare' for a generic VPS without Coolify (installs UFW and runs system updates only). Requires provider API token as environment variable (HETZNER_TOKEN, DIGITALOCEAN_TOKEN, VULTR_TOKEN, LINODE_TOKEN). WARNING: Creates a billable cloud resource. Blocked when KASTELL_SAFE_MODE=true. Server takes 3-5 minutes to fully initialize after provisioning.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| provider | Yes | Cloud provider to create server on | |
| region | No | Region/location ID (e.g. 'nbg1' for Hetzner, 'fra1' for DigitalOcean, 'ewr' for Vultr, 'us-east' for Linode). Uses template defaults if omitted | |
| size | No | Server type/plan ID (e.g. 'cax11' for Hetzner, 's-2vcpu-2gb' for DigitalOcean). Uses template defaults if omitted | |
| name | Yes | Server hostname, 3-63 chars, lowercase, starts with letter, only alphanumeric and hyphens, ends with letter or number | |
| template | No | Template for default region/size. 'starter' = cheapest, 'production' = more resources, 'dev' = development. Explicit region/size override template defaults. Default: starter | starter |
| mode | No | Server mode: 'coolify' installs Coolify, 'dokploy' installs Dokploy, 'bare' provisions generic VPS. Default: coolify | coolify |
Implementation Reference
- src/mcp/tools/serverProvision.ts:48-159 (handler)The handleServerProvision function executes the provisioning logic, checking for SAFE_MODE, calling the core provisioner, and returning successful or error responses for the MCP tool.
export async function handleServerProvision(params: { provider: SupportedProvider; region?: string; size?: string; name: string; template?: "starter" | "production" | "dev"; mode?: "coolify" | "dokploy" | "bare"; }, mcpServer?: McpServer): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: boolean }> { const mode = params.mode ?? "coolify"; // SAFE_MODE guard if (isSafeMode()) { return mcpError( "Provision is disabled in SAFE_MODE", "Set KASTELL_SAFE_MODE=false to enable server provisioning. WARNING: This creates billable cloud resources.", ); } await mcpLog(mcpServer, `Provisioning ${params.provider} server: ${params.name}`); try { const result = await provisionServer({ provider: params.provider, region: params.region, size: params.size, name: params.name, template: params.template, mode, }); if (!result.success) { return mcpError( result.error ?? "Provision failed", result.hint, [ { command: "server_info { action: 'list' }", reason: "Check existing servers", }, ], ); } if (!result.server) { return mcpError("Unexpected: server record missing"); } const server = result.server; const suggestedActions = mode === "bare" ? [ { command: `ssh root@${server.ip}`, reason: "Connect to your bare server via SSH", }, { command: `server_secure { action: 'secure-setup', server: '${server.name}' }`, reason: "Harden SSH security + install fail2ban", }, { command: `server_secure { action: 'firewall-setup', server: '${server.name}' }`, reason: "Setup UFW firewall", }, { command: `server_info { action: 'status', server: '${server.name}' }`, reason: "Check cloud provider status", }, ] : [ { command: `server_info { action: 'health', server: '${server.name}' }`, reason: "Check Coolify health (wait 3-5 minutes after creation for Coolify to initialize)", }, { command: `server_secure { action: 'secure-setup', server: '${server.name}' }`, reason: "Harden SSH security + install fail2ban", }, { command: `server_secure { action: 'firewall-setup', server: '${server.name}' }`, reason: "Setup UFW firewall with Coolify ports", }, { command: `server_info { action: 'status', server: '${server.name}' }`, reason: "Check cloud provider status", }, ]; await mcpLog(mcpServer, "Provision complete"); return mcpSuccess({ success: true, message: `Server "${server.name}" provisioned on ${server.provider}`, server: { id: server.id, name: server.name, provider: server.provider, ip: server.ip, region: server.region, size: server.size, mode, createdAt: server.createdAt, }, ...(result.hint ? { hint: result.hint } : {}), suggested_actions: suggestedActions, }); } catch (error: unknown) { return mcpError( error instanceof Error ? error.message : String(error), ); } } - The serverProvisionSchema defines the input validation for the server_provision tool using Zod.
export const serverProvisionSchema = { provider: z .enum(SUPPORTED_PROVIDERS) .describe("Cloud provider to create server on"), region: z .string() .optional() .describe( "Region/location ID (e.g. 'nbg1' for Hetzner, 'fra1' for DigitalOcean, 'ewr' for Vultr, 'us-east' for Linode). Uses template defaults if omitted", ), size: z .string() .optional() .describe( "Server type/plan ID (e.g. 'cax11' for Hetzner, 's-2vcpu-2gb' for DigitalOcean). Uses template defaults if omitted", ), name: z .string() .describe( "Server hostname, 3-63 chars, lowercase, starts with letter, only alphanumeric and hyphens, ends with letter or number", ), template: z .enum(["starter", "production", "dev"]) .default("starter") .describe( "Template for default region/size. 'starter' = cheapest, 'production' = more resources, 'dev' = development. Explicit region/size override template defaults. Default: starter", ), mode: z .enum(["coolify", "dokploy", "bare"]) .default("coolify") .describe( "Server mode: 'coolify' installs Coolify, 'dokploy' installs Dokploy, 'bare' provisions generic VPS. Default: coolify", ), }; - src/mcp/server.ts:146-158 (registration)Registration of the 'server_provision' tool within the MCP server setup.
server.registerTool("server_provision", { description: "Provision a new server on a cloud provider. Default: Coolify auto-install via cloud-init. Pass mode:'bare' for a generic VPS without Coolify (installs UFW and runs system updates only). Requires provider API token as environment variable (HETZNER_TOKEN, DIGITALOCEAN_TOKEN, VULTR_TOKEN, LINODE_TOKEN). WARNING: Creates a billable cloud resource. Blocked when KASTELL_SAFE_MODE=true. Server takes 3-5 minutes to fully initialize after provisioning.", inputSchema: serverProvisionSchema, annotations: { title: "Server Provisioning", readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true, }, }, async (params) => { return handleServerProvision(params, server);