Skip to content
This repository was archived by the owner on Feb 14, 2025. It is now read-only.

Commit

Permalink
Refactor McpClient for async and sync interactions
Browse files Browse the repository at this point in the history
Introduce new builder patterns and enhance type safety

- Add new builder patterns for McpClient and McpServer with sync/async variants
- Introduce dedicated McpClientFeatures and McpServerFeatures classes
- Enhance type safety and reactive support with proper Mono integration
- Add migration guide for 0.6.0 release
- Mark old builder methods as deprecated
- Update documentation to reflect new APIs

BREAKING CHANGE: The old builder patterns using McpClient.using() and McpServer.using()
are now deprecated in favor of new sync() and async() builders that provide
better type safety and clearer sync/async separation. Follow the migration guide.

Resolves #48

Signed-off-by: Dariusz Jędrzejczyk <[email protected]>
Co-authored-by: Christian Tzolov <[email protected]>
  • Loading branch information
chemicL and tzolov committed Jan 23, 2025
1 parent e1bdc98 commit 6839d3b
Show file tree
Hide file tree
Showing 25 changed files with 3,494 additions and 753 deletions.
258 changes: 258 additions & 0 deletions mcp-docs/0.6.0-MIGRATION-GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
# Spring AI MCP 0.5.0 Migration Guide

This guide outlines the steps required to migrate your code to Spring AI MCP 0.6.0.

## Key Changes

- New builder patterns for `McpClient` and `McpServer`
- Introduction of dedicated feature classes for sync/async operations
- Enhanced type safety and reactive support
- Deprecated methods and classes marked for removal

## Client Migration

### Creating Clients

Before:
```java
// Sync client
McpClient.using(transport)
.requestTimeout(Duration.ofSeconds(5))
.sync();

// Async client
McpClient.using(transport)
.requestTimeout(Duration.ofSeconds(5))
.async();
```

After:
```java
// Sync client
McpClient.sync(transport)
.requestTimeout(Duration.ofSeconds(5))
.build();

// Async client
McpClient.async(transport)
.requestTimeout(Duration.ofSeconds(5))
.build();
```

### Change Consumers

Before:
```java
// Sync client
McpClient.using(transport)
.toolsChangeConsumer(tools -> handleTools(tools))
.resourcesChangeConsumer(resources -> handleResources(resources))
.promptsChangeConsumer(prompts -> handlePrompts(prompts))
.sync();

// Async client
McpClient.using(transport)
.toolsChangeConsumer(tools -> handleTools(tools))
.resourcesChangeConsumer(resources -> handleResources(resources))
.promptsChangeConsumer(prompts -> handlePrompts(prompts))
.async();
```

After:
```java
// Sync client
McpClient.sync(transport)
.toolsChangeConsumer(tools -> handleTools(tools))
.resourcesChangeConsumer(resources -> handleResources(resources))
.promptsChangeConsumer(prompts -> handlePrompts(prompts))
.build();

// Async client
McpClient.async(transport)
.toolsChangeConsumer(tools -> Mono.fromRunnable(() -> handleTools(tools)))
.resourcesChangeConsumer(resources -> Mono.fromRunnable(() -> handleResources(resources)))
.promptsChangeConsumer(prompts -> Mono.fromRunnable(() -> handlePrompts(prompts)))
.build();
```

### Sampling Handlers

Before:
```java
// Sync client
McpClient.using(transport)
.sampling(request -> new CreateMessageResult("response"))
.sync();

// Async client
McpClient.using(transport)
.sampling(request -> new CreateMessageResult("response"))
.async();
```

After:
```java
// Sync client
McpClient.sync(transport)
.sampling(request -> new CreateMessageResult("response"))
.build();

// Async client
McpClient.async(transport)
.sampling(request -> Mono.just(new CreateMessageResult("response")))
.build();
```

## Server Migration

### Creating Servers

Before:
```java
// Sync server
McpServer.using(transport)
.serverInfo("test-server", "1.0.0")
.sync();

// Async server
McpServer.using(transport)
.serverInfo("test-server", "1.0.0")
.async();
```

After:
```java
// Sync server
McpServer.sync(transport)
.serverInfo("test-server", "1.0.0")
.build();

// Async server
McpServer.async(transport)
.serverInfo("test-server", "1.0.0")
.build();
```

### Tool Registration

Before:
```java
// Using ToolRegistration record
new ToolRegistration(
new Tool("calculator", "Performs calculations", schema),
args -> new CallToolResult("result")
);
```

After:
```java
// Sync server
new McpServerFeatures.SyncToolRegistration(
new Tool("calculator", "Performs calculations", schema),
args -> new CallToolResult("result")
);

// Async server
new McpServerFeatures.AsyncToolRegistration(
new Tool("calculator", "Performs calculations", schema),
args -> Mono.just(new CallToolResult("result"))
);
```

### Resource Registration

Before:
```java
// Using ResourceRegistration record
new ResourceRegistration(
new Resource("docs", "Documentation", "text/markdown"),
request -> new ReadResourceResult(content)
);
```

After:
```java
// Sync server
new McpServerFeatures.SyncResourceRegistration(
new Resource("docs", "Documentation", "text/markdown"),
request -> new ReadResourceResult(content)
);

// Async server
new McpServerFeatures.AsyncResourceRegistration(
new Resource("docs", "Documentation", "text/markdown"),
request -> Mono.just(new ReadResourceResult(content))
);
```

### Prompt Registration

Before:
```java
// Using PromptRegistration record
new PromptRegistration(
new Prompt("analyze", "Code analysis"),
request -> new GetPromptResult("result")
);
```

After:
```java
// Sync server
new McpServerFeatures.SyncPromptRegistration(
new Prompt("analyze", "Code analysis"),
request -> new GetPromptResult("result")
);

// Async server
new McpServerFeatures.AsyncPromptRegistration(
new Prompt("analyze", "Code analysis"),
request -> Mono.just(new GetPromptResult("result"))
);
```

## Spring Integration Changes

### Tool Helper Changes

Before:
```java
ToolHelper.toToolRegistration(functionCallback);
ToolHelper.toToolRegistration(functionCallbacks);
```

After:
```java
ToolHelper.toSyncToolRegistration(functionCallback);
ToolHelper.toSyncToolRegistration(functionCallbacks);
```

## Deprecated APIs

The following APIs are deprecated and will be removed in a future release:

- `McpClient.using()` - Use `McpClient.sync()` or `McpClient.async()` instead
- `McpServer.using()` - Use `McpServer.sync()` or `McpServer.async()` instead
- `McpServer.ToolRegistration` - Use `McpServerFeatures.SyncToolRegistration` or `McpServerFeatures.AsyncToolRegistration` instead
- `McpServer.ResourceRegistration` - Use `McpServerFeatures.SyncResourceRegistration` or `McpServerFeatures.AsyncResourceRegistration` instead
- `McpServer.PromptRegistration` - Use `McpServerFeatures.SyncPromptRegistration` or `McpServerFeatures.AsyncPromptRegistration` instead
- `ToolHelper.toToolRegistration()` - Use `ToolHelper.toSyncToolRegistration()` instead

## Benefits of Migration

1. **Improved Type Safety**: The new builder patterns and feature classes provide better compile-time type checking.

2. **Clear Async/Sync Separation**: Distinct builders and features for sync and async operations make the code intent clearer.

3. **Enhanced Reactive Support**: Async operations now properly integrate with Project Reactor's `Mono` type.

4. **Better Error Handling**: More consistent error handling across sync and async operations.

5. **Simplified Configuration**: Builder patterns provide a more intuitive way to configure clients and servers.

## Additional Notes

- The migration primarily focuses on builder patterns and feature organization
- Functional behavior remains the same after migration
- Async operations now properly integrate with Project Reactor
- All deprecated APIs will continue to work but will be removed in a future release
Loading

0 comments on commit 6839d3b

Please sign in to comment.