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}