feat: add health check server implementation#76
Conversation
- Add HealthCheckServer class for server health monitoring - Implement health check types and utilities - Add comprehensive unit tests for health check functionality - Integrate health check endpoints into server configuration - Update main server to include health check initialization
Reviewer's GuideImplements a dedicated HTTP-based HealthCheckServer exposing /health and /ready endpoints on a configurable localhost port, wires it into the LighthouseMCPServer lifecycle and configuration, and adds tests plus CLI/env wiring for enabling and configuring health checks and Lighthouse API connectivity monitoring. Sequence diagram for /ready health check request flowsequenceDiagram
actor Client
participant HealthCheckServer
participant AuthManager
participant LighthouseServiceFactory
participant ILighthouseService
participant LighthouseAPI
Client->>HealthCheckServer: GET /ready
HealthCheckServer->>HealthCheckServer: handleRequest(req, res)
HealthCheckServer->>HealthCheckServer: handleReady(res)
HealthCheckServer->>HealthCheckServer: checkSDK()
HealthCheckServer->>ILighthouseService: getStorageStats()
ILighthouseService-->>HealthCheckServer: storageStats
HealthCheckServer-->>HealthCheckServer: sdkCheck
HealthCheckServer->>HealthCheckServer: checkCache()
HealthCheckServer->>AuthManager: getCacheStats()
AuthManager-->>HealthCheckServer: cacheStats
HealthCheckServer-->>HealthCheckServer: cacheCheck
HealthCheckServer->>HealthCheckServer: checkServicePool()
HealthCheckServer->>LighthouseServiceFactory: getStats()
LighthouseServiceFactory-->>HealthCheckServer: poolStats
HealthCheckServer-->>HealthCheckServer: poolCheck
HealthCheckServer->>HealthCheckServer: checkLighthouseConnectivity()
alt recent_cached_result
HealthCheckServer-->>HealthCheckServer: use lastConnectivityCheck
else needs_fresh_check
HealthCheckServer->>LighthouseAPI: HTTPS GET /api/lighthouse/file_info
LighthouseAPI-->>HealthCheckServer: response
HealthCheckServer-->>HealthCheckServer: update lastConnectivityCheck
end
HealthCheckServer-->>HealthCheckServer: connectivityCheck
HealthCheckServer-->>HealthCheckServer: aggregate checks into ReadinessStatus
alt all checks up
HealthCheckServer-->>Client: 200 ReadinessStatus status=ready
else any check down
HealthCheckServer-->>Client: 503 ReadinessStatus status=not_ready
end
Class diagram for HealthCheckServer and health check typesclassDiagram
class LighthouseMCPServer {
-Server server
-ServerConfig config
-AuthManager authManager
-LighthouseServiceFactory serviceFactory
-ILighthouseService lighthouseService
-ToolRegistry registry
-Logger logger
-HealthCheckServer healthServer
+start(): Promise<void>
+stop(): Promise<void>
}
class HealthCheckServer {
-http.Server httpServer
-number startTime
-HealthCheckDependencies deps
-HealthCheckConfig healthConfig
-Logger logger
-lastConnectivityCheck lastConnectivityCheck
+HealthCheckServer(deps: HealthCheckDependencies, healthConfig: HealthCheckConfig)
+start(): Promise<void>
+stop(): Promise<void>
+getPort(): number
+checkLighthouseConnectivity(): Promise<ReadinessCheck>
-handleRequest(req: http.IncomingMessage, res: http.ServerResponse): void
-handleHealth(res: http.ServerResponse): void
-handleReady(res: http.ServerResponse): Promise<void>
-checkSDK(): ReadinessCheck
-checkCache(): ReadinessCheck
-checkServicePool(): ReadinessCheck
-pingLighthouseApi(apiUrl: string, timeout: number): Promise<number>
-sendJSON(res: http.ServerResponse, statusCode: number, body: unknown): void
}
class HealthCheckDependencies {
+AuthManager authManager
+LighthouseServiceFactory serviceFactory
+ILighthouseService lighthouseService
+ToolRegistry registry
+ServerConfig config
+Logger logger
}
class HealthCheckConfig {
+boolean enabled
+number port
+string lighthouseApiUrl
+number connectivityCheckInterval
+number connectivityTimeout
}
class HealthStatus {
+string status
+string timestamp
+number uptime
+string version
}
class ReadinessCheck {
+string status
}
class ReadinessStatus {
+string status
+string timestamp
+ReadinessCheck sdk
+ReadinessCheck cache
+ReadinessCheck lighthouse_api
+ReadinessCheck service_pool
}
class ServerConfig {
+HealthCheckConfig healthCheck
}
class AuthManager {
+getCacheStats(): unknown
}
class LighthouseServiceFactory {
+getStats(): unknown
}
class ILighthouseService {
+getStorageStats(): unknown
}
class ToolRegistry
class Logger {
+info(message: string, meta: unknown): void
+error(message: string, meta: unknown): void
}
LighthouseMCPServer --> HealthCheckServer : manages
LighthouseMCPServer --> ServerConfig : uses
LighthouseMCPServer --> AuthManager : uses
LighthouseMCPServer --> LighthouseServiceFactory : uses
LighthouseMCPServer --> ILighthouseService : uses
LighthouseMCPServer --> ToolRegistry : uses
LighthouseMCPServer --> Logger : uses
HealthCheckServer --> HealthCheckDependencies : aggregates
HealthCheckServer --> HealthCheckConfig : uses
HealthCheckServer --> HealthStatus : returns
HealthCheckServer --> ReadinessStatus : returns
HealthCheckServer --> ReadinessCheck : returns
HealthCheckDependencies --> AuthManager
HealthCheckDependencies --> LighthouseServiceFactory
HealthCheckDependencies --> ILighthouseService
HealthCheckDependencies --> ToolRegistry
HealthCheckDependencies --> ServerConfig
HealthCheckDependencies --> Logger
ServerConfig --> HealthCheckConfig
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- In
pingLighthouseApi, you always usehttps.getand default to port 443, which will break iflighthouseApiUrlis configured with anhttpURL or a non-HTTPS custom port; consider selectinghttpvshttpsand the default port based onurl.protocol. - When starting the health check server, the log message uses
this.healthConfig.port, which will be0when an OS-assigned port is requested; it would be more accurate to log the actual bound port viathis.httpServer.address()(and optionally updatehealthConfig.port). - In the CLI handling for
--health-port,parseIntmay returnNaNfor invalid input and will be passed through to the server; add validation and surface a clear error or fallback rather than allowing an invalid port to reachlisten.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `pingLighthouseApi`, you always use `https.get` and default to port 443, which will break if `lighthouseApiUrl` is configured with an `http` URL or a non-HTTPS custom port; consider selecting `http` vs `https` and the default port based on `url.protocol`.
- When starting the health check server, the log message uses `this.healthConfig.port`, which will be `0` when an OS-assigned port is requested; it would be more accurate to log the actual bound port via `this.httpServer.address()` (and optionally update `healthConfig.port`).
- In the CLI handling for `--health-port`, `parseInt` may return `NaN` for invalid input and will be passed through to the server; add validation and surface a clear error or fallback rather than allowing an invalid port to reach `listen`.
## Individual Comments
### Comment 1
<location> `apps/mcp-server/src/index.ts:110` </location>
<code_context>
+ if (!config.healthCheck) {
+ config.healthCheck = { enabled: true, port: 8080 };
+ }
+ config.healthCheck.port = parseInt(args[i]!, 10);
+ config.healthCheck.enabled = true;
+ }
</code_context>
<issue_to_address>
**issue (bug_risk):** Validate and guard against invalid `--health-port` values to avoid `NaN` ports.
`parseInt` can return `NaN` or an out-of-range value, which will be passed directly to `HealthCheckServer.listen` and fail at runtime. Please validate the parsed value (e.g., `Number.isInteger(port)` and `0 < port && port < 65536`) and either fall back to the default or exit with a clear error if invalid.
</issue_to_address>
### Comment 2
<location> `apps/mcp-server/src/health/HealthCheckServer.ts:222-229` </location>
<code_context>
+ const start = Date.now();
+ const url = new URL("/api/lighthouse/file_info?cid=test", apiUrl);
+
+ const req = https.get(
+ {
+ hostname: url.hostname,
+ path: url.pathname + url.search,
+ port: url.port || 443,
+ timeout,
+ },
+ (res) => {
+ // Any response means the API is reachable
+ res.resume(); // Drain the response
</code_context>
<issue_to_address>
**issue (bug_risk):** Honor the protocol of `lighthouseApiUrl` instead of unconditionally using HTTPS.
`pingLighthouseApi` always calls `https.get`, so it will break if `healthConfig.lighthouseApiUrl` is `http://` (common for local/dev). Use `url.protocol` to choose `http.get` vs `https.get` (e.g. `url.protocol === "http:" ? http.get : https.get`) so the health check works for both HTTP and HTTPS endpoints.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| if (!config.healthCheck) { | ||
| config.healthCheck = { enabled: true, port: 8080 }; | ||
| } | ||
| config.healthCheck.port = parseInt(args[i]!, 10); |
There was a problem hiding this comment.
issue (bug_risk): Validate and guard against invalid --health-port values to avoid NaN ports.
parseInt can return NaN or an out-of-range value, which will be passed directly to HealthCheckServer.listen and fail at runtime. Please validate the parsed value (e.g., Number.isInteger(port) and 0 < port && port < 65536) and either fall back to the default or exit with a clear error if invalid.
| const req = https.get( | ||
| { | ||
| hostname: url.hostname, | ||
| path: url.pathname + url.search, | ||
| port: url.port || 443, | ||
| timeout, | ||
| }, | ||
| (res) => { |
There was a problem hiding this comment.
issue (bug_risk): Honor the protocol of lighthouseApiUrl instead of unconditionally using HTTPS.
pingLighthouseApi always calls https.get, so it will break if healthConfig.lighthouseApiUrl is http:// (common for local/dev). Use url.protocol to choose http.get vs https.get (e.g. url.protocol === "http:" ? http.get : https.get) so the health check works for both HTTP and HTTPS endpoints.
Pull Request
Description
Type of change
Checklist
Related Issues
Screenshots (if applicable)
Summary by Sourcery
Add a dedicated HTTP health check server exposing liveness and readiness endpoints and wire it into the MCP server lifecycle and configuration.
New Features:
Tests: