Skip to content

Commit 4ff6c3b

Browse files
suxiaohunhuxiaoyang
andauthored
fix(server): return 200 for HEAD requests instead of 404 (#937)
StreamableHTTPServer.ServeHTTP and Handle only switch on POST/GET/DELETE; all other methods fall through to http.NotFound → 404. Many MCP clients and health-checkers probe with HEAD before issuing POST. Add HEAD case to both ServeHTTP and Handle method switches, returning 200 with an empty body. Co-authored-by: huxiaoyang <huxiaoyang@lingyu.local>
1 parent e395444 commit 4ff6c3b

4 files changed

Lines changed: 37 additions & 0 deletions

File tree

server/streamable_http.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,8 @@ func (s *StreamableHTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request)
429429
s.handleGet(hw, hr)
430430
case http.MethodDelete:
431431
s.handleDelete(hw, hr)
432+
case http.MethodHead:
433+
w.WriteHeader(http.StatusOK)
432434
default:
433435
http.NotFound(w, r)
434436
}

server/streamable_http_handle.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ func (s *StreamableHTTPServer) Handle(w HTTPResponseWriter, r *HTTPRequest) {
207207
s.handleGet(w, r)
208208
case http.MethodDelete:
209209
s.handleDelete(w, r)
210+
case http.MethodHead:
211+
w.WriteHeader(http.StatusOK)
210212
default:
211213
writeHTTPError(w, "404 page not found", http.StatusNotFound)
212214
}

server/streamable_http_handle_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,25 @@ func TestStreamableHTTPServer_Handle_UnknownMethod(t *testing.T) {
203203
assert.Equal(t, http.StatusNotFound, w.status)
204204
}
205205

206+
func TestStreamableHTTPServer_Handle_HeadReturns200(t *testing.T) {
207+
mcpServer := NewMCPServer("test-mcp-server", "1.0")
208+
srv := NewStreamableHTTPServer(mcpServer)
209+
210+
w := newBufferingHTTPResponseWriter()
211+
r := &HTTPRequest{
212+
Method: http.MethodHead,
213+
URL: &url.URL{Path: "/mcp"},
214+
Header: http.Header{},
215+
Context: t.Context(),
216+
}
217+
218+
srv.Handle(w, r)
219+
220+
assert.Equal(t, http.StatusOK, w.status)
221+
assert.True(t, w.wrote)
222+
assert.Empty(t, w.body)
223+
}
224+
206225
func TestStreamableHTTPServer_Handle_FlushableWriterMatchesServeHTTP(t *testing.T) {
207226
// A streamable HTTPResponseWriter going through Handle should produce
208227
// the same JSON body as net/http's default writer going through ServeHTTP

server/streamable_http_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2525,6 +2525,20 @@ func TestStreamableHTTP_Delete(t *testing.T) {
25252525
assert.Equal(t, sessionID, hookSession.SessionID())
25262526
}
25272527

2528+
func TestStreamableHTTP_HeadReturns200(t *testing.T) {
2529+
mcpServer := NewMCPServer("test-mcp-server", "1.0")
2530+
sseServer := NewStreamableHTTPServer(mcpServer)
2531+
testServer := httptest.NewServer(sseServer)
2532+
defer testServer.Close()
2533+
2534+
req, _ := http.NewRequest(http.MethodHead, testServer.URL, nil)
2535+
resp, err := testServer.Client().Do(req)
2536+
require.NoError(t, err)
2537+
defer resp.Body.Close()
2538+
2539+
assert.Equal(t, http.StatusOK, resp.StatusCode)
2540+
}
2541+
25282542
func TestStreamableHTTP_DrainNotifications(t *testing.T) {
25292543
t.Run("drain pending notifications after response is computed", func(t *testing.T) {
25302544
mcpServer := NewMCPServer("test-mcp-server", "1.0")

0 commit comments

Comments
 (0)