diff --git a/internal/server/health.go b/internal/server/health.go new file mode 100644 index 00000000..8a788182 --- /dev/null +++ b/internal/server/health.go @@ -0,0 +1,49 @@ +package server + +import ( + "encoding/json" + "net/http" +) + +// HealthResponse represents the JSON structure for the /health endpoint response +// as defined in MCP Gateway Specification section 8.1.1 +type HealthResponse struct { + Status string `json:"status"` // "healthy" or "unhealthy" + SpecVersion string `json:"specVersion"` // MCP Gateway Specification version + GatewayVersion string `json:"gatewayVersion"` // Gateway implementation version + Servers map[string]ServerStatus `json:"servers"` // Map of server names to their health status +} + +// BuildHealthResponse constructs a HealthResponse from the unified server's status +func BuildHealthResponse(unifiedServer *UnifiedServer) HealthResponse { + // Get server status + serverStatus := unifiedServer.GetServerStatus() + + // Determine overall health based on server status + overallStatus := "healthy" + for _, status := range serverStatus { + if status.Status == "error" { + overallStatus = "unhealthy" + break + } + } + + return HealthResponse{ + Status: overallStatus, + SpecVersion: MCPGatewaySpecVersion, + GatewayVersion: gatewayVersion, + Servers: serverStatus, + } +} + +// HandleHealth returns an http.HandlerFunc that handles the /health endpoint +// This function is used by both routed and unified modes to ensure consistent behavior +func HandleHealth(unifiedServer *UnifiedServer) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + response := BuildHealthResponse(unifiedServer) + json.NewEncoder(w).Encode(response) + } +} diff --git a/internal/server/routed.go b/internal/server/routed.go index 233c2d42..d608c6bb 100644 --- a/internal/server/routed.go +++ b/internal/server/routed.go @@ -110,29 +110,7 @@ func CreateHTTPServerForRoutedMode(addr string, unifiedServer *UnifiedServer, ap } // Health check (spec 8.1.1) - healthHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - - // Get server status - serverStatus := unifiedServer.GetServerStatus() - - // Determine overall health based on server status - overallStatus := "healthy" - for _, status := range serverStatus { - if status.Status == "error" { - overallStatus = "unhealthy" - break - } - } - - w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(map[string]interface{}{ - "status": overallStatus, - "specVersion": MCPGatewaySpecVersion, - "gatewayVersion": gatewayVersion, - "servers": serverStatus, - }) - }) + healthHandler := HandleHealth(unifiedServer) mux.Handle("/health", withResponseLogging(healthHandler)) // Close endpoint for graceful shutdown (spec 5.1.3) diff --git a/internal/server/transport.go b/internal/server/transport.go index 7c3f4d64..fcd1ab3c 100644 --- a/internal/server/transport.go +++ b/internal/server/transport.go @@ -158,29 +158,7 @@ func CreateHTTPServerForMCP(addr string, unifiedServer *UnifiedServer, apiKey st mux.Handle("/mcp", finalHandler) // Health check (spec 8.1.1) - healthHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - - // Get server status - serverStatus := unifiedServer.GetServerStatus() - - // Determine overall health based on server status - overallStatus := "healthy" - for _, status := range serverStatus { - if status.Status == "error" { - overallStatus = "unhealthy" - break - } - } - - w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(map[string]interface{}{ - "status": overallStatus, - "specVersion": MCPGatewaySpecVersion, - "gatewayVersion": gatewayVersion, - "servers": serverStatus, - }) - }) + healthHandler := HandleHealth(unifiedServer) mux.Handle("/health", withResponseLogging(healthHandler)) // Close endpoint for graceful shutdown (spec 5.1.3)