Back to Browse

Hetzner MCP Server

Cloud & DevOpsUse Caution4.8MCP RegistryLocal
Free

Server data from the Official MCP Registry

MCP server for the Hetzner Cloud API — servers, networks, volumes, firewalls, and more.

About

MCP server for the Hetzner Cloud API — servers, networks, volumes, firewalls, and more.

Security Report

4.8
Use Caution4.8High Risk

This is a well-structured MCP server for Hetzner Cloud API management with proper authentication requirements and appropriate permission scoping. The code demonstrates good security practices with input validation via Zod schemas, proper HTTP request abstraction, and clear separation of concerns. No critical vulnerabilities or malicious patterns were detected. Minor code quality observations exist but do not materially impact security. Supply chain analysis found 5 known vulnerabilities in dependencies (0 critical, 1 high severity). Package verification found 1 issue.

4 files analyzed · 10 issues found

Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.

Permissions Required

This plugin requests these system permissions. Most are normal for its category.

HTTP Network Access

Connects to external APIs or services over the internet.

env_vars

Check that this permission is expected for this type of plugin.

How to Install

Add this to your MCP configuration file:

{
  "mcpServers": {
    "io-github-lazyants-hetzner": {
      "args": [
        "-y",
        "@lazyants/hetzner-mcp-server"
      ],
      "command": "npx"
    }
  }
}

Documentation

View on GitHub

From the project's GitHub README.

hetzner-mcp-server

Tests

MCP server for the Hetzner Cloud API. Manage servers, networks, volumes, firewalls, load balancers, and more through the Model Context Protocol.

185 tools across 15 resource domains, with 9 entry points so you can pick the right server for your MCP client's tool limit. A read-only API-reference Resource (reference://hetzner/api) is also exposed on every entry point.

Installation

npm install -g @lazyants/hetzner-mcp-server

Or run directly:

npx @lazyants/hetzner-mcp-server

Configuration

Set your Hetzner Cloud API token:

export HETZNER_API_TOKEN=your-token-here

Get a token from the Hetzner Cloud Console under Security > API Tokens.

The Storage Box tools call a separate host (https://api.hetzner.com/v1). They use HETZNER_STORAGE_API_TOKEN if set, otherwise fall back to HETZNER_API_TOKEN, so a single token keeps working. Set HETZNER_STORAGE_API_TOKEN only if you scope Storage Box access to a dedicated token:

export HETZNER_STORAGE_API_TOKEN=your-storage-token-here  # optional

Entry Points

CommandDomainsTools
hetzner-mcp-serverAll 15 domains185
hetzner-mcp-serversServers, Datacenters/Locations/Server Types, Pricing34
hetzner-mcp-networkingNetworks, Firewalls21
hetzner-mcp-load-balancersLoad Balancers, Certificates28
hetzner-mcp-ipsFloating IPs, Primary IPs20
hetzner-mcp-storageVolumes, Images17
hetzner-mcp-storage-boxesStorage Boxes (+ snapshots, subaccounts, types)29
hetzner-mcp-configSSH Keys, ISOs, Placement Groups14
hetzner-mcp-dnsDNS Zones22

Use split servers to reduce context size — pick only the splits you need.

Claude Code

Add to ~/.claude/settings.json:

{
  "mcpServers": {
    "hetzner": {
      "command": "npx",
      "args": ["-y", "@lazyants/hetzner-mcp-server"],
      "env": {
        "HETZNER_API_TOKEN": "your-token-here"
      }
    }
  }
}

Or use split servers (pick the splits you need):

{
  "mcpServers": {
    "hetzner-servers": {
      "command": "npx",
      "args": ["-y", "-p", "@lazyants/hetzner-mcp-server", "hetzner-mcp-servers"],
      "env": { "HETZNER_API_TOKEN": "your-token-here" }
    },
    "hetzner-networking": {
      "command": "npx",
      "args": ["-y", "-p", "@lazyants/hetzner-mcp-server", "hetzner-mcp-networking"],
      "env": { "HETZNER_API_TOKEN": "your-token-here" }
    }
  }
}

Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "hetzner": {
      "command": "npx",
      "args": ["-y", "@lazyants/hetzner-mcp-server"],
      "env": {
        "HETZNER_API_TOKEN": "your-token-here"
      }
    }
  }
}

Tools

Servers (27 tools) — servers

hetzner_list_servers, hetzner_get_server, hetzner_create_server, hetzner_update_server, hetzner_delete_server, hetzner_power_on, hetzner_power_off, hetzner_reboot, hetzner_reset, hetzner_shutdown, hetzner_rebuild_server, hetzner_resize_server, hetzner_enable_rescue, hetzner_disable_rescue, hetzner_get_server_metrics, hetzner_list_server_actions, hetzner_change_server_protection, hetzner_request_console, hetzner_enable_backup, hetzner_disable_backup, hetzner_change_alias_ips, hetzner_change_dns_ptr, hetzner_attach_server_to_network, hetzner_detach_server_from_network, hetzner_add_server_to_placement_group, hetzner_remove_server_from_placement_group, hetzner_reset_server_password

Images (7 tools) — storage

hetzner_list_images, hetzner_get_image, hetzner_update_image, hetzner_delete_image, hetzner_create_image, hetzner_change_image_protection, hetzner_list_image_actions

ISOs (4 tools) — config

hetzner_list_isos, hetzner_get_iso, hetzner_attach_iso, hetzner_detach_iso

Placement Groups (5 tools) — config

hetzner_list_placement_groups, hetzner_get_placement_group, hetzner_create_placement_group, hetzner_update_placement_group, hetzner_delete_placement_group

Reference Data (7 tools) — servers

hetzner_list_datacenters, hetzner_get_datacenter, hetzner_list_locations, hetzner_get_location, hetzner_list_server_types, hetzner_get_server_type, hetzner_get_pricing

hetzner_list_datacenters / hetzner_get_datacenter are deprecated by Hetzner and removed after 2026-10-01 (HTTP 410). Use hetzner_list_server_types (locations[].available/recommended) and hetzner_list_locations instead.

Networks (12 tools) — networking

hetzner_list_networks, hetzner_get_network, hetzner_create_network, hetzner_update_network, hetzner_delete_network, hetzner_add_subnet, hetzner_delete_subnet, hetzner_add_route, hetzner_delete_route, hetzner_change_network_protection, hetzner_change_ip_range, hetzner_list_network_actions

Firewalls (9 tools) — networking

hetzner_list_firewalls, hetzner_get_firewall, hetzner_create_firewall, hetzner_update_firewall, hetzner_delete_firewall, hetzner_set_firewall_rules, hetzner_apply_firewall, hetzner_remove_firewall, hetzner_list_firewall_actions

Load Balancers (21 tools) — load-balancers

hetzner_list_load_balancers, hetzner_get_load_balancer, hetzner_create_load_balancer, hetzner_update_load_balancer, hetzner_delete_load_balancer, hetzner_add_lb_target, hetzner_remove_lb_target, hetzner_add_lb_service, hetzner_update_lb_service, hetzner_delete_lb_service, hetzner_change_lb_algorithm, hetzner_change_lb_type, hetzner_attach_lb_to_network, hetzner_detach_lb_from_network, hetzner_get_lb_metrics, hetzner_list_lb_types, hetzner_change_load_balancer_protection, hetzner_list_load_balancer_actions, hetzner_enable_lb_public_interface, hetzner_disable_lb_public_interface, hetzner_change_lb_dns_ptr

Certificates (7 tools) — load-balancers

hetzner_list_certificates, hetzner_get_certificate, hetzner_create_certificate, hetzner_update_certificate, hetzner_delete_certificate, hetzner_retry_certificate, hetzner_list_certificate_actions

Volumes (10 tools) — storage

hetzner_list_volumes, hetzner_get_volume, hetzner_create_volume, hetzner_update_volume, hetzner_delete_volume, hetzner_attach_volume, hetzner_detach_volume, hetzner_resize_volume, hetzner_change_volume_protection, hetzner_list_volume_actions

Floating IPs (10 tools) — ips

hetzner_list_floating_ips, hetzner_get_floating_ip, hetzner_create_floating_ip, hetzner_update_floating_ip, hetzner_delete_floating_ip, hetzner_assign_floating_ip, hetzner_unassign_floating_ip, hetzner_change_floating_ip_rdns, hetzner_change_floating_ip_protection, hetzner_list_floating_ip_actions

Primary IPs (10 tools) — ips

hetzner_list_primary_ips, hetzner_get_primary_ip, hetzner_create_primary_ip, hetzner_update_primary_ip, hetzner_delete_primary_ip, hetzner_assign_primary_ip, hetzner_unassign_primary_ip, hetzner_change_primary_ip_rdns, hetzner_change_primary_ip_protection, hetzner_list_primary_ip_actions

SSH Keys (5 tools) — config

hetzner_list_ssh_keys, hetzner_get_ssh_key, hetzner_create_ssh_key, hetzner_update_ssh_key, hetzner_delete_ssh_key

DNS Zones (22 tools) — dns

hetzner_list_zones, hetzner_get_zone, hetzner_create_zone, hetzner_update_zone, hetzner_delete_zone, hetzner_change_zone_protection, hetzner_change_zone_ttl, hetzner_change_zone_primary_nameservers, hetzner_export_zonefile, hetzner_import_zonefile, hetzner_list_zone_actions, hetzner_list_zone_rrsets, hetzner_get_zone_rrset, hetzner_create_zone_rrset, hetzner_update_zone_rrset, hetzner_delete_zone_rrset, hetzner_change_zone_rrset_protection, hetzner_change_zone_rrset_ttl, hetzner_add_zone_rrset_records, hetzner_remove_zone_rrset_records, hetzner_set_zone_rrset_records, hetzner_update_zone_rrset_records

Storage Boxes (29 tools) — storage-boxes

Storage Boxes use the https://api.hetzner.com/v1 host. Token: HETZNER_STORAGE_API_TOKEN (falls back to HETZNER_API_TOKEN).

hetzner_list_storage_boxes, hetzner_create_storage_box, hetzner_get_storage_box, hetzner_update_storage_box, hetzner_delete_storage_box, hetzner_list_storage_box_folders, hetzner_list_storage_box_actions, hetzner_change_storage_box_protection, hetzner_change_storage_box_type, hetzner_reset_storage_box_password, hetzner_update_storage_box_access_settings, hetzner_rollback_storage_box_snapshot, hetzner_enable_storage_box_snapshot_plan, hetzner_disable_storage_box_snapshot_plan, hetzner_list_storage_box_types, hetzner_get_storage_box_type, hetzner_list_storage_box_snapshots, hetzner_create_storage_box_snapshot, hetzner_get_storage_box_snapshot, hetzner_update_storage_box_snapshot, hetzner_delete_storage_box_snapshot, hetzner_list_storage_box_subaccounts, hetzner_create_storage_box_subaccount, hetzner_get_storage_box_subaccount, hetzner_update_storage_box_subaccount, hetzner_delete_storage_box_subaccount, hetzner_change_storage_box_subaccount_home_directory, hetzner_reset_storage_box_subaccount_password, hetzner_update_storage_box_subaccount_access_settings

Security

  • Never commit your API token to version control
  • Use read-only tokens when you only need to list/get resources
  • Create and delete tools cost real money — Hetzner bills for provisioned resources
  • The server handles rate limiting automatically (3,600 requests/hour, exponential backoff on 429)

Disclaimer

Create, update, and delete operations may incur charges on your Hetzner Cloud account. Use read-only API tokens when possible. The authors are not responsible for any costs incurred.

Releasing

Releases ship via the GitHub Release event. Maintainer flow:

  1. Bump the version in package.json and server.json (both #/version and #/packages[0].version), then run npm install --package-lock-only to sync package-lock.json. node scripts/check-versions.mjs hard-fails unless package.json#/version matches server.json#/packages[0].version; server.json#/version is checked loosely — it may legitimately be ahead (registry-only republishes bump just that field), so a stale value passes with a WARN: line and no failure. Read the script's output rather than trusting its exit code. CHANGELOG.md is not checked at all.

  2. Update CHANGELOG.md.

  3. Commit, and merge the version bump to main before creating the release. Then create the tag yourself, on a SHA you have checked, and only then create the release from it:

    V=X.Y.Z && PR=<release-pr-number> &&
      SHA="$(gh pr view "$PR" --json mergeCommit -q .mergeCommit.oid)" && test -n "$SHA" &&
      git fetch origin main && git merge-base --is-ancestor "$SHA" origin/main &&
      PKG="$(git show "$SHA:package.json")" &&
      test "$(printf '%s' "$PKG" | node -pe 'JSON.parse(require("fs").readFileSync(0,"utf8")).version')" = "$V" &&
      CL="$(git show "$SHA:CHANGELOG.md")" &&
      printf '%s\n' "$CL" | awk -v v="$V" 'index($0,"## ["v"]")==1{f=1;next} /^## \[/{f=0} /^\[[0-9]+\.[0-9]+\.[0-9]+\]:/{f=0} f' > "/tmp/notes-v$V.md" &&
      grep -q '[^[:space:]]' "/tmp/notes-v$V.md" &&
      git tag -a "v$V" "$SHA" -m "v$V" &&
      git push origin "v$V" &&
      gh release create "v$V" --verify-tag --notes-file "/tmp/notes-v$V.md"
    

    Never run a bare gh release create vX.Y.Z. With no existing tag it places one on the tip of the default branch, so running it while the bump is still on a release branch tags the previous release's commit. The workflow then publishes whatever version it finds in that commit's package.json, and you get a vX.Y.Z GitHub Release that silently republishes the old version. The publish workflow now refuses to continue when GITHUB_REF_NAME is not v<package.json version>, so that exact scenario fails before npm publish rather than silently republishing. The sequence above is still required, and guards a case the workflow cannot: the workflow guard only runs once a release already exists, and it passes for any commit carrying the right version — so it catches a mis-tagged release, not the wrong commit being tagged.

    Each element is load-bearing:

    • gh pr view … .mergeCommit.oid names the release PR's own squash commit. Do not substitute git rev-parse origin/main — that is merely whatever is on main at the moment you look, so an unrelated merge landing in the gap gets tagged and shipped instead. gh exits 0 and prints nothing for an unmerged PR, hence the explicit test -n.
    • The && chain stops on the first failure instead of falling through to the irreversible step. Both git show calls are assigned to a variable rather than piped directly, so their exit status is actually checked — a pipeline reports only its last command's status unless pipefail is set, which is not assumed here.
    • git merge-base --is-ancestor proves the commit is reachable from main. Mere existence is not enough — a commit can be present locally because some other branch was fetched.
    • The version test reads package.json out of the target commit, not the working tree, which would still show the right version while $SHA pointed elsewhere.
    • The awk lifts that version's section out of the commit's CHANGELOG.md for --notes-file. It stops at the next ## [ heading or at the first link-reference definition, because the oldest entry has no heading after it and would otherwise swallow the entire link-reference block. grep -q rather than test -s guards the result: a section empty apart from its blank line still produces a one-byte file, which test -s accepts.
  4. The Publish to npm + MCP Registry workflow runs automatically: it npm publishes with provenance, polls the registry until the tarball is available, then pushes the matching server.json to the MCP Registry via mcp-publisher.

The workflow skips npm publish cleanly if the version is already on npm (cutover guard for releases that were partially published manually).

npm authentication

Publishing uses npm Trusted Publishing: the workflow's GitHub OIDC token (id-token: write) is exchanged for a one-shot publish token at runtime. No NPM_TOKEN secret needs to live in the repo.

The binding is configured in the npm web UI (package → Trusted Publishers): provider GitHub Actions, organization lazyants, repository hetzner-mcp-server, workflow publish-registry.yml.

License

FSL-1.1-MIT — see LICENSE for the full terms. Versions 1.1.1 and earlier remain MIT-licensed.

Reviews

No reviews yet

Be the first to review this server!

Hetzner MCP Server - MCP server for the Hetzner Cloud API — servers, networks, | MCP Marketplace