1111import java .net .http .HttpResponse ;
1212import java .net .http .HttpResponse .BodyHandler ;
1313import java .time .Duration ;
14+ import java .util .Collections ;
15+ import java .util .Comparator ;
1416import java .util .List ;
1517import java .util .Optional ;
1618import java .util .concurrent .CompletionException ;
1719import java .util .concurrent .atomic .AtomicReference ;
1820import java .util .function .Consumer ;
1921import java .util .function .Function ;
2022
21- import org .reactivestreams .Publisher ;
22- import org .slf4j .Logger ;
23- import org .slf4j .LoggerFactory ;
24-
25- import io .modelcontextprotocol .json .TypeRef ;
26- import io .modelcontextprotocol .json .McpJsonMapper ;
27-
23+ import io .modelcontextprotocol .client .transport .ResponseSubscribers .ResponseEvent ;
2824import io .modelcontextprotocol .client .transport .customizer .McpAsyncHttpClientRequestCustomizer ;
2925import io .modelcontextprotocol .client .transport .customizer .McpSyncHttpClientRequestCustomizer ;
30- import io .modelcontextprotocol .client .transport .ResponseSubscribers .ResponseEvent ;
3126import io .modelcontextprotocol .common .McpTransportContext ;
27+ import io .modelcontextprotocol .json .McpJsonMapper ;
28+ import io .modelcontextprotocol .json .TypeRef ;
3229import io .modelcontextprotocol .spec .ClosedMcpTransportSession ;
3330import io .modelcontextprotocol .spec .DefaultMcpTransportSession ;
3431import io .modelcontextprotocol .spec .DefaultMcpTransportStream ;
4239import io .modelcontextprotocol .spec .ProtocolVersions ;
4340import io .modelcontextprotocol .util .Assert ;
4441import io .modelcontextprotocol .util .Utils ;
42+ import org .reactivestreams .Publisher ;
43+ import org .slf4j .Logger ;
44+ import org .slf4j .LoggerFactory ;
4545import reactor .core .Disposable ;
4646import reactor .core .publisher .Flux ;
4747import reactor .core .publisher .FluxSink ;
@@ -78,8 +78,6 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
7878
7979 private static final Logger logger = LoggerFactory .getLogger (HttpClientStreamableHttpTransport .class );
8080
81- private static final String MCP_PROTOCOL_VERSION = ProtocolVersions .MCP_2025_06_18 ;
82-
8381 private static final String DEFAULT_ENDPOINT = "/mcp" ;
8482
8583 /**
@@ -125,9 +123,14 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
125123
126124 private final AtomicReference <Consumer <Throwable >> exceptionHandler = new AtomicReference <>();
127125
126+ private final List <String > supportedProtocolVersions ;
127+
128+ private final String latestSupportedProtocolVersion ;
129+
128130 private HttpClientStreamableHttpTransport (McpJsonMapper jsonMapper , HttpClient httpClient ,
129131 HttpRequest .Builder requestBuilder , String baseUri , String endpoint , boolean resumableStreams ,
130- boolean openConnectionOnStartup , McpAsyncHttpClientRequestCustomizer httpRequestCustomizer ) {
132+ boolean openConnectionOnStartup , McpAsyncHttpClientRequestCustomizer httpRequestCustomizer ,
133+ List <String > supportedProtocolVersions ) {
131134 this .jsonMapper = jsonMapper ;
132135 this .httpClient = httpClient ;
133136 this .requestBuilder = requestBuilder ;
@@ -137,12 +140,16 @@ private HttpClientStreamableHttpTransport(McpJsonMapper jsonMapper, HttpClient h
137140 this .openConnectionOnStartup = openConnectionOnStartup ;
138141 this .activeSession .set (createTransportSession ());
139142 this .httpRequestCustomizer = httpRequestCustomizer ;
143+ this .supportedProtocolVersions = Collections .unmodifiableList (supportedProtocolVersions );
144+ this .latestSupportedProtocolVersion = this .supportedProtocolVersions .stream ()
145+ .sorted (Comparator .reverseOrder ())
146+ .findFirst ()
147+ .get ();
140148 }
141149
142150 @ Override
143151 public List <String > protocolVersions () {
144- return List .of (ProtocolVersions .MCP_2024_11_05 , ProtocolVersions .MCP_2025_03_26 ,
145- ProtocolVersions .MCP_2025_06_18 );
152+ return supportedProtocolVersions ;
146153 }
147154
148155 public static Builder builder (String baseUri ) {
@@ -186,7 +193,7 @@ private Publisher<Void> createDelete(String sessionId) {
186193 .uri (uri )
187194 .header ("Cache-Control" , "no-cache" )
188195 .header (HttpHeaders .MCP_SESSION_ID , sessionId )
189- .header (HttpHeaders .PROTOCOL_VERSION , MCP_PROTOCOL_VERSION )
196+ .header (HttpHeaders .PROTOCOL_VERSION , this . latestSupportedProtocolVersion )
190197 .DELETE ();
191198 var transportContext = ctx .getOrDefault (McpTransportContext .KEY , McpTransportContext .EMPTY );
192199 return Mono .from (this .httpRequestCustomizer .customize (builder , "DELETE" , uri , null , transportContext ));
@@ -257,7 +264,7 @@ private Mono<Disposable> reconnect(McpTransportStream<Disposable> stream) {
257264 var builder = requestBuilder .uri (uri )
258265 .header (HttpHeaders .ACCEPT , TEXT_EVENT_STREAM )
259266 .header ("Cache-Control" , "no-cache" )
260- .header (HttpHeaders .PROTOCOL_VERSION , MCP_PROTOCOL_VERSION )
267+ .header (HttpHeaders .PROTOCOL_VERSION , this . latestSupportedProtocolVersion )
261268 .GET ();
262269 var transportContext = connectionCtx .getOrDefault (McpTransportContext .KEY , McpTransportContext .EMPTY );
263270 return Mono .from (this .httpRequestCustomizer .customize (builder , "GET" , uri , null , transportContext ));
@@ -432,7 +439,7 @@ public Mono<Void> sendMessage(McpSchema.JSONRPCMessage sentMessage) {
432439 .header (HttpHeaders .ACCEPT , APPLICATION_JSON + ", " + TEXT_EVENT_STREAM )
433440 .header (HttpHeaders .CONTENT_TYPE , APPLICATION_JSON )
434441 .header (HttpHeaders .CACHE_CONTROL , "no-cache" )
435- .header (HttpHeaders .PROTOCOL_VERSION , MCP_PROTOCOL_VERSION )
442+ .header (HttpHeaders .PROTOCOL_VERSION , this . latestSupportedProtocolVersion )
436443 .POST (HttpRequest .BodyPublishers .ofString (jsonBody ));
437444 var transportContext = ctx .getOrDefault (McpTransportContext .KEY , McpTransportContext .EMPTY );
438445 return Mono
@@ -624,6 +631,9 @@ public static class Builder {
624631
625632 private Duration connectTimeout = Duration .ofSeconds (10 );
626633
634+ private List <String > supportedProtocolVersions = List .of (ProtocolVersions .MCP_2024_11_05 ,
635+ ProtocolVersions .MCP_2025_03_26 , ProtocolVersions .MCP_2025_06_18 );
636+
627637 /**
628638 * Creates a new builder with the specified base URI.
629639 * @param baseUri the base URI of the MCP server
@@ -772,6 +782,30 @@ public Builder connectTimeout(Duration connectTimeout) {
772782 return this ;
773783 }
774784
785+ /**
786+ * Sets the list of supported protocol versions used in version negotiation. By
787+ * default, the client will send the latest of those versions in the
788+ * {@code MCP-Protocol-Version} header.
789+ * <p>
790+ * Setting this value only updates the values used in version negotiation, and
791+ * does NOT impact the actual capabilities of the transport. It should only be
792+ * used for compatibility with servers having strict requirements around the
793+ * {@code MCP-Protocol-Version} header.
794+ * @param supportedProtocolVersions protocol versions supported by this transport
795+ * @return this builder
796+ * @see <a href=
797+ * "https://modelcontextprotocol.io/specification/2024-11-05/basic/lifecycle#version-negotiation">version
798+ * negotiation specification</a>
799+ * @see <a href=
800+ * "https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#protocol-version-header">Protocol
801+ * Version Header</a>
802+ */
803+ public Builder supportedProtocolVersions (List <String > supportedProtocolVersions ) {
804+ Assert .notEmpty (supportedProtocolVersions , "supportedProtocolVersions must not be empty" );
805+ this .supportedProtocolVersions = Collections .unmodifiableList (supportedProtocolVersions );
806+ return this ;
807+ }
808+
775809 /**
776810 * Construct a fresh instance of {@link HttpClientStreamableHttpTransport} using
777811 * the current builder configuration.
@@ -781,7 +815,7 @@ public HttpClientStreamableHttpTransport build() {
781815 HttpClient httpClient = this .clientBuilder .connectTimeout (this .connectTimeout ).build ();
782816 return new HttpClientStreamableHttpTransport (jsonMapper == null ? McpJsonMapper .getDefault () : jsonMapper ,
783817 httpClient , requestBuilder , baseUri , endpoint , resumableStreams , openConnectionOnStartup ,
784- httpRequestCustomizer );
818+ httpRequestCustomizer , supportedProtocolVersions );
785819 }
786820
787821 }
0 commit comments