hetzner-mcp

hetzner-mcp

MCP server for Hetzner. Enables managing cloud projects, account resources, and dedicated servers, with the entire REST API reachable through a searchable tool catalog.

Category
访问服务器

README

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 install

What 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.

Quick start

The shortest working setup is one environment variable:

export HETZNER_TOKEN=<your Hetzner Cloud API token>
npx @donedynamics/hetzner-mcp install

install 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 it

Several 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
cloud (default) api.hetzner.cloud/v1 one Cloud project — servers, volumes, networks, firewalls, load balancers, DNS
hetzner api.hetzner.com/v1 the account — Storage Boxes
robot robot-ws.your-server.de 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 Find resources by name, by label selector, or by listing a type — across one connection or all of them
get_resource The full stored configuration of one resource
get_action Read an Action, optionally waiting for it to finish, or list a resource's recent Actions
get_metrics CPU, disk and network for a server; connections, requests and bandwidth for a load balancer
get_pricing What Hetzner publishes, with the currency and the VAT rate
create_server Provision a server (billable — see below)
control_resource Power and boot control, rescue mode, ISO and network attachment, volume attach/detach/resize, IP assignment, load balancer targets
manage_dns Zones and record sets
set_labels Set labels — which is what makes find_resources powerful
search_operationsdescribe_operationexecute_read_operation / execute_write_operation Everything else in the API, all 221 operations
execute_destructive_operation 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
HETZNER_TOKEN[_<NAME>] A Cloud connection
HETZNER_ACCOUNT_TOKEN[_<NAME>] An account-API connection
HETZNER_ROBOT_USER_<NAME> + HETZNER_ROBOT_PASSWORD_<NAME> A Robot connection
HETZNER_CONNECTION Which connection reads default to
HETZNER_ALLOW_DESTRUCTIVE Register the destructive door
HETZNER_READ_ONLY Refuse every write, server-wide
HETZNER_MCP_CONFIG Path to a config file
HETZNER_LOG_LEVEL error · warn · info · debug

Documentation

Development

npm install
npm test          # 1238 tests
npm run typecheck
npm run codegen   # regenerate the catalog from the vendored OpenAPI specs
npm run build

The 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

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选
mcp-server-qdrant

mcp-server-qdrant

这个仓库展示了如何为向量搜索引擎 Qdrant 创建一个 MCP (Managed Control Plane) 服务器的示例。

官方
精选
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选