Pod

Yes, this is on purpose. Pod is built for agents, so the default page is plain HTML.
Human? View the normal website.
Agent? You probably prefer /mcp/hetzner/issues.md or /mcp/hetzner/issues.json, or Pod over MCP.

Reported issues for hetzner

Pod holds 18 of 19 problems reported by people outside the maintainer team. Issues filed by the project's own owners, members and collaborators are excluded entirely — a maintainer's release checklist is not a warning to a prospective user.

Back to hetzner.

Most discussed

Harden get-action-exclusion policy test against concatenated/indirected GET paths

Surfaced by codex review during #53 (PR #67).

PR #67 widened the check-(a) regex in src/tests/get-action-exclusion.test.ts to also match storageBoxRequest( (previously hetznerRequest( only). codex noted the underlying regex-based source-text scan still has ordinary false-negative paths — both of these forbidden calls pass with zero violations:

storageBoxRequest('GET', '/actions/' + actionId);      // string concatenation

const path = `/actions/${actionId}`;
storageBoxRequest('

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/69) · 2026-07-18 · closed · 1 comment

### Fleet: lockstep drift — shared-helper divergence, lockfile patch lag, drift-check script

The fleet deliberately copies shared code instead of extracting a package; these are the places where the copies have drifted or should be re-synced in one pass.

## Findings

### axios patch-version drift across fleet lockfiles (1.18.0 vs 1.17.0), all behind latest 1.18.1

`hetzner-mcp-server/package-lock.json:1127` — **low** refactor

**Evidence:** hetzner-mcp-server/package-lock.json L1126-1127: "node_modules/axios": { "version": "1.17.0" }  |  transkribus-mcp-server/package-lock.json L1126-1

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/59) · 2026-07-03 · closed · 1 comment

### Small cleanups: hetzner_list_server_actions missing sort/status filters; rrsetPath helper in zones.ts

## Findings

### hetzner_list_server_actions is the only 1 of 11 list-actions tools missing sort/status filters

`hetzner-mcp-server/src/tools/servers.ts:272` — **low** refactor

**Evidence:** inputSchema: z.object({ id: IdSchema.describe('Server ID'), ...PaginationParams }) — no SortParam/ActionStatusFilterParam, while the other ten list_*_actions tools (volumes.ts:167-171, floating-ips.ts:166-170, zones.ts:214-218, etc.) all spread '...SortParam, ...ActionStatusFilterParam, ...PaginationParams

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/55) · 2026-07-03 · closed · 1 comment

### Port the hardened Retry-After parser from lexware #54 (HTTP-date → NaN → immediate retry; unbounded sleep)

Same fleet bug-class lexware fixed in lazyants/lexware-mcp-server#54 — the fix (`parseRetryAfterMs` + `retry-after.test.ts`) is vendor-neutral and can be copied nearly verbatim. Sibling issue exists for transkribus.

## Findings

### 429 Retry-After parsed with parseInt only — HTTP-date value yields NaN delay (immediate retry hammering); huge delta-seconds sleeps unbounded

`hetzner-mcp-server/src/services/hetzner.ts:72` — **low** bug

**Evidence:** "const retryAfter = error.response.headers['re

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/50) · 2026-07-03 · closed · 1 comment

### Scrub config.params/url in the axios sanitizer (response.data value-redaction: decided against)

Follow-up from #44 (PR #46). Originally filed as an open fleet-wide design question. **Triaged 2026-08-20 against `fdf1336`: the question is now answered — transkribus v3.0.0 (PR #37, trk #26) shipped the reference design, and part of it has already landed here.** Scope narrowed to what is actually left.

## Decided — no work

**1. Fail-closed sanitizer + combined-regex value redaction across `response.data` / headers / statusText / message / stack: NOT taken for hetzner.**

Transkribus needs it

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/47) · 2026-06-22 · open · 1 comment

### Defense-in-depth: drop leaky { cause: err } on axios rethrows

`src/services/hetzner.ts` `request()` rethrows with `new Error(msg, { cause: err })`, where `err` is the `AxiosError` whose `config.headers.Authorization` holds the bearer token. The fleet documents this as a secret-leak risk (`util.inspect`/`console.error(err)` walking the cause chain can surface the token).

**Not currently exploitable / not introduced by #42:** pre-existing on `main`; the only consumers (`handleToolRequest`, `toolError`) read `err.message` ONLY and never walk the cause. #42 m

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/44) · 2026-06-20 · closed · 1 comment

### CI audit gate is red: fast-uri/hono override pins have rotted, axios lockfile stale (6 vulns, 2 high)

The CI gate `npm audit --audit-level=moderate --omit=dev` in `.github/workflows/test.yml` **fails on the current checkout**: exit 1, **6 vulnerabilities (3 high, 2 moderate, 1 low)**.

Nothing in this repo changed — the advisory database did. Two override pins were correct when written and have since **rotted in place** as later GHSAs extended their ranges.

## Measured — re-measured 2026-08-20 against `fdf1336`

The table below **replaces** the original 2026-07-26 measurement. Three lines chang

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/71) · 2026-07-26 · closed · 0 comments

### list-actions sort/status filters: single comma-separated string vs repeatable query keys

Surfaced by codex review during the #55a work (PR #64).

The shared `SortParam` and `ActionStatusFilterParam` in `src/schemas/common.ts` model `sort` and `status` as single optional strings (`status` is documented as a "comma-separated list of running, success, error"). These are spread into all 11 `hetzner_list_*_actions` tools.

Hetzner's action-list endpoints (`GET /<resource>/{id}/actions`) may expect **repeatable query keys** (`?status=running&status=success`, `?sort=id:asc&sort=command:des

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/68) · 2026-07-18 · open · 0 comments

## Most recent

### pathSeg('..') does not stop traversal where the URL template supplies literal slashes

Latent, found during transkribus-mcp-server #32 (PR #37).

`pathSeg` (= `encodeURIComponent`) does **not** stop `..` path traversal when a URL template supplies its own literal slashes, because `encodeURIComponent` never escapes `.` — `pathSeg('..') === '..'`. So for a template like `/x/${pathSeg(seg)}/y`, `seg='..'` still normalizes up a directory after the server decodes.

hetzner's own `src/schemas/common.ts` `pathSeg` + its `common.test.ts` lock have **no** `''`/`'.'`/`'..'` cases. Transkrib

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/62) · 2026-07-17 · closed · 0 comments

### 429 backoff mis-parses Retry-After HTTP-date and ratelimit-reset to NaN → immediate retry

The 429 retry interceptor computes its delay with `parseInt(...) * 1000`, which yields `NaN` for the RFC 7231 HTTP-date form of `Retry-After` (only delta-seconds parse). `setTimeout(NaN)` fires immediately, collapsing the backoff into a tight retry loop against an already rate-limited API. Same class as lexware #54 (fixed there with `parseRetryAfterMs`, shipped in lexware 4.0.0).

- `src/services/hetzner.ts:72` — `delay = parseInt(retryAfter, 10) * 1000` (the `Retry-After` path).
- `src/services

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/61) · 2026-07-17 · closed · 0 comments

### Fleet: fleet-root docs drift (CLAUDE.md versions/counts, stale REGISTRY-STEPS.md + publishing guide, hygiene SKILL.md Zod4 claim)

These files live at the local fleet root (not inside any of the three server repos); tracked here per the Fleet: convention.

**Re-verified 2026-08-20 against `fdf1336`.** Two of the five findings moved; the evidence below replaces the 2026-07-03 measurement.

## 1. Fleet CLAUDE.md npm version table — CONFIRMED, but the cited numbers were superseded and it has rotted again

The original evidence (`3.2.0/2.3.0/2.1.1`) is stale — the table was since updated and now reads `4.2.0 / 2.3.1 / 3.0.0`. M

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/60) · 2026-07-03 · open · 0 comments

### Feature ideas from audit: wait_for_action, metrics `step`, list-filter parity, vswitch route param, pricing filter

Curated from the audit's gap analysis against the live Hetzner API docs. Ordered by value.

## Proposals

- **Add a hetzner_wait_for_action convenience tool (poll per-resource action list until terminal status)** _(medium)_ — Nearly every mutating tool (create_server, resize, rebuild, attach_volume, change_type, import_zonefile...) returns an async `action` object, and Hetzner deprecated the per-action-id GET endpoints in April 2026 — so an LLM client today must hand-loop hetzner_list_*_actions 

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/56) · 2026-07-03 · open · 0 comments

### Fleet: packaging hygiene — compiled tests ship in all three npm tarballs; add pack guards

Applies to all three fleet repos. **Re-measured 2026-08-20 against `fdf1336` via `npm pack --dry-run --json`.**

## Finding

**The compiled test suite ships to every npm consumer.** Of the **211 files** in the hetzner tarball, **102 are `dist/tests/**`** — 34 `.test.js`, plus a `.d.ts` and `.js.map` for each. Nearly half the published package is tests.

Root cause is one line: `tsconfig.json:17` `"include": ["src/**/*"]` with `"outDir": "dist"` compiles `src/tests/**` into `dist/tests/**`, and `

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/57) · 2026-07-03 · open · 0 comments

### Dead code: src/types/ (~550 lines, one real import) and dead pagination constants

## Findings

### src/types/ is ~550 lines of dead code — only ZONE_RRSET_TYPES is ever imported

`hetzner-mcp-server/src/types/common.ts:1` — **medium** refactor

**Evidence:** Only import from the whole tree: 'src/tools/zones.ts:15:import { ZONE_RRSET_TYPES } from ../types/zones.js'. No handler uses hetznerRequest<T>/storageBoxRequest<T> generics, so 15 files of interfaces (Server, HetznerAction, ZoneRRSet...) type-check nothing and silently drift; services/hetzner.ts even re-declares its own '

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/54) · 2026-07-03 · closed · 0 comments

### Registrar-list duplication leaves 29 Storage Box tools outside the Zod4 required[] guard (+ other scan blind spots)

The zod4-schema-enumeration test is the fleet's primary defense against the Zod 4 optin required[]-drop, and it silently omits the entire Storage Box domain because registrar lists are hand-copied in 11 places.

## Findings

### Zod4 required[]/describe regression guard omits all 29 Storage Box tools

`hetzner-mcp-server/src/tests/zod4-schema-enumeration.test.ts:54` — **medium** test-gap

**Evidence:** The header claims "This test enumerates EVERY tool registered against a freshly-built MCP serv

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/53) · 2026-07-03 · closed · 0 comments

### hetzner_create_server exposes `automount` but not the `volumes` param it depends on

## Findings

### hetzner_create_server exposes `automount` but not the `volumes` param it depends on

`hetzner-mcp-server/src/tools/servers.ts:64` — **low** bug

**Evidence:** Schema has `automount: z.boolean().optional().describe('Auto-mount volumes after attach')` but no `volumes` field. The live spec's POST /servers body includes `volumes` (volume IDs to attach at creation); `automount` only applies to those volumes. As exposed, `automount` promises behavior the tool can never trigger — a dea

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/52) · 2026-07-03 · closed · 0 comments

### Error sanitizer keeps config.data — request-body secrets survive on the cause chain

Distinct from #47 (which is about `response.data`): this is the **request** body. Certificate `private_key`, Storage Box passwords and TSIG keys travel through request bodies and survive `scrubConfig`.

## Findings

### Axios error sanitizer keeps config.data — request-body secrets (certificate private_key, Storage Box passwords, TSIG keys) survive on the cause chain

`hetzner-mcp-server/src/services/hetzner.ts:144` — **low** security

**Evidence:** scrubConfig only scrubs headers/auth: "scrubAu

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/51) · 2026-07-03 · closed · 0 comments

### hetzner_create_primary_ip: replace removed `datacenter` param with `location` (+ optional `assignee_id`)

API drift verified against the live Hetzner OpenAPI spec (2026-07-03): the create schema now has `additionalProperties: false` and no `datacenter` property, so the tool cannot place an unassigned Primary IP at all. Related to the deprecation wave tracked in #43 (reference-data tools), but this one breaks a create tool.

## Findings

### hetzner_create_primary_ip still sends removed `datacenter` param and lacks its `location` replacement

`hetzner-mcp-server/src/tools/primary-ips.ts:49` — **mediu

[Read the thread](https://github.com/lazyants/hetzner-mcp-server/issues/49) · 2026-07-03 · closed · 0 comments

The remaining reports are on [the project's issue tracker](https://github.com/lazyants/hetzner-mcp-server/issues).