From 73b8a7f134b44d522dba1d20e3b4376bd58baa0c Mon Sep 17 00:00:00 2001 From: Jonathan Amsterdam Date: Wed, 20 Aug 2025 14:58:44 -0400 Subject: [PATCH] mcp: make request headers available to tools (#333) Add HTTP request headers to RequestExtra, so tools and other user-defined handlers can access them. Fixes #331. --- mcp/shared.go | 2 ++ mcp/streamable.go | 17 ++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/mcp/shared.go b/mcp/shared.go index c2162fb..b7b8bda 100644 --- a/mcp/shared.go +++ b/mcp/shared.go @@ -16,6 +16,7 @@ import ( "encoding/json" "fmt" "log" + "net/http" "reflect" "slices" "strings" @@ -400,6 +401,7 @@ type ServerRequest[P Params] struct { // the transport layer. type RequestExtra struct { TokenInfo *auth.TokenInfo // bearer token info (e.g. from OAuth) if any + Header http.Header // header from HTTP request, if any } func (*ClientRequest[P]) isRequest() {} diff --git a/mcp/streamable.go b/mcp/streamable.go index 89ff45c..eb42ca5 100644 --- a/mcp/streamable.go +++ b/mcp/streamable.go @@ -580,10 +580,6 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques // This also requires access to the negotiated version, which would either be // set by the MCP-Protocol-Version header, or would require peeking into the // session. - if err != nil { - http.Error(w, fmt.Sprintf("malformed payload: %v", err), http.StatusBadRequest) - return - } incoming, _, err := readBatch(body) if err != nil { http.Error(w, fmt.Sprintf("malformed payload: %v", err), http.StatusBadRequest) @@ -592,17 +588,20 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques requests := make(map[jsonrpc.ID]struct{}) tokenInfo := auth.TokenInfoFromContext(req.Context()) for _, msg := range incoming { - if req, ok := msg.(*jsonrpc.Request); ok { + if jreq, ok := msg.(*jsonrpc.Request); ok { // Preemptively check that this is a valid request, so that we can fail // the HTTP request. If we didn't do this, a request with a bad method or // missing ID could be silently swallowed. - if _, err := checkRequest(req, serverMethodInfos); err != nil { + if _, err := checkRequest(jreq, serverMethodInfos); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } - req.Extra = &RequestExtra{TokenInfo: tokenInfo} - if req.IsCall() { - requests[req.ID] = struct{}{} + jreq.Extra = &RequestExtra{ + TokenInfo: tokenInfo, + Header: req.Header, + } + if jreq.IsCall() { + requests[jreq.ID] = struct{}{} } } }