MCPcopy Create free account
hub / github.com/modelcontextprotocol/go-sdk / ServeHTTP

Method ServeHTTP

mcp/sse.go:192–288  ·  view source on GitHub ↗
(w http.ResponseWriter, req *http.Request)

Source from the content-addressed store, hash-verified

190}
191
192func (h *SSEHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
193 // DNS rebinding protection: auto-enabled for localhost servers.
194 // See: https://modelcontextprotocol.io/specification/2025-11-25/basic/security_best_practices#local-mcp-server-compromise
195 if !h.opts.DisableLocalhostProtection && disablelocalhostprotection != "1" {
196 if localAddr, ok := req.Context().Value(http.LocalAddrContextKey).(net.Addr); ok && localAddr != nil {
197 if util.IsLoopback(localAddr.String()) && !util.IsLoopback(req.Host) {
198 http.Error(w, fmt.Sprintf("Forbidden: invalid Host header %q", req.Host), http.StatusForbidden)
199 return
200 }
201 }
202 }
203
204 // Validate 'Content-Type' header.
205 if disablecontenttypecheck != "1" && req.Method == http.MethodPost {
206 mediaType, _, err := mime.ParseMediaType(req.Header.Get("Content-Type"))
207 if err != nil || mediaType != "application/json" {
208 http.Error(w, "Content-Type must be 'application/json'", http.StatusUnsupportedMediaType)
209 return
210 }
211 }
212
213 sessionID := req.URL.Query().Get("sessionid")
214
215 // For POST requests, the message body is a message to send to a session.
216 if req.Method == http.MethodPost {
217 // Look up the session.
218 if sessionID == "" {
219 http.Error(w, "sessionid must be provided", http.StatusBadRequest)
220 return
221 }
222 h.mu.Lock()
223 session := h.sessions[sessionID]
224 h.mu.Unlock()
225 if session == nil {
226 http.Error(w, "session not found", http.StatusNotFound)
227 return
228 }
229
230 session.ServeHTTP(w, req)
231 return
232 }
233
234 if req.Method != http.MethodGet {
235 w.Header().Set("Allow", "GET, POST")
236 http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
237 return
238 }
239
240 // GET requests create a new session, and serve messages over SSE.
241
242 // TODO: it's not entirely documented whether we should check Accept here.
243 // Let's again be lax and assume the client will accept SSE.
244
245 w.Header().Set("Content-Type", "text/event-stream")
246 w.Header().Set("Cache-Control", "no-cache")
247 w.Header().Set("Connection", "keep-alive")
248
249 sessionID = rand.Text()

Callers 4

RequireBearerTokenFunction · 0.45
TestRequireBearerTokenFunction · 0.45
mustNotPanicFunction · 0.45

Calls 6

IsLoopbackFunction · 0.92
ConnectMethod · 0.65
CloseMethod · 0.65
ValueMethod · 0.45
ErrorMethod · 0.45
DoneMethod · 0.45

Tested by 3

TestRequireBearerTokenFunction · 0.36
mustNotPanicFunction · 0.36