@@ -2,7 +2,9 @@ package mcp
22
33import (
44 "fmt"
5+ "io"
56 "net/http"
7+ "net/http/httptest"
68 "runtime"
79 "sync"
810 "testing"
@@ -262,6 +264,54 @@ func (s *UserAgentPropagationSuite) TestFallsBackToServerPrefixWhenNoClientInfo(
262264 })
263265}
264266
267+ func (s * UserAgentPropagationSuite ) TestDoesNotPanicWhenClientInfoIsNil () {
268+ // Regression test for https://github.com/containers/kubernetes-mcp-server/issues/842
269+ // Fixed in https://github.com/containers/kubernetes-mcp-server/pull/844
270+ //
271+ // The MCP spec mandates that clientInfo is sent during initialization:
272+ // https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization
273+ // However, some non-compliant clients omit it, which caused a nil pointer panic
274+ // in the user-agent middleware. This test verifies that the server handles
275+ // non-compliant clients gracefully by sending a raw initialize request without clientInfo.
276+ provider , err := internalk8s .NewProvider (s .Cfg )
277+ s .Require ().NoError (err )
278+ s .mcpServer , err = NewServer (Configuration {StaticConfig : s .Cfg }, provider )
279+ s .Require ().NoError (err )
280+ handler := s .mcpServer .ServeHTTP ()
281+ strippedHandler := http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
282+ r .Header .Del ("User-Agent" )
283+ handler .ServeHTTP (w , r )
284+ })
285+ httpServer := httptest .NewServer (strippedHandler )
286+ defer httpServer .Close ()
287+
288+ // Send raw initialize request without clientInfo (non-compliant client)
289+ endpoint := httpServer .URL + "/mcp"
290+ initResp := test .McpRawPost (s .T (), endpoint , "" ,
291+ `{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26"}}` )
292+ defer func () { _ = initResp .Body .Close () }()
293+ _ , _ = io .ReadAll (initResp .Body )
294+ sessionID := initResp .Header .Get ("Mcp-Session-Id" )
295+ s .Require ().NotEmpty (sessionID , "Expected session ID in response" )
296+
297+ // Send tool call - this would panic before the fix when ClientInfo was nil
298+ toolResp := test .McpRawPost (s .T (), endpoint , sessionID ,
299+ `{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"pods_list","arguments":{}}}` )
300+ defer func () { _ = toolResp .Body .Close () }()
301+
302+ s .pathHeadersMux .Lock ()
303+ podsHeaders := s .pathHeaders ["/api/v1/namespaces/default/pods" ]
304+ s .pathHeadersMux .Unlock ()
305+
306+ s .Require ().NotNil (podsHeaders , "No requests were made to /api/v1/namespaces/default/pods" )
307+ s .Run ("User-Agent uses server prefix only when clientInfo is nil" , func () {
308+ s .Equal (
309+ fmt .Sprintf ("kubernetes-mcp-server/0.0.0 (%s/%s)" , runtime .GOOS , runtime .GOARCH ),
310+ podsHeaders .Get ("User-Agent" ),
311+ )
312+ })
313+ }
314+
265315func TestUserAgentPropagation (t * testing.T ) {
266316 suite .Run (t , new (UserAgentPropagationSuite ))
267317}
0 commit comments