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:
parent
3f3b699b2b
commit
a5026ea7b7
2 changed files with 26 additions and 3 deletions
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue