Skip to content

Commit e851582

Browse files
committed
feat: implement MCP protocol version header support
Add MCP-Protocol-Version header to all HTTP requests as required by MCP specification 2025-06-18. This enables proper server-side version negotiation and backwards compatibility handling. - Add protocol version constants (2025-06-18 for streamable HTTP, 2024-11-05 for SSE) - Include MCP-Protocol-Version header in all GET/POST/DELETE requests - Update WebClientStreamableHttpTransport, WebFluxSseClientTransport, HttpClientSseClientTransport, and HttpClientStreamableHttpTransport Complies with MCP specification requirement that HTTP clients MUST include protocol version header on all requests to MCP servers. Related to #398 , #363 , #250 Signed-off-by: Christian Tzolov <[email protected]>
1 parent 67de84b commit e851582

File tree

4 files changed

+43
-7
lines changed

4 files changed

+43
-7
lines changed

mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/client/transport/WebClientStreamableHttpTransport.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ public class WebClientStreamableHttpTransport implements McpClientTransport {
6666

6767
private static final Logger logger = LoggerFactory.getLogger(WebClientStreamableHttpTransport.class);
6868

69+
private static final String MCP_PROTOCOL_VERSION = "2025-06-18";
70+
71+
private static final String MCP_PROTOCOL_VERSION_HEADER_NAME = "MCP-Protocol-Version";
72+
6973
private static final String DEFAULT_ENDPOINT = "/mcp";
7074

7175
/**
@@ -128,12 +132,20 @@ public Mono<Void> connect(Function<Mono<McpSchema.JSONRPCMessage>, Mono<McpSchem
128132

129133
private DefaultMcpTransportSession createTransportSession() {
130134
Function<String, Publisher<Void>> onClose = sessionId -> sessionId == null ? Mono.empty()
131-
: webClient.delete().uri(this.endpoint).headers(httpHeaders -> {
132-
httpHeaders.add("mcp-session-id", sessionId);
133-
}).retrieve().toBodilessEntity().onErrorComplete(e -> {
134-
logger.warn("Got error when closing transport", e);
135-
return true;
136-
}).then();
135+
: webClient.delete()
136+
.uri(this.endpoint)
137+
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
138+
.headers(httpHeaders -> {
139+
httpHeaders.add("mcp-session-id", sessionId);
140+
httpHeaders.add(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION);
141+
})
142+
.retrieve()
143+
.toBodilessEntity()
144+
.onErrorComplete(e -> {
145+
logger.warn("Got error when closing transport", e);
146+
return true;
147+
})
148+
.then();
137149
return new DefaultMcpTransportSession(onClose);
138150
}
139151

@@ -186,6 +198,7 @@ private Mono<Disposable> reconnect(McpTransportStream<Disposable> stream) {
186198
Disposable connection = webClient.get()
187199
.uri(this.endpoint)
188200
.accept(MediaType.TEXT_EVENT_STREAM)
201+
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
189202
.headers(httpHeaders -> {
190203
transportSession.sessionId().ifPresent(id -> httpHeaders.add("mcp-session-id", id));
191204
if (stream != null) {
@@ -246,6 +259,7 @@ public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message) {
246259
Disposable connection = webClient.post()
247260
.uri(this.endpoint)
248261
.accept(MediaType.APPLICATION_JSON, MediaType.TEXT_EVENT_STREAM)
262+
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
249263
.headers(httpHeaders -> {
250264
transportSession.sessionId().ifPresent(id -> httpHeaders.add("mcp-session-id", id));
251265
})

mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/client/transport/WebFluxSseClientTransport.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ public class WebFluxSseClientTransport implements McpClientTransport {
6262

6363
private static final Logger logger = LoggerFactory.getLogger(WebFluxSseClientTransport.class);
6464

65+
private static final String MCP_PROTOCOL_VERSION = "2024-11-05";
66+
67+
private static final String MCP_PROTOCOL_VERSION_HEADER_NAME = "MCP-Protocol-Version";
68+
6569
/**
6670
* Event type for JSON-RPC messages received through the SSE connection. The server
6771
* sends messages with this event type to transmit JSON-RPC protocol data.
@@ -250,6 +254,7 @@ public Mono<Void> sendMessage(JSONRPCMessage message) {
250254
return webClient.post()
251255
.uri(messageEndpointUri)
252256
.contentType(MediaType.APPLICATION_JSON)
257+
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
253258
.bodyValue(jsonText)
254259
.retrieve()
255260
.toBodilessEntity()
@@ -282,6 +287,7 @@ protected Flux<ServerSentEvent<String>> eventStream() {// @formatter:off
282287
.get()
283288
.uri(this.sseEndpoint)
284289
.accept(MediaType.TEXT_EVENT_STREAM)
290+
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
285291
.retrieve()
286292
.bodyToFlux(SSE_TYPE)
287293
.retryWhen(Retry.from(retrySignal -> retrySignal.handle(inboundRetryHandler)));

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@
6161
*/
6262
public class HttpClientSseClientTransport implements McpClientTransport {
6363

64+
private static final String MCP_PROTOCOL_VERSION = "2024-11-05";
65+
66+
private static final String MCP_PROTOCOL_VERSION_HEADER_NAME = "MCP-Protocol-Version";
67+
6468
private static final Logger logger = LoggerFactory.getLogger(HttpClientSseClientTransport.class);
6569

6670
/** SSE event type for JSON-RPC messages */
@@ -391,6 +395,7 @@ public Mono<Void> connect(Function<Mono<JSONRPCMessage>, Mono<JSONRPCMessage>> h
391395
.uri(uri)
392396
.header("Accept", "text/event-stream")
393397
.header("Cache-Control", "no-cache")
398+
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
394399
.GET();
395400
return Mono.from(this.httpRequestCustomizer.customize(builder, "GET", uri, null));
396401
}).flatMap(requestBuilder -> Mono.create(sink -> {
@@ -516,7 +521,10 @@ private Mono<String> serializeMessage(final JSONRPCMessage message) {
516521
private Mono<HttpResponse<String>> sendHttpPost(final String endpoint, final String body) {
517522
final URI requestUri = Utils.resolveUri(baseUri, endpoint);
518523
return Mono.defer(() -> {
519-
var builder = this.requestBuilder.copy().uri(requestUri).POST(HttpRequest.BodyPublishers.ofString(body));
524+
var builder = this.requestBuilder.copy()
525+
.uri(requestUri)
526+
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
527+
.POST(HttpRequest.BodyPublishers.ofString(body));
520528
return Mono.from(this.httpRequestCustomizer.customize(builder, "POST", requestUri, body));
521529
}).flatMap(customizedBuilder -> {
522530
var request = customizedBuilder.build();

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
7272

7373
private static final Logger logger = LoggerFactory.getLogger(HttpClientStreamableHttpTransport.class);
7474

75+
private static final String MCP_PROTOCOL_VERSION = "2025-06-18";
76+
77+
private static final String MCP_PROTOCOL_VERSION_HEADER_NAME = "MCP-Protocol-Version";
78+
7579
private static final String DEFAULT_ENDPOINT = "/mcp";
7680

7781
/**
@@ -157,12 +161,14 @@ private DefaultMcpTransportSession createTransportSession() {
157161
}
158162

159163
private Publisher<Void> createDelete(String sessionId) {
164+
160165
var uri = Utils.resolveUri(this.baseUri, this.endpoint);
161166
return Mono.defer(() -> {
162167
var builder = this.requestBuilder.copy()
163168
.uri(uri)
164169
.header("Cache-Control", "no-cache")
165170
.header("mcp-session-id", sessionId)
171+
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
166172
.DELETE();
167173
return Mono.from(this.httpRequestCustomizer.customize(builder, "DELETE", uri, null));
168174
}).flatMap(requestBuilder -> {
@@ -231,6 +237,7 @@ private Mono<Disposable> reconnect(McpTransportStream<Disposable> stream) {
231237
var builder = requestBuilder.uri(uri)
232238
.header("Accept", TEXT_EVENT_STREAM)
233239
.header("Cache-Control", "no-cache")
240+
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
234241
.GET();
235242
return Mono.from(this.httpRequestCustomizer.customize(builder, "GET", uri, null));
236243
})
@@ -384,6 +391,7 @@ public Mono<Void> sendMessage(McpSchema.JSONRPCMessage sentMessage) {
384391
.header("Accept", APPLICATION_JSON + ", " + TEXT_EVENT_STREAM)
385392
.header("Content-Type", APPLICATION_JSON)
386393
.header("Cache-Control", "no-cache")
394+
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
387395
.POST(HttpRequest.BodyPublishers.ofString(jsonBody));
388396
return Mono.from(this.httpRequestCustomizer.customize(builder, "GET", uri, jsonBody));
389397
}).flatMapMany(requestBuilder -> Flux.<ResponseEvent>create(responseEventSink -> {

0 commit comments

Comments
 (0)