Skip to main content
Glama
Xodus-CO
by Xodus-CO
README.md
# HCloud MCP

Standalone **MCP (Model Context Protocol) server** for the [Hetzner Cloud API](https://docs.hetzner.cloud/). Use it with any MCP client: Cursor, Claude Desktop, CLI tools, [smithery.ai](https://smithery.ai), or custom agents.

- **Repository:** [github.com/Xodus-CO/hcloud-mcp](https://github.com/Xodus-CO/hcloud-mcp)
- **Cursor Plugin:** [github.com/Xodus-CO/hetzner-mcp](https://github.com/Xodus-CO/hetzner-mcp) — install from the Cursor Plugin marketplace.
- **Hetzner Cloud:** [Get started](https://hetzner.cloud/?ref=IAYKetqPnlq9) — new signups get €20 credit.

---

## Requirements

- Node.js 18+
- A Hetzner Cloud API token. [Generate one](https://docs.hetzner.com/cloud/api/getting-started/generating-api-token) in the console (project → Security → API Tokens). Set it as `HCLOUD_TOKEN` in the environment or in your MCP client config.

## Installation

### From npm (recommended)

```bash
npm install -g hcloud-mcp
```

Or use `npx` to run without a global install.

### From source

```bash
git clone https://github.com/Xodus-CO/hcloud-mcp
cd hcloud-mcp
npm install
npm run build
```

## Configuration

Add the server to your MCP client config. It uses MCP over **stdio** and requires `HCLOUD_TOKEN` in the environment.

**Example** — `mcp.json` (or your client’s equivalent) using the npm binary:

```json
{
  "mcpServers": {
    "hetzner-cloud": {
      "command": "npx",
      "args": ["hcloud-mcp"],
      "env": {
        "HCLOUD_TOKEN": "your_hetzner_cloud_api_token"
      }
    }
  }
}
```

If you installed from source, use an **absolute path** to `run.js` in `args` so the server runs from the project directory (e.g. when the MCP client’s CWD is different, as in dev containers):

```json
"command": "node",
"args": ["/path/to/hcloud-mcp/run.js"]
```

Replace `/path/to/hcloud-mcp` with your actual project path (e.g. `/home/<username>/hcloud-mcp`).

## Tools

The server exposes Hetzner Cloud API operations as MCP tools:

| Area                   | Tools                                                                                                                                                                                                                                                                                                  |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Servers**            | `list_servers`, `get_server`, `create_server`, `delete_server`, `update_server`, `change_server_type`; power: `power_on_server`, `power_off_server`, `reboot_server`, `shutdown_server`, `reset_server`; `attach_iso`, `detach_iso`; `attach_server_to_network`, `detach_server_from_network`          |
| **Load Balancers**     | `list_load_balancers`, `get_load_balancer`, `create_load_balancer`, `update_load_balancer`, `delete_load_balancer`; `add_load_balancer_target`, `remove_load_balancer_target`; `add_load_balancer_service`, `update_load_balancer_service`, `delete_load_balancer_service`; `list_load_balancer_types` |
| **Networks**           | `list_networks`, `get_network`, `create_network`, `update_network`, `delete_network`; `add_network_subnet`, `delete_network_subnet`                                                                                                                                                                    |
| **Volumes**            | `list_volumes`, `get_volume`, `create_volume`, `update_volume`, `delete_volume`; `attach_volume`, `detach_volume`                                                                                                                                                                                      |
| **Firewalls**          | `list_firewalls`, `get_firewall`, `create_firewall`, `update_firewall`, `delete_firewall`; `apply_firewall_to_resources`, `remove_firewall_from_resources`, `set_firewall_rules`                                                                                                                       |
| **Floating IPs**       | `list_floating_ips`, `create_floating_ip`, `update_floating_ip`, `delete_floating_ip`; `assign_floating_ip`, `unassign_floating_ip`                                                                                                                                                                    |
| **Primary IPs**        | `list_primary_ips`, `create_primary_ip`, `get_primary_ip`, `update_primary_ip`, `delete_primary_ip`; `assign_primary_ip`, `unassign_primary_ip` (server must be off)                                                                                                                                   |
| **SSH Keys**           | `list_ssh_keys`, `create_ssh_key`, `update_ssh_key`, `delete_ssh_key`                                                                                                                                                                                                                                  |
| **Placement Groups**   | `list_placement_groups`, `create_placement_group`, `update_placement_group`, `delete_placement_group`                                                                                                                                                                                                  |
| **Metadata & actions** | `list_locations`, `list_images`, `list_server_types`, `list_load_balancer_types`, `list_datacenters`, `get_pricing`; `list_actions`, `get_action` (poll async operations)                                                                                                                              |

> **Note:** Subnets (not networks) are scoped to a `network_zone` (e.g., `eu-central`). Each Subnet has a `network_zone`; all Subnets within a Network share the same `network_zone`. Servers must be created in locations that match the Subnet's `network_zone`, so resources in the Network are constrained by the shared subnet `network_zone`.

## Usage examples

With the MCP client connected, you can ask the agent to run tools using natural language.

### Simple

- _List my servers in Nuremberg_
- _Create a cx22 server with Ubuntu 24.04_
- _Create a cx22 server with Ubuntu 24.04 using my SSH key 'macbook'_
- _Attach a 10GB volume to web-01_
- _Set up a load balancer for my web servers_
- _List load balancer types_
- _Show current pricing for cpx31 servers_
- _Get status of action 12345_

### Complex

- _Create a private network 10.0.0.0/16 in eu-central, add a subnet, then create two servers in that zone (e.g. fsn1 and nbg1) and attach them_
- _Create a firewall for SSH and HTTP, attach to my web servers, then create a load balancer and add those servers as targets_
- _List running actions and get status of action 12345_
- _Create a Primary IP in ash-dc1, power off web-01, assign the IP, power back on_
- _Create a 20GB volume and a cx22 server in nbg1, attach the volume to the server, and show me the device path_
- _Power off server 12345, change its type to cpx31, then power it back on_
- _Add server web-02 as a target to my load balancer prod-lb_
- _Tear down: detach/delete volumes, delete LB and firewall, unassign/delete floating IPs, delete servers web-01 and web-02_

## Development

| File                    | Purpose                                                     |
| ----------------------- | ----------------------------------------------------------- |
| `src/index.ts`          | Entry point, stdio transport, `HCLOUD_TOKEN` check          |
| `src/register-tools.ts` | Tool definitions and Hetzner API calls (uses SDK McpServer) |

**Scripts:**

```bash
npm run build   # compile
npm run start   # run (requires HCLOUD_TOKEN)
npm run dev     # watch and recompile
npm run test:api   # test list_* Hetzner API calls (requires HCLOUD_TOKEN)
npm run test:mcp   # integration test: MCP client calls list_locations (requires HCLOUD_TOKEN)
npm run audit:api  # verify create_* request body shapes (DRY_RUN=1, no resources created)
```

## License

MIT

TDQS

C2.9/5.0

Scored across 67 tools

Disambiguation4/5

Most tools have clearly distinct purposes targeting specific resources and actions, such as create_server vs. update_server. However, there is some potential overlap between power_off_server and shutdown_server (both stop a server) and between reboot_server and reset_server (both restart a server), which could cause minor confusion for an agent.

Naming Consistency5/5

Tool names follow a highly consistent verb_noun pattern throughout, with clear action prefixes like create_, list_, update_, delete_, attach_, detach_, etc. All names use snake_case uniformly, making them predictable and easy to parse.

Tool Count2/5

With 67 tools, the count is excessive for typical MCP server purposes, making it overwhelming for agents to navigate. While the server covers a broad cloud infrastructure domain, the toolset feels bloated and could benefit from consolidation or better scoping to reduce cognitive load.

Completeness5/5

The toolset provides comprehensive CRUD and lifecycle coverage for all major resources (servers, networks, load balancers, volumes, etc.), including create, list, update, delete, attach/detach, and power management operations. There are no obvious gaps, ensuring agents can handle full workflows without dead ends.

Maintenance

ActivityInactive
ResponsivenessNo issues