@@ -35,20 +35,27 @@ public static IEndpointConventionBuilder MapMcp(this IEndpointRouteBuilder endpo
3535 . WithMetadata ( new AcceptsMetadata ( [ "application/json" ] ) )
3636 . WithMetadata ( new ProducesResponseTypeMetadata ( StatusCodes . Status200OK , contentTypes : [ "text/event-stream" ] ) )
3737 . WithMetadata ( new ProducesResponseTypeMetadata ( StatusCodes . Status202Accepted ) ) ;
38- streamableHttpGroup . MapGet ( "" , streamableHttpHandler . HandleGetRequestAsync )
39- . WithMetadata ( new ProducesResponseTypeMetadata ( StatusCodes . Status200OK , contentTypes : [ "text/event-stream" ] ) ) ;
40- streamableHttpGroup . MapDelete ( "" , streamableHttpHandler . HandleDeleteRequestAsync ) ;
41-
42- // Map legacy HTTP with SSE endpoints.
43- var sseHandler = endpoints . ServiceProvider . GetRequiredService < SseHandler > ( ) ;
44- var sseGroup = mcpGroup . MapGroup ( "" )
45- . WithDisplayName ( b => $ "MCP HTTP with SSE | { b . DisplayName } ") ;
46-
47- sseGroup . MapGet ( "/sse" , sseHandler . HandleSseRequestAsync )
48- . WithMetadata ( new ProducesResponseTypeMetadata ( StatusCodes . Status200OK , contentTypes : [ "text/event-stream" ] ) ) ;
49- sseGroup . MapPost ( "/message" , sseHandler . HandleMessageRequestAsync )
50- . WithMetadata ( new AcceptsMetadata ( [ "application/json" ] ) )
51- . WithMetadata ( new ProducesResponseTypeMetadata ( StatusCodes . Status202Accepted ) ) ;
38+
39+ if ( ! streamableHttpHandler . HttpServerTransportOptions . Stateless )
40+ {
41+ // The GET and DELETE endpoints are not mapped in Stateless mode since there's no way to send unsolicited messages
42+ // for the GET to handle, and there is no server-side state for the DELETE to clean up.
43+ streamableHttpGroup . MapGet ( "" , streamableHttpHandler . HandleGetRequestAsync )
44+ . WithMetadata ( new ProducesResponseTypeMetadata ( StatusCodes . Status200OK , contentTypes : [ "text/event-stream" ] ) ) ;
45+ streamableHttpGroup . MapDelete ( "" , streamableHttpHandler . HandleDeleteRequestAsync ) ;
46+
47+ // Map legacy HTTP with SSE endpoints only if not in Stateless mode, because we cannot guarantee the /message requests
48+ // will be handled by the same process as the /sse request.
49+ var sseHandler = endpoints . ServiceProvider . GetRequiredService < SseHandler > ( ) ;
50+ var sseGroup = mcpGroup . MapGroup ( "" )
51+ . WithDisplayName ( b => $ "MCP HTTP with SSE | { b . DisplayName } ") ;
52+
53+ sseGroup . MapGet ( "/sse" , sseHandler . HandleSseRequestAsync )
54+ . WithMetadata ( new ProducesResponseTypeMetadata ( StatusCodes . Status200OK , contentTypes : [ "text/event-stream" ] ) ) ;
55+ sseGroup . MapPost ( "/message" , sseHandler . HandleMessageRequestAsync )
56+ . WithMetadata ( new AcceptsMetadata ( [ "application/json" ] ) )
57+ . WithMetadata ( new ProducesResponseTypeMetadata ( StatusCodes . Status202Accepted ) ) ;
58+ }
5259
5360 return mcpGroup ;
5461 }
0 commit comments