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 HttpClient httpClient;
|
||||||
|
|
||||||
|
private final HttpRequest.Builder requestBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pattern to extract the data content from SSE data field lines. Matches lines
|
* Pattern to extract the data content from SSE data field lines. Matches lines
|
||||||
* starting with "data:" and captures the remaining content.
|
* 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
|
* @param httpClient the {@link HttpClient} instance to use for SSE connections
|
||||||
*/
|
*/
|
||||||
public FlowSseClient(HttpClient httpClient) {
|
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.httpClient = httpClient;
|
||||||
|
this.requestBuilder = requestBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -109,8 +121,7 @@ public class FlowSseClient {
|
||||||
* @throws RuntimeException if the connection fails with a non-200 status code
|
* @throws RuntimeException if the connection fails with a non-200 status code
|
||||||
*/
|
*/
|
||||||
public void subscribe(String url, SseEventHandler eventHandler) {
|
public void subscribe(String url, SseEventHandler eventHandler) {
|
||||||
HttpRequest request = HttpRequest.newBuilder()
|
HttpRequest request = this.requestBuilder.uri(URI.create(url))
|
||||||
.uri(URI.create(url))
|
|
||||||
.header("Accept", "text/event-stream")
|
.header("Accept", "text/event-stream")
|
||||||
.header("Cache-Control", "no-cache")
|
.header("Cache-Control", "no-cache")
|
||||||
.GET()
|
.GET()
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,9 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
||||||
*/
|
*/
|
||||||
private final HttpClient httpClient;
|
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 */
|
/** JSON object mapper for message serialization/deserialization */
|
||||||
protected ObjectMapper objectMapper;
|
protected ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
|
@ -126,15 +129,33 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
||||||
*/
|
*/
|
||||||
public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, String baseUri, String sseEndpoint,
|
public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, String baseUri, String sseEndpoint,
|
||||||
ObjectMapper objectMapper) {
|
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.notNull(objectMapper, "ObjectMapper must not be null");
|
||||||
Assert.hasText(baseUri, "baseUri must not be empty");
|
Assert.hasText(baseUri, "baseUri must not be empty");
|
||||||
Assert.hasText(sseEndpoint, "sseEndpoint must not be empty");
|
Assert.hasText(sseEndpoint, "sseEndpoint must not be empty");
|
||||||
Assert.notNull(clientBuilder, "clientBuilder must not be null");
|
Assert.notNull(clientBuilder, "clientBuilder must not be null");
|
||||||
|
Assert.notNull(requestBuilder, "requestBuilder must not be null");
|
||||||
this.baseUri = baseUri;
|
this.baseUri = baseUri;
|
||||||
this.sseEndpoint = sseEndpoint;
|
this.sseEndpoint = sseEndpoint;
|
||||||
this.objectMapper = objectMapper;
|
this.objectMapper = objectMapper;
|
||||||
this.httpClient = clientBuilder.connectTimeout(Duration.ofSeconds(10)).build();
|
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 ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
private HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new builder with the specified base URI.
|
* Creates a new builder with the specified base URI.
|
||||||
* @param baseUri the base URI of the MCP server
|
* @param baseUri the base URI of the MCP server
|
||||||
|
|
@ -190,6 +213,17 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
||||||
return this;
|
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.
|
* Sets the object mapper for JSON serialization/deserialization.
|
||||||
* @param objectMapper the object mapper
|
* @param objectMapper the object mapper
|
||||||
|
|
@ -206,7 +240,7 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
||||||
* @return a new transport instance
|
* @return a new transport instance
|
||||||
*/
|
*/
|
||||||
public HttpClientSseClientTransport build() {
|
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 {
|
try {
|
||||||
String jsonText = this.objectMapper.writeValueAsString(message);
|
String jsonText = this.objectMapper.writeValueAsString(message);
|
||||||
HttpRequest request = HttpRequest.newBuilder()
|
HttpRequest request = this.requestBuilder.uri(URI.create(this.baseUri + endpoint))
|
||||||
.uri(URI.create(this.baseUri + endpoint))
|
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
.POST(HttpRequest.BodyPublishers.ofString(jsonText))
|
.POST(HttpRequest.BodyPublishers.ofString(jsonText))
|
||||||
.build();
|
.build();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue