http.go

 1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2//
 3// SPDX-License-Identifier: LicenseRef-MutuaL-1.2
 4
 5package mcp
 6
 7import (
 8	"crypto/subtle"
 9	"net/http"
10	"strings"
11
12	sdk "github.com/modelcontextprotocol/go-sdk/mcp"
13)
14
15// HTTPHandler returns the authenticated Streamable HTTP MCP handler.
16func (s *Server) HTTPHandler(token string) http.Handler {
17	streamable := sdk.NewStreamableHTTPHandler(func(*http.Request) *sdk.Server {
18		return s.sdk
19	}, nil)
20
21	return newHTTPHandler(token, streamable)
22}
23
24func newHTTPHandler(token string, mcpHandler http.Handler) http.Handler {
25	mux := http.NewServeMux()
26	mux.Handle("/mcp", requireBearerToken(token, mcpHandler))
27
28	return mux
29}
30
31func requireBearerToken(token string, next http.Handler) http.Handler {
32	if token == "" {
33		return next
34	}
35
36	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
37		scheme, value, ok := strings.Cut(r.Header.Get("Authorization"), " ")
38		if !ok || !strings.EqualFold(scheme, "Bearer") ||
39			subtle.ConstantTimeCompare([]byte(value), []byte(token)) != 1 {
40			w.Header().Set("WWW-Authenticate", "Bearer")
41			http.Error(w, "unauthorized", http.StatusUnauthorized)
42			return
43		}
44
45		next.ServeHTTP(w, r)
46	})
47}