44
55package io .modelcontextprotocol .client .transport ;
66
7+ import java .io .IOException ;
8+ import java .net .URI ;
9+ import java .net .http .HttpClient ;
10+ import java .net .http .HttpRequest ;
11+ import java .net .http .HttpResponse ;
12+ import java .net .http .HttpResponse .BodyHandler ;
13+ import java .time .Duration ;
14+ import java .util .Collections ;
15+ import java .util .Comparator ;
16+ import java .util .List ;
17+ import java .util .Optional ;
18+ import java .util .concurrent .CompletionException ;
19+ import java .util .concurrent .atomic .AtomicReference ;
20+ import java .util .function .Consumer ;
21+ import java .util .function .Function ;
22+
23+ import io .modelcontextprotocol .client .McpAsyncClient ;
24+ import io .modelcontextprotocol .client .transport .ResponseSubscribers .ResponseEvent ;
725import io .modelcontextprotocol .client .transport .ResponseSubscribers .ResponseEvent ;
826import io .modelcontextprotocol .client .transport .customizer .McpAsyncHttpClientRequestCustomizer ;
927import io .modelcontextprotocol .client .transport .customizer .McpSyncHttpClientRequestCustomizer ;
1028import io .modelcontextprotocol .common .McpTransportContext ;
29+ import io .modelcontextprotocol .json .McpJsonMapper ;
30+ import io .modelcontextprotocol .json .TypeRef ;
1131import io .modelcontextprotocol .spec .ClosedMcpTransportSession ;
1232import io .modelcontextprotocol .json .McpJsonMapper ;
1333import io .modelcontextprotocol .json .TypeRef ;
@@ -76,8 +96,6 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
7696
7797 private static final Logger logger = LoggerFactory .getLogger (HttpClientStreamableHttpTransport .class );
7898
79- private static final String MCP_PROTOCOL_VERSION = ProtocolVersions .MCP_2025_06_18 ;
80-
8199 private static final String DEFAULT_ENDPOINT = "/mcp" ;
82100
83101 /**
@@ -125,10 +143,14 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
125143
126144 private final AtomicReference <Consumer <Void >> connectionClosedHandler = new AtomicReference <>();
127145
146+ private final List <String > supportedProtocolVersions ;
147+
148+ private final String latestSupportedProtocolVersion ;
149+
128150 private HttpClientStreamableHttpTransport (McpJsonMapper jsonMapper , HttpClient httpClient ,
129151 HttpRequest .Builder requestBuilder , String baseUri , String endpoint , boolean resumableStreams ,
130152 boolean openConnectionOnStartup , McpAsyncHttpClientRequestCustomizer httpRequestCustomizer ,
131- Consumer <Void > connectionClosedHandler ) {
153+ Consumer <Void > connectionClosedHandler , List < String > supportedProtocolVersions ) {
132154 this .jsonMapper = jsonMapper ;
133155 this .httpClient = httpClient ;
134156 this .requestBuilder = requestBuilder ;
@@ -139,12 +161,16 @@ private HttpClientStreamableHttpTransport(McpJsonMapper jsonMapper, HttpClient h
139161 this .activeSession .set (createTransportSession ());
140162 this .httpRequestCustomizer = httpRequestCustomizer ;
141163 this .connectionClosedHandler .set (connectionClosedHandler );
164+ this .supportedProtocolVersions = Collections .unmodifiableList (supportedProtocolVersions );
165+ this .latestSupportedProtocolVersion = this .supportedProtocolVersions .stream ()
166+ .sorted (Comparator .reverseOrder ())
167+ .findFirst ()
168+ .get ();
142169 }
143170
144171 @ Override
145172 public List <String > protocolVersions () {
146- return List .of (ProtocolVersions .MCP_2024_11_05 , ProtocolVersions .MCP_2025_03_26 ,
147- ProtocolVersions .MCP_2025_06_18 );
173+ return supportedProtocolVersions ;
148174 }
149175
150176 public static Builder builder (String baseUri ) {
@@ -188,7 +214,9 @@ private Publisher<Void> createDelete(String sessionId) {
188214 .uri (uri )
189215 .header ("Cache-Control" , "no-cache" )
190216 .header (HttpHeaders .MCP_SESSION_ID , sessionId )
191- .header (HttpHeaders .PROTOCOL_VERSION , MCP_PROTOCOL_VERSION )
217+ .header (HttpHeaders .PROTOCOL_VERSION ,
218+ ctx .getOrDefault (McpAsyncClient .NEGOTIATED_PROTOCOL_VERSION ,
219+ this .latestSupportedProtocolVersion ))
192220 .DELETE ();
193221 var transportContext = ctx .getOrDefault (McpTransportContext .KEY , McpTransportContext .EMPTY );
194222 return Mono .from (this .httpRequestCustomizer .customize (builder , "DELETE" , uri , null , transportContext ));
@@ -273,7 +301,9 @@ private Mono<Disposable> reconnect(McpTransportStream<Disposable> stream) {
273301 var builder = requestBuilder .uri (uri )
274302 .header (HttpHeaders .ACCEPT , TEXT_EVENT_STREAM )
275303 .header ("Cache-Control" , "no-cache" )
276- .header (HttpHeaders .PROTOCOL_VERSION , MCP_PROTOCOL_VERSION )
304+ .header (HttpHeaders .PROTOCOL_VERSION ,
305+ connectionCtx .getOrDefault (McpAsyncClient .NEGOTIATED_PROTOCOL_VERSION ,
306+ this .latestSupportedProtocolVersion ))
277307 .GET ();
278308 var transportContext = connectionCtx .getOrDefault (McpTransportContext .KEY , McpTransportContext .EMPTY );
279309 return Mono .from (this .httpRequestCustomizer .customize (builder , "GET" , uri , null , transportContext ));
@@ -449,7 +479,9 @@ public Mono<Void> sendMessage(McpSchema.JSONRPCMessage sentMessage) {
449479 .header (HttpHeaders .ACCEPT , APPLICATION_JSON + ", " + TEXT_EVENT_STREAM )
450480 .header (HttpHeaders .CONTENT_TYPE , APPLICATION_JSON )
451481 .header (HttpHeaders .CACHE_CONTROL , "no-cache" )
452- .header (HttpHeaders .PROTOCOL_VERSION , MCP_PROTOCOL_VERSION )
482+ .header (HttpHeaders .PROTOCOL_VERSION ,
483+ ctx .getOrDefault (McpAsyncClient .NEGOTIATED_PROTOCOL_VERSION ,
484+ this .latestSupportedProtocolVersion ))
453485 .POST (HttpRequest .BodyPublishers .ofString (jsonBody ));
454486 var transportContext = ctx .getOrDefault (McpTransportContext .KEY , McpTransportContext .EMPTY );
455487 return Mono
@@ -643,6 +675,9 @@ public static class Builder {
643675
644676 private Consumer <Void > connectionClosedHandler = null ;
645677
678+ private List <String > supportedProtocolVersions = List .of (ProtocolVersions .MCP_2024_11_05 ,
679+ ProtocolVersions .MCP_2025_03_26 , ProtocolVersions .MCP_2025_06_18 );
680+
646681 /**
647682 * Creates a new builder with the specified base URI.
648683 * @param baseUri the base URI of the MCP server
@@ -791,6 +826,30 @@ public Builder connectTimeout(Duration connectTimeout) {
791826 return this ;
792827 }
793828
829+ /**
830+ * Sets the list of supported protocol versions used in version negotiation. By
831+ * default, the client will send the latest of those versions in the
832+ * {@code MCP-Protocol-Version} header.
833+ * <p>
834+ * Setting this value only updates the values used in version negotiation, and
835+ * does NOT impact the actual capabilities of the transport. It should only be
836+ * used for compatibility with servers having strict requirements around the
837+ * {@code MCP-Protocol-Version} header.
838+ * @param supportedProtocolVersions protocol versions supported by this transport
839+ * @return this builder
840+ * @see <a href=
841+ * "https://modelcontextprotocol.io/specification/2024-11-05/basic/lifecycle#version-negotiation">version
842+ * negotiation specification</a>
843+ * @see <a href=
844+ * "https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#protocol-version-header">Protocol
845+ * Version Header</a>
846+ */
847+ public Builder supportedProtocolVersions (List <String > supportedProtocolVersions ) {
848+ Assert .notEmpty (supportedProtocolVersions , "supportedProtocolVersions must not be empty" );
849+ this .supportedProtocolVersions = Collections .unmodifiableList (supportedProtocolVersions );
850+ return this ;
851+ }
852+
794853 /**
795854 * Set the connection closed handler.
796855 * @param connectionClosedHandler the connection closed handler
@@ -811,7 +870,7 @@ public HttpClientStreamableHttpTransport build() {
811870 HttpClient httpClient = this .clientBuilder .connectTimeout (this .connectTimeout ).build ();
812871 return new HttpClientStreamableHttpTransport (jsonMapper == null ? McpJsonMapper .getDefault () : jsonMapper ,
813872 httpClient , requestBuilder , baseUri , endpoint , resumableStreams , openConnectionOnStartup ,
814- httpRequestCustomizer , connectionClosedHandler );
873+ httpRequestCustomizer , connectionClosedHandler , supportedProtocolVersions );
815874 }
816875
817876 }
0 commit comments