Skip to content

Commit 95ba8e7

Browse files
Kehrlanntzolov
authored andcommitted
refactor: move and rename HTTP request customizers to dedicated package (#453)
- Move Mcp(Async)HttpRequestCustomizer from client.transport to client.transport.customizer - Rename (Async)HttpRequestCustomizer to Mcp(Async)HttpRequestCustomizer - Add DelegatingMcpAsyncHttpRequestCustomizer and DelegatingMcpSyncHttpRequestCustomizer for composing multiple customizers - Update all references across transport classes and tests - Improve package organization and naming consistency with MCP prefix
1 parent b4fef52 commit 95ba8e7

11 files changed

+238
-34
lines changed

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

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import com.fasterxml.jackson.core.type.TypeReference;
2323
import com.fasterxml.jackson.databind.ObjectMapper;
2424

25+
import io.modelcontextprotocol.client.transport.customizer.McpAsyncHttpRequestCustomizer;
26+
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpRequestCustomizer;
2527
import io.modelcontextprotocol.client.transport.ResponseSubscribers.ResponseEvent;
2628
import io.modelcontextprotocol.spec.McpClientTransport;
2729
import io.modelcontextprotocol.spec.McpSchema;
@@ -112,7 +114,7 @@ public class HttpClientSseClientTransport implements McpClientTransport {
112114
/**
113115
* Customizer to modify requests before they are executed.
114116
*/
115-
private final AsyncHttpRequestCustomizer httpRequestCustomizer;
117+
private final McpAsyncHttpRequestCustomizer httpRequestCustomizer;
116118

117119
/**
118120
* Creates a new transport instance with default HTTP client and object mapper.
@@ -186,7 +188,7 @@ public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, HttpReques
186188
@Deprecated(forRemoval = true)
187189
HttpClientSseClientTransport(HttpClient httpClient, HttpRequest.Builder requestBuilder, String baseUri,
188190
String sseEndpoint, ObjectMapper objectMapper) {
189-
this(httpClient, requestBuilder, baseUri, sseEndpoint, objectMapper, AsyncHttpRequestCustomizer.NOOP);
191+
this(httpClient, requestBuilder, baseUri, sseEndpoint, objectMapper, McpAsyncHttpRequestCustomizer.NOOP);
190192
}
191193

192194
/**
@@ -202,7 +204,7 @@ public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, HttpReques
202204
* @throws IllegalArgumentException if objectMapper, clientBuilder, or headers is null
203205
*/
204206
HttpClientSseClientTransport(HttpClient httpClient, HttpRequest.Builder requestBuilder, String baseUri,
205-
String sseEndpoint, ObjectMapper objectMapper, AsyncHttpRequestCustomizer httpRequestCustomizer) {
207+
String sseEndpoint, ObjectMapper objectMapper, McpAsyncHttpRequestCustomizer httpRequestCustomizer) {
206208
Assert.notNull(objectMapper, "ObjectMapper must not be null");
207209
Assert.hasText(baseUri, "baseUri must not be empty");
208210
Assert.hasText(sseEndpoint, "sseEndpoint must not be empty");
@@ -246,7 +248,7 @@ public static class Builder {
246248

247249
private HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
248250

249-
private AsyncHttpRequestCustomizer httpRequestCustomizer = AsyncHttpRequestCustomizer.NOOP;
251+
private McpAsyncHttpRequestCustomizer httpRequestCustomizer = McpAsyncHttpRequestCustomizer.NOOP;
250252

251253
private Duration connectTimeout = Duration.ofSeconds(10);
252254

@@ -352,16 +354,16 @@ public Builder objectMapper(ObjectMapper objectMapper) {
352354
* executing them.
353355
* <p>
354356
* This overrides the customizer from
355-
* {@link #asyncHttpRequestCustomizer(AsyncHttpRequestCustomizer)}.
357+
* {@link #asyncHttpRequestCustomizer(McpAsyncHttpRequestCustomizer)}.
356358
* <p>
357-
* Do NOT use a blocking {@link SyncHttpRequestCustomizer} in a non-blocking
358-
* context. Use {@link #asyncHttpRequestCustomizer(AsyncHttpRequestCustomizer)}
359+
* Do NOT use a blocking {@link McpSyncHttpRequestCustomizer} in a non-blocking
360+
* context. Use {@link #asyncHttpRequestCustomizer(McpAsyncHttpRequestCustomizer)}
359361
* instead.
360362
* @param syncHttpRequestCustomizer the request customizer
361363
* @return this builder
362364
*/
363-
public Builder httpRequestCustomizer(SyncHttpRequestCustomizer syncHttpRequestCustomizer) {
364-
this.httpRequestCustomizer = AsyncHttpRequestCustomizer.fromSync(syncHttpRequestCustomizer);
365+
public Builder httpRequestCustomizer(McpSyncHttpRequestCustomizer syncHttpRequestCustomizer) {
366+
this.httpRequestCustomizer = McpAsyncHttpRequestCustomizer.fromSync(syncHttpRequestCustomizer);
365367
return this;
366368
}
367369

@@ -370,13 +372,13 @@ public Builder httpRequestCustomizer(SyncHttpRequestCustomizer syncHttpRequestCu
370372
* executing them.
371373
* <p>
372374
* This overrides the customizer from
373-
* {@link #httpRequestCustomizer(SyncHttpRequestCustomizer)}.
375+
* {@link #httpRequestCustomizer(McpSyncHttpRequestCustomizer)}.
374376
* <p>
375377
* Do NOT use a blocking implementation in a non-blocking context.
376378
* @param asyncHttpRequestCustomizer the request customizer
377379
* @return this builder
378380
*/
379-
public Builder asyncHttpRequestCustomizer(AsyncHttpRequestCustomizer asyncHttpRequestCustomizer) {
381+
public Builder asyncHttpRequestCustomizer(McpAsyncHttpRequestCustomizer asyncHttpRequestCustomizer) {
380382
this.httpRequestCustomizer = asyncHttpRequestCustomizer;
381383
return this;
382384
}

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

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import com.fasterxml.jackson.core.type.TypeReference;
2626
import com.fasterxml.jackson.databind.ObjectMapper;
2727

28+
import io.modelcontextprotocol.client.transport.customizer.McpAsyncHttpRequestCustomizer;
29+
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpRequestCustomizer;
2830
import io.modelcontextprotocol.client.transport.ResponseSubscribers.ResponseEvent;
2931
import io.modelcontextprotocol.spec.DefaultMcpTransportSession;
3032
import io.modelcontextprotocol.spec.DefaultMcpTransportStream;
@@ -113,7 +115,7 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
113115

114116
private final boolean resumableStreams;
115117

116-
private final AsyncHttpRequestCustomizer httpRequestCustomizer;
118+
private final McpAsyncHttpRequestCustomizer httpRequestCustomizer;
117119

118120
private final AtomicReference<DefaultMcpTransportSession> activeSession = new AtomicReference<>();
119121

@@ -123,7 +125,7 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
123125

124126
private HttpClientStreamableHttpTransport(ObjectMapper objectMapper, HttpClient httpClient,
125127
HttpRequest.Builder requestBuilder, String baseUri, String endpoint, boolean resumableStreams,
126-
boolean openConnectionOnStartup, AsyncHttpRequestCustomizer httpRequestCustomizer) {
128+
boolean openConnectionOnStartup, McpAsyncHttpRequestCustomizer httpRequestCustomizer) {
127129
this.objectMapper = objectMapper;
128130
this.httpClient = httpClient;
129131
this.requestBuilder = requestBuilder;
@@ -598,7 +600,7 @@ public static class Builder {
598600

599601
private HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
600602

601-
private AsyncHttpRequestCustomizer httpRequestCustomizer = AsyncHttpRequestCustomizer.NOOP;
603+
private McpAsyncHttpRequestCustomizer httpRequestCustomizer = McpAsyncHttpRequestCustomizer.NOOP;
602604

603605
private Duration connectTimeout = Duration.ofSeconds(10);
604606

@@ -709,16 +711,16 @@ public Builder openConnectionOnStartup(boolean openConnectionOnStartup) {
709711
* executing them.
710712
* <p>
711713
* This overrides the customizer from
712-
* {@link #asyncHttpRequestCustomizer(AsyncHttpRequestCustomizer)}.
714+
* {@link #asyncHttpRequestCustomizer(McpAsyncHttpRequestCustomizer)}.
713715
* <p>
714-
* Do NOT use a blocking {@link SyncHttpRequestCustomizer} in a non-blocking
715-
* context. Use {@link #asyncHttpRequestCustomizer(AsyncHttpRequestCustomizer)}
716+
* Do NOT use a blocking {@link McpSyncHttpRequestCustomizer} in a non-blocking
717+
* context. Use {@link #asyncHttpRequestCustomizer(McpAsyncHttpRequestCustomizer)}
716718
* instead.
717719
* @param syncHttpRequestCustomizer the request customizer
718720
* @return this builder
719721
*/
720-
public Builder httpRequestCustomizer(SyncHttpRequestCustomizer syncHttpRequestCustomizer) {
721-
this.httpRequestCustomizer = AsyncHttpRequestCustomizer.fromSync(syncHttpRequestCustomizer);
722+
public Builder httpRequestCustomizer(McpSyncHttpRequestCustomizer syncHttpRequestCustomizer) {
723+
this.httpRequestCustomizer = McpAsyncHttpRequestCustomizer.fromSync(syncHttpRequestCustomizer);
722724
return this;
723725
}
724726

@@ -727,13 +729,13 @@ public Builder httpRequestCustomizer(SyncHttpRequestCustomizer syncHttpRequestCu
727729
* executing them.
728730
* <p>
729731
* This overrides the customizer from
730-
* {@link #httpRequestCustomizer(SyncHttpRequestCustomizer)}.
732+
* {@link #httpRequestCustomizer(McpSyncHttpRequestCustomizer)}.
731733
* <p>
732734
* Do NOT use a blocking implementation in a non-blocking context.
733735
* @param asyncHttpRequestCustomizer the request customizer
734736
* @return this builder
735737
*/
736-
public Builder asyncHttpRequestCustomizer(AsyncHttpRequestCustomizer asyncHttpRequestCustomizer) {
738+
public Builder asyncHttpRequestCustomizer(McpAsyncHttpRequestCustomizer asyncHttpRequestCustomizer) {
737739
this.httpRequestCustomizer = asyncHttpRequestCustomizer;
738740
return this;
739741
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2024-2025 the original author or authors.
3+
*/
4+
package io.modelcontextprotocol.client.transport.customizer;
5+
6+
import io.modelcontextprotocol.util.Assert;
7+
import java.net.URI;
8+
import java.net.http.HttpRequest;
9+
import java.util.List;
10+
import org.reactivestreams.Publisher;
11+
import reactor.core.publisher.Mono;
12+
13+
/**
14+
* Composable {@link McpAsyncHttpRequestCustomizer} that applies multiple customizers, in
15+
* order.
16+
*
17+
* @author Daniel Garnier-Moiroux
18+
*/
19+
public class DelegatingMcpAsyncHttpRequestCustomizer implements McpAsyncHttpRequestCustomizer {
20+
21+
private final List<McpAsyncHttpRequestCustomizer> customizers;
22+
23+
public DelegatingMcpAsyncHttpRequestCustomizer(List<McpAsyncHttpRequestCustomizer> customizers) {
24+
Assert.notNull(customizers, "Customizers must not be null");
25+
this.customizers = customizers;
26+
}
27+
28+
@Override
29+
public Publisher<HttpRequest.Builder> customize(HttpRequest.Builder builder, String method, URI endpoint,
30+
String body) {
31+
var result = Mono.just(builder);
32+
for (var customizer : this.customizers) {
33+
result = result.flatMap(b -> Mono.from(customizer.customize(b, method, endpoint, body)));
34+
}
35+
return result;
36+
}
37+
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2024-2025 the original author or authors.
3+
*/
4+
5+
package io.modelcontextprotocol.client.transport.customizer;
6+
7+
import io.modelcontextprotocol.util.Assert;
8+
import java.net.URI;
9+
import java.net.http.HttpRequest;
10+
import java.util.List;
11+
12+
/**
13+
* Composable {@link McpSyncHttpRequestCustomizer} that applies multiple customizers, in
14+
* order.
15+
*
16+
* @author Daniel Garnier-Moiroux
17+
*/
18+
public class DelegatingMcpSyncHttpRequestCustomizer implements McpSyncHttpRequestCustomizer {
19+
20+
private final List<McpSyncHttpRequestCustomizer> delegates;
21+
22+
public DelegatingMcpSyncHttpRequestCustomizer(List<McpSyncHttpRequestCustomizer> customizers) {
23+
Assert.notNull(customizers, "Customizers must not be null");
24+
this.delegates = customizers;
25+
}
26+
27+
@Override
28+
public void customize(HttpRequest.Builder builder, String method, URI endpoint, String body) {
29+
this.delegates.forEach(delegate -> delegate.customize(builder, method, endpoint, body));
30+
}
31+
32+
}

mcp/src/main/java/io/modelcontextprotocol/client/transport/AsyncHttpRequestCustomizer.java renamed to mcp/src/main/java/io/modelcontextprotocol/client/transport/customizer/McpAsyncHttpRequestCustomizer.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright 2024-2025 the original author or authors.
33
*/
44

5-
package io.modelcontextprotocol.client.transport;
5+
package io.modelcontextprotocol.client.transport.customizer;
66

77
import java.net.URI;
88
import java.net.http.HttpRequest;
@@ -19,27 +19,27 @@
1919
*
2020
* @author Daniel Garnier-Moiroux
2121
*/
22-
public interface AsyncHttpRequestCustomizer {
22+
public interface McpAsyncHttpRequestCustomizer {
2323

2424
Publisher<HttpRequest.Builder> customize(HttpRequest.Builder builder, String method, URI endpoint,
2525
@Nullable String body);
2626

27-
AsyncHttpRequestCustomizer NOOP = new Noop();
27+
McpAsyncHttpRequestCustomizer NOOP = new Noop();
2828

2929
/**
3030
* Wrap a sync implementation in an async wrapper.
3131
* <p>
3232
* Do NOT wrap a blocking implementation for use in a non-blocking context. For a
3333
* blocking implementation, consider using {@link Schedulers#boundedElastic()}.
3434
*/
35-
static AsyncHttpRequestCustomizer fromSync(SyncHttpRequestCustomizer customizer) {
35+
static McpAsyncHttpRequestCustomizer fromSync(McpSyncHttpRequestCustomizer customizer) {
3636
return (builder, method, uri, body) -> Mono.fromSupplier(() -> {
3737
customizer.customize(builder, method, uri, body);
3838
return builder;
3939
});
4040
}
4141

42-
class Noop implements AsyncHttpRequestCustomizer {
42+
class Noop implements McpAsyncHttpRequestCustomizer {
4343

4444
@Override
4545
public Publisher<HttpRequest.Builder> customize(HttpRequest.Builder builder, String method, URI endpoint,

mcp/src/main/java/io/modelcontextprotocol/client/transport/SyncHttpRequestCustomizer.java renamed to mcp/src/main/java/io/modelcontextprotocol/client/transport/customizer/McpSyncHttpRequestCustomizer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright 2024-2025 the original author or authors.
33
*/
44

5-
package io.modelcontextprotocol.client.transport;
5+
package io.modelcontextprotocol.client.transport.customizer;
66

77
import java.net.URI;
88
import java.net.http.HttpRequest;
@@ -14,7 +14,7 @@
1414
*
1515
* @author Daniel Garnier-Moiroux
1616
*/
17-
public interface SyncHttpRequestCustomizer {
17+
public interface McpSyncHttpRequestCustomizer {
1818

1919
void customize(HttpRequest.Builder builder, String method, URI endpoint, @Nullable String body);
2020

mcp/src/test/java/io/modelcontextprotocol/client/transport/HttpClientSseClientTransportTests.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import java.util.function.Function;
1616

1717
import com.fasterxml.jackson.databind.ObjectMapper;
18+
import io.modelcontextprotocol.client.transport.customizer.McpAsyncHttpRequestCustomizer;
19+
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpRequestCustomizer;
1820
import io.modelcontextprotocol.spec.McpSchema;
1921
import io.modelcontextprotocol.spec.McpSchema.JSONRPCRequest;
2022
import org.junit.jupiter.api.AfterAll;
@@ -72,7 +74,7 @@ static class TestHttpClientSseClientTransport extends HttpClientSseClientTranspo
7274
public TestHttpClientSseClientTransport(final String baseUri) {
7375
super(HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build(),
7476
HttpRequest.newBuilder().header("Content-Type", "application/json"), baseUri, "/sse",
75-
new ObjectMapper(), AsyncHttpRequestCustomizer.NOOP);
77+
new ObjectMapper(), McpAsyncHttpRequestCustomizer.NOOP);
7678
}
7779

7880
public int getInboundMessageCount() {
@@ -389,7 +391,7 @@ void testChainedCustomizations() {
389391

390392
@Test
391393
void testRequestCustomizer() {
392-
var mockCustomizer = mock(SyncHttpRequestCustomizer.class);
394+
var mockCustomizer = mock(McpSyncHttpRequestCustomizer.class);
393395

394396
// Create a transport with the customizer
395397
var customizedTransport = HttpClientSseClientTransport.builder(host)
@@ -423,7 +425,7 @@ void testRequestCustomizer() {
423425

424426
@Test
425427
void testAsyncRequestCustomizer() {
426-
var mockCustomizer = mock(AsyncHttpRequestCustomizer.class);
428+
var mockCustomizer = mock(McpAsyncHttpRequestCustomizer.class);
427429
when(mockCustomizer.customize(any(), any(), any(), any()))
428430
.thenAnswer(invocation -> Mono.just(invocation.getArguments()[0]));
429431

mcp/src/test/java/io/modelcontextprotocol/client/transport/HttpClientStreamableHttpTransportEmptyJsonResponseTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import com.sun.net.httpserver.HttpServer;
2424

25+
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpRequestCustomizer;
2526
import io.modelcontextprotocol.server.transport.TomcatTestUtil;
2627
import io.modelcontextprotocol.spec.McpSchema;
2728
import io.modelcontextprotocol.spec.ProtocolVersions;
@@ -70,7 +71,7 @@ static void stopContainer() {
7071
void testNotificationInitialized() throws URISyntaxException {
7172

7273
var uri = new URI(host + "/mcp");
73-
var mockRequestCustomizer = mock(SyncHttpRequestCustomizer.class);
74+
var mockRequestCustomizer = mock(McpSyncHttpRequestCustomizer.class);
7475
var transport = HttpClientStreamableHttpTransport.builder(host)
7576
.httpRequestCustomizer(mockRequestCustomizer)
7677
.build();

mcp/src/test/java/io/modelcontextprotocol/client/transport/HttpClientStreamableHttpTransportTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
package io.modelcontextprotocol.client.transport;
66

7+
import io.modelcontextprotocol.client.transport.customizer.McpAsyncHttpRequestCustomizer;
8+
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpRequestCustomizer;
79
import io.modelcontextprotocol.spec.McpSchema;
810
import java.net.URI;
911
import java.net.URISyntaxException;
@@ -63,7 +65,7 @@ void withTransport(HttpClientStreamableHttpTransport transport, Consumer<HttpCli
6365
@Test
6466
void testRequestCustomizer() throws URISyntaxException {
6567
var uri = new URI(host + "/mcp");
66-
var mockRequestCustomizer = mock(SyncHttpRequestCustomizer.class);
68+
var mockRequestCustomizer = mock(McpSyncHttpRequestCustomizer.class);
6769

6870
var transport = HttpClientStreamableHttpTransport.builder(host)
6971
.httpRequestCustomizer(mockRequestCustomizer)
@@ -88,7 +90,7 @@ void testRequestCustomizer() throws URISyntaxException {
8890
@Test
8991
void testAsyncRequestCustomizer() throws URISyntaxException {
9092
var uri = new URI(host + "/mcp");
91-
var mockRequestCustomizer = mock(AsyncHttpRequestCustomizer.class);
93+
var mockRequestCustomizer = mock(McpAsyncHttpRequestCustomizer.class);
9294
when(mockRequestCustomizer.customize(any(), any(), any(), any()))
9395
.thenAnswer(invocation -> Mono.just(invocation.getArguments()[0]));
9496

0 commit comments

Comments
 (0)