feat(mcp): Add support for custom context paths in HTTP Servlet SSE server transport

Enhance HttpServletSseServerTransportProvider to support deployment under non-root context paths by:

- Adding baseUrl field and DEFAULT_BASE_URL constant
- Creating new constructor that accepts a baseUrl parameter
- Extending Builder with baseUrl configuration method
- Prepending baseUrl to message endpoint in SSE events
- Add HttpServletSseServerCustomContextPathTests to verify custom context path functionality
- Extract common Tomcat server setup code to TomcatTestUtil for test reuse

Related to #79

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
Christian Tzolov 2025-04-06 18:41:25 +02:00
commit 8fc72aed88

View file

@ -80,9 +80,14 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
/** Event type for endpoint information */
public static final String ENDPOINT_EVENT_TYPE = "endpoint";
public static final String DEFAULT_BASE_URL = "";
/** JSON object mapper for serialization/deserialization */
private final ObjectMapper objectMapper;
/** Base URL for the server transport */
private final String baseUrl;
/** The endpoint path for handling client messages */
private final String messageEndpoint;
@ -108,7 +113,22 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
*/
public HttpServletSseServerTransportProvider(ObjectMapper objectMapper, String messageEndpoint,
String sseEndpoint) {
this(objectMapper, DEFAULT_BASE_URL, messageEndpoint, sseEndpoint);
}
/**
* Creates a new HttpServletSseServerTransportProvider instance with a custom SSE
* endpoint.
* @param objectMapper The JSON object mapper to use for message
* serialization/deserialization
* @param baseUrl The base URL for the server transport
* @param messageEndpoint The endpoint path where clients will send their messages
* @param sseEndpoint The endpoint path where clients will establish SSE connections
*/
public HttpServletSseServerTransportProvider(ObjectMapper objectMapper, String baseUrl, String messageEndpoint,
String sseEndpoint) {
this.objectMapper = objectMapper;
this.baseUrl = baseUrl;
this.messageEndpoint = messageEndpoint;
this.sseEndpoint = sseEndpoint;
}
@ -203,7 +223,7 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
this.sessions.put(sessionId, session);
// Send initial endpoint event
this.sendEvent(writer, ENDPOINT_EVENT_TYPE, messageEndpoint + "?sessionId=" + sessionId);
this.sendEvent(writer, ENDPOINT_EVENT_TYPE, this.baseUrl + this.messageEndpoint + "?sessionId=" + sessionId);
}
/**
@ -449,6 +469,8 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
private ObjectMapper objectMapper = new ObjectMapper();
private String baseUrl = DEFAULT_BASE_URL;
private String messageEndpoint;
private String sseEndpoint = DEFAULT_SSE_ENDPOINT;
@ -464,6 +486,17 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
return this;
}
/**
* Sets the base URL for the server transport.
* @param baseUrl The base URL to use
* @return This builder instance for method chaining
*/
public Builder baseUrl(String baseUrl) {
Assert.notNull(baseUrl, "Base URL must not be null");
this.baseUrl = baseUrl;
return this;
}
/**
* Sets the endpoint path where clients will send their messages.
* @param messageEndpoint The message endpoint path
@ -502,7 +535,7 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
if (messageEndpoint == null) {
throw new IllegalStateException("MessageEndpoint must be set");
}
return new HttpServletSseServerTransportProvider(objectMapper, messageEndpoint, sseEndpoint);
return new HttpServletSseServerTransportProvider(objectMapper, baseUrl, messageEndpoint, sseEndpoint);
}
}