Skip to content

Commit d449c8a

Browse files
authored
/heath for http, see (#225)
1 parent 070e0d3 commit d449c8a

File tree

4 files changed

+136
-136
lines changed

4 files changed

+136
-136
lines changed

internal/auth/oauth/endpoints.go

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,6 @@ func (em *EndpointManager) RegisterEndpoints(mux *http.ServeMux) {
119119

120120
// OAuth 2.0 token endpoint for Authorization Code exchange
121121
mux.HandleFunc("/oauth2/v2.0/token", em.tokenHandler())
122-
123-
// Health check endpoint (unauthenticated)
124-
mux.HandleFunc("/health", em.healthHandler())
125122
}
126123

127124
// authServerMetadataProxyHandler proxies authorization server metadata from Azure AD
@@ -375,38 +372,6 @@ func (em *EndpointManager) tokenIntrospectionHandler() http.HandlerFunc {
375372
}
376373
}
377374

378-
// healthHandler provides a simple health check endpoint
379-
func (em *EndpointManager) healthHandler() http.HandlerFunc {
380-
return func(w http.ResponseWriter, r *http.Request) {
381-
// Set CORS headers for all requests
382-
em.setCORSHeaders(w, r)
383-
384-
// Handle preflight OPTIONS request
385-
if r.Method == http.MethodOptions {
386-
w.WriteHeader(http.StatusNoContent)
387-
return
388-
}
389-
390-
if r.Method != http.MethodGet {
391-
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
392-
return
393-
}
394-
395-
response := map[string]interface{}{
396-
"status": "healthy",
397-
"oauth": map[string]interface{}{
398-
"enabled": em.cfg.OAuthConfig.Enabled,
399-
},
400-
}
401-
402-
w.Header().Set("Content-Type", "application/json")
403-
if err := json.NewEncoder(w).Encode(response); err != nil {
404-
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
405-
return
406-
}
407-
}
408-
}
409-
410375
// protectedResourceMetadataHandler handles OAuth 2.0 Protected Resource Metadata requests
411376
func (em *EndpointManager) protectedResourceMetadataHandler() http.HandlerFunc {
412377
return func(w http.ResponseWriter, r *http.Request) {

internal/auth/oauth/endpoints_test.go

Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ func TestEndpointManager_RegisterEndpoints(t *testing.T) {
5353
{"POST", "/oauth/register", http.StatusBadRequest}, // Missing required data
5454
{"POST", "/oauth/introspect", http.StatusBadRequest}, // Missing token param
5555
{"GET", "/oauth/callback", http.StatusBadRequest}, // Missing required params
56-
{"GET", "/health", http.StatusOK},
5756
}
5857

5958
for _, tc := range testCases {
@@ -192,41 +191,6 @@ func TestTokenIntrospectionEndpointMissingToken(t *testing.T) {
192191
}
193192
}
194193

195-
func TestHealthEndpoint(t *testing.T) {
196-
cfg := createTestConfig()
197-
198-
provider, _ := NewAzureOAuthProvider(cfg.OAuthConfig)
199-
manager := NewEndpointManager(provider, cfg)
200-
201-
req := httptest.NewRequest("GET", "/health", nil)
202-
w := httptest.NewRecorder()
203-
204-
handler := manager.healthHandler()
205-
handler(w, req)
206-
207-
if w.Code != http.StatusOK {
208-
t.Errorf("Expected status 200, got %d", w.Code)
209-
}
210-
211-
var response map[string]interface{}
212-
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
213-
t.Fatalf("Failed to parse response: %v", err)
214-
}
215-
216-
if response["status"] != "healthy" {
217-
t.Errorf("Expected status healthy, got %v", response["status"])
218-
}
219-
220-
oauth, ok := response["oauth"].(map[string]interface{})
221-
if !ok {
222-
t.Error("Expected oauth object in response")
223-
}
224-
225-
if oauth["enabled"] != true {
226-
t.Errorf("Expected oauth enabled true, got %v", oauth["enabled"])
227-
}
228-
}
229-
230194
func TestValidateClientRegistration(t *testing.T) {
231195
cfg := createTestConfig()
232196

@@ -488,13 +452,13 @@ func TestCORSHeaders(t *testing.T) {
488452

489453
for _, tt := range tests {
490454
t.Run(tt.name, func(t *testing.T) {
491-
req := httptest.NewRequest("GET", "/health", nil)
455+
req := httptest.NewRequest("GET", "/.well-known/oauth-protected-resource", nil)
492456
if tt.origin != "" {
493457
req.Header.Set("Origin", tt.origin)
494458
}
495459
w := httptest.NewRecorder()
496460

497-
handler := manager.healthHandler()
461+
handler := manager.protectedResourceMetadataHandler()
498462
handler(w, req)
499463

500464
corsOrigin := w.Header().Get("Access-Control-Allow-Origin")

internal/server/server.go

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,39 @@ func (s *Service) registerPrompts() {
178178
prompts.RegisterHealthPrompts(s.mcpServer, s.cfg)
179179
}
180180

181+
// healthHandler provides a simple health check endpoint
182+
func (s *Service) healthHandler() http.HandlerFunc {
183+
return func(w http.ResponseWriter, r *http.Request) {
184+
if r.Method != http.MethodGet {
185+
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
186+
return
187+
}
188+
189+
response := map[string]interface{}{
190+
"status": "healthy",
191+
"version": version.GetVersion(),
192+
"transport": s.cfg.Transport,
193+
"oauth": map[string]interface{}{
194+
"enabled": s.cfg.OAuthConfig.Enabled,
195+
},
196+
}
197+
198+
w.Header().Set("Content-Type", "application/json")
199+
if err := json.NewEncoder(w).Encode(response); err != nil {
200+
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
201+
return
202+
}
203+
}
204+
}
205+
181206
// createCustomHTTPServerWithHelp404 creates a custom HTTP server that provides
182207
// helpful 404 responses for the MCP server
183208
func (s *Service) createCustomHTTPServerWithHelp404(addr string) *http.Server {
184209
mux := http.NewServeMux()
185210

211+
// Register health check endpoint (always available)
212+
mux.HandleFunc("/health", s.healthHandler())
213+
186214
// Register OAuth endpoints if OAuth is enabled
187215
if s.cfg.OAuthConfig.Enabled {
188216
if s.endpointManager == nil {
@@ -194,7 +222,7 @@ func (s *Service) createCustomHTTPServerWithHelp404(addr string) *http.Server {
194222

195223
// Handle all other paths with a helpful 404 response
196224
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
197-
if r.URL.Path != "/mcp" {
225+
if r.URL.Path != "/mcp" && r.URL.Path != "/health" {
198226
w.Header().Set("Content-Type", "application/json")
199227
w.WriteHeader(http.StatusNotFound)
200228

@@ -206,6 +234,7 @@ func (s *Service) createCustomHTTPServerWithHelp404(addr string) *http.Server {
206234
"requests": "POST /mcp - Send MCP requests (requires Mcp-Session-Id header)",
207235
"listen": "GET /mcp - Listen for notifications (requires Mcp-Session-Id header)",
208236
"terminate": "DELETE /mcp - Terminate session (requires Mcp-Session-Id header)",
237+
"health": "GET /health - Health check",
209238
},
210239
}
211240

@@ -216,7 +245,6 @@ func (s *Service) createCustomHTTPServerWithHelp404(addr string) *http.Server {
216245
"auth-server-metadata": "GET /.well-known/oauth-authorization-server - Authorization server metadata",
217246
"client-registration": "POST /oauth/register - Dynamic client registration",
218247
"token-introspection": "POST /oauth/introspect - Token introspection",
219-
"health": "GET /health - Health check",
220248
}
221249
for k, v := range oauthEndpoints {
222250
response["endpoints"].(map[string]string)[k] = v
@@ -241,6 +269,9 @@ func (s *Service) createCustomHTTPServerWithHelp404(addr string) *http.Server {
241269
func (s *Service) createCustomSSEServerWithHelp404(sseServer *server.SSEServer, addr string) *http.Server {
242270
mux := http.NewServeMux()
243271

272+
// Register health check endpoint (always available)
273+
mux.HandleFunc("/health", s.healthHandler())
274+
244275
// Register OAuth endpoints if OAuth is enabled
245276
if s.cfg.OAuthConfig.Enabled {
246277
if s.endpointManager == nil {
@@ -266,7 +297,7 @@ func (s *Service) createCustomSSEServerWithHelp404(sseServer *server.SSEServer,
266297

267298
// Handle all other paths with a helpful 404 response
268299
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
269-
if r.URL.Path != "/sse" && r.URL.Path != "/message" {
300+
if r.URL.Path != "/sse" && r.URL.Path != "/message" && r.URL.Path != "/health" {
270301
w.Header().Set("Content-Type", "application/json")
271302
w.WriteHeader(http.StatusNotFound)
272303

@@ -276,6 +307,7 @@ func (s *Service) createCustomSSEServerWithHelp404(sseServer *server.SSEServer,
276307
"endpoints": map[string]string{
277308
"sse": "GET /sse - Establish SSE connection for real-time notifications",
278309
"message": "POST /message - Send MCP JSON-RPC messages",
310+
"health": "GET /health - Health check",
279311
},
280312
}
281313

@@ -292,7 +324,6 @@ func (s *Service) createCustomSSEServerWithHelp404(sseServer *server.SSEServer,
292324
"auth-server-metadata": "GET /.well-known/oauth-authorization-server - Authorization server metadata",
293325
"client-registration": "POST /oauth/register - Dynamic client registration",
294326
"token-introspection": "POST /oauth/introspect - Token introspection",
295-
"health": "GET /health - Health check",
296327
}
297328
for k, v := range oauthEndpoints {
298329
response["endpoints"].(map[string]string)[k] = v

0 commit comments

Comments
 (0)