- 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
154 lines
4 KiB
Markdown
154 lines
4 KiB
Markdown
# 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");
|
|
});
|
|
}
|