feat: Make SSE endpoint configurable in server transports
This commit updates the WebFluxSseServerTransport, WebMvcSseServerTransport, and HttpServletSseServerTransport classes to accept the SSE endpoint path as a constructor argument. This change provides more flexibility in configuring the SSE endpoint, allowing it to be customized instead of being hardcoded to "/sse". It also aligns the Java SDK's behavior with the Python SDK's SseServerTransport, which already supports this customization. A default SSE endpoint of "/sse" is maintained for backward compatibility. Also, addressed minor code quality issues identified by SonarLint and reordered modifiers for static final fields to conform with the Java Language Specification. Signed-off-by: Alexandros Pappas <alexandros.pappas@yiluhub.com>
This commit is contained in:
parent
f3e3a65ca6
commit
c2ece20cc2
2 changed files with 111 additions and 58 deletions
|
|
@ -72,31 +72,31 @@ import org.springframework.web.reactive.function.client.WebClient;
|
|||
*/
|
||||
public class WebFluxSseClientTransport implements ClientMcpTransport {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(WebFluxSseClientTransport.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(WebFluxSseClientTransport.class);
|
||||
|
||||
/**
|
||||
* Event type for JSON-RPC messages received through the SSE connection. The server
|
||||
* sends messages with this event type to transmit JSON-RPC protocol data.
|
||||
*/
|
||||
private final static String MESSAGE_EVENT_TYPE = "message";
|
||||
private static final String MESSAGE_EVENT_TYPE = "message";
|
||||
|
||||
/**
|
||||
* Event type for receiving the message endpoint URI from the server. The server MUST
|
||||
* send this event when a client connects, providing the URI where the client should
|
||||
* send its messages via HTTP POST.
|
||||
*/
|
||||
private final static String ENDPOINT_EVENT_TYPE = "endpoint";
|
||||
private static final String ENDPOINT_EVENT_TYPE = "endpoint";
|
||||
|
||||
/**
|
||||
* Default SSE endpoint path as specified by the MCP transport specification. This
|
||||
* endpoint is used to establish the SSE connection with the server.
|
||||
*/
|
||||
private final static String SSE_ENDPOINT = "/sse";
|
||||
private static final String SSE_ENDPOINT = "/sse";
|
||||
|
||||
/**
|
||||
* Type reference for parsing SSE events containing string data.
|
||||
*/
|
||||
private final static ParameterizedTypeReference<ServerSentEvent<String>> SSE_TYPE = new ParameterizedTypeReference<>() {
|
||||
private static final ParameterizedTypeReference<ServerSentEvent<String>> SSE_TYPE = new ParameterizedTypeReference<>() {
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -57,32 +57,35 @@ import org.springframework.web.reactive.function.server.ServerResponse;
|
|||
* {@link Sinks} for thread-safe message broadcasting.
|
||||
*
|
||||
* @author Christian Tzolov
|
||||
* @author Alexandros Pappas
|
||||
* @see ServerMcpTransport
|
||||
* @see ServerSentEvent
|
||||
*/
|
||||
public class WebFluxSseServerTransport implements ServerMcpTransport {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(WebFluxSseServerTransport.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(WebFluxSseServerTransport.class);
|
||||
|
||||
/**
|
||||
* Event type for JSON-RPC messages sent through the SSE connection.
|
||||
*/
|
||||
public final static String MESSAGE_EVENT_TYPE = "message";
|
||||
public static final String MESSAGE_EVENT_TYPE = "message";
|
||||
|
||||
/**
|
||||
* Event type for sending the message endpoint URI to clients.
|
||||
*/
|
||||
public final static String ENDPOINT_EVENT_TYPE = "endpoint";
|
||||
public static final String ENDPOINT_EVENT_TYPE = "endpoint";
|
||||
|
||||
/**
|
||||
* Default SSE endpoint path as specified by the MCP transport specification.
|
||||
*/
|
||||
public final static String SSE_ENDPOINT = "/sse";
|
||||
public static final String DEFAULT_SSE_ENDPOINT = "/sse";
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final String messageEndpoint;
|
||||
|
||||
private final String sseEndpoint;
|
||||
|
||||
private final RouterFunction<?> routerFunction;
|
||||
|
||||
/**
|
||||
|
|
@ -106,18 +109,34 @@ public class WebFluxSseServerTransport implements ServerMcpTransport {
|
|||
* setup. Must not be null.
|
||||
* @throws IllegalArgumentException if either parameter is null
|
||||
*/
|
||||
public WebFluxSseServerTransport(ObjectMapper objectMapper, String messageEndpoint) {
|
||||
public WebFluxSseServerTransport(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(SSE_ENDPOINT, this::handleSseConnection)
|
||||
.POST(messageEndpoint, this::handleMessage)
|
||||
.GET(this.sseEndpoint, this::handleSseConnection)
|
||||
.POST(this.messageEndpoint, this::handleMessage)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new WebFlux SSE server transport instance with the default SSE
|
||||
* endpoint.
|
||||
* @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 WebFluxSseServerTransport(ObjectMapper objectMapper, String messageEndpoint) {
|
||||
this(objectMapper, messageEndpoint, DEFAULT_SSE_ENDPOINT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the message handler for this transport. In the WebFlux SSE
|
||||
* implementation, this method stores the handler for processing incoming messages but
|
||||
|
|
@ -243,7 +262,7 @@ public class WebFluxSseServerTransport implements ServerMcpTransport {
|
|||
* <p>
|
||||
* The router function defines two endpoints:
|
||||
* <ul>
|
||||
* <li>GET {SSE_ENDPOINT} - For establishing SSE connections</li>
|
||||
* <li>GET {sseEndpoint} - For establishing SSE connections</li>
|
||||
* <li>POST {messageEndpoint} - For receiving client messages</li>
|
||||
* </ul>
|
||||
* @return The configured {@link RouterFunction} for handling HTTP requests
|
||||
|
|
@ -343,11 +362,7 @@ public class WebFluxSseServerTransport implements ServerMcpTransport {
|
|||
.bodyValue(new McpError(error.getMessage()));
|
||||
});
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
logger.error("Failed to deserialize message: {}", e.getMessage());
|
||||
return ServerResponse.badRequest().bodyValue(new McpError("Invalid message format"));
|
||||
}
|
||||
catch (IOException e) {
|
||||
catch (IllegalArgumentException | IOException e) {
|
||||
logger.error("Failed to deserialize message: {}", e.getMessage());
|
||||
return ServerResponse.badRequest().bodyValue(new McpError("Invalid message format"));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue