Skip to content

Commit c477064

Browse files
committed
refactor: standardize protocol version handling and HTTP headers
- Add protocolVersion() method to transport and transport provider interfaces and implementations - Replace hardcoded HTTP header strings with HttpHeaders constants - Update protocol versions to be transport-specific rather than global - Deprecate McpSchema.LATEST_PROTOCOL_VERSION in favor of transport-specific versions - Standardize header names: MCP-Protocol-Version, mcp-session-id, last-event-id - Update clients and servers to use transport.protocolVersion() for initialization - Refactor tests to use transport-specific protocol versions This change improves maintainability by centralizing header name constants and allows different transports to support different protocol versions independently. Signed-off-by: Christian Tzolov <[email protected]>
1 parent e851582 commit c477064

27 files changed

+144
-45
lines changed

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

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import io.modelcontextprotocol.spec.DefaultMcpTransportSession;
2525
import io.modelcontextprotocol.spec.DefaultMcpTransportStream;
26+
import io.modelcontextprotocol.spec.HttpHeaders;
2627
import io.modelcontextprotocol.spec.McpClientTransport;
2728
import io.modelcontextprotocol.spec.McpError;
2829
import io.modelcontextprotocol.spec.McpSchema;
@@ -66,9 +67,7 @@ public class WebClientStreamableHttpTransport implements McpClientTransport {
6667

6768
private static final Logger logger = LoggerFactory.getLogger(WebClientStreamableHttpTransport.class);
6869

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";
70+
private static final String MCP_PROTOCOL_VERSION = "2025-03-26";
7271

7372
private static final String DEFAULT_ENDPOINT = "/mcp";
7473

@@ -107,6 +106,11 @@ private WebClientStreamableHttpTransport(ObjectMapper objectMapper, WebClient.Bu
107106
this.activeSession.set(createTransportSession());
108107
}
109108

109+
@Override
110+
public String protocolVersion() {
111+
return MCP_PROTOCOL_VERSION;
112+
}
113+
110114
/**
111115
* Create a stateful builder for creating {@link WebClientStreamableHttpTransport}
112116
* instances.
@@ -134,10 +138,10 @@ private DefaultMcpTransportSession createTransportSession() {
134138
Function<String, Publisher<Void>> onClose = sessionId -> sessionId == null ? Mono.empty()
135139
: webClient.delete()
136140
.uri(this.endpoint)
137-
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
141+
.header(HttpHeaders.PROTOCOL_VERSION, MCP_PROTOCOL_VERSION)
138142
.headers(httpHeaders -> {
139-
httpHeaders.add("mcp-session-id", sessionId);
140-
httpHeaders.add(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION);
143+
httpHeaders.add(HttpHeaders.MCP_SESSION_ID, sessionId);
144+
httpHeaders.add(HttpHeaders.PROTOCOL_VERSION, MCP_PROTOCOL_VERSION);
141145
})
142146
.retrieve()
143147
.toBodilessEntity()
@@ -198,11 +202,11 @@ private Mono<Disposable> reconnect(McpTransportStream<Disposable> stream) {
198202
Disposable connection = webClient.get()
199203
.uri(this.endpoint)
200204
.accept(MediaType.TEXT_EVENT_STREAM)
201-
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
205+
.header(HttpHeaders.PROTOCOL_VERSION, MCP_PROTOCOL_VERSION)
202206
.headers(httpHeaders -> {
203-
transportSession.sessionId().ifPresent(id -> httpHeaders.add("mcp-session-id", id));
207+
transportSession.sessionId().ifPresent(id -> httpHeaders.add(HttpHeaders.MCP_SESSION_ID, id));
204208
if (stream != null) {
205-
stream.lastId().ifPresent(id -> httpHeaders.add("last-event-id", id));
209+
stream.lastId().ifPresent(id -> httpHeaders.add(HttpHeaders.LAST_EVENT_ID, id));
206210
}
207211
})
208212
.exchangeToFlux(response -> {
@@ -259,14 +263,14 @@ public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message) {
259263
Disposable connection = webClient.post()
260264
.uri(this.endpoint)
261265
.accept(MediaType.APPLICATION_JSON, MediaType.TEXT_EVENT_STREAM)
262-
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
266+
.header(HttpHeaders.PROTOCOL_VERSION, MCP_PROTOCOL_VERSION)
263267
.headers(httpHeaders -> {
264-
transportSession.sessionId().ifPresent(id -> httpHeaders.add("mcp-session-id", id));
268+
transportSession.sessionId().ifPresent(id -> httpHeaders.add(HttpHeaders.MCP_SESSION_ID, id));
265269
})
266270
.bodyValue(message)
267271
.exchangeToFlux(response -> {
268272
if (transportSession
269-
.markInitialized(response.headers().asHttpHeaders().getFirst("mcp-session-id"))) {
273+
.markInitialized(response.headers().asHttpHeaders().getFirst(HttpHeaders.MCP_SESSION_ID))) {
270274
// Once we have a session, we try to open an async stream for
271275
// the server to send notifications and requests out-of-band.
272276
reconnect(null).contextWrite(sink.contextView()).subscribe();

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

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

1010
import com.fasterxml.jackson.core.type.TypeReference;
1111
import com.fasterxml.jackson.databind.ObjectMapper;
12+
13+
import io.modelcontextprotocol.spec.HttpHeaders;
1214
import io.modelcontextprotocol.spec.McpClientTransport;
1315
import io.modelcontextprotocol.spec.McpError;
1416
import io.modelcontextprotocol.spec.McpSchema;
@@ -64,8 +66,6 @@ public class WebFluxSseClientTransport implements McpClientTransport {
6466

6567
private static final String MCP_PROTOCOL_VERSION = "2024-11-05";
6668

67-
private static final String MCP_PROTOCOL_VERSION_HEADER_NAME = "MCP-Protocol-Version";
68-
6969
/**
7070
* Event type for JSON-RPC messages received through the SSE connection. The server
7171
* sends messages with this event type to transmit JSON-RPC protocol data.
@@ -170,6 +170,11 @@ public WebFluxSseClientTransport(WebClient.Builder webClientBuilder, ObjectMappe
170170
this.sseEndpoint = sseEndpoint;
171171
}
172172

173+
@Override
174+
public String protocolVersion() {
175+
return MCP_PROTOCOL_VERSION;
176+
}
177+
173178
/**
174179
* Establishes a connection to the MCP server using Server-Sent Events (SSE). This
175180
* method initiates the SSE connection and sets up the message processing pipeline.
@@ -254,7 +259,7 @@ public Mono<Void> sendMessage(JSONRPCMessage message) {
254259
return webClient.post()
255260
.uri(messageEndpointUri)
256261
.contentType(MediaType.APPLICATION_JSON)
257-
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
262+
.header(HttpHeaders.PROTOCOL_VERSION, MCP_PROTOCOL_VERSION)
258263
.bodyValue(jsonText)
259264
.retrieve()
260265
.toBodilessEntity()
@@ -287,7 +292,7 @@ protected Flux<ServerSentEvent<String>> eventStream() {// @formatter:off
287292
.get()
288293
.uri(this.sseEndpoint)
289294
.accept(MediaType.TEXT_EVENT_STREAM)
290-
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
295+
.header(HttpHeaders.PROTOCOL_VERSION, MCP_PROTOCOL_VERSION)
291296
.retrieve()
292297
.bodyToFlux(SSE_TYPE)
293298
.retryWhen(Retry.from(retrySignal -> retrySignal.handle(inboundRetryHandler)));

mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxSseServerTransportProvider.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
7979
*/
8080
public static final String ENDPOINT_EVENT_TYPE = "endpoint";
8181

82+
private static final String MCP_PROTOCOL_VERSION = "2025-06-18";
83+
8284
/**
8385
* Default SSE endpoint path as specified by the MCP transport specification.
8486
*/
@@ -212,6 +214,11 @@ public WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String baseU
212214
}
213215
}
214216

217+
@Override
218+
public String protocolVersion() {
219+
return "2024-11-05";
220+
}
221+
215222
@Override
216223
public void setSessionFactory(McpServerSession.Factory sessionFactory) {
217224
this.sessionFactory = sessionFactory;

mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxStatelessServerTransport.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
import java.io.IOException;
2323
import java.util.List;
24-
import java.util.function.Function;
2524

2625
/**
2726
* Implementation of a WebFlux based {@link McpStatelessServerTransport}.

mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxStreamableServerTransportProvider.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ private WebFluxStreamableServerTransportProvider(ObjectMapper objectMapper, Stri
9595

9696
}
9797

98+
@Override
99+
public String protocolVersion() {
100+
return "2025-03-26";
101+
}
102+
98103
@Override
99104
public void setSessionFactory(McpStreamableServerSession.Factory sessionFactory) {
100105
this.sessionFactory = sessionFactory;

mcp-spring/mcp-spring-webmvc/src/main/java/io/modelcontextprotocol/server/transport/WebMvcSseServerTransportProvider.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,11 @@ public WebMvcSseServerTransportProvider(ObjectMapper objectMapper, String baseUr
209209
}
210210
}
211211

212+
@Override
213+
public String protocolVersion() {
214+
return "2024-11-05";
215+
}
216+
212217
@Override
213218
public void setSessionFactory(McpServerSession.Factory sessionFactory) {
214219
this.sessionFactory = sessionFactory;

mcp-spring/mcp-spring-webmvc/src/main/java/io/modelcontextprotocol/server/transport/WebMvcStreamableServerTransportProvider.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,11 @@ private WebMvcStreamableServerTransportProvider(ObjectMapper objectMapper, Strin
147147
}
148148
}
149149

150+
@Override
151+
public String protocolVersion() {
152+
return "2025-03-26";
153+
}
154+
150155
@Override
151156
public void setSessionFactory(McpStreamableServerSession.Factory sessionFactory) {
152157
this.sessionFactory = sessionFactory;

mcp-spring/mcp-spring-webmvc/src/test/java/io/modelcontextprotocol/server/WebMvcSseCustomContextPathTests.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,15 @@ static class TestConfig {
9191
@Bean
9292
public WebMvcSseServerTransportProvider webMvcSseServerTransportProvider() {
9393

94-
return new WebMvcSseServerTransportProvider(new ObjectMapper(), CUSTOM_CONTEXT_PATH, MESSAGE_ENDPOINT,
95-
WebMvcSseServerTransportProvider.DEFAULT_SSE_ENDPOINT);
94+
return WebMvcSseServerTransportProvider.builder()
95+
.objectMapper(new ObjectMapper())
96+
.baseUrl(CUSTOM_CONTEXT_PATH)
97+
.messageEndpoint(MESSAGE_ENDPOINT)
98+
.sseEndpoint(WebMvcSseServerTransportProvider.DEFAULT_SSE_ENDPOINT)
99+
.build();
100+
// return new WebMvcSseServerTransportProvider(new ObjectMapper(),
101+
// CUSTOM_CONTEXT_PATH, MESSAGE_ENDPOINT,
102+
// WebMvcSseServerTransportProvider.DEFAULT_SSE_ENDPOINT);
96103
}
97104

98105
@Bean

mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,8 @@ public class McpAsyncClient {
272272
asyncProgressNotificationHandler(progressConsumersFinal));
273273

274274
this.initializer = new LifecycleInitializer(clientCapabilities, clientInfo,
275-
List.of(McpSchema.LATEST_PROTOCOL_VERSION), initializationTimeout,
276-
ctx -> new McpClientSession(requestTimeout, transport, requestHandlers, notificationHandlers,
277-
con -> con.contextWrite(ctx)));
275+
List.of(transport.protocolVersion()), initializationTimeout, ctx -> new McpClientSession(requestTimeout,
276+
transport, requestHandlers, notificationHandlers, con -> con.contextWrite(ctx)));
278277
this.transport.setExceptionHandler(this.initializer::handleException);
279278
}
280279

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@ public HttpClientSseClientTransport(HttpClient.Builder clientBuilder, HttpReques
215215
this.httpRequestCustomizer = httpRequestCustomizer;
216216
}
217217

218+
@Override
219+
public String protocolVersion() {
220+
return MCP_PROTOCOL_VERSION;
221+
}
222+
218223
/**
219224
* Creates a new builder for {@link HttpClientSseClientTransport}.
220225
* @param baseUri the base URI of the MCP server

0 commit comments

Comments
 (0)