Skip to content

Commit 3fa4152

Browse files
zhangzhenhuatzolov
zhangzhenhua
authored andcommittedApr 6, 2025·
feat(webflux): Add base URL support to WebFluxSseServerTransportProvider (#102)
Adds the ability to specify a base URL prefix for message endpoints in the WebFlux SSE server transport provider. This enhancement allows for proper URL construction when the server is running behind a proxy or in a context with a base path. - Add new constructor with baseUrl parameter - Add basePath() method to Builder class - Modify SSE endpoint event to include baseUrl prefix Signed-off-by: Christian Tzolov <[email protected]>
1 parent 0db4c0f commit 3fa4152

File tree

1 file changed

+58
-17
lines changed

1 file changed

+58
-17
lines changed
 

‎mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxSseServerTransportProvider.java

+58-17
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,16 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
8282
*/
8383
public static final String DEFAULT_SSE_ENDPOINT = "/sse";
8484

85+
public static final String DEFAULT_BASE_URL = "";
86+
8587
private final ObjectMapper objectMapper;
8688

89+
/**
90+
* Base URL for the message endpoint. This is used to construct the full URL for
91+
* clients to send their JSON-RPC messages.
92+
*/
93+
private final String baseUrl;
94+
8795
private final String messageEndpoint;
8896

8997
private final String sseEndpoint;
@@ -102,6 +110,20 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
102110
*/
103111
private volatile boolean isClosing = false;
104112

113+
/**
114+
* Constructs a new WebFlux SSE server transport provider instance with the default
115+
* SSE endpoint.
116+
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
117+
* of MCP messages. Must not be null.
118+
* @param messageEndpoint The endpoint URI where clients should send their JSON-RPC
119+
* messages. This endpoint will be communicated to clients during SSE connection
120+
* setup. Must not be null.
121+
* @throws IllegalArgumentException if either parameter is null
122+
*/
123+
public WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String messageEndpoint) {
124+
this(objectMapper, messageEndpoint, DEFAULT_SSE_ENDPOINT);
125+
}
126+
105127
/**
106128
* Constructs a new WebFlux SSE server transport provider instance.
107129
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
@@ -112,11 +134,28 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
112134
* @throws IllegalArgumentException if either parameter is null
113135
*/
114136
public WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String messageEndpoint, String sseEndpoint) {
137+
this(objectMapper, DEFAULT_BASE_URL, messageEndpoint, sseEndpoint);
138+
}
139+
140+
/**
141+
* Constructs a new WebFlux SSE server transport provider instance.
142+
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
143+
* of MCP messages. Must not be null.
144+
* @param baseUrl webflux messag base path
145+
* @param messageEndpoint The endpoint URI where clients should send their JSON-RPC
146+
* messages. This endpoint will be communicated to clients during SSE connection
147+
* setup. Must not be null.
148+
* @throws IllegalArgumentException if either parameter is null
149+
*/
150+
public WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String baseUrl, String messageEndpoint,
151+
String sseEndpoint) {
115152
Assert.notNull(objectMapper, "ObjectMapper must not be null");
153+
Assert.notNull(baseUrl, "Message base path must not be null");
116154
Assert.notNull(messageEndpoint, "Message endpoint must not be null");
117155
Assert.notNull(sseEndpoint, "SSE endpoint must not be null");
118156

119157
this.objectMapper = objectMapper;
158+
this.baseUrl = baseUrl;
120159
this.messageEndpoint = messageEndpoint;
121160
this.sseEndpoint = sseEndpoint;
122161
this.routerFunction = RouterFunctions.route()
@@ -125,20 +164,6 @@ public WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String messa
125164
.build();
126165
}
127166

128-
/**
129-
* Constructs a new WebFlux SSE server transport provider instance with the default
130-
* SSE endpoint.
131-
* @param objectMapper The ObjectMapper to use for JSON serialization/deserialization
132-
* of MCP messages. Must not be null.
133-
* @param messageEndpoint The endpoint URI where clients should send their JSON-RPC
134-
* messages. This endpoint will be communicated to clients during SSE connection
135-
* setup. Must not be null.
136-
* @throws IllegalArgumentException if either parameter is null
137-
*/
138-
public WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String messageEndpoint) {
139-
this(objectMapper, messageEndpoint, DEFAULT_SSE_ENDPOINT);
140-
}
141-
142167
@Override
143168
public void setSessionFactory(McpServerSession.Factory sessionFactory) {
144169
this.sessionFactory = sessionFactory;
@@ -179,7 +204,8 @@ public Mono<Void> notifyClients(String method, Map<String, Object> params) {
179204
.then();
180205
}
181206

182-
// FIXME: This javadoc makes claims about using isClosing flag but it's not actually
207+
// FIXME: This javadoc makes claims about using isClosing flag but it's not
208+
// actually
183209
// doing that.
184210
/**
185211
* Initiates a graceful shutdown of all the sessions. This method ensures all active
@@ -245,7 +271,7 @@ private Mono<ServerResponse> handleSseConnection(ServerRequest request) {
245271
logger.debug("Sending initial endpoint event to session: {}", sessionId);
246272
sink.next(ServerSentEvent.builder()
247273
.event(ENDPOINT_EVENT_TYPE)
248-
.data(messageEndpoint + "?sessionId=" + sessionId)
274+
.data(this.baseUrl + this.messageEndpoint + "?sessionId=" + sessionId)
249275
.build());
250276
sink.onCancel(() -> {
251277
logger.debug("Session {} cancelled", sessionId);
@@ -360,6 +386,8 @@ public static class Builder {
360386

361387
private ObjectMapper objectMapper;
362388

389+
private String baseUrl = DEFAULT_BASE_URL;
390+
363391
private String messageEndpoint;
364392

365393
private String sseEndpoint = DEFAULT_SSE_ENDPOINT;
@@ -377,6 +405,19 @@ public Builder objectMapper(ObjectMapper objectMapper) {
377405
return this;
378406
}
379407

408+
/**
409+
* Sets the project basePath as endpoint prefix where clients should send their
410+
* JSON-RPC messages
411+
* @param baseUrl the message basePath . Must not be null.
412+
* @return this builder instance
413+
* @throws IllegalArgumentException if basePath is null
414+
*/
415+
public Builder basePath(String baseUrl) {
416+
Assert.notNull(baseUrl, "basePath must not be null");
417+
this.baseUrl = baseUrl;
418+
return this;
419+
}
420+
380421
/**
381422
* Sets the endpoint URI where clients should send their JSON-RPC messages.
382423
* @param messageEndpoint The message endpoint URI. Must not be null.
@@ -411,7 +452,7 @@ public WebFluxSseServerTransportProvider build() {
411452
Assert.notNull(objectMapper, "ObjectMapper must be set");
412453
Assert.notNull(messageEndpoint, "Message endpoint must be set");
413454

414-
return new WebFluxSseServerTransportProvider(objectMapper, messageEndpoint, sseEndpoint);
455+
return new WebFluxSseServerTransportProvider(objectMapper, baseUrl, messageEndpoint, sseEndpoint);
415456
}
416457

417458
}

0 commit comments

Comments
 (0)
Please sign in to comment.