Adds the connect-by-code side of remote diagnostics and closes two real secret-leak vectors that an end-to-end gateway<->agent test surfaced. Gateway (gateway/, local stdio MCP, Claude connects once): - 14 read-only tools (server_health hub, read_log, list_logs, list_errors, get_queue_state, get_history, get_config_redacted, get_system_info, get_rotation_state, get_app_events + connect/disconnect/list/current). - The HOST is always supplied by the operator, never taken from the code. - TLS fingerprint pinning is enforced in the socket 'open' handler BEFORE the token is sent (wss opt-in); plain ws is loopback-only. - registry.json (holds bearer tokens) is gitignored; only an empty example ships. Security hardening (gates every off-box payload): - redactLogText now scrubs opaque bearer/token-family secrets that are NOT stored config credentials (e.g. a session token a hoster returns inside an error string): bare token/auth_token/refresh_token/session_token + standalone "Bearer <opaque>". Benign "token bucket" prose is left intact. - get_config_redacted deep-redacts every string leaf (JSON-safe, per-leaf, so the cookie/sess line patterns can't gobble across a compact-JSON field) and drops the history subtree (served by get_history with its own per-error redaction). This plugs leaks via globalSettings.pendingQueue[].error etc. Bind-address safety: - _safeDiagBindAddress() forces the diagnostic agent to 127.0.0.1/::1; the 0.0.0.0 UI option is removed. Direct LAN/Internet bind stays disabled until encrypted transport (wss) exists — remote access goes through an SSH/VPN tunnel to loopback. (Never plaintext ws:// on all interfaces.) Tests: end-to-end gateway<->agent gate (connect -> server_health/read_log/ get_config_redacted, asserts zero secret leakage, rejects doodstream log, path traversal and write ops); + redaction regression tests in the main suite. 385 app tests + 9 gateway tests pass; lint 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4.9 KiB
Remote Diagnostics Setup (read-only)
This guide explains how to let Claude Code run read-only diagnostics against a
Multi-Hoster-Uploader instance running on a remote Windows server, through the local
stdio MCP gateway in gateway/.
The gateway is an MCP server to Claude and a WebSocket client to a diagnostic agent inside the app. It never touches the screen, never injects input, and never writes anything on the server.
1. Enable diagnostics on the server and copy the code
On the server (the machine running the app):
- Open the app's Settings.
- Enable "Diagnose-Zugriff".
- Copy the connection code. It looks like
mhu1_<base64url...>.
The code carries a one-time auth token (and, for TLS, the server cert fingerprint). It does not carry a host — you supply the host yourself when you connect. Treat the code as a secret: anyone with the code and network reach to the agent can read diagnostics.
The agent's safe default is to bind to 127.0.0.1 (loopback only). It is not exposed to the
network. You reach it through a tunnel (next step).
2. Reach the agent over a tunnel (SSH local port-forward or WireGuard)
Because the agent binds to 127.0.0.1 on the server, open a tunnel from your machine to the
server's loopback. The agent's default port is 9110.
SSH local port-forward (recommended)
ssh -L 9110:127.0.0.1:9110 user@server
Leave that session open. Now 127.0.0.1:9110 on your machine is forwarded to
127.0.0.1:9110 on the server. You connect Claude to 127.0.0.1 (your local end of the
tunnel), not the server's public IP.
WireGuard (alternative)
Bring up a WireGuard tunnel to the server, then connect to the server's WireGuard address (or, if
you forward loopback over the tunnel, 127.0.0.1). Use whichever address resolves to the agent's
127.0.0.1:9110 on the server.
Only expose the agent directly on a LAN/VPN IP if you fully trust that network segment. The default loopback + tunnel is the secure choice.
3. Install the gateway and register it with Claude (one time)
On the machine running Claude Code:
cd gateway
npm install
Register the gateway as an MCP server (one time):
claude mcp add --transport stdio mhu-diag -- node "C:\Users\ploet\Desktop\Claude Projekte\multi-hoster-uploader\gateway\index.js"
Adjust the absolute path if your checkout lives elsewhere.
4. Usage
With the tunnel up, tell Claude:
server prod-3 at 127.0.0.1, code mhu1_<...>
Claude will:
- call
connect_server(code:"mhu1_...", host:"127.0.0.1"), - immediately read the app version via
get_system_info, - remember the server under its label in
registry.json.
Next time you can just say:
connect_server(label:"prod-3")
with no code — the gateway dials it from the registry. Then ask Claude "what's wrong?" — it will
typically start with server_health, the one-shot hub that aggregates errors, queue, rotation
and system info in a single call. Other read-only tools: read_log, list_logs, list_errors,
get_queue_state, get_history, get_config_redacted, get_rotation_state, get_app_events.
5. Failure → meaning
When a connect or a request fails, the gateway returns a human-readable cause. Quick reference:
| Symptom / signal | What it means / what to do |
|---|---|
ECONNREFUSED |
app not running / wrong port / inbound firewall closed |
ETIMEDOUT |
firewall DROP / NAT not forwarded / tunnel down |
| close code 4001 | auth timeout, retry |
| close code 4002 | stale or rotated code — re-copy the current code from the server |
| close code 4003 | brute-force lockout, wait 60s |
connected but no auth-ok |
old app version without the diagnostic agent — update that server |
| wss fingerprint mismatch | server cert changed (reinstalled?) — re-copy the code |
If you tunnel and still get ECONNREFUSED, check that the SSH session is up and that the agent is
actually listening on 127.0.0.1:9110 on the server (Diagnose-Zugriff enabled).
6. What this is — and is not
- It is READ-ONLY. It reads logs, errors, queue/history, redacted config, rotation and system info. No screen capture. No input injection. No writes or config changes.
- The code is a secret (it carries the auth token). Don't paste it into public channels.
gateway/registry.jsonstores tokens for remembered servers and is git-ignored — never commit it.