feat(transport): Add customizable HTTP request builder support (#86)
Enhances FlowSseClient and HttpClientSseClientTransport to accept a custom HttpRequest.Builder, allowing for greater flexibility when configuring HTTP requests. This enables clients to customize headers, timeouts, and other request properties across all SSE connections and message sending operations. Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
parent
8d5872fd66
commit
eb8e3744a7
2 changed files with 50 additions and 6 deletions
|
|
@ -39,6 +39,8 @@ public class FlowSseClient {
|
|||
|
||||
private final HttpClient httpClient;
|
||||
|
||||
private final HttpRequest.Builder requestBuilder;
|
||||
|
||||
/**
|
||||
* Pattern to extract the data content from SSE data field lines. Matches lines
|
||||
* starting with "data:" and captures the remaining content.
|
||||
|
|
@ -92,7 +94,17 @@ public class FlowSseClient {
|
|||
* @param httpClient the {@link HttpClient} instance to use for SSE connections
|
||||
*/
|
||||
public FlowSseClient(HttpClient httpClient) {
|
||||
this(httpClient, HttpRequest.newBuilder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FlowSseClient with the specified HTTP client and request builder.
|
||||
* @param httpClient the {@link HttpClient} instance to use for SSE connections
|
||||
* @param requestBuilder the {@link HttpRequest.Builder} to use for SSE requests
|
||||
*/
|
||||
public FlowSseClient(HttpClient httpClient, HttpRequest.Builder requestBuilder) {
|
||||
this.httpClient = httpClient;
|
||||
this.requestBuilder = requestBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -109,8 +121,7 @@ public class FlowSseClient {
|
|||
* @throws RuntimeException if the connection fails with a non-200 status code
|
||||
*/
|
||||
public void subscribe(String url, SseEventHandler eventHandler) {
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
HttpRequest request = this.requestBuilder.uri(URI.create(url))
|
||||
.header("Accept", "text/event-stream")
|
||||
.header("Cache-Control", "no-cache")
|
||||
.GET()
|
||||
|
|
|
|||
|
|
@ -82,6 +82,9 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
*/
|
||||
private final HttpClient httpClient;
|
||||
|
||||
/** HTTP request builder for building requests to send messages to the server */
|
||||
private final HttpRequest.Builder requestBuilder;
|
||||
|
||||
/** JSON object mapper for message serialization/deserialization */
|
||||
protected ObjectMapper objectMapper;
|
||||
|
||||
|
|
@ -126,15 +129,33 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
*/
|
||||
public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, String baseUri, String sseEndpoint,
|
||||
ObjectMapper objectMapper) {
|
||||
this(clientBuilder, HttpRequest.newBuilder(), baseUri, sseEndpoint, objectMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new transport instance with custom HTTP client builder, object mapper,
|
||||
* and headers.
|
||||
* @param clientBuilder the HTTP client builder to use
|
||||
* @param requestBuilder the HTTP request builder to use
|
||||
* @param baseUri the base URI of the MCP server
|
||||
* @param sseEndpoint the SSE endpoint path
|
||||
* @param objectMapper the object mapper for JSON serialization/deserialization
|
||||
* @throws IllegalArgumentException if objectMapper, clientBuilder, or headers is null
|
||||
*/
|
||||
public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, HttpRequest.Builder requestBuilder,
|
||||
String baseUri, String sseEndpoint, ObjectMapper objectMapper) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
Assert.hasText(baseUri, "baseUri must not be empty");
|
||||
Assert.hasText(sseEndpoint, "sseEndpoint must not be empty");
|
||||
Assert.notNull(clientBuilder, "clientBuilder must not be null");
|
||||
Assert.notNull(requestBuilder, "requestBuilder must not be null");
|
||||
this.baseUri = baseUri;
|
||||
this.sseEndpoint = sseEndpoint;
|
||||
this.objectMapper = objectMapper;
|
||||
this.httpClient = clientBuilder.connectTimeout(Duration.ofSeconds(10)).build();
|
||||
this.sseClient = new FlowSseClient(this.httpClient);
|
||||
this.requestBuilder = requestBuilder;
|
||||
|
||||
this.sseClient = new FlowSseClient(this.httpClient, requestBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -159,6 +180,8 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
|
||||
|
||||
/**
|
||||
* Creates a new builder with the specified base URI.
|
||||
* @param baseUri the base URI of the MCP server
|
||||
|
|
@ -190,6 +213,17 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the HTTP request builder.
|
||||
* @param requestBuilder the HTTP request builder
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder requestBuilder(HttpRequest.Builder requestBuilder) {
|
||||
Assert.notNull(requestBuilder, "requestBuilder must not be null");
|
||||
this.requestBuilder = requestBuilder;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the object mapper for JSON serialization/deserialization.
|
||||
* @param objectMapper the object mapper
|
||||
|
|
@ -206,7 +240,7 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
* @return a new transport instance
|
||||
*/
|
||||
public HttpClientSseClientTransport build() {
|
||||
return new HttpClientSseClientTransport(clientBuilder, baseUri, sseEndpoint, objectMapper);
|
||||
return new HttpClientSseClientTransport(clientBuilder, requestBuilder, baseUri, sseEndpoint, objectMapper);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -301,8 +335,7 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
|
||||
try {
|
||||
String jsonText = this.objectMapper.writeValueAsString(message);
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(this.baseUri + endpoint))
|
||||
HttpRequest request = this.requestBuilder.uri(URI.create(this.baseUri + endpoint))
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonText))
|
||||
.build();
|
||||
|
|
|
|||
Loading…
Reference in a new issue