Skip to content

Commit 3305e7d

Browse files
committed
Make McpService take a protocol version in every request. Default to 2025-03-26 protocol version
1 parent 37b9322 commit 3305e7d

File tree

3 files changed

+42
-13
lines changed

3 files changed

+42
-13
lines changed

mcp/mcp-server/src/main/java/software/amazon/smithy/java/mcp/server/McpServer.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public final class McpServer implements Server {
3737
private final InputStream is;
3838
private final OutputStream os;
3939
private final CountDownLatch done = new CountDownLatch(1);
40+
private volatile ProtocolVersion protocolVersion;
4041

4142
McpServer(McpServerBuilder builder) {
4243
this.mcpService = builder.mcpService;
@@ -69,7 +70,18 @@ private void listen() {
6970
}
7071

7172
private void handleRequest(JsonRpcRequest req) {
72-
var response = mcpService.handleRequest(req, this::writeResponse);
73+
// For StdIO transport, protocol version is only sent in initialize request
74+
// Extract and store it for future requests
75+
if ("initialize".equals(req.getMethod())) {
76+
var maybeVersion = req.getParams().getMember("protocolVersion");
77+
if (maybeVersion == null) {
78+
this.protocolVersion = ProtocolVersion.defaultVersion();
79+
} else {
80+
this.protocolVersion = ProtocolVersion.version(maybeVersion.asString());
81+
}
82+
}
83+
84+
var response = mcpService.handleRequest(req, this::writeResponse, protocolVersion);
7385
if (response != null) {
7486
writeResponse(response);
7587
}

mcp/mcp-server/src/main/java/software/amazon/smithy/java/mcp/server/McpService.java

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ public final class McpService {
7878
private final Map<String, Service> services;
7979
private final AtomicReference<JsonRpcRequest> initializeRequest = new AtomicReference<>();
8080
private final ToolFilter toolFilter;
81-
private volatile ProtocolVersion protocolVersion;
8281

8382
McpService(Map<String, Service> services, List<McpServerProxy> proxyList, String name, ToolFilter toolFilter) {
8483
this.services = services;
@@ -97,17 +96,22 @@ public final class McpService {
9796
*
9897
* @param req The JSON-RPC request to handle
9998
* @param asyncResponseCallback Callback for async responses (used for proxy calls)
99+
* @param protocolVersion The protocol version for this request (may be null)
100100
* @return The response for synchronous operations, or null for async operations
101101
*/
102-
public JsonRpcResponse handleRequest(JsonRpcRequest req, Consumer<JsonRpcResponse> asyncResponseCallback) {
102+
public JsonRpcResponse handleRequest(
103+
JsonRpcRequest req,
104+
Consumer<JsonRpcResponse> asyncResponseCallback,
105+
ProtocolVersion protocolVersion
106+
) {
103107
try {
104108
validate(req);
105109
return switch (req.getMethod()) {
106110
case "initialize" -> handleInitialize(req);
107111
case "prompts/list" -> handlePromptsList(req);
108112
case "prompts/get" -> handlePromptsGet(req);
109-
case "tools/list" -> handleToolsList(req);
110-
case "tools/call" -> handleToolsCall(req, asyncResponseCallback);
113+
case "tools/list" -> handleToolsList(req, protocolVersion);
114+
case "tools/call" -> handleToolsCall(req, asyncResponseCallback, protocolVersion);
111115
default -> null; // Notifications or unknown methods
112116
};
113117
} catch (Exception e) {
@@ -120,7 +124,7 @@ private JsonRpcResponse handleInitialize(JsonRpcRequest req) {
120124
var maybeVersion = req.getParams().getMember("protocolVersion");
121125
String pv = null;
122126
if (maybeVersion != null) {
123-
protocolVersion = ProtocolVersion.version(maybeVersion.asString());
127+
var protocolVersion = ProtocolVersion.version(maybeVersion.asString());
124128
if (!(protocolVersion instanceof ProtocolVersion.UnknownVersion)) {
125129
pv = protocolVersion.identifier();
126130
}
@@ -166,8 +170,8 @@ private JsonRpcResponse handlePromptsGet(JsonRpcRequest req) {
166170
return createSuccessResponse(req.getId(), result);
167171
}
168172

169-
private JsonRpcResponse handleToolsList(JsonRpcRequest req) {
170-
var supportsOutputSchema = supportsOutputSchema();
173+
private JsonRpcResponse handleToolsList(JsonRpcRequest req, ProtocolVersion protocolVersion) {
174+
var supportsOutputSchema = supportsOutputSchema(protocolVersion);
171175
var result = ListToolsResult.builder()
172176
.tools(tools.values()
173177
.stream()
@@ -178,7 +182,11 @@ private JsonRpcResponse handleToolsList(JsonRpcRequest req) {
178182
return createSuccessResponse(req.getId(), result);
179183
}
180184

181-
private JsonRpcResponse handleToolsCall(JsonRpcRequest req, Consumer<JsonRpcResponse> asyncResponseCallback) {
185+
private JsonRpcResponse handleToolsCall(
186+
JsonRpcRequest req,
187+
Consumer<JsonRpcResponse> asyncResponseCallback,
188+
ProtocolVersion protocolVersion
189+
) {
182190
var operationName = req.getParams().getMember("name").asString();
183191
var tool = tools.get(operationName);
184192

@@ -209,7 +217,7 @@ private JsonRpcResponse handleToolsCall(JsonRpcRequest req, Consumer<JsonRpcResp
209217
var adaptedDoc = adaptDocument(argumentsDoc, operation.getApiOperation().inputSchema());
210218
var input = adaptedDoc.asShape(operation.getApiOperation().inputBuilder());
211219
var output = operation.function().apply(input, null);
212-
var result = formatStructuredContent(tool, (SerializableShape) output);
220+
var result = formatStructuredContent(tool, (SerializableShape) output, protocolVersion);
213221
return createSuccessResponse(req.getId(), result);
214222
}
215223
}
@@ -283,17 +291,21 @@ public Map<String, McpServerProxy> getProxies() {
283291
return proxies;
284292
}
285293

286-
private boolean supportsOutputSchema() {
294+
private boolean supportsOutputSchema(ProtocolVersion protocolVersion) {
287295
return protocolVersion != null && protocolVersion.compareTo(ProtocolVersion.v2025_06_18.INSTANCE) >= 0;
288296
}
289297

290-
private CallToolResult formatStructuredContent(Tool tool, SerializableShape output) {
298+
private CallToolResult formatStructuredContent(
299+
Tool tool,
300+
SerializableShape output,
301+
ProtocolVersion protocolVersion
302+
) {
291303
var result = CallToolResult.builder()
292304
.content(List.of(TextContent.builder()
293305
.text(CODEC.serializeToString(output))
294306
.build()));
295307

296-
if (supportsOutputSchema()) {
308+
if (supportsOutputSchema(protocolVersion)) {
297309
var outputSchema = tool.toolInfo().getOutputSchema();
298310
if (outputSchema != null) {
299311
result.structuredContent(Document.of(output));

mcp/mcp-server/src/main/java/software/amazon/smithy/java/mcp/server/ProtocolVersion.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,15 @@ public final int compareTo(ProtocolVersion o) {
6262

6363
public static ProtocolVersion version(String identifier) {
6464
return switch (identifier) {
65+
case null -> v2025_03_26.INSTANCE;
6566
case "2024-11-05" -> v2024_11_05.INSTANCE;
6667
case "2025-03-26" -> v2025_03_26.INSTANCE;
6768
case "2025-06-18" -> v2025_06_18.INSTANCE;
6869
default -> new UnknownVersion(identifier);
6970
};
7071
}
72+
73+
public static ProtocolVersion defaultVersion() {
74+
return v2025_03_26.INSTANCE;
75+
}
7176
}

0 commit comments

Comments
 (0)