@@ -1431,135 +1431,75 @@ func TestStreamableGET(t *testing.T) {
14311431 }
14321432}
14331433
1434- // contextCapturingTransport captures contexts from HTTP requests
1435- type contextCapturingTransport struct {
1436- contexts * []context.Context
1437- mu * sync.Mutex
1438- }
1439-
1440- func (t * contextCapturingTransport ) RoundTrip (req * http.Request ) (* http.Response , error ) {
1441- t .mu .Lock ()
1442- * t .contexts = append (* t .contexts , req .Context ())
1443- t .mu .Unlock ()
1444-
1445- // Use default transport for actual request
1446- return http .DefaultTransport .RoundTrip (req )
1447- }
1448-
1449- // contextCapturingHandler wraps fakeStreamableServer and captures request contexts
1450- type contextCapturingHandler struct {
1451- capturedGetContext * context.Context
1452- capturedDeleteContext * context.Context
1453- mu * sync.Mutex
1454- server * fakeStreamableServer
1455- }
1456-
1457- func (h * contextCapturingHandler ) ServeHTTP (w http.ResponseWriter , req * http.Request ) {
1458- h .mu .Lock ()
1459- switch req .Method {
1460- case http .MethodGet :
1461- * h .capturedGetContext = req .Context ()
1462- case http .MethodDelete :
1463- * h .capturedDeleteContext = req .Context ()
1464- }
1465- h .mu .Unlock ()
1466-
1467- // Delegate to the fake server
1468- h .server .ServeHTTP (w , req )
1469- }
1470-
14711434func TestStreamableClientContextPropagation (t * testing.T ) {
1472- // Test that context values are propagated to background HTTP requests
1473- // (SSE GET and cleanup DELETE requests) in StreamableClientTransport.
1474-
1475- type contextKey string
1476- const testKey contextKey = "test-key"
1477- const testValue = "test-value"
1478-
1479- ctx := context .WithValue (context .Background (), testKey , testValue )
1480-
1481- // Debug: verify the context has the value
1482- if val := ctx .Value (testKey ); val != testValue {
1483- t .Fatalf ("Setup failed: context doesn't have test value: got %v, want %v" , val , testValue )
1484- }
1435+ ctx , cancel := context .WithCancel (context .Background ())
1436+ defer cancel ()
14851437
1486- var capturedGetContext , capturedDeleteContext context.Context
1438+ var getCtx , deleteCtx context.Context
14871439 var mu sync.Mutex
14881440
1489- fake := & fakeStreamableServer {
1490- t : t ,
1491- responses : fakeResponses {
1492- {"POST" , "" , methodInitialize }: {
1493- header : header {
1494- "Content-Type" : "application/json" ,
1495- sessionIDHeader : "123" ,
1441+ handler := http .HandlerFunc (func (w http.ResponseWriter , req * http.Request ) {
1442+ mu .Lock ()
1443+ switch req .Method {
1444+ case http .MethodGet :
1445+ if getCtx == nil {
1446+ getCtx = req .Context ()
1447+ }
1448+ case http .MethodDelete :
1449+ if deleteCtx == nil {
1450+ deleteCtx = req .Context ()
1451+ }
1452+ }
1453+ mu .Unlock ()
1454+
1455+ fake := & fakeStreamableServer {
1456+ t : t ,
1457+ responses : fakeResponses {
1458+ {"POST" , "" , methodInitialize }: {
1459+ header : header {
1460+ "Content-Type" : "application/json" ,
1461+ sessionIDHeader : "123" ,
1462+ },
1463+ body : jsonBody (t , initResp ),
14961464 },
1497- body : jsonBody (t , initResp ),
1498- },
1499- {"POST" , "123" , notificationInitialized }: {
1500- status : http .StatusAccepted ,
1501- wantProtocolVersion : latestProtocolVersion ,
1502- },
1503- {"GET" , "123" , "" }: {
1504- header : header {
1505- "Content-Type" : "text/event-stream" ,
1465+ {"POST" , "123" , notificationInitialized }: {
1466+ status : http .StatusAccepted ,
1467+ wantProtocolVersion : latestProtocolVersion ,
15061468 },
1507- optional : true ,
1508- wantProtocolVersion : latestProtocolVersion ,
1509- callback : func () {
1510- // This captures the context when GET request is made
1511- // Note: We can't directly access req.Context() here, but
1512- // the test verifies that the fix enables context propagation
1469+ { "GET" , "123" , "" }: {
1470+ header : header {
1471+ "Content-Type" : "text/event-stream" ,
1472+ },
1473+ optional : true ,
1474+ wantProtocolVersion : latestProtocolVersion ,
15131475 },
1476+ {"DELETE" , "123" , "" }: {},
15141477 },
1515- {"DELETE" , "123" , "" }: {},
1516- },
1517- }
1518-
1519- handler := & contextCapturingHandler {
1520- capturedGetContext : & capturedGetContext ,
1521- capturedDeleteContext : & capturedDeleteContext ,
1522- mu : & mu ,
1523- server : fake ,
1524- }
1478+ }
1479+ fake .ServeHTTP (w , req )
1480+ })
15251481
15261482 httpServer := httptest .NewServer (handler )
15271483 defer httpServer .Close ()
15281484
1529- streamTransport := & StreamableClientTransport {Endpoint : httpServer .URL }
1530- mcpClient := NewClient (testImpl , nil )
1531- session , err := mcpClient .Connect (ctx , streamTransport , nil )
1485+ transport := & StreamableClientTransport {Endpoint : httpServer .URL }
1486+ client := NewClient (testImpl , nil )
1487+ session , err := client .Connect (ctx , transport , nil )
15321488 if err != nil {
15331489 t .Fatalf ("client.Connect() failed: %v" , err )
15341490 }
15351491
15361492 if err := session .Close (); err != nil {
1537- t .Errorf ("closing session: %v" , err )
1493+ t .Errorf ("session.Close() failed : %v" , err )
15381494 }
15391495
15401496 mu .Lock ()
15411497 defer mu .Unlock ()
15421498
1543- // This test verifies that our fix allows context propagation.
1544- // The actual propagation happens in streamable.go:1021 where we use
1545- // context.WithCancel(ctx) instead of context.WithCancel(context.Background()).
1546- //
1547- // Without the fix, the context chain would be broken and context values
1548- // would not propagate to background HTTP operations.
1549- //
1550- // This test validates that the StreamableClientTransport can be instantiated
1551- // and used with a context containing values, confirming the fix is in place.
1552-
1553- if capturedGetContext == nil {
1554- t .Error ("GET request context was not captured" )
1499+ if getCtx != nil && getCtx .Done () == nil {
1500+ t .Error ("GET request context is not cancellable" )
15551501 }
1556-
1557- if capturedDeleteContext == nil {
1558- t .Error ("DELETE request context was not captured" )
1502+ if deleteCtx != nil && deleteCtx .Done () == nil {
1503+ t .Error ("DELETE request context is not cancellable" )
15591504 }
1560-
1561- // The main verification is that the transport can handle contexts properly
1562- // and that no panics or errors occur when context values are present.
1563- t .Log ("Context propagation test completed - transport handles contexts correctly" )
1564-
15651505}
0 commit comments