1414import java .util .concurrent .ConcurrentHashMap ;
1515import java .util .concurrent .atomic .AtomicBoolean ;
1616
17+ import io .modelcontextprotocol .common .McpTransportContext ;
1718import io .modelcontextprotocol .json .McpJsonMapper ;
1819import io .modelcontextprotocol .json .TypeRef ;
19- import io .modelcontextprotocol .common .McpTransportContext ;
2020import io .modelcontextprotocol .server .McpTransportContextExtractor ;
2121import io .modelcontextprotocol .spec .McpError ;
2222import io .modelcontextprotocol .spec .McpSchema ;
2626import io .modelcontextprotocol .spec .ProtocolVersions ;
2727import io .modelcontextprotocol .util .Assert ;
2828import io .modelcontextprotocol .util .KeepAliveScheduler ;
29- import io .modelcontextprotocol .util .UriBuilder ;
3029import jakarta .servlet .AsyncContext ;
3130import jakarta .servlet .ServletException ;
3231import jakarta .servlet .annotation .WebServlet ;
7069@ WebServlet (asyncSupported = true )
7170public class HttpServletSseServerTransportProvider extends HttpServlet implements McpServerTransportProvider {
7271
73- /** Logger for this class */
72+ /**
73+ * Logger for this class
74+ */
7475 private static final Logger logger = LoggerFactory .getLogger (HttpServletSseServerTransportProvider .class );
7576
7677 public static final String UTF_8 = "UTF-8" ;
@@ -79,40 +80,60 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
7980
8081 public static final String FAILED_TO_SEND_ERROR_RESPONSE = "Failed to send error response: {}" ;
8182
82- /** Default endpoint path for SSE connections */
83+ /**
84+ * Default endpoint path for SSE connections
85+ */
8386 public static final String DEFAULT_SSE_ENDPOINT = "/sse" ;
8487
85- /** Event type for regular messages */
88+ /**
89+ * Event type for regular messages
90+ */
8691 public static final String MESSAGE_EVENT_TYPE = "message" ;
8792
88- /** Event type for endpoint information */
93+ /**
94+ * Event type for endpoint information
95+ */
8996 public static final String ENDPOINT_EVENT_TYPE = "endpoint" ;
9097
9198 public static final String SESSION_ID = "sessionId" ;
9299
93100 public static final String DEFAULT_BASE_URL = "" ;
94101
95- /** JSON mapper for serialization/deserialization */
102+ /**
103+ * JSON mapper for serialization/deserialization
104+ */
96105 private final McpJsonMapper jsonMapper ;
97106
98- /** Base URL for the server transport */
107+ /**
108+ * Base URL for the server transport
109+ */
99110 private final String baseUrl ;
100111
101- /** The endpoint path for handling client messages */
112+ /**
113+ * The endpoint path for handling client messages
114+ */
102115 private final String messageEndpoint ;
103116
104- /** The endpoint path for handling SSE connections */
117+ /**
118+ * The endpoint path for handling SSE connections
119+ */
105120 private final String sseEndpoint ;
106121
107- /** Map of active client sessions, keyed by session ID */
122+ /**
123+ * Map of active client sessions, keyed by session ID
124+ */
108125 private final Map <String , McpServerSession > sessions = new ConcurrentHashMap <>();
109126
110127 private McpTransportContextExtractor <HttpServletRequest > contextExtractor ;
111128
112- /** Flag indicating if the transport is in the process of shutting down */
129+ /**
130+ * Flag indicating if the transport is in the process of shutting down
131+ */
113132 private final AtomicBoolean isClosing = new AtomicBoolean (false );
114133
115- /** Session factory for creating new sessions */
134+ /**
135+ * Session factory for creating new sessions
136+ */
116137 private McpServerSession .Factory sessionFactory ;
117138
118139 /**
@@ -256,7 +277,12 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response)
256277 * @return the fully qualified endpoint URL as a string
257278 */
258279 private String buildEndpointUrl (String sessionId ) {
259- return UriBuilder .from (this .baseUrl ).path (this .messageEndpoint ).queryParam (SESSION_ID , sessionId ).buildString ();
280+ // for WebMVC compatibility
281+ if (this .baseUrl .endsWith ("/" )) {
282+ return this .baseUrl .substring (0 , this .baseUrl .length () - 1 ) + this .messageEndpoint + "?sessionId="
283+ + sessionId ;
284+ }
285+ return this .baseUrl + this .messageEndpoint + "?sessionId=" + sessionId ;
260286 }
261287
262288 /**
@@ -447,8 +473,8 @@ public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message) {
447473 * Converts data from one type to another using the configured JsonMapper.
448474 * @param data The source data object to convert
449475 * @param typeRef The target type reference
450- * @return The converted object of type T
451476 * @param <T> The target type
477+ * @return The converted object of type T
452478 */
453479 @ Override
454480 public <T > T unmarshalFrom (Object data , TypeRef <T > typeRef ) {
0 commit comments