mcp: decode a Base64-wrapped Mcp-Name before comparing it to the body (#1242)

The 2026-07-28 transport spec lets a client Base64-wrap a name or
resource URI that is not header-safe (`=?base64?...?=`) and requires the
server to decode it before comparing. `validateMcpHeaders` decoded
`Mcp-Param-*` values that way but compared `Mcp-Name` raw, so a
spec-legal encoded name was refused as a header mismatch.

This decodes `Mcp-Name` before comparing, mirroring the existing
`Mcp-Param-*` path, and rejects an invalid Base64 wrapper with a clear
error. Added table cases covering a valid encoded name and an invalid
one (red before, green after).

Fixes #1234

Co-authored-by: Arpan Mondal <arpanmondal@Arpans-MacBook-Pro.local>
Co-authored-by: Guglielmo Colombo <guglielmoc@google.com>
This commit is contained in:
ARPAN MONDAL 2026-09-06 15:36:58 +05:30 • committed by GitHub
commit a5026ea7b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 26 additions and 3 deletions

View file

@ -378,13 +378,18 @@ func validateMcpHeaders(header http.Header, msg jsonrpc.Message, toolLookup func
if nameInHeader == "" {
return fmt.Errorf("missing required Mcp-Name header for method %q", msg.Method)
}
var ok bool
// A name that is not header-safe may be Base64-wrapped by the client
// (=?base64?...?=), so decode before comparing, as with Mcp-Param-*.
decodedName, ok := decodeHeaderValue(nameInHeader)
if !ok {
return errors.New("header mismatch: Mcp-Name header contains invalid Base64 encoding")
}
nameInBody, ok = extractName(msg.Method, msg.Params)
if !ok {
return fmt.Errorf("failed to extract name from parameters for method %q", msg.Method)
}
if nameInHeader != nameInBody {
return fmt.Errorf("header mismatch: Mcp-Name header value '%s' does not match body value '%s'", nameInHeader, nameInBody)
if decodedName != nameInBody {
return fmt.Errorf("header mismatch: Mcp-Name header value '%s' does not match body value '%s'", decodedName, nameInBody)
}
}

View file

@ -6,6 +6,7 @@ package mcp
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
@ -335,6 +336,23 @@ func TestValidateMcpHeaders(t *testing.T) {
msg: &jsonrpc.Request{Method: "prompts/get", Params: mustMarshal(&GetPromptParams{Name: "code_review"})},
wantErr: false,
},
{
name: "Base64-encoded Mcp-Name is decoded before comparison",
version: minVersionForStandardHeaders,
methodHeader: "tools/call",
nameHeader: base64Prefix + base64.StdEncoding.EncodeToString([]byte("café-tool")) + base64Suffix,
msg: &jsonrpc.Request{Method: "tools/call", Params: mustMarshal(&CallToolParams{Name: "café-tool"})},
wantErr: false,
},
{
name: "Mcp-Name with invalid Base64 encoding",
version: minVersionForStandardHeaders,
methodHeader: "tools/call",
nameHeader: base64Prefix + "not valid base64!" + base64Suffix,
msg: &jsonrpc.Request{Method: "tools/call", Params: mustMarshal(&CallToolParams{Name: "my-tool"})},
wantErr: true,
wantErrContain: "invalid Base64 encoding",
},
{
name: "valid initialize (no name needed)",
version: minVersionForStandardHeaders,