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:
parent
c83a45f880
commit
abd0facf4e
10 changed files with 5727 additions and 471 deletions
|
|
@ -1,78 +0,0 @@
|
|||
# MCP Session Components
|
||||
|
||||
## Overview
|
||||
|
||||
The MCP (Model Context Protocol) session components implement the [MCP specification](https://spec.modelcontextprotocol.io/) for managing bidirectional JSON-RPC communication between clients and model servers.
|
||||
The implementation provides a robust foundation for request-response patterns and notification handling.
|
||||
|
||||
## Core Components
|
||||
|
||||
### McpSession Interface
|
||||
|
||||
The `McpSession` interface defines the contract for MCP communication with three primary operations:
|
||||
|
||||
1. Request-Response Communication
|
||||
```java
|
||||
<T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef);
|
||||
```
|
||||
|
||||
2. Notification Handling
|
||||
```java
|
||||
Mono<Void> sendNotification(String method, Map<String, Object> params);
|
||||
```
|
||||
|
||||
3. Session Lifecycle Management
|
||||
```java
|
||||
Mono<Void> closeGracefully();
|
||||
```
|
||||
|
||||
### DefaultMcpSession Implementation
|
||||
|
||||
The `DefaultMcpSession` provides the concrete implementation of the MCP session with the following key features:
|
||||
|
||||
#### 1. Message Correlation
|
||||
- Uses unique request IDs combining session UUID prefix and atomic counter
|
||||
- Maintains thread-safe tracking of pending responses
|
||||
- Implements timeout management for requests
|
||||
|
||||
#### 2. Handler Registration
|
||||
```java
|
||||
public interface RequestHandler {
|
||||
Mono<Object> handle(Object params);
|
||||
}
|
||||
|
||||
public interface NotificationHandler {
|
||||
Mono<Void> handle(Object params);
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Transport Integration
|
||||
- Abstracts transport details through `McpTransport` interface
|
||||
- Supports different transport implementations (SSE, STDIO)
|
||||
- Manages message serialization using Jackson
|
||||
|
||||
## Implementation Details
|
||||
|
||||
- The session processes three types of messages: McpSchema.JSONRPCResponse, McpSchema.JSONRPCRequest, McpSchema.JSONRPCNotificaiton.
|
||||
- The implementation ensures thread safety through
|
||||
|
||||
### Error Handling
|
||||
|
||||
WIP
|
||||
|
||||
## Integration Guidelines
|
||||
|
||||
1. **Transport Selection**
|
||||
- Choose appropriate transport (SSE, STDIO) based on use case
|
||||
- Configure transport-specific parameters
|
||||
- Handle transport lifecycle properly
|
||||
|
||||
2. **Message Handling**
|
||||
- Register handlers before starting session
|
||||
- Use appropriate error codes from MCP specification
|
||||
- Implement proper request/response correlation
|
||||
|
||||
3. **Type Safety**
|
||||
- Use appropriate TypeReference for response deserialization
|
||||
- Validate request parameters
|
||||
- Handle type conversion errors
|
||||
181
docs/MCP-layers.svg
Normal file
181
docs/MCP-layers.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 81 KiB |
|
|
@ -1,50 +1,82 @@
|
|||
@startuml Core Components
|
||||
|
||||
' Core Interfaces
|
||||
interface McpTransport {
|
||||
+Mono<Void> connect(Function<Mono<JSONRPCMessage>,
|
||||
Mono<JSONRPCMessage>> handler)
|
||||
+Mono<Void> sendMessage()
|
||||
+Mono<Void> connect(Function<Mono<JSONRPCMessage>, Mono<JSONRPCMessage>> handler)
|
||||
+Mono<Void> sendMessage(JSONRPCMessage message)
|
||||
+void close()
|
||||
+Mono<Void> closeGracefully()
|
||||
+<T> T unmarshalFrom(Object data, TypeReference<T> typeRef)
|
||||
}
|
||||
|
||||
interface McpSession {
|
||||
+<T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef)
|
||||
+Mono<Void> sendNotification(String method, Map<String, Object> params)
|
||||
+Mono<Void> closeGracefully()
|
||||
+close()
|
||||
+void close()
|
||||
}
|
||||
|
||||
' Core Implementation Classes
|
||||
class DefaultMcpSession {
|
||||
-McpTransport transport
|
||||
-ObjectMapper objectMapper
|
||||
+interface RequestHandler
|
||||
+interface NotificationHandler
|
||||
}
|
||||
|
||||
' Client Classes
|
||||
class McpClient {
|
||||
+{static} async()
|
||||
+{static} sync()
|
||||
+{static} Builder using(McpTransport transport)
|
||||
+{static} McpAsyncClient async(McpTransport transport)
|
||||
+{static} McpSyncClient sync(McpTransport transport)
|
||||
}
|
||||
|
||||
class McpAsyncClient {
|
||||
+Mono<InitializeResult> initialize()
|
||||
+Mono<CallToolResult> callTool()
|
||||
+Mono<CallToolResult> callTool(CallToolRequest request)
|
||||
+Mono<ListToolsResult> listTools()
|
||||
+Mono<ListResourcesResult> listResources()
|
||||
+Mono<ReadResourceResult> readResource()
|
||||
+Mono<ReadResourceResult> readResource(ReadResourceRequest request)
|
||||
+Mono<ListResourceTemplatesResult> listResourceTemplates()
|
||||
+Mono<ListPromptsResult> listPrompts()
|
||||
+Mono<GetPromptResult> getPrompt()
|
||||
+Mono<GetPromptResult> getPrompt(GetPromptRequest request)
|
||||
}
|
||||
|
||||
class McpSyncClient {
|
||||
+InitializeResult initialize()
|
||||
+CallToolResult callTool()
|
||||
+CallToolResult callTool(CallToolRequest request)
|
||||
+ListToolsResult listTools()
|
||||
+ListResourcesResult listResources()
|
||||
+ReadResourceResult readResource()
|
||||
+ReadResourceResult readResource(ReadResourceRequest request)
|
||||
+ListResourceTemplatesResult listResourceTemplates()
|
||||
+ListPromptsResult listPrompts()
|
||||
+GetPromptResult getPrompt()
|
||||
+GetPromptResult getPrompt(GetPromptRequest request)
|
||||
}
|
||||
|
||||
' Server Classes
|
||||
class McpServer {
|
||||
+{static} Builder using(McpTransport transport)
|
||||
}
|
||||
|
||||
class McpAsyncServer {
|
||||
+Mono<Void> addTool(ToolHandler toolHandler)
|
||||
+Mono<Void> removeTool(String toolName)
|
||||
+Mono<Void> notifyToolsListChanged()
|
||||
+Mono<Void> notifyResourcesListChanged()
|
||||
+Mono<Void> notifyPromptsListChanged()
|
||||
+interface ToolHandler
|
||||
}
|
||||
|
||||
class McpSyncServer {
|
||||
+void addTool(ToolHandler toolHandler)
|
||||
+void removeTool(String toolName)
|
||||
+void notifyToolsListChanged()
|
||||
+void notifyResourcesListChanged()
|
||||
+void notifyPromptsListChanged()
|
||||
+McpAsyncServer getAsyncServer()
|
||||
}
|
||||
|
||||
' Transport Implementations
|
||||
class StdioClientTransport {
|
||||
-Process serverProcess
|
||||
-ServerParameters parameters
|
||||
|
|
@ -54,12 +86,21 @@ class SseClientTransport {
|
|||
-WebClient webClient
|
||||
}
|
||||
|
||||
class StdioServerTransport {
|
||||
}
|
||||
|
||||
class SseServerTransport {
|
||||
}
|
||||
|
||||
' Schema and Error Classes
|
||||
class McpSchema {
|
||||
+class ErrorCodes
|
||||
+interface Request
|
||||
+interface JSONRPCMessage
|
||||
+interface ResourceContents
|
||||
+interface Content
|
||||
+interface ServerCapabilities
|
||||
+{static} JSONRPCMessage deserializeJsonRpcMessage()
|
||||
}
|
||||
|
||||
class McpError {
|
||||
|
|
@ -67,13 +108,24 @@ class McpError {
|
|||
-String message
|
||||
}
|
||||
|
||||
McpTransport <|-- StdioClientTransport
|
||||
McpTransport <|-- SseClientTransport
|
||||
McpSession <|-- DefaultMcpSession
|
||||
' Relationships
|
||||
McpTransport <|.. StdioClientTransport
|
||||
McpTransport <|.. SseClientTransport
|
||||
McpTransport <|.. StdioServerTransport
|
||||
McpTransport <|.. SseServerTransport
|
||||
|
||||
McpSession <|.. DefaultMcpSession
|
||||
DefaultMcpSession --o McpAsyncClient
|
||||
DefaultMcpSession --o McpAsyncServer
|
||||
|
||||
McpClient ..> McpAsyncClient : creates
|
||||
McpClient ..> McpSyncClient : creates
|
||||
McpSyncClient o-- McpAsyncClient
|
||||
|
||||
McpServer ..> McpAsyncServer : creates
|
||||
McpServer ..> McpSyncServer : creates
|
||||
McpSyncServer o-- McpAsyncServer
|
||||
|
||||
DefaultMcpSession o-- McpTransport
|
||||
McpSchema <.. McpSession : uses
|
||||
McpError ..> McpSession : throws
|
||||
|
|
@ -92,8 +144,11 @@ package "MCP Schema" {
|
|||
|
||||
class InitializeRequest
|
||||
class CallToolRequest
|
||||
class CreateMessageRequest
|
||||
class CompleteRequest
|
||||
class ListToolsRequest
|
||||
class ListResourcesRequest
|
||||
class ReadResourceRequest
|
||||
class ListResourceTemplatesRequest
|
||||
class ListPromptsRequest
|
||||
class GetPromptRequest
|
||||
}
|
||||
|
||||
|
|
@ -113,13 +168,27 @@ package "Resource Types" {
|
|||
class TextContent
|
||||
class ImageContent
|
||||
class EmbeddedResource
|
||||
|
||||
interface Annotated {
|
||||
+Annotations annotations()
|
||||
}
|
||||
|
||||
interface PromptOrResourceReference {
|
||||
+String type()
|
||||
}
|
||||
|
||||
class PromptReference
|
||||
class ResourceReference
|
||||
}
|
||||
|
||||
JSONRPCMessage <|.. Request
|
||||
Request <|.. InitializeRequest
|
||||
Request <|.. CallToolRequest
|
||||
Request <|.. CreateMessageRequest
|
||||
Request <|.. CompleteRequest
|
||||
Request <|.. ListToolsRequest
|
||||
Request <|.. ListResourcesRequest
|
||||
Request <|.. ReadResourceRequest
|
||||
Request <|.. ListResourceTemplatesRequest
|
||||
Request <|.. ListPromptsRequest
|
||||
Request <|.. GetPromptRequest
|
||||
|
||||
ResourceContents <|.. TextResourceContents
|
||||
|
|
@ -129,4 +198,7 @@ Content <|.. TextContent
|
|||
Content <|.. ImageContent
|
||||
Content <|.. EmbeddedResource
|
||||
|
||||
PromptOrResourceReference <|.. PromptReference
|
||||
PromptOrResourceReference <|.. ResourceReference
|
||||
|
||||
@enduml
|
||||
|
|
|
|||
299
docs/ref-client.md
Normal file
299
docs/ref-client.md
Normal 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
|
||||
154
docs/ref-errors.md
Normal file
154
docs/ref-errors.md
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
# MCP Error Handling Reference
|
||||
|
||||
## McpError Class
|
||||
|
||||
`org.springframework.ai.mcp.spec.McpError`
|
||||
|
||||
The `McpError` class is a runtime exception that represents errors that occur during Model Context Protocol (MCP) operations. It extends `RuntimeException` and provides a way to encapsulate error information from the MCP protocol.
|
||||
|
||||
### Overview
|
||||
|
||||
The McpError class is designed to handle various error scenarios that can occur during MCP communication, including protocol errors, transport errors, and application-specific errors.
|
||||
|
||||
### Class Definition
|
||||
|
||||
```java
|
||||
public class McpError extends RuntimeException {
|
||||
public McpError(Object error) {
|
||||
super(error.toString());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Common Error Scenarios
|
||||
|
||||
1. **Transport Errors**
|
||||
- Connection failures
|
||||
- Timeout errors
|
||||
- Protocol violations
|
||||
|
||||
2. **Protocol Errors**
|
||||
- Invalid JSON-RPC messages
|
||||
- Missing required fields
|
||||
- Invalid method names
|
||||
|
||||
3. **Application Errors**
|
||||
- Tool execution failures
|
||||
- Resource access errors
|
||||
- Invalid parameters
|
||||
|
||||
### Error Handling Best Practices
|
||||
|
||||
#### Client-Side Error Handling
|
||||
|
||||
```java
|
||||
McpClient client = McpClient.using(transport)
|
||||
.async();
|
||||
|
||||
client.sendRequest("method", params)
|
||||
.onErrorResume(McpError.class, error -> {
|
||||
// Handle MCP-specific errors
|
||||
logger.error("MCP error occurred: {}", error.getMessage());
|
||||
return Mono.empty();
|
||||
})
|
||||
.onErrorResume(Exception.class, error -> {
|
||||
// Handle other exceptions
|
||||
logger.error("Unexpected error: {}", error.getMessage());
|
||||
return Mono.empty();
|
||||
});
|
||||
```
|
||||
|
||||
#### Server-Side Error Handling
|
||||
|
||||
```java
|
||||
McpServer.using(transport)
|
||||
.tool(new McpSchema.Tool("example", "Example tool", inputSchema),
|
||||
args -> {
|
||||
try {
|
||||
// Tool implementation
|
||||
return new McpSchema.CallToolResult(result);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Convert to MCP error
|
||||
throw new McpError("Tool execution failed: " + e.getMessage());
|
||||
}
|
||||
})
|
||||
.async();
|
||||
```
|
||||
|
||||
### Implementation Notes
|
||||
|
||||
- McpError is a runtime exception, so it doesn't require explicit declaration in method signatures
|
||||
- The error message is created by calling toString() on the provided error object
|
||||
- Error handling should be implemented at both client and server sides
|
||||
- Reactive error handling using Project Reactor's error operators is recommended
|
||||
- Consider logging errors for debugging and monitoring purposes
|
||||
|
||||
### Error Recovery Strategies
|
||||
|
||||
1. **Retry Logic**
|
||||
```java
|
||||
client.sendRequest("method", params)
|
||||
.retry(3) // Retry up to 3 times
|
||||
.onErrorResume(McpError.class, error -> {
|
||||
// Handle failure after retries
|
||||
return Mono.empty();
|
||||
});
|
||||
```
|
||||
|
||||
2. **Fallback Values**
|
||||
```java
|
||||
client.sendRequest("method", params)
|
||||
.onErrorReturn(McpError.class, fallbackValue);
|
||||
```
|
||||
|
||||
3. **Circuit Breaking**
|
||||
```java
|
||||
// Using Resilience4j or similar library
|
||||
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("mcpClient");
|
||||
client.sendRequest("method", params)
|
||||
.transform(CircuitBreakerOperator.of(circuitBreaker));
|
||||
```
|
||||
|
||||
### Error Logging and Monitoring
|
||||
|
||||
```java
|
||||
client.sendRequest("method", params)
|
||||
.doOnError(McpError.class, error -> {
|
||||
// Log error details
|
||||
logger.error("MCP error: {}", error.getMessage());
|
||||
// Update metrics
|
||||
errorCounter.increment();
|
||||
});
|
||||
```
|
||||
|
||||
### Integration with Spring Error Handling
|
||||
|
||||
```java
|
||||
@ControllerAdvice
|
||||
public class McpErrorHandler {
|
||||
@ExceptionHandler(McpError.class)
|
||||
public ResponseEntity<ErrorResponse> handleMcpError(McpError error) {
|
||||
ErrorResponse response = new ErrorResponse(
|
||||
"MCP_ERROR",
|
||||
error.getMessage()
|
||||
);
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(response);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Testing Error Scenarios
|
||||
|
||||
```java
|
||||
@Test
|
||||
void testMcpError() {
|
||||
McpError error = new McpError("Test error");
|
||||
assertEquals("Test error", error.getMessage());
|
||||
|
||||
assertThrows(McpError.class, () -> {
|
||||
throw new McpError("Test error");
|
||||
});
|
||||
}
|
||||
91
docs/ref-index.md
Normal file
91
docs/ref-index.md
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# Spring AI MCP Reference Documentation
|
||||
|
||||
This documentation covers the Spring AI implementation of the Model Context Protocol (MCP) specification. The implementation follows the [official MCP specification](https://spec.modelcontextprotocol.io/specification/).
|
||||
|
||||
## Component Hierarchy
|
||||
|
||||
### 1. Transport Layer
|
||||
[Transport](ref-transport.md)
|
||||
- McpTransport Interface
|
||||
- Transport Implementations (SSE, STDIO)
|
||||
- Message Serialization/Deserialization
|
||||
|
||||
### 2. Session Layer
|
||||
[Session Management](ref-session.md)
|
||||
- McpSession Interface
|
||||
- DefaultMcpSession Implementation
|
||||
- Uses McpTransport for communication
|
||||
|
||||
### 3. High-Level Components
|
||||
Both components operate at the same level, using McpSession internally:
|
||||
|
||||
[Client](ref-client.md)
|
||||
- McpClient Factory
|
||||
- Synchronous and Asynchronous Implementations
|
||||
- Client Configuration and Builder Pattern
|
||||
|
||||
[Server](ref-server.md)
|
||||
- McpServer Factory
|
||||
- Synchronous and Asynchronous Implementations
|
||||
- Server Configuration and Builder Pattern
|
||||
|
||||
### 4. Supporting Components
|
||||
|
||||
[Error Handling](ref-errors.md)
|
||||
- McpError
|
||||
- Error Codes and Handling
|
||||
- Exception Hierarchy
|
||||
|
||||
|
||||
## Component Relationships
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐
|
||||
│ McpClient │ │ McpServer │
|
||||
└─────────────┘ └─────────────┘
|
||||
│ │
|
||||
└─────────┬────────┘
|
||||
│
|
||||
┌───────────────┐
|
||||
│ McpSession │
|
||||
└───────────────┘
|
||||
│
|
||||
┌───────────────┐
|
||||
│ McpTransport │
|
||||
└───────────────┘
|
||||
```
|
||||
|
||||
## Package Organization
|
||||
|
||||
The implementation is organized under the `org.springframework.ai.mcp` package with the following structure:
|
||||
|
||||
- `org.springframework.ai.mcp.spec` - Core interfaces and classes
|
||||
- McpTransport
|
||||
- McpSession
|
||||
- McpSchema
|
||||
- McpError
|
||||
- `org.springframework.ai.mcp.client` - Client implementations
|
||||
- McpClient
|
||||
- McpAsyncClient
|
||||
- McpSyncClient
|
||||
- Client-specific transports
|
||||
- `org.springframework.ai.mcp.server` - Server implementations
|
||||
- McpServer
|
||||
- McpAsyncServer
|
||||
- McpSyncServer
|
||||
- Server-specific transports
|
||||
- `org.springframework.ai.mcp.util` - Utility classes
|
||||
- Assert
|
||||
- Utils
|
||||
|
||||
## Key Features
|
||||
|
||||
- Synchronous and Asynchronous implementations
|
||||
- Multiple transport options (SSE, STDIO)
|
||||
- Comprehensive error handling
|
||||
- Builder pattern for configuration
|
||||
- Reactive programming support with Project Reactor
|
||||
- Type-safe message handling
|
||||
- Resource and prompt management
|
||||
- Tool discovery and execution
|
||||
- Change notification system
|
||||
162
docs/ref-server.md
Normal file
162
docs/ref-server.md
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
# MCP Server Reference
|
||||
|
||||
## McpServer Factory
|
||||
|
||||
`org.springframework.ai.mcp.server.McpServer`
|
||||
|
||||
The `McpServer` class serves as a factory for creating Model Context Protocol (MCP) servers. It provides the main entry point for establishing MCP servers, offering both synchronous and asynchronous server implementations.
|
||||
|
||||
### Overview
|
||||
|
||||
The server factory uses a builder pattern for flexible configuration, allowing you to customize various aspects of the server including server information, capabilities, tools, resource providers, and prompt providers.
|
||||
|
||||
### Server Types
|
||||
|
||||
The factory can create two types of servers:
|
||||
- `McpAsyncServer` for non-blocking operations
|
||||
- `McpSyncServer` for blocking operations
|
||||
|
||||
### Builder Configuration
|
||||
|
||||
#### Basic Usage
|
||||
```java
|
||||
McpServer.using(transport)
|
||||
.serverInfo("my-server", "1.0.0")
|
||||
.addTool(new MyToolHandler())
|
||||
.async(); // or .sync()
|
||||
```
|
||||
|
||||
#### Builder Methods
|
||||
|
||||
##### using(McpTransport transport)
|
||||
```java
|
||||
public static Builder using(McpTransport transport)
|
||||
```
|
||||
Start building an MCP server with the specified transport.
|
||||
|
||||
##### serverInfo(Implementation serverInfo)
|
||||
```java
|
||||
public Builder serverInfo(McpSchema.Implementation serverInfo)
|
||||
```
|
||||
Set the server implementation information.
|
||||
|
||||
##### serverInfo(String name, String version)
|
||||
```java
|
||||
public Builder serverInfo(String name, String version)
|
||||
```
|
||||
Set the server implementation information using name and version.
|
||||
|
||||
##### serverCapabilities(ServerCapabilities capabilities)
|
||||
```java
|
||||
public Builder serverCapabilities(McpSchema.ServerCapabilities serverCapabilities)
|
||||
```
|
||||
Set the server capabilities configuration.
|
||||
|
||||
##### addTool(ToolHandler handler)
|
||||
```java
|
||||
public <T extends McpAsyncServer.ToolHandler> Builder addTool(T toolHandler)
|
||||
```
|
||||
Add a tool handler to the server.
|
||||
|
||||
##### tool(Tool tool, Function<Map<String, Object>, CallToolResult> handler)
|
||||
```java
|
||||
public Builder tool(McpSchema.Tool tool, Function<Map<String, Object>, McpSchema.CallToolResult> handler)
|
||||
```
|
||||
Add a tool with its handler function.
|
||||
|
||||
##### addTools(List<ToolHandler> handlers)
|
||||
```java
|
||||
public Builder addTools(List<ToolHandler> toolHandlers)
|
||||
```
|
||||
Add multiple tool handlers to the server.
|
||||
|
||||
##### resourcesProvider(Function<String, List<Resource>> provider)
|
||||
```java
|
||||
public Builder resourcesProvider(Function<String, List<McpSchema.Resource>> resourcesProvider)
|
||||
```
|
||||
Set the resources provider function.
|
||||
|
||||
##### promptsProvider(Function<String, List<Prompt>> provider)
|
||||
```java
|
||||
public Builder promptsProvider(Function<String, List<McpSchema.Prompt>> promptsProvider)
|
||||
```
|
||||
Set the prompts provider function.
|
||||
|
||||
##### sync()
|
||||
```java
|
||||
public McpSyncServer sync()
|
||||
```
|
||||
Build and return a synchronous MCP server.
|
||||
|
||||
##### async()
|
||||
```java
|
||||
public AsyncServerBuilder async()
|
||||
```
|
||||
Build and return an asynchronous server builder.
|
||||
|
||||
### Usage Examples
|
||||
|
||||
#### Creating a Basic Server
|
||||
```java
|
||||
McpTransport transport = // obtain transport instance
|
||||
McpServer.using(transport)
|
||||
.serverInfo("my-server", "1.0.0")
|
||||
.sync();
|
||||
```
|
||||
|
||||
#### Creating a Server with Tools
|
||||
```java
|
||||
McpServer.using(transport)
|
||||
.serverInfo("calculation-server", "1.0.0")
|
||||
.tool(
|
||||
new McpSchema.Tool("calculate", "Performs calculations", Map.of(
|
||||
"operation", Map.of("type", "string"),
|
||||
"numbers", Map.of("type", "array")
|
||||
)),
|
||||
args -> {
|
||||
// Handle calculation
|
||||
return new McpSchema.CallToolResult(/* result */);
|
||||
}
|
||||
)
|
||||
.async();
|
||||
```
|
||||
|
||||
#### Creating a Server with Resources and Prompts
|
||||
```java
|
||||
McpServer.using(transport)
|
||||
.serverInfo("content-server", "1.0.0")
|
||||
.resourcesProvider(cursor -> {
|
||||
// Return list of resources based on cursor
|
||||
return List.of(/* resources */);
|
||||
})
|
||||
.promptsProvider(cursor -> {
|
||||
// Return list of prompts based on cursor
|
||||
return List.of(/* prompts */);
|
||||
})
|
||||
.sync();
|
||||
```
|
||||
|
||||
### Implementation Notes
|
||||
|
||||
- The server factory uses a builder pattern for configuration
|
||||
- Default server info is "mcp-server" version "1.0.0" if not specified
|
||||
- Tool handlers must be thread-safe as they may be called concurrently
|
||||
- The synchronous server is implemented as a wrapper around the asynchronous server
|
||||
- Resource and prompt providers use cursor-based pagination
|
||||
- The AsyncServerBuilder allows adding tools after server creation
|
||||
|
||||
### Tool Handler Interface
|
||||
|
||||
```java
|
||||
public interface ToolHandler {
|
||||
String getName();
|
||||
String getDescription();
|
||||
Map<String, Object> getInputSchema();
|
||||
McpSchema.CallToolResult call(Map<String, Object> arguments);
|
||||
}
|
||||
```
|
||||
|
||||
Tool handlers implement this interface to define:
|
||||
- Tool name and description
|
||||
- Input schema for validation
|
||||
- Execution logic in the call method
|
||||
116
docs/ref-session.md
Normal file
116
docs/ref-session.md
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
# MCP Session Reference
|
||||
|
||||
## McpSession Interface
|
||||
|
||||
`org.springframework.ai.mcp.spec.McpSession`
|
||||
|
||||
The MCP (Model Context Protocol) session components implement the [MCP specification](https://spec.modelcontextprotocol.io/) for managing bidirectional JSON-RPC communication between clients and model servers.
|
||||
The implementation provides a foundation for request-response patterns and notification handling, as well as managing the session lifecycle.
|
||||
|
||||
### Overview
|
||||
|
||||
The session operates asynchronously using Project Reactor's `Mono` type for non-blocking operations. It supports both request-response patterns and one-way notifications.
|
||||
|
||||
### Methods
|
||||
|
||||
#### Request-Response
|
||||
|
||||
```java
|
||||
<T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef)
|
||||
```
|
||||
|
||||
Sends a request to the model server and expects a response of type T.
|
||||
|
||||
**Parameters:**
|
||||
- `method`: The name of the method to be called on the server
|
||||
- `requestParams`: The parameters to be sent with the request
|
||||
- `typeRef`: The TypeReference describing the expected response type
|
||||
|
||||
**Returns:**
|
||||
- A `Mono` that will emit the response when received
|
||||
|
||||
#### Notification
|
||||
|
||||
```java
|
||||
Mono<Void> sendNotification(String method, Map<String, Object> params)
|
||||
```
|
||||
|
||||
Sends a notification to the model server with parameters.
|
||||
|
||||
**Parameters:**
|
||||
- `method`: The name of the notification method to be called on the server
|
||||
- `params`: A map of parameters to be sent with the notification
|
||||
|
||||
**Returns:**
|
||||
- A `Mono` that completes when the notification has been sent
|
||||
|
||||
#### Close Gracefully
|
||||
```java
|
||||
Mono<Void> closeGracefully()
|
||||
```
|
||||
|
||||
Closes the session and releases any associated resources asynchronously.
|
||||
|
||||
**Returns:**
|
||||
- A `Mono` that completes when the session has been closed
|
||||
|
||||
#### Close
|
||||
```java
|
||||
void close()
|
||||
```
|
||||
|
||||
Closes the session and releases any associated resources synchronously.
|
||||
|
||||
### DefaultMcpSession Implementation
|
||||
|
||||
The `DefaultMcpSession` provides the concrete implementation of the MCP session with the following key features:
|
||||
|
||||
#### 1. Message Correlation
|
||||
- Uses unique request IDs combining session UUID prefix and atomic counter
|
||||
- Maintains thread-safe tracking of pending responses
|
||||
- Implements timeout management for requests
|
||||
|
||||
#### 2. Handler Registration
|
||||
```java
|
||||
public interface RequestHandler {
|
||||
Mono<Object> handle(Object params);
|
||||
}
|
||||
|
||||
public interface NotificationHandler {
|
||||
Mono<Void> handle(Object params);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Usage Example
|
||||
|
||||
```java
|
||||
McpSession session = // obtain session instance
|
||||
|
||||
// Send a request
|
||||
TypeReference<ResponseType> typeRef = new TypeReference<ResponseType>() {};
|
||||
Mono<ResponseType> response = session.sendRequest("method.name", requestParams, typeRef);
|
||||
|
||||
// Send a notification without parameters
|
||||
Mono<Void> notificationResult = session.sendNotification("notification.method");
|
||||
|
||||
// Send a notification with parameters
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("key", "value");
|
||||
Mono<Void> paramNotificationResult = session.sendNotification("notification.method", params);
|
||||
|
||||
// Close the session gracefully
|
||||
session.closeGracefully()
|
||||
.subscribe(
|
||||
null,
|
||||
error -> System.err.println("Error closing session: " + error),
|
||||
() -> System.out.println("Session closed successfully")
|
||||
);
|
||||
```
|
||||
|
||||
### Implementation Notes
|
||||
|
||||
- The interface is designed to be transport-agnostic, allowing different transport implementations (SSE, STDIO) to be used.
|
||||
- All operations except `close()` are non-blocking and return `Mono` instances.
|
||||
- The `sendRequest` method uses Jackson's `TypeReference` for type-safe deserialization of responses.
|
||||
- The default implementation of `sendNotification(String)` delegates to `sendNotification(String, Map)` with null parameters.
|
||||
124
docs/ref-transport.md
Normal file
124
docs/ref-transport.md
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
# MCP Transport Reference
|
||||
|
||||
## McpTransport Interface
|
||||
|
||||
`org.springframework.ai.mcp.spec.McpTransport`
|
||||
|
||||
The `McpTransport` interface defines the asynchronous transport layer for the Model Context Protocol (MCP). It provides the foundation for implementing custom transport mechanisms, handling bidirectional communication between client and server components using JSON-RPC format.
|
||||
|
||||
### Overview
|
||||
|
||||
The transport layer is designed to be protocol-agnostic, allowing for various implementations such as WebSocket, HTTP, or custom protocols. It manages the lifecycle of connections and handles message exchange between components.
|
||||
|
||||
### Key Responsibilities
|
||||
|
||||
- Managing the lifecycle of the transport connection
|
||||
- Handling incoming messages and errors from the server
|
||||
- Sending outbound messages to the server
|
||||
- Message serialization and deserialization
|
||||
|
||||
### Methods
|
||||
|
||||
#### Connect
|
||||
```java
|
||||
Mono<Void> connect(Function<Mono<JSONRPCMessage>, Mono<JSONRPCMessage>> handler)
|
||||
```
|
||||
|
||||
Initializes and starts the transport connection.
|
||||
|
||||
**Parameters:**
|
||||
- `handler`: A function that processes incoming messages and returns response messages
|
||||
|
||||
**Returns:**
|
||||
- A `Mono<Void>` that completes when the connection is established
|
||||
|
||||
#### Send Message
|
||||
```java
|
||||
Mono<Void> sendMessage(JSONRPCMessage message)
|
||||
```
|
||||
|
||||
Sends a message to the server asynchronously.
|
||||
|
||||
**Parameters:**
|
||||
- `message`: The JSON-RPC message to be sent to the server
|
||||
|
||||
**Returns:**
|
||||
- A `Mono<Void>` that completes when the message has been sent
|
||||
|
||||
#### Close Gracefully
|
||||
```java
|
||||
Mono<Void> closeGracefully()
|
||||
```
|
||||
|
||||
Closes the transport connection and releases any associated resources asynchronously.
|
||||
|
||||
**Returns:**
|
||||
- A `Mono<Void>` that completes when the connection has been closed
|
||||
|
||||
#### Close
|
||||
```java
|
||||
default void close()
|
||||
```
|
||||
|
||||
Synchronously closes the transport connection. By default, this method delegates to `closeGracefully()` and subscribes to the result.
|
||||
|
||||
#### Unmarshal From
|
||||
```java
|
||||
<T> T unmarshalFrom(Object data, TypeReference<T> typeRef)
|
||||
```
|
||||
|
||||
Deserializes data into the specified type.
|
||||
|
||||
**Parameters:**
|
||||
- `data`: The data to deserialize
|
||||
- `typeRef`: The TypeReference describing the target type
|
||||
|
||||
**Returns:**
|
||||
- The deserialized object of type T
|
||||
|
||||
### Implementation Notes
|
||||
|
||||
- The transport layer uses Project Reactor's `Mono` type for non-blocking operations
|
||||
- Messages are exchanged using the JSON-RPC format as specified by the MCP protocol
|
||||
- The interface is designed to be extensible, allowing for different transport implementations
|
||||
- Current implementations include:
|
||||
- SSE (Server-Sent Events) Transport
|
||||
- STDIO Transport (Standard Input/Output)
|
||||
|
||||
### Usage Example
|
||||
|
||||
```java
|
||||
McpTransport transport = // obtain transport instance
|
||||
|
||||
// Connect and handle messages
|
||||
transport.connect(message -> {
|
||||
// Process incoming message
|
||||
return processMessage(message);
|
||||
}).subscribe();
|
||||
|
||||
// Send a message
|
||||
JSONRPCMessage message = new JSONRPCMessage();
|
||||
// ... configure message
|
||||
transport.sendMessage(message)
|
||||
.subscribe(
|
||||
null,
|
||||
error -> System.err.println("Error sending message: " + error),
|
||||
() -> System.out.println("Message sent successfully")
|
||||
);
|
||||
|
||||
// Close the transport
|
||||
transport.closeGracefully()
|
||||
.subscribe(
|
||||
null,
|
||||
error -> System.err.println("Error closing transport: " + error),
|
||||
() -> System.out.println("Transport closed successfully")
|
||||
);
|
||||
```
|
||||
|
||||
### Transport Implementations
|
||||
|
||||
#### SSE Transport
|
||||
The SSE (Server-Sent Events) transport implementation provides a unidirectional communication channel from the server to the client using HTTP streaming.
|
||||
|
||||
#### STDIO Transport
|
||||
The STDIO transport implementation uses standard input/output streams for communication, making it suitable for command-line applications and process-based communication.
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 44 KiB |
Loading…
Reference in a new issue