feat: Add MCP server with Server stdio/sse transport improve MCP client

- Implement MCP server with async/sync support and builder pattern configuration
 - Add Server stdio/SSE transport layers with robust error handling
 - Convert McpClient and McpServer to interfaces for better extensibility
 - Add sampling capabilities for LLM interactions (text/image)
 - Implement dynamic root management and runtime tool management
 - Add comprehensive prompt and resource capabilities
 - Add support for dynamic root management (add/remove roots at runtime)

 Architecture Changes

 - Introduce registration records for tools, resources, and prompts
 - Improve thread safety with concurrent collections
 - Enhance resource template handling
 - Implement builder patterns for Server/Client capabilities
 - Add support for server capabilities and implementation info

Transport Layer:
 - Implement SseServerTransport with SSE endpoints
 - Add StdioServerTransport for process-based communication
 - Reorganize transport packages for better organization
 - Improve transport error handling and shutdown processes

Documentation:

 - Add detailed MCP reference documentation
 - Include architecture diagrams and API documentation
 - Add comprehensive test coverage for all components
 - Include sample projects demonstrating stdio/SSE transports

BREAKING CHANGES:

 Transport Package Reorganization

 - Move StdioClientTransport to o.s.ai.mcp.client.transport
 - Move SseClientTransport to o.s.ai.mcp.client.transport
 - Move ServerParameters to o.s.ai.mcp.client.transport
 - StdioClientTransport.errorHandler changed to private with
   setter method Migration: Use setErrorHandler() method
   instead of direct field access

 API Changes

 - Replace static factory methods with builder pattern
 - Update ServerCapabilities to use builder pattern
 - Make StdioClientTransport.errorHandler private with setter
 - Replace rootsListProvider with direct root management
 - Remove deprecated static factory methods

Resolves #27,#25,#24,#11
Related to #12
This commit is contained in:
Christian Tzolov 2024-12-19 19:38:38 +01:00
commit abd0facf4e

299
docs/ref-client.md Normal file
View file

@ -0,0 +1,299 @@
# MCP Client Reference
## McpClient Factory
`org.springframework.ai.mcp.client.McpClient`
The `McpClient` class serves as a factory for creating Model Context Protocol (MCP) clients. It provides the main entry point for establishing connections with MCP servers, offering both synchronous and asynchronous client implementations.
### Overview
The client factory uses a builder pattern for flexible configuration, allowing you to customize various aspects of the client including timeout durations, notification handlers, and more.
### Client Types
The factory can create two types of clients:
- `McpAsyncClient` for non-blocking operations
- `McpSyncClient` for blocking operations
### Builder Configuration
#### Basic Usage
```java
McpClient.using(transport)
.requestTimeout(Duration.ofSeconds(5))
.sync(); // or .async()
```
#### Builder Methods
##### using(McpTransport transport)
```java
public static Builder using(McpTransport transport)
```
Start building an MCP client with the specified transport.
##### requestTimeout(Duration requestTimeout)
```java
public Builder requestTimeout(Duration requestTimeout)
```
Set the request timeout duration (default is 20 seconds).
##### capabilities(ClientCapabilities capabilities)
```java
public Builder capabilities(ClientCapabilities capabilities)
```
Set the client capabilities that define what features the client supports.
##### clientInfo(Implementation clientInfo)
```java
public Builder clientInfo(Implementation clientInfo)
```
Set the client implementation information (name and version).
##### roots(List<Root> roots)
```java
public Builder roots(List<Root> roots)
```
Add a list of roots that define filesystem boundaries for server operations.
##### roots(Root... roots)
```java
public Builder roots(Root... roots)
```
Add roots that define filesystem boundaries for server operations.
##### toolsChangeConsumer(Consumer<List<Tool>> consumer)
```java
public Builder toolsChangeConsumer(Consumer<List<McpSchema.Tool>> toolsChangeConsumer)
```
Add a consumer for tool changes notifications.
##### resourcesChangeConsumer(Consumer<List<Resource>> consumer)
```java
public Builder resourcesChangeConsumer(Consumer<List<McpSchema.Resource>> resourcesChangeConsumer)
```
Add a consumer for resource changes notifications.
##### promptsChangeConsumer(Consumer<List<Prompt>> consumer)
```java
public Builder promptsChangeConsumer(Consumer<List<McpSchema.Prompt>> promptsChangeConsumer)
```
Add a consumer for prompt changes notifications.
##### sync()
```java
public McpSyncClient sync()
```
Build and return a synchronous MCP client.
##### async()
```java
public McpAsyncClient async()
```
Build and return an asynchronous MCP client.
### Usage Examples
#### Creating a Synchronous Client
```java
McpTransport transport = // obtain transport instance
// Configure client capabilities
ClientCapabilities capabilities = ClientCapabilities.builder()
.experimental(Map.of("feature", "value"))
.roots(true)
.sampling()
.build();
McpSyncClient client = McpClient.using(transport)
.requestTimeout(Duration.ofSeconds(10))
.rootsListChangedNotification(true)
.toolsChangeConsumer(tools -> {
System.out.println("Tools updated: " + tools);
})
.sync();
// Initialize client with capabilities
client.initialize(LATEST_PROTOCOL_VERSION, capabilities,
new Implementation("client-name", "1.0.0"));
```
#### Creating an Asynchronous Client
```java
McpTransport transport = // obtain transport instance
McpAsyncClient client = McpClient.using(transport)
.requestTimeout(Duration.ofSeconds(5))
.resourcesChangeConsumer(resources -> {
System.out.println("Resources updated: " + resources);
})
.async();
```
#### Using Multiple Change Consumers
```java
McpClient.using(transport)
.toolsChangeConsumer(tools -> {
// Handle tool changes
})
.toolsChangeConsumer(tools -> {
// Additional tool change handling
})
.resourcesChangeConsumer(resources -> {
// Handle resource changes
})
.sync();
```
### Client Capabilities
The `ClientCapabilities` class represents features that clients can implement to enrich connected MCP servers. It uses a builder pattern for easy configuration.
#### ClientCapabilities Builder
```java
ClientCapabilities capabilities = ClientCapabilities.builder()
.experimental(experimentalMap)
.roots(true)
.sampling()
.build();
```
##### Builder Methods
###### experimental(Map<String, Object> experimental)
```java
public Builder experimental(Map<String, Object> experimental)
```
Set experimental features map for work-in-progress capabilities.
###### roots(Boolean listChanged)
```java
public Builder roots(Boolean listChanged)
```
Configure root capabilities with listChanged parameter. Roots define the boundaries of where servers can operate within the filesystem.
###### sampling()
```java
public Builder sampling()
```
Add sampling capabilities that allow servers to request LLM sampling from language models via clients.
### Client Operations
#### Root Management
Both synchronous and asynchronous clients provide methods for managing filesystem roots:
##### Synchronous API
```java
void addRoot(Root root) // Add a new root
void removeRoot(String rootUri) // Remove a root by URI
void rootsListChangedNotification() // Notify about roots list changes
```
##### Asynchronous API
```java
Mono<Void> addRoot(Root root) // Add a new root
Mono<Void> removeRoot(String rootUri) // Remove a root by URI
Mono<Void> rootsListChangedNotification() // Notify about roots list changes
```
#### Tools API
Methods for interacting with server tools:
##### Synchronous API
```java
CallToolResult callTool(CallToolRequest request) // Execute a tool
ListToolsResult listTools() // List all available tools
ListToolsResult listTools(String cursor) // List tools with pagination
```
##### Asynchronous API
```java
Mono<CallToolResult> callTool(CallToolRequest request)
Mono<ListToolsResult> listTools()
Mono<ListToolsResult> listTools(String cursor)
```
#### Resources API
Methods for working with server resources:
##### Synchronous API
```java
ListResourcesResult listResources() // List all resources
ListResourcesResult listResources(String cursor) // List resources with pagination
ReadResourceResult readResource(Resource resource) // Read a resource
ReadResourceResult readResource(ReadResourceRequest request) // Read a resource by request
ListResourceTemplatesResult listResourceTemplates() // List resource templates
void subscribeResource(SubscribeRequest request) // Subscribe to resource updates
void unsubscribeResource(UnsubscribeRequest request) // Unsubscribe from updates
void sendResourcesListChanged() // Notify about resource changes
```
##### Asynchronous API
```java
Mono<ListResourcesResult> listResources()
Mono<ListResourcesResult> listResources(String cursor)
Mono<ReadResourceResult> readResource(Resource resource)
Mono<ReadResourceResult> readResource(ReadResourceRequest request)
Mono<ListResourceTemplatesResult> listResourceTemplates()
Mono<Void> subscribeResource(SubscribeRequest request)
Mono<Void> unsubscribeResource(UnsubscribeRequest request)
Mono<Void> sendResourcesListChanged()
```
#### Prompts API
Methods for working with server prompts:
##### Synchronous API
```java
ListPromptsResult listPrompts() // List all prompts
ListPromptsResult listPrompts(String cursor) // List prompts with pagination
GetPromptResult getPrompt(GetPromptRequest request) // Get a specific prompt
void promptListChangedNotification() // Notify about prompt changes
```
##### Asynchronous API
```java
Mono<ListPromptsResult> listPrompts()
Mono<ListPromptsResult> listPrompts(String cursor)
Mono<GetPromptResult> getPrompt(GetPromptRequest request)
Mono<Void> promptListChangedNotification()
```
#### Lifecycle Management
Methods for managing client lifecycle:
##### Synchronous API
```java
InitializeResult initialize() // Initialize client connection
void close() // Close client immediately
boolean closeGracefully() // Close client with graceful shutdown
Object ping() // Send ping request
```
##### Asynchronous API
```java
Mono<InitializeResult> initialize()
void close()
Mono<Void> closeGracefully()
Mono<Object> ping()
```
### Implementation Notes
- The client factory uses a builder pattern for configuration
- Default request timeout is 20 seconds
- Multiple consumers can be registered for tools, resources, and prompts changes
- The builder validates that the transport is not null
- Deprecated static factory methods are available but using the builder pattern is recommended
- The synchronous client is implemented as a wrapper around the asynchronous client
- ClientCapabilities uses a builder pattern for configuring client features
- The synchronous client blocks on async operations with the configured request timeout
- Resource subscriptions require server support for the subscribe capability
- Root management requires client to be configured with root capabilities