Skip to content

Commit eb8e374

Browse files
renxiawangtzolov
authored andcommitted
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 <[email protected]>
1 parent 8d5872f commit eb8e374

File tree

2 files changed

+50
-6
lines changed

2 files changed

+50
-6
lines changed

mcp/src/main/java/io/modelcontextprotocol/client/transport/FlowSseClient.java

+13-2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ public class FlowSseClient {
3939

4040
private final HttpClient httpClient;
4141

42+
private final HttpRequest.Builder requestBuilder;
43+
4244
/**
4345
* Pattern to extract the data content from SSE data field lines. Matches lines
4446
* starting with "data:" and captures the remaining content.
@@ -92,7 +94,17 @@ public interface SseEventHandler {
9294
* @param httpClient the {@link HttpClient} instance to use for SSE connections
9395
*/
9496
public FlowSseClient(HttpClient httpClient) {
97+
this(httpClient, HttpRequest.newBuilder());
98+
}
99+
100+
/**
101+
* Creates a new FlowSseClient with the specified HTTP client and request builder.
102+
* @param httpClient the {@link HttpClient} instance to use for SSE connections
103+
* @param requestBuilder the {@link HttpRequest.Builder} to use for SSE requests
104+
*/
105+
public FlowSseClient(HttpClient httpClient, HttpRequest.Builder requestBuilder) {
95106
this.httpClient = httpClient;
107+
this.requestBuilder = requestBuilder;
96108
}
97109

98110
/**
@@ -109,8 +121,7 @@ public FlowSseClient(HttpClient httpClient) {
109121
* @throws RuntimeException if the connection fails with a non-200 status code
110122
*/
111123
public void subscribe(String url, SseEventHandler eventHandler) {
112-
HttpRequest request = HttpRequest.newBuilder()
113-
.uri(URI.create(url))
124+
HttpRequest request = this.requestBuilder.uri(URI.create(url))
114125
.header("Accept", "text/event-stream")
115126
.header("Cache-Control", "no-cache")
116127
.GET()

mcp/src/main/java/io/modelcontextprotocol/client/transport/HttpClientSseClientTransport.java

+37-4
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ public class HttpClientSseClientTransport implements McpClientTransport {
8282
*/
8383
private final HttpClient httpClient;
8484

85+
/** HTTP request builder for building requests to send messages to the server */
86+
private final HttpRequest.Builder requestBuilder;
87+
8588
/** JSON object mapper for message serialization/deserialization */
8689
protected ObjectMapper objectMapper;
8790

@@ -126,15 +129,33 @@ public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, String bas
126129
*/
127130
public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, String baseUri, String sseEndpoint,
128131
ObjectMapper objectMapper) {
132+
this(clientBuilder, HttpRequest.newBuilder(), baseUri, sseEndpoint, objectMapper);
133+
}
134+
135+
/**
136+
* Creates a new transport instance with custom HTTP client builder, object mapper,
137+
* and headers.
138+
* @param clientBuilder the HTTP client builder to use
139+
* @param requestBuilder the HTTP request builder to use
140+
* @param baseUri the base URI of the MCP server
141+
* @param sseEndpoint the SSE endpoint path
142+
* @param objectMapper the object mapper for JSON serialization/deserialization
143+
* @throws IllegalArgumentException if objectMapper, clientBuilder, or headers is null
144+
*/
145+
public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, HttpRequest.Builder requestBuilder,
146+
String baseUri, String sseEndpoint, ObjectMapper objectMapper) {
129147
Assert.notNull(objectMapper, "ObjectMapper must not be null");
130148
Assert.hasText(baseUri, "baseUri must not be empty");
131149
Assert.hasText(sseEndpoint, "sseEndpoint must not be empty");
132150
Assert.notNull(clientBuilder, "clientBuilder must not be null");
151+
Assert.notNull(requestBuilder, "requestBuilder must not be null");
133152
this.baseUri = baseUri;
134153
this.sseEndpoint = sseEndpoint;
135154
this.objectMapper = objectMapper;
136155
this.httpClient = clientBuilder.connectTimeout(Duration.ofSeconds(10)).build();
137-
this.sseClient = new FlowSseClient(this.httpClient);
156+
this.requestBuilder = requestBuilder;
157+
158+
this.sseClient = new FlowSseClient(this.httpClient, requestBuilder);
138159
}
139160

140161
/**
@@ -159,6 +180,8 @@ public static class Builder {
159180

160181
private ObjectMapper objectMapper = new ObjectMapper();
161182

183+
private HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
184+
162185
/**
163186
* Creates a new builder with the specified base URI.
164187
* @param baseUri the base URI of the MCP server
@@ -190,6 +213,17 @@ public Builder clientBuilder(HttpClient.Builder clientBuilder) {
190213
return this;
191214
}
192215

216+
/**
217+
* Sets the HTTP request builder.
218+
* @param requestBuilder the HTTP request builder
219+
* @return this builder
220+
*/
221+
public Builder requestBuilder(HttpRequest.Builder requestBuilder) {
222+
Assert.notNull(requestBuilder, "requestBuilder must not be null");
223+
this.requestBuilder = requestBuilder;
224+
return this;
225+
}
226+
193227
/**
194228
* Sets the object mapper for JSON serialization/deserialization.
195229
* @param objectMapper the object mapper
@@ -206,7 +240,7 @@ public Builder objectMapper(ObjectMapper objectMapper) {
206240
* @return a new transport instance
207241
*/
208242
public HttpClientSseClientTransport build() {
209-
return new HttpClientSseClientTransport(clientBuilder, baseUri, sseEndpoint, objectMapper);
243+
return new HttpClientSseClientTransport(clientBuilder, requestBuilder, baseUri, sseEndpoint, objectMapper);
210244
}
211245

212246
}
@@ -301,8 +335,7 @@ public Mono<Void> sendMessage(JSONRPCMessage message) {
301335

302336
try {
303337
String jsonText = this.objectMapper.writeValueAsString(message);
304-
HttpRequest request = HttpRequest.newBuilder()
305-
.uri(URI.create(this.baseUri + endpoint))
338+
HttpRequest request = this.requestBuilder.uri(URI.create(this.baseUri + endpoint))
306339
.header("Content-Type", "application/json")
307340
.POST(HttpRequest.BodyPublishers.ofString(jsonText))
308341
.build();

0 commit comments

Comments
 (0)