@@ -302,6 +302,48 @@ public async Task Server_SkipsHeaderValidation_ForNonDraftVersion()
302302 Assert . Equal ( HttpStatusCode . OK , response . StatusCode ) ;
303303 }
304304
305+ [ Fact ]
306+ public async Task Server_RejectsInvalidUtf8EncodedHeaderValue ( )
307+ {
308+ await StartAsync ( ) ;
309+ await InitializeWithDraftVersionAsync ( ) ;
310+
311+ // Create a separate HttpClient that sends raw UTF-8 bytes in Mcp-* headers
312+ // instead of properly base64-encoding non-ASCII values.
313+ var handler = new SocketsHttpHandler
314+ {
315+ ConnectCallback = SocketsHttpHandler . ConnectCallback ,
316+ RequestHeaderEncodingSelector = ( headerName , _ ) =>
317+ headerName . StartsWith ( "Mcp-" , StringComparison . OrdinalIgnoreCase )
318+ ? Encoding . UTF8
319+ : null
320+ } ;
321+
322+ using var utf8Client = new HttpClient ( handler ) ;
323+ ConfigureHttpClient ( utf8Client ) ;
324+ utf8Client . DefaultRequestHeaders . Accept . Add ( new ( "application/json" ) ) ;
325+ utf8Client . DefaultRequestHeaders . Accept . Add ( new ( "text/event-stream" ) ) ;
326+
327+ // Send a tools/call with raw UTF-8 non-ASCII in the Mcp-Name header.
328+ // Kestrel reads header bytes as Latin-1, so the UTF-8 bytes for "café☕"
329+ // will be garbled and won't match the body value, causing rejection.
330+ var callJson = CallTool ( "café☕" , """{"region":"us-west1","priority":42,"verbose":false,"emptyVal":""}""" ) ;
331+
332+ using var request = new HttpRequestMessage ( HttpMethod . Post , "" ) ;
333+ request . Content = new StringContent ( callJson , Encoding . UTF8 , "application/json" ) ;
334+ request . Headers . Add ( "MCP-Protocol-Version" , "DRAFT-2026-v1" ) ;
335+ request . Headers . TryAddWithoutValidation ( "Mcp-Method" , "tools/call" ) ;
336+ // Raw UTF-8 non-ASCII value in Mcp-Name — server must reject this
337+ request . Headers . TryAddWithoutValidation ( "Mcp-Name" , "café☕" ) ;
338+ request . Headers . TryAddWithoutValidation ( "Mcp-Param-Region" , "us-west1" ) ;
339+ request . Headers . TryAddWithoutValidation ( "Mcp-Param-Priority" , "42" ) ;
340+ request . Headers . TryAddWithoutValidation ( "Mcp-Param-Verbose" , "false" ) ;
341+ request . Headers . TryAddWithoutValidation ( "Mcp-Param-EmptyVal" , "" ) ;
342+
343+ using var response = await utf8Client . SendAsync ( request , TestContext . Current . CancellationToken ) ;
344+ Assert . Equal ( HttpStatusCode . BadRequest , response . StatusCode ) ;
345+ }
346+
305347 #endregion
306348
307349 #region Client-side encoding tests (unit tests for McpHeaderEncoder)
0 commit comments