refactor(client): enhance HttpClientSseClientTransport with flexible customization API (#117)
- Add builder customizeClient() and customizeRequest() methods - Enable HTTP client and request configuration through consumer-based customization - Deprecate direct constructors in favor of the more flexible builder approach - Add test coverage for customization capabilities Co-authored-by: Christian Tzolov <christian.tzolov@broadcom.com> Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
parent
fbea833384
commit
fab434c088
1 changed files with 185 additions and 22 deletions
|
|
@ -13,6 +13,7 @@ import java.util.concurrent.CompletableFuture;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
|
@ -103,7 +104,10 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
/**
|
||||
* Creates a new transport instance with default HTTP client and object mapper.
|
||||
* @param baseUri the base URI of the MCP server
|
||||
* @deprecated Use {@link HttpClientSseClientTransport#builder(String)} instead. This
|
||||
* constructor will be removed in future versions.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public HttpClientSseClientTransport(String baseUri) {
|
||||
this(HttpClient.newBuilder(), baseUri, new ObjectMapper());
|
||||
}
|
||||
|
|
@ -114,7 +118,10 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
* @param baseUri the base URI of the MCP server
|
||||
* @param objectMapper the object mapper for JSON serialization/deserialization
|
||||
* @throws IllegalArgumentException if objectMapper or clientBuilder is null
|
||||
* @deprecated Use {@link HttpClientSseClientTransport#builder(String)} instead. This
|
||||
* constructor will be removed in future versions.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, String baseUri, ObjectMapper objectMapper) {
|
||||
this(clientBuilder, baseUri, DEFAULT_SSE_ENDPOINT, objectMapper);
|
||||
}
|
||||
|
|
@ -126,7 +133,10 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
* @param sseEndpoint the SSE endpoint path
|
||||
* @param objectMapper the object mapper for JSON serialization/deserialization
|
||||
* @throws IllegalArgumentException if objectMapper or clientBuilder is null
|
||||
* @deprecated Use {@link HttpClientSseClientTransport#builder(String)} instead. This
|
||||
* constructor will be removed in future versions.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, String baseUri, String sseEndpoint,
|
||||
ObjectMapper objectMapper) {
|
||||
this(clientBuilder, HttpRequest.newBuilder(), baseUri, sseEndpoint, objectMapper);
|
||||
|
|
@ -141,18 +151,37 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
* @param sseEndpoint the SSE endpoint path
|
||||
* @param objectMapper the object mapper for JSON serialization/deserialization
|
||||
* @throws IllegalArgumentException if objectMapper, clientBuilder, or headers is null
|
||||
* @deprecated Use {@link HttpClientSseClientTransport#builder(String)} instead. This
|
||||
* constructor will be removed in future versions.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, HttpRequest.Builder requestBuilder,
|
||||
String baseUri, String sseEndpoint, ObjectMapper objectMapper) {
|
||||
this(clientBuilder.connectTimeout(Duration.ofSeconds(10)).build(), requestBuilder, baseUri, sseEndpoint,
|
||||
objectMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new transport instance with custom HTTP client builder, object mapper,
|
||||
* and headers.
|
||||
* @param httpClient the HTTP client 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
|
||||
*/
|
||||
HttpClientSseClientTransport(HttpClient httpClient, 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(httpClient, "httpClient 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.httpClient = httpClient;
|
||||
this.requestBuilder = requestBuilder;
|
||||
|
||||
this.sseClient = new FlowSseClient(this.httpClient, requestBuilder);
|
||||
|
|
@ -164,7 +193,7 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
* @return a new builder instance
|
||||
*/
|
||||
public static Builder builder(String baseUri) {
|
||||
return new Builder(baseUri);
|
||||
return new Builder().baseUri(baseUri);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -172,25 +201,50 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
*/
|
||||
public static class Builder {
|
||||
|
||||
private final String baseUri;
|
||||
private String baseUri;
|
||||
|
||||
private String sseEndpoint = DEFAULT_SSE_ENDPOINT;
|
||||
|
||||
private HttpClient.Builder clientBuilder = HttpClient.newBuilder();
|
||||
private HttpClient.Builder clientBuilder = HttpClient.newBuilder()
|
||||
.version(HttpClient.Version.HTTP_1_1)
|
||||
.connectTimeout(Duration.ofSeconds(10));
|
||||
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
|
||||
private HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
|
||||
.header("Content-Type", "application/json");
|
||||
|
||||
/**
|
||||
* Creates a new builder instance.
|
||||
*/
|
||||
Builder() {
|
||||
// Default constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder with the specified base URI.
|
||||
* @param baseUri the base URI of the MCP server
|
||||
* @deprecated Use {@link HttpClientSseClientTransport#builder(String)} instead.
|
||||
* This constructor is deprecated and will be removed or made {@code protected} or
|
||||
* {@code private} in a future release.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public Builder(String baseUri) {
|
||||
Assert.hasText(baseUri, "baseUri must not be empty");
|
||||
this.baseUri = baseUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the base URI.
|
||||
* @param baseUri the base URI
|
||||
* @return this builder
|
||||
*/
|
||||
Builder baseUri(String baseUri) {
|
||||
Assert.hasText(baseUri, "baseUri must not be empty");
|
||||
this.baseUri = baseUri;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SSE endpoint path.
|
||||
* @param sseEndpoint the SSE endpoint path
|
||||
|
|
@ -213,6 +267,17 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the HTTP client builder.
|
||||
* @param clientCustomizer the consumer to customize the HTTP client builder
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder customizeClient(final Consumer<HttpClient.Builder> clientCustomizer) {
|
||||
Assert.notNull(clientCustomizer, "clientCustomizer must not be null");
|
||||
clientCustomizer.accept(clientBuilder);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the HTTP request builder.
|
||||
* @param requestBuilder the HTTP request builder
|
||||
|
|
@ -224,6 +289,17 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the HTTP client builder.
|
||||
* @param requestCustomizer the consumer to customize the HTTP request builder
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder customizeRequest(final Consumer<HttpRequest.Builder> requestCustomizer) {
|
||||
Assert.notNull(requestCustomizer, "requestCustomizer must not be null");
|
||||
requestCustomizer.accept(requestBuilder);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the object mapper for JSON serialization/deserialization.
|
||||
* @param objectMapper the object mapper
|
||||
|
|
@ -240,7 +316,8 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
* @return a new transport instance
|
||||
*/
|
||||
public HttpClientSseClientTransport build() {
|
||||
return new HttpClientSseClientTransport(clientBuilder, requestBuilder, baseUri, sseEndpoint, objectMapper);
|
||||
return new HttpClientSseClientTransport(clientBuilder.build(), requestBuilder, baseUri, sseEndpoint,
|
||||
objectMapper);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -336,7 +413,6 @@ public class HttpClientSseClientTransport implements McpClientTransport {
|
|||
try {
|
||||
String jsonText = this.objectMapper.writeValueAsString(message);
|
||||
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