|
11 | 11 | import java.net.http.HttpResponse; |
12 | 12 | import java.nio.ByteBuffer; |
13 | 13 | import java.time.Duration; |
| 14 | +import java.util.ArrayList; |
14 | 15 | import java.util.Collections; |
15 | 16 | import java.util.Comparator; |
16 | 17 | import java.util.List; |
|
22 | 23 | import java.util.function.Function; |
23 | 24 |
|
24 | 25 | import io.modelcontextprotocol.client.McpAsyncClient; |
| 26 | +import io.modelcontextprotocol.client.transport.customizer.DelegatingMcpAsyncHttpClientRequestCustomizer; |
25 | 27 | import io.modelcontextprotocol.client.transport.customizer.McpAsyncHttpClientRequestCustomizer; |
26 | 28 | import io.modelcontextprotocol.client.transport.customizer.McpHttpClientAuthorizationErrorHandler; |
27 | 29 | import io.modelcontextprotocol.client.transport.customizer.McpHttpClientTransportAuthorizationErrorHandler; |
@@ -672,7 +674,7 @@ public static class Builder { |
672 | 674 |
|
673 | 675 | private HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(); |
674 | 676 |
|
675 | | - private McpAsyncHttpClientRequestCustomizer httpRequestCustomizer = McpAsyncHttpClientRequestCustomizer.NOOP; |
| 677 | + private final List<McpAsyncHttpClientRequestCustomizer> httpRequestCustomizers = new ArrayList<>(); |
676 | 678 |
|
677 | 679 | private Duration connectTimeout = Duration.ofSeconds(10); |
678 | 680 |
|
@@ -776,36 +778,92 @@ public Builder openConnectionOnStartup(boolean openConnectionOnStartup) { |
776 | 778 |
|
777 | 779 | /** |
778 | 780 | * Sets the customizer for {@link HttpRequest.Builder}, to modify requests before |
779 | | - * executing them. |
| 781 | + * executing them. The customizer is internally converted to |
| 782 | + * {@link McpAsyncHttpClientRequestCustomizer}. |
780 | 783 | * <p> |
781 | | - * This overrides the customizer from |
782 | | - * {@link #asyncHttpRequestCustomizer(McpAsyncHttpClientRequestCustomizer)}. |
| 784 | + * This replaces all customizers previously registered on this builder. |
783 | 785 | * <p> |
784 | 786 | * Do NOT use a blocking {@link McpSyncHttpClientRequestCustomizer} in a |
785 | 787 | * non-blocking context. Use |
786 | 788 | * {@link #asyncHttpRequestCustomizer(McpAsyncHttpClientRequestCustomizer)} |
787 | 789 | * instead. |
788 | 790 | * @param syncHttpRequestCustomizer the request customizer |
789 | 791 | * @return this builder |
| 792 | + * @deprecated Use {@link #addHttpRequestCustomizer} instead. |
790 | 793 | */ |
| 794 | + @Deprecated |
791 | 795 | public Builder httpRequestCustomizer(McpSyncHttpClientRequestCustomizer syncHttpRequestCustomizer) { |
792 | | - this.httpRequestCustomizer = McpAsyncHttpClientRequestCustomizer.fromSync(syncHttpRequestCustomizer); |
793 | | - return this; |
| 796 | + Assert.notNull(syncHttpRequestCustomizer, "syncHttpRequestCustomizer must not be null"); |
| 797 | + this.httpRequestCustomizers.clear(); |
| 798 | + return addHttpRequestCustomizer(syncHttpRequestCustomizer); |
794 | 799 | } |
795 | 800 |
|
796 | 801 | /** |
797 | 802 | * Sets the customizer for {@link HttpRequest.Builder}, to modify requests before |
798 | 803 | * executing them. |
799 | 804 | * <p> |
800 | | - * This overrides the customizer from |
801 | | - * {@link #httpRequestCustomizer(McpSyncHttpClientRequestCustomizer)}. |
| 805 | + * This replaces all customizers previously registered on this builder. |
802 | 806 | * <p> |
803 | 807 | * Do NOT use a blocking implementation in a non-blocking context. |
804 | 808 | * @param asyncHttpRequestCustomizer the request customizer |
805 | 809 | * @return this builder |
| 810 | + * @deprecated Use {@link #addAsyncHttpRequestCustomizer} instead. |
806 | 811 | */ |
| 812 | + @Deprecated |
807 | 813 | public Builder asyncHttpRequestCustomizer(McpAsyncHttpClientRequestCustomizer asyncHttpRequestCustomizer) { |
808 | | - this.httpRequestCustomizer = asyncHttpRequestCustomizer; |
| 814 | + Assert.notNull(asyncHttpRequestCustomizer, "asyncHttpRequestCustomizer must not be null"); |
| 815 | + this.httpRequestCustomizers.clear(); |
| 816 | + return addAsyncHttpRequestCustomizer(asyncHttpRequestCustomizer); |
| 817 | + } |
| 818 | + |
| 819 | + /** |
| 820 | + * Adds a customizer for {@link HttpRequest.Builder}, to modify requests before |
| 821 | + * executing them. Customizers are applied in the order they are added, after |
| 822 | + * those already registered on this builder. The customizer is internally |
| 823 | + * converted to {@link McpAsyncHttpClientRequestCustomizer}. |
| 824 | + * <p> |
| 825 | + * Do NOT use a blocking {@link McpSyncHttpClientRequestCustomizer} in a |
| 826 | + * non-blocking context. Use |
| 827 | + * {@link #addAsyncHttpRequestCustomizer(McpAsyncHttpClientRequestCustomizer)} |
| 828 | + * instead. |
| 829 | + * @param syncHttpRequestCustomizer the request customizer |
| 830 | + * @return this builder |
| 831 | + */ |
| 832 | + public Builder addHttpRequestCustomizer(McpSyncHttpClientRequestCustomizer syncHttpRequestCustomizer) { |
| 833 | + Assert.notNull(syncHttpRequestCustomizer, "syncHttpRequestCustomizer must not be null"); |
| 834 | + this.httpRequestCustomizers.add(McpAsyncHttpClientRequestCustomizer.fromSync(syncHttpRequestCustomizer)); |
| 835 | + return this; |
| 836 | + } |
| 837 | + |
| 838 | + /** |
| 839 | + * Adds a customizer for {@link HttpRequest.Builder}, to modify requests before |
| 840 | + * executing them. Customizers are applied in the order they are added, after |
| 841 | + * those already registered on this builder. |
| 842 | + * <p> |
| 843 | + * Do NOT use a blocking implementation in a non-blocking context. |
| 844 | + * @param asyncHttpRequestCustomizer the request customizer |
| 845 | + * @return this builder |
| 846 | + */ |
| 847 | + public Builder addAsyncHttpRequestCustomizer(McpAsyncHttpClientRequestCustomizer asyncHttpRequestCustomizer) { |
| 848 | + Assert.notNull(asyncHttpRequestCustomizer, "asyncHttpRequestCustomizer must not be null"); |
| 849 | + this.httpRequestCustomizers.add(asyncHttpRequestCustomizer); |
| 850 | + return this; |
| 851 | + } |
| 852 | + |
| 853 | + /** |
| 854 | + * Provides access to the mutable list of request customizers registered on this |
| 855 | + * builder, so they can be inspected, reordered, added or removed. Customizers are |
| 856 | + * applied in list order. Synchronous customizers registered through |
| 857 | + * {@link #httpRequestCustomizer(McpSyncHttpClientRequestCustomizer)} or |
| 858 | + * {@link #addHttpRequestCustomizer(McpSyncHttpClientRequestCustomizer)} appear in |
| 859 | + * the list wrapped as {@link McpAsyncHttpClientRequestCustomizer}. |
| 860 | + * @param customizersConsumer a consumer of the list of customizers |
| 861 | + * @return this builder |
| 862 | + */ |
| 863 | + public Builder asyncHttpRequestCustomizers( |
| 864 | + Consumer<List<McpAsyncHttpClientRequestCustomizer>> customizersConsumer) { |
| 865 | + Assert.notNull(customizersConsumer, "customizersConsumer must not be null"); |
| 866 | + customizersConsumer.accept(this.httpRequestCustomizers); |
809 | 867 | return this; |
810 | 868 | } |
811 | 869 |
|
@@ -910,7 +968,16 @@ public HttpClientStreamableHttpTransport build() { |
910 | 968 | HttpClient httpClient = this.clientBuilder.connectTimeout(this.connectTimeout).build(); |
911 | 969 | return new HttpClientStreamableHttpTransport(jsonMapper == null ? McpJsonDefaults.getMapper() : jsonMapper, |
912 | 970 | httpClient, requestBuilder, baseUri, endpoint, resumableStreams, openConnectionOnStartup, |
913 | | - httpRequestCustomizer, authorizationErrorHandler, supportedProtocolVersions, maxResponseSize); |
| 971 | + httpRequestCustomizer(), authorizationErrorHandler, supportedProtocolVersions, maxResponseSize); |
| 972 | + } |
| 973 | + |
| 974 | + private McpAsyncHttpClientRequestCustomizer httpRequestCustomizer() { |
| 975 | + Assert.noNullElements(this.httpRequestCustomizers, "httpRequestCustomizers must not contain null elements"); |
| 976 | + return switch (this.httpRequestCustomizers.size()) { |
| 977 | + case 0 -> McpAsyncHttpClientRequestCustomizer.NOOP; |
| 978 | + case 1 -> this.httpRequestCustomizers.get(0); |
| 979 | + default -> new DelegatingMcpAsyncHttpClientRequestCustomizer(List.copyOf(this.httpRequestCustomizers)); |
| 980 | + }; |
914 | 981 | } |
915 | 982 |
|
916 | 983 | } |
|
0 commit comments