java-sdk/migration-0.8.0.md
Dariusz Jędrzejczyk 34a733509d refactor: introduce session-based architecture for MCP server (#31)
This commit introduces a major refactoring of the MCP Java SDK to implement a session-based architecture
for server-side implementations. The changes improve the SDK's ability to handle multiple concurrent
client connections and provide an API better aligned with the MCP specification.

Key changes:

- Introduce McpServerTransportProvider interface to manage client connections
- Rename ClientMcpTransport to McpClientTransport and ServerMcpTransport to McpServerTransport
- Add exchange objects (McpAsyncServerExchange, McpSyncServerExchange) for client interaction
- Update handler signatures to include exchange parameter: (args) -> result to (exchange, args) -> result
- Rename Registration classes to Specification classes
- Update method names (e.g., rootsChangeConsumers to rootsChangeHandlers)
- Deprecate old interfaces and classes for removal in 0.9.0
- Add migration guide (migration-0.8.0.md)

Resolves #9, #15

Co-authored-by: Christian Tzolov <christian.tzolov@broadcom.com>
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2025-03-20 21:49:51 +01:00

328 lines
11 KiB
Markdown

# MCP Java SDK Migration Guide: 0.7.0 to 0.8.0
This document outlines the breaking changes and provides guidance on how to migrate your code from version 0.7.0 to 0.8.0.
The 0.8.0 refactoring introduces a session-based architecture for server-side MCP implementations.
It improves the SDK's ability to handle multiple concurrent client connections and provides an API better aligned with the MCP specification.
The main changes include:
1. Introduction of a session-based architecture
2. New transport provider abstraction
3. Exchange objects for client interaction
4. Renamed and reorganized interfaces
5. Updated handler signatures
## Breaking Changes
### 1. Interface Renaming
Several interfaces have been renamed to better reflect their roles:
| 0.7.0 (Old) | 0.8.0 (New) |
|-------------|-------------|
| `ClientMcpTransport` | `McpClientTransport` |
| `ServerMcpTransport` | `McpServerTransport` |
| `DefaultMcpSession` | `McpClientSession`, `McpServerSession` |
### 2. New Server Transport Architecture
The most significant change is the introduction of the `McpServerTransportProvider` interface, which replaces direct usage of `ServerMcpTransport` when creating servers. This new pattern separates the concerns of:
1. **Transport Provider**: Manages connections with clients and creates individual transports for each connection
2. **Server Transport**: Handles communication with a specific client connection
| 0.7.0 (Old) | 0.8.0 (New) |
|-------------|-------------|
| `ServerMcpTransport` | `McpServerTransportProvider` + `McpServerTransport` |
| Direct transport usage | Session-based transport usage |
#### Before (0.7.0):
```java
// Create a transport
ServerMcpTransport transport = new WebFluxSseServerTransport(objectMapper, "/mcp/message");
// Create a server with the transport
McpServer.sync(transport)
.serverInfo("my-server", "1.0.0")
.build();
```
#### After (0.8.0):
```java
// Create a transport provider
McpServerTransportProvider transportProvider = new WebFluxSseServerTransportProvider(objectMapper, "/mcp/message");
// Create a server with the transport provider
McpServer.sync(transportProvider)
.serverInfo("my-server", "1.0.0")
.build();
```
### 3. Handler Method Signature Changes
Tool, resource, and prompt handlers now receive an additional `exchange` parameter that provides access to client capabilities and methods to interact with the client:
| 0.7.0 (Old) | 0.8.0 (New) |
|-------------|-------------|
| `(args) -> result` | `(exchange, args) -> result` |
The exchange objects (`McpAsyncServerExchange` and `McpSyncServerExchange`) provide context for the current session and access to session-specific operations.
#### Before (0.7.0):
```java
// Tool handler
.tool(calculatorTool, args -> new CallToolResult("Result: " + calculate(args)))
// Resource handler
.resource(fileResource, req -> new ReadResourceResult(readFile(req)))
// Prompt handler
.prompt(analysisPrompt, req -> new GetPromptResult("Analysis prompt"))
```
#### After (0.8.0):
```java
// Tool handler
.tool(calculatorTool, (exchange, args) -> new CallToolResult("Result: " + calculate(args)))
// Resource handler
.resource(fileResource, (exchange, req) -> new ReadResourceResult(readFile(req)))
// Prompt handler
.prompt(analysisPrompt, (exchange, req) -> new GetPromptResult("Analysis prompt"))
```
### 4. Registration vs. Specification
The naming convention for handlers has changed from "Registration" to "Specification":
| 0.7.0 (Old) | 0.8.0 (New) |
|-------------|-------------|
| `AsyncToolRegistration` | `AsyncToolSpecification` |
| `SyncToolRegistration` | `SyncToolSpecification` |
| `AsyncResourceRegistration` | `AsyncResourceSpecification` |
| `SyncResourceRegistration` | `SyncResourceSpecification` |
| `AsyncPromptRegistration` | `AsyncPromptSpecification` |
| `SyncPromptRegistration` | `SyncPromptSpecification` |
### 5. Roots Change Handler Updates
The roots change handlers now receive an exchange parameter:
#### Before (0.7.0):
```java
.rootsChangeConsumers(List.of(
roots -> {
// Process roots
}
))
```
#### After (0.8.0):
```java
.rootsChangeHandlers(List.of(
(exchange, roots) -> {
// Process roots with access to exchange
}
))
```
### 6. Server Creation Method Changes
The `McpServer` factory methods now accept `McpServerTransportProvider` instead of `ServerMcpTransport`:
| 0.7.0 (Old) | 0.8.0 (New) |
|-------------|-------------|
| `McpServer.async(ServerMcpTransport)` | `McpServer.async(McpServerTransportProvider)` |
| `McpServer.sync(ServerMcpTransport)` | `McpServer.sync(McpServerTransportProvider)` |
The method names for creating servers have been updated:
Root change handlers now receive an exchange object:
| 0.7.0 (Old) | 0.8.0 (New) |
|-------------|-------------|
| `rootsChangeConsumers(List<Consumer<List<Root>>>)` | `rootsChangeHandlers(List<BiConsumer<McpSyncServerExchange, List<Root>>>)` |
| `rootsChangeConsumer(Consumer<List<Root>>)` | `rootsChangeHandler(BiConsumer<McpSyncServerExchange, List<Root>>)` |
### 7. Direct Server Methods Moving to Exchange
Several methods that were previously available directly on the server are now accessed through the exchange object:
| 0.7.0 (Old) | 0.8.0 (New) |
|-------------|-------------|
| `server.listRoots()` | `exchange.listRoots()` |
| `server.createMessage()` | `exchange.createMessage()` |
| `server.getClientCapabilities()` | `exchange.getClientCapabilities()` |
| `server.getClientInfo()` | `exchange.getClientInfo()` |
The direct methods are deprecated and will be removed in 0.9.0:
- `McpSyncServer.listRoots()`
- `McpSyncServer.getClientCapabilities()`
- `McpSyncServer.getClientInfo()`
- `McpSyncServer.createMessage()`
- `McpAsyncServer.listRoots()`
- `McpAsyncServer.getClientCapabilities()`
- `McpAsyncServer.getClientInfo()`
- `McpAsyncServer.createMessage()`
## Deprecation Notices
The following components are deprecated in 0.8.0 and will be removed in 0.9.0:
- `ClientMcpTransport` interface (use `McpClientTransport` instead)
- `ServerMcpTransport` interface (use `McpServerTransport` instead)
- `DefaultMcpSession` class (use `McpClientSession` instead)
- `WebFluxSseServerTransport` class (use `WebFluxSseServerTransportProvider` instead)
- `WebMvcSseServerTransport` class (use `WebMvcSseServerTransportProvider` instead)
- `StdioServerTransport` class (use `StdioServerTransportProvider` instead)
- All `*Registration` classes (use corresponding `*Specification` classes instead)
- Direct server methods for client interaction (use exchange object instead)
## Migration Examples
### Example 1: Creating a Server
#### Before (0.7.0):
```java
// Create a transport
ServerMcpTransport transport = new WebFluxSseServerTransport(objectMapper, "/mcp/message");
// Create a server with the transport
var server = McpServer.sync(transport)
.serverInfo("my-server", "1.0.0")
.tool(calculatorTool, args -> new CallToolResult("Result: " + calculate(args)))
.rootsChangeConsumers(List.of(
roots -> System.out.println("Roots changed: " + roots)
))
.build();
// Get client capabilities directly from server
ClientCapabilities capabilities = server.getClientCapabilities();
```
#### After (0.8.0):
```java
// Create a transport provider
McpServerTransportProvider transportProvider = new WebFluxSseServerTransportProvider(objectMapper, "/mcp/message");
// Create a server with the transport provider
var server = McpServer.sync(transportProvider)
.serverInfo("my-server", "1.0.0")
.tool(calculatorTool, (exchange, args) -> {
// Get client capabilities from exchange
ClientCapabilities capabilities = exchange.getClientCapabilities();
return new CallToolResult("Result: " + calculate(args));
})
.rootsChangeHandlers(List.of(
(exchange, roots) -> System.out.println("Roots changed: " + roots)
))
.build();
```
### Example 2: Implementing a Tool with Client Interaction
#### Before (0.7.0):
```java
McpServerFeatures.SyncToolRegistration tool = new McpServerFeatures.SyncToolRegistration(
new Tool("weather", "Get weather information", schema),
args -> {
String location = (String) args.get("location");
// Cannot interact with client from here
return new CallToolResult("Weather for " + location + ": Sunny");
}
);
var server = McpServer.sync(transport)
.tools(tool)
.build();
// Separate call to create a message
CreateMessageResult result = server.createMessage(new CreateMessageRequest(...));
```
#### After (0.8.0):
```java
McpServerFeatures.SyncToolSpecification tool = new McpServerFeatures.SyncToolSpecification(
new Tool("weather", "Get weather information", schema),
(exchange, args) -> {
String location = (String) args.get("location");
// Can interact with client directly from the tool handler
CreateMessageResult result = exchange.createMessage(new CreateMessageRequest(...));
return new CallToolResult("Weather for " + location + ": " + result.content());
}
);
var server = McpServer.sync(transportProvider)
.tools(tool)
.build();
```
### Example 3: Converting Existing Registration Classes
If you have custom implementations of the registration classes, you can convert them to the new specification classes:
#### Before (0.7.0):
```java
McpServerFeatures.AsyncToolRegistration toolReg = new McpServerFeatures.AsyncToolRegistration(
tool,
args -> Mono.just(new CallToolResult("Result"))
);
McpServerFeatures.AsyncResourceRegistration resourceReg = new McpServerFeatures.AsyncResourceRegistration(
resource,
req -> Mono.just(new ReadResourceResult(List.of()))
);
```
#### After (0.8.0):
```java
// Option 1: Create new specification directly
McpServerFeatures.AsyncToolSpecification toolSpec = new McpServerFeatures.AsyncToolSpecification(
tool,
(exchange, args) -> Mono.just(new CallToolResult("Result"))
);
// Option 2: Convert from existing registration (during transition)
McpServerFeatures.AsyncToolRegistration oldToolReg = /* existing registration */;
McpServerFeatures.AsyncToolSpecification toolSpec = oldToolReg.toSpecification();
// Similarly for resources
McpServerFeatures.AsyncResourceSpecification resourceSpec = new McpServerFeatures.AsyncResourceSpecification(
resource,
(exchange, req) -> Mono.just(new ReadResourceResult(List.of()))
);
```
## Architecture Changes
### Session-Based Architecture
In 0.8.0, the MCP Java SDK introduces a session-based architecture where each client connection has its own session. This allows for better isolation between clients and more efficient resource management.
The `McpServerTransportProvider` is responsible for creating `McpServerTransport` instances for each session, and the `McpServerSession` manages the communication with a specific client.
### Exchange Objects
The new exchange objects (`McpAsyncServerExchange` and `McpSyncServerExchange`) provide access to client-specific information and methods. They are passed to handler functions as the first parameter, allowing handlers to interact with the specific client that made the request.
## Conclusion
The changes in version 0.8.0 represent a significant architectural improvement to the MCP Java SDK. While they require some code changes, the new design provides a more flexible and maintainable foundation for building MCP applications.
For assistance with migration or to report issues, please open an issue on the GitHub repository.