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
10 changed files with 5727 additions and 471 deletions

View file

@ -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

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 81 KiB

View file

@ -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
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

154
docs/ref-errors.md Normal file
View 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
View 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
View 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
View 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
View 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

Before After
Before After