You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Wire server discovery protocol into thv serve (#4319)
* Wire server discovery protocol into thv serve
The discovery package (pkg/server/discovery/) was already implemented
and tested but had zero imports in the codebase. This wires it into
the serve command so clients (CLI, Studio) can auto-discover a running
server without hardcoded ports or environment variables.
On startup, thv serve now generates a cryptographic nonce, writes a
discovery file to $XDG_STATE_HOME/toolhive/server/server.json with
the actual listen URL (supporting port 0 and Unix sockets), and
returns the nonce via the X-Toolhive-Nonce health check header. On
shutdown the file is removed.
The skills client now tries discovery before falling back to the
TOOLHIVE_API_URL env var or the default localhost:8080, with loopback
and socket-path validation on discovered URLs.
Additional fixes: SIGTERM handling in the serve command, a 30-second
shutdown timeout (was unbounded), symlink rejection on the discovery
file read path, directory permission tightening after MkdirAll, and
constant-time nonce comparison.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Juan Antonio Osorio <ozz@stacklok.com>
* Address review feedback on server discovery
- Wrap writeDiscoveryFile check-then-write in WithFileLock to prevent
TOCTOU race when two servers start simultaneously
- Log FindProcess errors at Debug level instead of silently discarding
- Consolidate ListenURL tests into a table-driven test
- Rename healtcheck_test.go to healthcheck_test.go (fix typo)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Juan Antonio Osorio <ozz@stacklok.com>
* Create discovery directory before acquiring lock file
The discovery lock file is created in the same directory as
server.json, but the directory may not exist on a fresh system.
MkdirAll was called inside the lock callback (via WriteServerInfo),
but the lock acquisition itself needs the directory to already exist.
Create the directory before calling WithFileLock so the lock file
can be written.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review feedback on discovery wiring
- Extract shared HTTPClientForURL in the discovery package to
deduplicate transport setup between health.go and the skills client
- Propagate context.Context through NewDefaultClient and
resolveViaDiscovery instead of using context.Background()
- Add comment explaining intentional opts-shadowing order so
caller-supplied options can override discovery defaults
- Use url.JoinPath in buildHealthClient instead of string concatenation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Signed-off-by: Juan Antonio Osorio <ozz@stacklok.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0 commit comments