feat(core): add roots list support and improve documentation
- Add roots list capability to allow servers to understand filesystem boundaries - Move architecture diagram and add detailed documentation for transports and sessions - Enhance client capabilities with roots and sampling features - Rename withRequestTimeout to requestTimeout for better API consistency - Add tests for roots list functionality Resolves #8
This commit is contained in:
parent
7a98a935af
commit
82c64f5ad3
6 changed files with 810 additions and 45 deletions
144
docs/CLIENT.SSE.TRANSPORT.md
Normal file
144
docs/CLIENT.SSE.TRANSPORT.md
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
# SSE Server Transport Implementation for MCP
|
||||
|
||||
## Overview
|
||||
|
||||
The `SseClientTransport` class implements the Model Context Protocol (MCP) HTTP with SSE transport specification, providing a bidirectional communication channel between clients and servers. This implementation is part of the Spring AI MCP Core library and follows the [MCP HTTP with SSE Transport Specification](https://spec.modelcontextprotocol.io/specification/basic/transports/#http-with-sse).
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Bidirectional Communication**:
|
||||
- Inbound: Receives messages through SSE connection
|
||||
- Outbound: Sends messages via HTTP POST requests
|
||||
|
||||
- **Error Handling**:
|
||||
- Automatic reconnection for transient failures
|
||||
- Graceful shutdown capabilities
|
||||
- Comprehensive error reporting
|
||||
|
||||
- **Message Flow**:
|
||||
1. Client establishes SSE connection to `/sse` endpoint
|
||||
2. Server sends 'endpoint' event with message URI
|
||||
3. Client uses provided URI for outbound messages
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Transport Architecture
|
||||
|
||||
The transport consists of two main processing pipelines:
|
||||
|
||||
1. **Inbound Processing**:
|
||||
- Establishes SSE connection to `/sse` endpoint
|
||||
- Handles two types of events:
|
||||
- `message`: JSON-RPC protocol messages
|
||||
- `endpoint`: Server-provided URI for outbound messages
|
||||
- Implements automatic retry logic for connection failures
|
||||
|
||||
2. **Outbound Processing**:
|
||||
- Sends messages via HTTP POST to server-provided endpoint
|
||||
- Uses dedicated scheduler for sequential message processing
|
||||
- Handles JSON serialization and HTTP communication
|
||||
|
||||
### Key Components
|
||||
|
||||
- **WebClient**: Handles HTTP communications for both SSE and POST requests
|
||||
- **ObjectMapper**: Manages JSON serialization/deserialization
|
||||
- **Scheduler**: Ensures sequential outbound message processing
|
||||
- **Message Endpoint Sink**: Manages server-provided endpoint URI
|
||||
|
||||
## Usage Example
|
||||
|
||||
```java
|
||||
// Create WebClient builder with base URL
|
||||
WebClient.Builder webClientBuilder = WebClient.builder()
|
||||
.baseUrl("http://localhost:3001");
|
||||
|
||||
// Initialize transport
|
||||
SseClientTransport transport = new SseClientTransport(webClientBuilder);
|
||||
|
||||
// Create a JSON-RPC request
|
||||
JSONRPCRequest request = new JSONRPCRequest(
|
||||
McpSchema.JSONRPC_VERSION,
|
||||
"method-name",
|
||||
"request-id",
|
||||
Map.of("key", "value")
|
||||
);
|
||||
|
||||
// Send message
|
||||
transport.sendMessage(request)
|
||||
.subscribe(
|
||||
success -> System.out.println("Message sent successfully"),
|
||||
error -> System.err.println("Error sending message: " + error)
|
||||
);
|
||||
|
||||
// Graceful shutdown when done
|
||||
transport.closeGracefully()
|
||||
.subscribe();
|
||||
```
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Message Processing
|
||||
|
||||
1. **Inbound Messages**:
|
||||
- Received through SSE connection
|
||||
- Automatically deserialized from JSON
|
||||
- Routed to appropriate handlers based on event type
|
||||
|
||||
2. **Outbound Messages**:
|
||||
- Serialized to JSON
|
||||
- Sent via HTTP POST
|
||||
- Processed sequentially on dedicated thread
|
||||
|
||||
### Error Handling
|
||||
|
||||
- **Connection Failures**:
|
||||
- Automatic retry for transient failures
|
||||
- Configurable retry policies
|
||||
- Graceful handling of permanent failures
|
||||
|
||||
- **Message Processing Errors**:
|
||||
- Comprehensive error reporting
|
||||
- Clean failure handling
|
||||
- Maintains system stability
|
||||
|
||||
### Shutdown Process
|
||||
|
||||
The transport implements a graceful shutdown mechanism that:
|
||||
1. Marks transport as closing
|
||||
2. Disposes of all subscriptions
|
||||
3. Cleans up schedulers
|
||||
4. Completes message endpoint sink
|
||||
|
||||
## Technical Specifications
|
||||
|
||||
- **Protocol**: HTTP with Server-Sent Events (SSE)
|
||||
- **Message Format**: JSON-RPC 2.0
|
||||
- **Content Type**: application/json for outbound, text/event-stream for inbound
|
||||
- **Endpoints**:
|
||||
- SSE Connection: `/sse`
|
||||
- Message Endpoint: Dynamically provided by server
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Spring WebFlux for reactive HTTP client
|
||||
- Jackson for JSON processing
|
||||
- Project Reactor for reactive streams
|
||||
- SLF4J for logging
|
||||
|
||||
## Thread Safety
|
||||
|
||||
The implementation is thread-safe and designed for concurrent use:
|
||||
- Inbound processing uses SSE event loop
|
||||
- Outbound processing uses dedicated single-threaded scheduler
|
||||
- State management uses thread-safe constructs
|
||||
|
||||
## Testing
|
||||
|
||||
The implementation includes comprehensive tests covering:
|
||||
- Message processing
|
||||
- Error handling
|
||||
- Connection management
|
||||
- Shutdown procedures
|
||||
- Edge cases and failure scenarios
|
||||
|
||||
For detailed test examples, see `SseClientTransportTests.java`.
|
||||
123
docs/CLIENT.STDIO.TRANSPORT.md
Normal file
123
docs/CLIENT.STDIO.TRANSPORT.md
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
# StdioClientTransport
|
||||
|
||||
The `StdioClientTransport` class implements the [MCP Stdio Transport](https://spec.modelcontextprotocol.io/specification/basic/transports/#stdio) specification, providing communication with MCP servers over standard input/output streams.
|
||||
|
||||
## Overview
|
||||
|
||||
The Stdio transport uses standard input/output streams for bidirectional communication between the client and server:
|
||||
- Messages are sent to the server via stdout
|
||||
- Messages are received from the server via stdin
|
||||
- Error and debug information is sent via stderr
|
||||
|
||||
## Message Format
|
||||
|
||||
Messages are exchanged as newline-delimited JSON-RPC messages:
|
||||
- Each message is a single line of JSON text
|
||||
- Messages are terminated with a newline character (`\n`)
|
||||
- Messages follow the JSON-RPC 2.0 specification
|
||||
- UTF-8 encoding is used for all messages
|
||||
|
||||
### Message Types
|
||||
|
||||
The transport handles three types of JSON-RPC messages:
|
||||
|
||||
1. **Requests** - Messages with both `method` and `id` fields:
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "example.method",
|
||||
"params": {}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Notifications** - Messages with `method` but no `id` field:
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "example.notification",
|
||||
"params": {}
|
||||
}
|
||||
```
|
||||
|
||||
3. **Responses** - Messages with either `result` or `error` fields:
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": {}
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Process Management
|
||||
|
||||
The transport manages a server process with:
|
||||
- Command and arguments specified via `ServerParameters`
|
||||
- Environment variables for configuration
|
||||
- Proper process cleanup on shutdown
|
||||
|
||||
### Threading Model
|
||||
|
||||
The implementation uses three dedicated threads:
|
||||
1. **Inbound** - Reads and processes messages from stdin
|
||||
2. **Outbound** - Writes messages to stdout
|
||||
3. **Error** - Handles stderr messages
|
||||
|
||||
### Error Handling
|
||||
|
||||
Errors are handled at multiple levels:
|
||||
- Process startup failures
|
||||
- Stream I/O errors
|
||||
- Message parsing errors
|
||||
- Process termination handling
|
||||
|
||||
## Usage Example
|
||||
|
||||
```java
|
||||
// Create server parameters
|
||||
ServerParameters params = ServerParameters.builder()
|
||||
.command("path/to/server")
|
||||
.args(List.of("--arg1", "value1"))
|
||||
.env(Map.of("ENV_VAR", "value"))
|
||||
.build();
|
||||
|
||||
// Create transport
|
||||
StdioClientTransport transport = new StdioClientTransport(params);
|
||||
|
||||
// Start transport
|
||||
transport.start();
|
||||
|
||||
// Send message
|
||||
JSONRPCRequest request = new JSONRPCRequest();
|
||||
request.setId(1);
|
||||
request.setMethod("example.method");
|
||||
request.setParams(new HashMap<>());
|
||||
transport.send(request);
|
||||
|
||||
// Close transport
|
||||
transport.closeGracefully().block();
|
||||
```
|
||||
|
||||
## Error Messages
|
||||
|
||||
Error messages from the server process are:
|
||||
- Written to stderr
|
||||
- Logged at ERROR level
|
||||
- Emitted through the error sink for handling
|
||||
- UTF-8 encoded
|
||||
|
||||
## Debugging
|
||||
|
||||
For debugging purposes:
|
||||
1. Enable DEBUG level logging to see detailed message flow
|
||||
2. Monitor stderr for server process errors
|
||||
3. Check process exit codes for abnormal termination
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The transport ensures thread safety through dedicated schedulers
|
||||
- Messages are processed asynchronously using Project Reactor
|
||||
- Resources are properly cleaned up on shutdown
|
||||
- The implementation is resilient to various failure modes
|
||||
78
docs/MCP-SESSION.md
Normal file
78
docs/MCP-SESSION.md
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
# 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
|
||||
132
docs/class-diagrams.puml
Normal file
132
docs/class-diagrams.puml
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
@startuml Core Components
|
||||
|
||||
interface McpTransport {
|
||||
+Mono<Void> connect(Function<Mono<JSONRPCMessage>,
|
||||
Mono<JSONRPCMessage>> handler)
|
||||
+Mono<Void> sendMessage()
|
||||
+void close()
|
||||
+Mono<Void> closeGracefully()
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
class DefaultMcpSession {
|
||||
-McpTransport transport
|
||||
-ObjectMapper objectMapper
|
||||
}
|
||||
|
||||
class McpClient {
|
||||
+{static} async()
|
||||
+{static} sync()
|
||||
}
|
||||
|
||||
class McpAsyncClient {
|
||||
+Mono<InitializeResult> initialize()
|
||||
+Mono<CallToolResult> callTool()
|
||||
+Mono<ListToolsResult> listTools()
|
||||
+Mono<ListResourcesResult> listResources()
|
||||
+Mono<ReadResourceResult> readResource()
|
||||
+Mono<ListPromptsResult> listPrompts()
|
||||
+Mono<GetPromptResult> getPrompt()
|
||||
}
|
||||
|
||||
class McpSyncClient {
|
||||
+InitializeResult initialize()
|
||||
+CallToolResult callTool()
|
||||
+ListToolsResult listTools()
|
||||
+ListResourcesResult listResources()
|
||||
+ReadResourceResult readResource()
|
||||
+ListPromptsResult listPrompts()
|
||||
+GetPromptResult getPrompt()
|
||||
}
|
||||
|
||||
class StdioClientTransport {
|
||||
-Process serverProcess
|
||||
-ServerParameters parameters
|
||||
}
|
||||
|
||||
class SseClientTransport {
|
||||
-WebClient webClient
|
||||
}
|
||||
|
||||
class McpSchema {
|
||||
+class ErrorCodes
|
||||
+interface Request
|
||||
+interface JSONRPCMessage
|
||||
+interface ResourceContents
|
||||
+interface Content
|
||||
}
|
||||
|
||||
class McpError {
|
||||
-int code
|
||||
-String message
|
||||
}
|
||||
|
||||
McpTransport <|-- StdioClientTransport
|
||||
McpTransport <|-- SseClientTransport
|
||||
McpSession <|-- DefaultMcpSession
|
||||
DefaultMcpSession --o McpAsyncClient
|
||||
McpClient ..> McpAsyncClient : creates
|
||||
McpClient ..> McpSyncClient : creates
|
||||
McpSyncClient o-- McpAsyncClient
|
||||
DefaultMcpSession o-- McpTransport
|
||||
McpSchema <.. McpSession : uses
|
||||
McpError ..> McpSession : throws
|
||||
|
||||
@enduml
|
||||
|
||||
@startuml Message Flow
|
||||
|
||||
package "MCP Schema" {
|
||||
interface JSONRPCMessage {
|
||||
+String jsonrpc()
|
||||
}
|
||||
|
||||
interface Request {
|
||||
}
|
||||
|
||||
class InitializeRequest
|
||||
class CallToolRequest
|
||||
class CreateMessageRequest
|
||||
class CompleteRequest
|
||||
class GetPromptRequest
|
||||
}
|
||||
|
||||
package "Resource Types" {
|
||||
interface ResourceContents {
|
||||
+String uri()
|
||||
+String mimeType()
|
||||
}
|
||||
|
||||
class TextResourceContents
|
||||
class BlobResourceContents
|
||||
|
||||
interface Content {
|
||||
+String type()
|
||||
}
|
||||
|
||||
class TextContent
|
||||
class ImageContent
|
||||
class EmbeddedResource
|
||||
}
|
||||
|
||||
JSONRPCMessage <|.. Request
|
||||
Request <|.. InitializeRequest
|
||||
Request <|.. CallToolRequest
|
||||
Request <|.. CreateMessageRequest
|
||||
Request <|.. CompleteRequest
|
||||
Request <|.. GetPromptRequest
|
||||
|
||||
ResourceContents <|.. TextResourceContents
|
||||
ResourceContents <|.. BlobResourceContents
|
||||
|
||||
Content <|.. TextContent
|
||||
Content <|.. ImageContent
|
||||
Content <|.. EmbeddedResource
|
||||
|
||||
@enduml
|
||||
BIN
docs/spring-ai-mcp-architecture.jpg
Normal file
BIN
docs/spring-ai-mcp-architecture.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 736 KiB |
1
docs/spring-ai-mcp-uml-classdiagram.svg
Normal file
1
docs/spring-ai-mcp-uml-classdiagram.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 28 KiB |
Loading…
Reference in a new issue