hetzner-mcp
Provides tools for managing Hetzner Cloud projects, account resources (such as Storage Boxes), and dedicated servers, including provisioning servers, controlling power and boot, managing DNS, setting labels, and accessing the full Hetzner REST API.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@hetzner-mcpfind all servers with label env=prod"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
hetzner-mcp
An MCP server for Hetzner. Cloud projects, account resources and dedicated servers from one connection, with the whole REST API reachable — not just the parts somebody wrapped in a tool.
npx @donedynamics/hetzner-mcp installWhat it is
Hetzner's APIs have 221 operations. Publishing 221 tools would spend the host's context budget on schemas it never calls, so this server publishes thirteen: the loop an operator actually repeats, plus a searchable catalog that reaches everything else.
It is built for people running more than one thing. A Hetzner Cloud token is created inside a project and cannot see any other project — there is no project parameter anywhere in the API — so ten projects across three accounts are simply ten connections, and every tool takes the connection by name.
Related MCP server: hcloud-mcp
Quick start
The shortest working setup is one environment variable:
export HETZNER_TOKEN=<your Hetzner Cloud API token>
npx @donedynamics/hetzner-mcp installinstall detects the MCP clients on your machine — Claude Code, Claude Desktop,
Codex, Cursor, Zed, opencode, Kimi, MiniMax — shows you exactly what it will
write, and writes only what you approve. It writes a pointer: a command and
at most a connection name. It never writes a credential into a client config.
npx @donedynamics/hetzner-mcp install --dry-run # show the diff, change nothing
npx @donedynamics/hetzner-mcp install --pin # pin the exact version
npx @donedynamics/hetzner-mcp doctor # what is configured, and what is wrong with itSeveral projects, several accounts
Put the name in the variable and you have a second connection:
export HETZNER_TOKEN_PROD=... # connection "prod"
export HETZNER_TOKEN_STAGING=... # connection "staging"
export HETZNER_ACCOUNT_TOKEN=... # connection "account" (Storage Boxes)Every tool then takes connection: "prod", and find_resources takes
connection: "*" to search all of them at once. With exactly one connection
configured, the parameter does not exist at all — there is nothing to choose.
For per-connection settings — a read-only production connection, a credential from 1Password, a longer timeout — use a config file. Full reference: docs/connections.md.
{
"version": 1,
"defaultConnection": "prod",
"connections": {
"prod": { "tokenEnv": "HZ_PROD", "readOnly": true },
"prod-write": { "tokenCommand": ["op", "read", "op://Infra/hcloud/credential"] },
"storage": { "surface": "hetzner", "tokenEnv": "HZ_ACCOUNT" }
}
}Credentials cannot go in that file. The schema has no token property and
rejects unknown keys, so writing one is a startup error that tells you the three
places it can live instead.
Three surfaces
Hetzner is not one API, and this server does not pretend otherwise:
Surface | Address | A credential covers |
|
| one Cloud project — servers, volumes, networks, firewalls, load balancers, DNS |
|
| the account — Storage Boxes |
|
| the account — dedicated servers (planned, v0.3) |
The surface is always visible, because a cloud server is a virtual machine
billed by the hour and a robot server is leased physical hardware on a monthly
contract with a cancellation period. Merging those two into one word is how
"reboot the server" becomes a question nobody can answer safely.
You never configure an address. Hetzner runs exactly one instance of each API, so it is derived from the surface — a value you could type there could only repeat what the server already knows, or be wrong.
The tools
Tool | What it does |
| Find resources by name, by label selector, or by listing a type — across one connection or all of them |
| The full stored configuration of one resource |
| Read an Action, optionally waiting for it to finish, or list a resource's recent Actions |
| CPU, disk and network for a server; connections, requests and bandwidth for a load balancer |
| What Hetzner publishes, with the currency and the VAT rate |
| Provision a server (billable — see below) |
| Power and boot control, rescue mode, ISO and network attachment, volume attach/detach/resize, IP assignment, load balancer targets |
| Zones and record sets |
| Set labels — which is what makes |
| Everything else in the API, all 221 operations |
| Deletes, rebuilds and overwrites — registered only when explicitly enabled |
Most of this API is asynchronous
144 of Hetzner's 221 operations return an Action rather than a result: the
call returns {action: {status: "running"}} and the work happens afterwards. So
waiting is the default here rather than a convenience, and every response says
in meta.action.awaited whether the work actually finished or the wait gave up.
A tool that reported a running Action as done would be worse than one that never
waited, because you could not tell.
Safety
Deletes are off by default. execute_destructive_operation is not
registered unless HETZNER_ALLOW_DESTRUCTIVE=true — not listed-and-refusing,
absent. Nothing in tools/list then carries destructiveHint: true, so a host
that auto-approves non-destructive tools is auto-approving something genuinely
non-destructive.
Four operations are destructive without being deletes, and the build fails if any of them stops matching: rebuilding a server, importing a zone file, replacing a record set, and rolling a Storage Box back to a snapshot.
Read-only is a ceiling. HETZNER_READ_ONLY=true, or readOnly on one
connection, refuses every non-GET at the HTTP client before the socket opens. A
connection cannot opt back out of it.
No tool schema can name a host. There is no baseUrl, url, host or
credential parameter anywhere. connection is an enum over the names you
configured. An injected instruction to point at another server has nowhere to
land.
One thing to know before you use writes
Operations that open a bill are not gated. With a write-capable connection,
provisioning a server is reachable without any additional flag. The server makes
the cost visible rather than absent — search_operations marks those operations
costly, and a call that created something reports Hetzner's published price in
meta.billing.
That is a real mitigation for a model reasoning in good faith and not a
mitigation against prompt injection. If it is the wrong trade for you, use a
read-only Hetzner token, or readOnly: true, and keep writes on a separate
connection you name explicitly.
The full threat model is in SECURITY.md, including the parts where the news is not good.
Environment reference
Variable | Effect |
| A Cloud connection |
| An account-API connection |
| A Robot connection |
| Which connection reads default to |
| Register the destructive door |
| Refuse every write, server-wide |
| Path to a config file |
|
|
Documentation
docs/connections.md — connections, credentials, precedence
SECURITY.md — threat model and recommended posture
docs/clients/ — per-client installation notes
Development
npm install
npm test # 1238 tests
npm run typecheck
npm run codegen # regenerate the catalog from the vendored OpenAPI specs
npm run buildThe catalog is generated from Hetzner's own OpenAPI specifications, which are
vendored into scripts/ and committed. Every MCP client spawns this process
fresh, so parsing 3.4 MB of spec on each start — or fetching it — would be worse
than a file in git. CI regenerates and diffs, so an upstream change breaks the
build loudly instead of shipping a stale tool surface.
Contributions welcome — see CONTRIBUTING.md.
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityDmaintenanceA Model Context Protocol server that allows language models to manage Hetzner Cloud resources through structured functions, including servers, volumes, firewalls, and SSH keys.30133MIT
- AlicenseCqualityDmaintenanceA Model Context Protocol server for the Hetzner Cloud API that enables natural language management of cloud infrastructure. Users can list, create, and modify servers, networks, volumes, and load balancers through MCP-compatible clients.6710MIT
- Alicense-qualityCmaintenanceOpen-source MCP server for managing Hetzner Cloud infrastructure with two management layers: * Layer 1 — Hetzner Cloud API (35 tools): Server power control, metrics, snapshots, backups, firewalls, DNS zones and records, rescue mode, server rebuild and rescale. Works even when the server OS is unresponsive. * Layer 2 — SSH (25 tools): Service management (systemd), Nginx config and reload,MIT
- AlicenseBqualityCmaintenanceEnables conversational management of Hetzner Cloud, DNS, and Storage Box infrastructure through 137 MCP tools for CRUD operations and actions like server power control, DNS zone management, and storage box snapshots.100MIT
Related MCP Connectors
Personal assistant MCP server with search, execute, packages, jobs, secrets, and integrations.
An MCP server that let you interact with Cycloid.io Internal Development Portal and Platform
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/devrim-1283/hetzner-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server