Releases: ni-c/hetzner-dns-mcp
Release list
v0.3.0
Added
Dockerfile(multi-stage, non-root, stdio entrypoint) and.dockerignore,
so registries that build and introspect the server in a container no longer
have to guess a build.- Multi-arch container images (amd64/arm64) at
ghcr.io/ni-c/hetzner-dns-mcp, published from CI with an SBOM and
max-mode build provenance and scanned with Trivy on every push and pull
request.server.jsonlists the image as an OCI package, so the MCP
registry offers it alongside the npm package. HETZNER_READ_ONLY=trueregisters only the seven read-only tools. The write
tools are not registered at all rather than rejected when called, so there is
no code path from a write request to the API.- Documentation site at hetzner-dns-mcp.ni-c.de
with a guide, the full tool reference and the security model.
Changed
- A missing
HETZNER_API_TOKENno longer exits at startup. The server
completes the MCP handshake and lists its tools without credentials; the
token is required when a tool actually calls the API, which then fails with
the same setup instructions as before. Base URL validation still exits,
since a bad base URL can leak the token. - Breaking: the
confirmboolean is gone. Destructive tools now take an
optionalconfirmTokeninstead — see below. Callers that passed
confirm: truewill be refused and handed a token to call again with. engines.noderaised to>=22; Node 20 is end-of-life and is no longer in
the CI matrix. The container has been on Node 24 all along.- Published source maps embed their sources, since only
dist/is shipped and
the maps previously pointed at asrc/that is not in the tarball.
Security
-
Destructive tools require a server-issued confirmation token. Every
irreversible tool refuses its first call and returns a random, single-use
token with a five-minute lifetime; a second call must repeat the identical
arguments and pass it. Forset_records,remove_records,
import_zonefileandchange_primary_nameserversthe token is bound to a
SHA-256 fingerprint of the payload, so a confirmation for one record list
cannot write a different one.The previous
confirmboolean was a value the model set itself, while the
refusal messages pasted the current RRSet contents back as raw API JSON.
Together that was a self-approving loop: an instruction hidden in a TXT
record value or a zone-file comment arrived verbatim in the very message
asking for confirmation. A token cannot be produced that way, because it
only ever exists in a previous result from this server. -
Removing protection now counts as destructive.
change_zone_protectionand
change_rrset_protectionhad no guard at all, so unprotecting a zone and
deleting it was two uninterrupted calls; disabling protection is now gated
exactly like the deletion it enables, while enabling it stays immediate. -
Confirmation messages no longer quote anything read back from the API. They
report record counts and TTLs only. -
API responses are wrapped in an
<untrusted-data>envelope, keys matching
tsig_key,token,secret,passwordorcredentialare redacted,
single values are truncated at 4 000 characters and whole results at
200 000. -
Upstream error bodies are truncated at 2 000 characters and HTML error pages
— a reverse proxy or WAF in front of the API — are dropped entirely instead
of being pasted into the model's context. -
HETZNER_API_TOKENandHETZNER_API_BASE_URLare deleted from the
environment once read, so a later crash report or diagnostic dump cannot
expose them. An unparseable base URL is no longer echoed back, since it can
contain auser:token@part. -
mcp-publisheris pinned to a release and verified against its SHA-256
before it runs. It was fetched from/releases/latestunverified, in a job
holdingid-token: write. -
The runtime image no longer ships npm, npx or corepack; they are never
invoked there, but their vendored dependencies kept appearing in scans. -
CI additionally runs CodeQL and a Trivy scan of the image for both
architectures.
v0.2.3
Changed
- zod updated to v4 (the MCP SDK supports
^3.25 || ^4.0);z.record()
now uses the explicit two-argument form. - Dev dependencies updated: TypeScript 6 (
@types/nodeis listed explicitly
in the tsconfigtypesfield, as TS 6 no longer auto-includes@types
packages),@eslint/js10 (matching ESLint 10).
v0.2.2
Added
- Listed in the official MCP Registry
asio.github.ni-c/hetzner-dns-mcp; the release workflow publishes registry
updates automatically via GitHub OIDC (server.json,mcpNamefield).
Changed
- Dev dependencies updated: vitest 4 (+ matching
@vitest/coverage-v8),
ESLint 10,@types/node26; GitHub Actions pins bumped to current
major versions. Coverage thresholds rebased to vitest 4's stricter
AST-based measurement.
v0.2.1
Added
- Release workflow: pushing a
vX.Y.Ztag runs the tests, publishes to npm
via Trusted Publishing (OIDC, with provenance) and creates a GitHub release
with the notes from this changelog. - CI: test matrix extended to Node 24, coverage report (thresholds enforced,
uploaded as artifact), weeklynpm auditjob, Dependabot for npm packages
and pinned GitHub Actions.
v0.2.0
First public release of hetzner-dns-mcp — a Model Context Protocol (MCP) server for managing DNS zones and records via the Hetzner Cloud API.
Features
- 22 tools covering zones, RRSets (record sets) and zone actions: list/create/update/delete, zone file import/export, TTLs, protection, primary nameservers
- Targets the current Hetzner Cloud DNS API (
api.hetzner.cloud) — the legacydns.hetzner.comAPI (shut down May 2026) is not supported - Configuration via
HETZNER_API_TOKEN(and optionalHETZNER_API_BASE_URL)
Safety & hardening (0.2.0)
- All destructive tools (
delete_zone,delete_rrset,import_zonefile,set_records,remove_records,change_primary_nameservers) require an explicitconfirm=trueand report the current state when refusing HETZNER_API_BASE_URLis validated (https only, no embedded credentials, warning on non-default hosts)- Zone/RRSet name parameters are restricted to a safe character set;
./..are rejected (URL path traversal) - API requests refuse redirects and time out after 30 s
- CI:
GITHUB_TOKENrestricted tocontents: read, actions pinned to commit SHAs
Install
claude mcp add hetzner-dns -s user \
-e HETZNER_API_TOKEN=your-token \
-- npx -y hetzner-dns-mcpSee the README for Claude Desktop and Codex setup.
Full changelog: CHANGELOG.md