diff --git a/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxSseServerTransportProvider.java b/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxSseServerTransportProvider.java index af2ff06..df8dd02 100644 --- a/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxSseServerTransportProvider.java +++ b/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxSseServerTransportProvider.java @@ -82,8 +82,16 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv */ public static final String DEFAULT_SSE_ENDPOINT = "/sse"; + public static final String DEFAULT_BASE_URL = ""; + private final ObjectMapper objectMapper; + /** + * Base URL for the message endpoint. This is used to construct the full URL for + * clients to send their JSON-RPC messages. + */ + private final String baseUrl; + private final String messageEndpoint; private final String sseEndpoint; @@ -102,29 +110,6 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv */ private volatile boolean isClosing = false; - /** - * Constructs a new WebFlux SSE server transport provider instance. - * @param objectMapper The ObjectMapper to use for JSON serialization/deserialization - * of MCP messages. Must not be null. - * @param messageEndpoint The endpoint URI where clients should send their JSON-RPC - * messages. This endpoint will be communicated to clients during SSE connection - * setup. Must not be null. - * @throws IllegalArgumentException if either parameter is null - */ - public WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String messageEndpoint, String sseEndpoint) { - Assert.notNull(objectMapper, "ObjectMapper must not be null"); - Assert.notNull(messageEndpoint, "Message endpoint must not be null"); - Assert.notNull(sseEndpoint, "SSE endpoint must not be null"); - - this.objectMapper = objectMapper; - this.messageEndpoint = messageEndpoint; - this.sseEndpoint = sseEndpoint; - this.routerFunction = RouterFunctions.route() - .GET(this.sseEndpoint, this::handleSseConnection) - .POST(this.messageEndpoint, this::handleMessage) - .build(); - } - /** * Constructs a new WebFlux SSE server transport provider instance with the default * SSE endpoint. @@ -139,6 +124,46 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv this(objectMapper, messageEndpoint, DEFAULT_SSE_ENDPOINT); } + /** + * Constructs a new WebFlux SSE server transport provider instance. + * @param objectMapper The ObjectMapper to use for JSON serialization/deserialization + * of MCP messages. Must not be null. + * @param messageEndpoint The endpoint URI where clients should send their JSON-RPC + * messages. This endpoint will be communicated to clients during SSE connection + * setup. Must not be null. + * @throws IllegalArgumentException if either parameter is null + */ + public WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String messageEndpoint, String sseEndpoint) { + this(objectMapper, DEFAULT_BASE_URL, messageEndpoint, sseEndpoint); + } + + /** + * Constructs a new WebFlux SSE server transport provider instance. + * @param objectMapper The ObjectMapper to use for JSON serialization/deserialization + * of MCP messages. Must not be null. + * @param baseUrl webflux messag base path + * @param messageEndpoint The endpoint URI where clients should send their JSON-RPC + * messages. This endpoint will be communicated to clients during SSE connection + * setup. Must not be null. + * @throws IllegalArgumentException if either parameter is null + */ + public WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String baseUrl, String messageEndpoint, + String sseEndpoint) { + Assert.notNull(objectMapper, "ObjectMapper must not be null"); + Assert.notNull(baseUrl, "Message base path must not be null"); + Assert.notNull(messageEndpoint, "Message endpoint must not be null"); + Assert.notNull(sseEndpoint, "SSE endpoint must not be null"); + + this.objectMapper = objectMapper; + this.baseUrl = baseUrl; + this.messageEndpoint = messageEndpoint; + this.sseEndpoint = sseEndpoint; + this.routerFunction = RouterFunctions.route() + .GET(this.sseEndpoint, this::handleSseConnection) + .POST(this.messageEndpoint, this::handleMessage) + .build(); + } + @Override public void setSessionFactory(McpServerSession.Factory sessionFactory) { this.sessionFactory = sessionFactory; @@ -179,7 +204,8 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv .then(); } - // FIXME: This javadoc makes claims about using isClosing flag but it's not actually + // FIXME: This javadoc makes claims about using isClosing flag but it's not + // actually // doing that. /** * Initiates a graceful shutdown of all the sessions. This method ensures all active @@ -245,7 +271,7 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv logger.debug("Sending initial endpoint event to session: {}", sessionId); sink.next(ServerSentEvent.builder() .event(ENDPOINT_EVENT_TYPE) - .data(messageEndpoint + "?sessionId=" + sessionId) + .data(this.baseUrl + this.messageEndpoint + "?sessionId=" + sessionId) .build()); sink.onCancel(() -> { logger.debug("Session {} cancelled", sessionId); @@ -360,6 +386,8 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv private ObjectMapper objectMapper; + private String baseUrl = DEFAULT_BASE_URL; + private String messageEndpoint; private String sseEndpoint = DEFAULT_SSE_ENDPOINT; @@ -377,6 +405,19 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv return this; } + /** + * Sets the project basePath as endpoint prefix where clients should send their + * JSON-RPC messages + * @param baseUrl the message basePath . Must not be null. + * @return this builder instance + * @throws IllegalArgumentException if basePath is null + */ + public Builder basePath(String baseUrl) { + Assert.notNull(baseUrl, "basePath must not be null"); + this.baseUrl = baseUrl; + return this; + } + /** * Sets the endpoint URI where clients should send their JSON-RPC messages. * @param messageEndpoint The message endpoint URI. Must not be null. @@ -411,7 +452,7 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv Assert.notNull(objectMapper, "ObjectMapper must be set"); Assert.notNull(messageEndpoint, "Message endpoint must be set"); - return new WebFluxSseServerTransportProvider(objectMapper, messageEndpoint, sseEndpoint); + return new WebFluxSseServerTransportProvider(objectMapper, baseUrl, messageEndpoint, sseEndpoint); } }