Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:28:30 +08:00
commit 171acedaa4
220 changed files with 85967 additions and 0 deletions

View File

@@ -0,0 +1,435 @@
# LangChain4j MCP Server API Reference
This document provides comprehensive API documentation for implementing MCP servers with LangChain4j.
## Core MCP Classes
### McpClient Interface
Primary interface for communicating with MCP servers.
**Key Methods:**
```java
// Tool Management
List<ToolSpecification> listTools();
String executeTool(ToolExecutionRequest request);
// Resource Management
List<McpResource> listResources();
String getResource(String uri);
List<McpResourceTemplate> listResourceTemplates();
// Prompt Management
List<Prompt> listPrompts();
String getPrompt(String name);
// Lifecycle Management
void close();
```
### DefaultMcpClient.Builder
Builder for creating MCP clients with configuration options.
**Configuration Methods:**
```java
McpClient client = new DefaultMcpClient.Builder()
.key("unique-client-id") // Unique identifier
.transport(transport) // Transport mechanism
.cacheToolList(true) // Enable tool caching
.logMessageHandler(handler) // Custom logging
.build();
```
### McpToolProvider.Builder
Builder for creating tool providers that bridge MCP servers to LangChain4j AI services.
**Configuration Methods:**
```java
McpToolProvider provider = McpToolProvider.builder()
.mcpClients(client1, client2) // Add MCP clients
.failIfOneServerFails(false) // Configure failure handling
.filterToolNames("tool1", "tool2") // Filter by names
.filter((client, tool) -> logic) // Custom filtering
.build();
```
## Transport Configuration
### StdioMcpTransport.Builder
For local process communication with npm packages or Docker containers.
```java
McpTransport transport = new StdioMcpTransport.Builder()
.command(List.of("npm", "exec", "@modelcontextprotocol/server-everything@0.6.2"))
.logEvents(true)
.build();
```
### HttpMcpTransport.Builder
For HTTP-based communication with remote MCP servers.
```java
McpTransport transport = new HttpMcpTransport.Builder()
.sseUrl("http://localhost:3001/sse")
.logRequests(true)
.logResponses(true)
.build();
```
### StreamableHttpMcpTransport.Builder
For streamable HTTP transport with enhanced performance.
```java
McpTransport transport = new StreamableHttpMcpTransport.Builder()
.url("http://localhost:3001/mcp")
.logRequests(true)
.logResponses(true)
.build();
```
## AI Service Integration
### AiServices.builder()
Create AI services integrated with MCP tool providers.
**Integration Methods:**
```java
AIAssistant assistant = AiServices.builder(AIAssistant.class)
.chatModel(chatModel)
.toolProvider(toolProvider)
.chatMemoryProvider(memoryProvider)
.build();
```
## Error Handling and Management
### Exception Handling
Handle MCP-specific exceptions gracefully:
```java
try {
String result = mcpClient.executeTool(request);
} catch (McpException e) {
log.error("MCP execution failed: {}", e.getMessage());
// Implement fallback logic
}
```
### Retry and Resilience
Implement retry logic for unreliable MCP servers:
```java
RetryTemplate retryTemplate = RetryTemplate.builder()
.maxAttempts(3)
.exponentialBackoff(1000, 2, 10000)
.build();
String result = retryTemplate.execute(context ->
mcpClient.executeTool(request));
```
## Configuration Properties
### Application Configuration
```yaml
mcp:
fail-if-one-server-fails: false
cache-tools: true
servers:
github:
type: docker
command: ["/usr/local/bin/docker", "run", "-e", "GITHUB_TOKEN", "-i", "mcp/github"]
log-events: true
database:
type: stdio
command: ["/usr/bin/npm", "exec", "@modelcontextprotocol/server-sqlite"]
log-events: false
```
### Spring Boot Configuration
```java
@Configuration
@EnableConfigurationProperties(McpProperties.class)
public class McpConfiguration {
@Bean
public List<McpClient> mcpClients(McpProperties properties) {
return properties.getServers().entrySet().stream()
.map(entry -> createMcpClient(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
}
@Bean
public McpToolProvider mcpToolProvider(List<McpClient> mcpClients, McpProperties properties) {
return McpToolProvider.builder()
.mcpClients(mcpClients)
.failIfOneServerFails(properties.isFailIfOneServerFails())
.build();
}
}
```
## Tool Specification and Execution
### Tool Specification
Define tools with proper schema:
```java
ToolSpecification toolSpec = ToolSpecification.builder()
.name("database_query")
.description("Execute SQL queries against the database")
.inputSchema(Map.of(
"type", "object",
"properties", Map.of(
"sql", Map.of(
"type", "string",
"description", "SQL query to execute"
)
)
))
.build();
```
### Tool Execution
Execute tools with structured requests:
```java
ToolExecutionRequest request = ToolExecutionRequest.builder()
.name("database_query")
.arguments("{\"sql\": \"SELECT * FROM users LIMIT 10\"}")
.build();
String result = mcpClient.executeTool(request);
```
## Resource Handling
### Resource Access
Access and utilize MCP resources:
```java
// List available resources
List<McpResource> resources = mcpClient.listResources();
// Get specific resource content
String content = mcpClient.getResource("resource://schema/database");
// Work with resource templates
List<McpResourceTemplate> templates = mcpClient.listResourceTemplates();
```
### Resource as Tools
Convert MCP resources to tools automatically:
```java
DefaultMcpResourcesAsToolsPresenter presenter =
new DefaultMcpResourcesAsToolsPresenter();
mcpToolProvider.provideTools(presenter);
// Adds 'list_resources' and 'get_resource' tools automatically
```
## Security and Filtering
### Tool Filtering
Implement security-conscious tool filtering:
```java
McpToolProvider secureProvider = McpToolProvider.builder()
.mcpClients(mcpClient)
.filter((client, tool) -> {
// Check user permissions
if (tool.name().startsWith("admin_") && !currentUser.hasRole("ADMIN")) {
return false;
}
return true;
})
.build();
```
### Resource Security
Apply security controls to resource access:
```java
public boolean canAccessResource(String uri, User user) {
if (uri.contains("sensitive/") && !user.hasRole("ADMIN")) {
return false;
}
return true;
}
```
## Performance Optimization
### Caching Strategy
Implement intelligent caching:
```java
// Enable tool caching for performance
McpClient client = new DefaultMcpClient.Builder()
.transport(transport)
.cacheToolList(true)
.build();
// Periodic cache refresh
@Scheduled(fixedRate = 300000) // 5 minutes
public void refreshToolCache() {
mcpClients.forEach(client -> {
try {
client.invalidateCache();
client.listTools(); // Preload cache
} catch (Exception e) {
log.warn("Cache refresh failed: {}", e.getMessage());
}
});
}
```
### Connection Pooling
Optimize connection management:
```java
@Bean
public Executor mcpExecutor() {
return Executors.newFixedThreadPool(10); // Dedicated thread pool
}
```
## Testing and Validation
### Mock Configuration
Setup for testing:
```java
@TestConfiguration
public class MockMcpConfiguration {
@Bean
@Primary
public McpClient mockMcpClient() {
McpClient mock = Mockito.mock(McpClient.class);
when(mock.listTools()).thenReturn(List.of(
ToolSpecification.builder()
.name("test_tool")
.description("Test tool")
.build()
));
when(mock.executeTool(any(ToolExecutionRequest.class)))
.thenReturn("Mock result");
return mock;
}
}
```
### Integration Testing
Test MCP integrations:
```java
@SpringBootTest
class McpIntegrationTest {
@Autowired
private AIAssistant assistant;
@Test
void shouldExecuteToolsSuccessfully() {
String response = assistant.chat("Execute test tool");
assertThat(response).contains("Mock result");
}
}
```
## Monitoring and Observability
### Health Checks
Monitor MCP server health:
```java
@Component
public class McpHealthChecker {
@EventListener
@Async
public void checkHealth() {
mcpClients.forEach(client -> {
try {
client.listTools(); // Simple health check
healthRegistry.markHealthy(client.key());
} catch (Exception e) {
healthRegistry.markUnhealthy(client.key(), e.getMessage());
}
});
}
}
```
### Metrics Collection
Collect execution metrics:
```java
@Bean
public Counter toolExecutionCounter(MeterRegistry meterRegistry) {
return meterRegistry.counter("mcp.tool.execution", "type", "total");
}
@Bean
public Timer toolExecutionTimer(MeterRegistry meterRegistry) {
return meterRegistry.timer("mcp.tool.execution.time");
}
```
## Migration and Versioning
### Version Compatibility
Handle version compatibility:
```java
public class VersionedMcpClient {
public boolean isCompatible(String serverVersion) {
return semanticVersionChecker.isCompatible(
REQUIRED_MCP_VERSION, serverVersion);
}
public McpClient createClient(ServerConfig config) {
if (!isCompatible(config.getVersion())) {
throw new IncompatibleVersionException(
"Server version " + config.getVersion() +
" is not compatible with required " + REQUIRED_MCP_VERSION);
}
return new DefaultMcpClient.Builder()
.transport(createTransport(config))
.build();
}
}
```
This API reference provides the complete foundation for implementing MCP servers and clients with LangChain4j, covering all major aspects from basic setup to advanced enterprise patterns.

View File

@@ -0,0 +1,592 @@
# LangChain4j MCP Server Implementation Examples
This document provides comprehensive, production-ready examples for implementing MCP servers with LangChain4j.
## Basic MCP Server Setup
### Simple MCP Server Implementation
Create a basic MCP server with single tool functionality:
```java
import dev.langchain4j.mcp.MCPServer;
import dev.langchain4j.mcp.ToolProvider;
import dev.langchain4j.mcp.server.StdioServer;
public class BasicMcpServer {
public static void main(String[] args) {
MCPServer server = MCPServer.builder()
.server(new StdioServer.Builder())
.addToolProvider(new SimpleWeatherToolProvider())
.build();
// Start the server
server.start();
}
}
class SimpleWeatherToolProvider implements ToolProvider {
@Override
public List<ToolSpecification> listTools() {
return List.of(ToolSpecification.builder()
.name("get_weather")
.description("Get weather information for a city")
.inputSchema(Map.of(
"type", "object",
"properties", Map.of(
"city", Map.of(
"type", "string",
"description", "City name to get weather for"
)
),
"required", List.of("city")
))
.build());
}
@Override
public String executeTool(String name, String arguments) {
if ("get_weather".equals(name)) {
JsonObject args = JsonParser.parseString(arguments).getAsJsonObject();
String city = args.get("city").getAsString();
// Simulate weather API call
return String.format("Weather in %s: Sunny, 22°C", city);
}
throw new UnsupportedOperationException("Unknown tool: " + name);
}
}
```
### Spring Boot MCP Server Integration
Integrate MCP server with Spring Boot application:
```java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class McpSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(McpSpringBootApplication.class, args);
}
@Bean
public MCPServer mcpServer() {
return MCPServer.builder()
.server(new StdioServer.Builder())
.addToolProvider(new DatabaseToolProvider())
.addToolProvider(new FileToolProvider())
.build();
}
}
@Component
class DatabaseToolProvider implements ToolProvider {
@Override
public List<ToolSpecification> listTools() {
return List.of(ToolSpecification.builder()
.name("query_database")
.description("Execute SQL queries against the database")
.inputSchema(Map.of(
"type", "object",
"properties", Map.of(
"sql", Map.of(
"type", "string",
"description", "SQL query to execute"
)
),
"required", List.of("sql")
))
.build());
}
@Override
public String executeTool(String name, String arguments) {
if ("query_database".equals(name)) {
JsonObject args = JsonParser.parseString(arguments).getAsJsonObject();
String sql = args.get("sql").getAsString();
// Execute database query
return executeDatabaseQuery(sql);
}
throw new UnsupportedOperationException("Unknown tool: " + name);
}
private String executeDatabaseQuery(String sql) {
// Implementation using Spring Data JPA
try {
return jdbcTemplate.queryForObject(sql, String.class);
} catch (Exception e) {
return "Error executing query: " + e.getMessage();
}
}
}
```
## Multi-Tool MCP Server
### Enterprise MCP Server with Multiple Tools
Create a comprehensive MCP server with multiple tool providers:
```java
@Component
public class EnterpriseMcpServer {
@Bean
public MCPServer enterpriseMcpServer(
GitHubToolProvider githubToolProvider,
DatabaseToolProvider databaseToolProvider,
FileToolProvider fileToolProvider,
EmailToolProvider emailToolProvider) {
return MCPServer.builder()
.server(new StdioServer.Builder())
.addToolProvider(githubToolProvider)
.addToolProvider(databaseToolProvider)
.addToolProvider(fileToolProvider)
.addToolProvider(emailToolProvider)
.enableLogging(true)
.setLogHandler(new CustomLogHandler())
.build();
}
}
@Component
class GitHubToolProvider implements ToolProvider {
@Override
public List<ToolSpecification> listTools() {
return List.of(
ToolSpecification.builder()
.name("get_issue")
.description("Get GitHub issue details")
.inputSchema(Map.of(
"type", "object",
"properties", Map.of(
"owner", Map.of(
"type", "string",
"description", "Repository owner"
),
"repo", Map.of(
"type", "string",
"description", "Repository name"
),
"issue_number", Map.of(
"type", "integer",
"description", "Issue number"
)
),
"required", List.of("owner", "repo", "issue_number")
))
.build(),
ToolSpecification.builder()
.name("list_issues")
.description("List GitHub issues for a repository")
.inputSchema(Map.of(
"type", "object",
"properties", Map.of(
"owner", Map.of(
"type", "string",
"description", "Repository owner"
),
"repo", Map.of(
"type", "string",
"description", "Repository name"
),
"state", Map.of(
"type", "string",
"description", "Issue state: open, closed, all",
"enum", List.of("open", "closed", "all")
)
),
"required", List.of("owner", "repo")
))
.build()
);
}
@Override
public String executeTool(String name, String arguments) {
switch (name) {
case "get_issue":
return getIssueDetails(arguments);
case "list_issues":
return listRepositoryIssues(arguments);
default:
throw new UnsupportedOperationException("Unknown tool: " + name);
}
}
private String getIssueDetails(String arguments) {
JsonObject args = JsonParser.parseString(arguments).getAsJsonObject();
String owner = args.get("owner").getAsString();
String repo = args.get("repo").getAsString();
int issueNumber = args.get("issue_number").getAsInt();
// Call GitHub API
GitHubIssue issue = githubService.getIssue(owner, repo, issueNumber);
return "Issue #" + issueNumber + ": " + issue.getTitle() +
"\nState: " + issue.getState() +
"\nCreated: " + issue.getCreatedAt();
}
private String listRepositoryIssues(String arguments) {
JsonObject args = JsonParser.parseString(arguments).getAsJsonObject();
String owner = args.get("owner").getAsString();
String repo = args.get("repo").getAsString();
String state = args.has("state") ? args.get("state").getAsString() : "open";
List<GitHubIssue> issues = githubService.listIssues(owner, repo, state);
return issues.stream()
.map(issue -> "#%d: %s (%s)".formatted(issue.getNumber(), issue.getTitle(), issue.getState()))
.collect(Collectors.joining("\n"));
}
}
```
## Resource Provider Implementation
### Static Resource Provider
Provide static resources for context enhancement:
```java
@Component
class StaticResourceProvider implements ResourceListProvider, ResourceReadHandler {
private final Map<String, String> resources = new HashMap<>();
public StaticResourceProvider() {
// Initialize with static resources
resources.put("company-policies", loadCompanyPolicies());
resources.put("api-documentation", loadApiDocumentation());
resources.put("best-practices", loadBestPractices());
}
@Override
public List<McpResource> listResources() {
return resources.keySet().stream()
.map(uri -> McpResource.builder()
.uri(uri)
.name(uri.replace("-", " "))
.description("Documentation resource")
.mimeType("text/plain")
.build())
.collect(Collectors.toList());
}
@Override
public String readResource(String uri) {
if (!resources.containsKey(uri)) {
throw new ResourceNotFoundException("Resource not found: " + uri);
}
return resources.get(uri);
}
private String loadCompanyPolicies() {
// Load company policies from file or database
return "Company Policies:\n1. Work hours: 9-5\n2. Security compliance\n3. Data privacy";
}
private String loadApiDocumentation() {
// Load API documentation
return "API Documentation:\nGET /api/users - List users\nPOST /api/users - Create user";
}
}
```
### Dynamic Resource Provider
Create dynamic resources that update in real-time:
```java
@Component
class DynamicResourceProvider implements ResourceListProvider, ResourceReadHandler {
@Autowired
private MetricsService metricsService;
@Override
public List<McpResource> listResources() {
return List.of(
McpResource.builder()
.uri("system-metrics")
.name("System Metrics")
.description("Real-time system performance metrics")
.mimeType("application/json")
.build(),
McpResource.builder()
.uri("user-analytics")
.name("User Analytics")
.description("User behavior and usage statistics")
.mimeType("application/json")
.build()
);
}
@Override
public String readResource(String uri) {
switch (uri) {
case "system-metrics":
return metricsService.getCurrentSystemMetrics();
case "user-analytics":
return metricsService.getUserAnalytics();
default:
throw new ResourceNotFoundException("Resource not found: " + uri);
}
}
}
```
## Prompt Template Provider
### Prompt Template Server
Create prompt templates for common AI tasks:
```java
@Component
class PromptTemplateProvider implements PromptListProvider, PromptGetHandler {
private final Map<String, PromptTemplate> templates = new HashMap<>();
public PromptTemplateProvider() {
templates.put("code-review", PromptTemplate.builder()
.name("Code Review")
.description("Review code for quality, security, and best practices")
.template("Review the following code for:\n" +
"1. Code quality and readability\n" +
"2. Security vulnerabilities\n" +
"3. Performance optimizations\n" +
"4. Best practices compliance\n\n" +
"Code:\n" +
"```{code}```\n\n" +
"Provide a detailed analysis with specific recommendations.")
.build());
templates.put("documentation-generation", PromptTemplate.builder()
.name("Documentation Generator")
.description("Generate technical documentation from code")
.template("Generate comprehensive documentation for the following code:\n" +
"{code}\n\n" +
"Include:\n" +
"1. Function/method signatures\n" +
"2. Parameters and return values\n" +
"3. Purpose and usage examples\n" +
"4. Dependencies and requirements")
.build());
}
@Override
public List<Prompt> listPrompts() {
return templates.values().stream()
.map(template -> Prompt.builder()
.name(template.getName())
.description(template.getDescription())
.build())
.collect(Collectors.toList());
}
@Override
public String getPrompt(String name, Map<String, String> arguments) {
PromptTemplate template = templates.get(name);
if (template == null) {
throw new PromptNotFoundException("Prompt not found: " + name);
}
// Replace template variables
String content = template.getTemplate();
for (Map.Entry<String, String> entry : arguments.entrySet()) {
content = content.replace("{" + entry.getKey() + "}", entry.getValue());
}
return content;
}
}
```
## Error Handling and Validation
### Robust Error Handling
Implement comprehensive error handling and validation:
```java
@Component
class RobustToolProvider implements ToolProvider {
@Override
public List<ToolSpecification> listTools() {
return List.of(ToolSpecification.builder()
.name("secure_data_access")
.description("Access sensitive data with proper validation")
.inputSchema(Map.of(
"type", "object",
"properties", Map.of(
"data_type", Map.of(
"type", "string",
"description", "Type of data to access",
"enum", List.of("user_data", "system_data", "admin_data")
),
"user_id", Map.of(
"type", "string",
"description", "User ID requesting access"
)
),
"required", List.of("data_type", "user_id")
))
.build());
}
@Override
public String executeTool(String name, String arguments) {
if ("secure_data_access".equals(name)) {
try {
JsonObject args = JsonParser.parseString(arguments).getAsJsonObject();
String dataType = args.get("data_type").getAsString();
String userId = args.get("user_id").getAsString();
// Validate user permissions
if (!hasPermission(userId, dataType)) {
return "Access denied: Insufficient permissions";
}
// Get data securely
return getSecureData(dataType, userId);
} catch (JsonParseException e) {
return "Invalid JSON format: " + e.getMessage();
} catch (Exception e) {
return "Error accessing data: " + e.getMessage();
}
}
throw new UnsupportedOperationException("Unknown tool: " + name);
}
private boolean hasPermission(String userId, String dataType) {
// Implement permission checking
if ("admin_data".equals(dataType)) {
return userRepository.isAdmin(userId);
}
return true;
}
private String getSecureData(String dataType, String userId) {
// Implement secure data retrieval
if ("user_data".equals(dataType)) {
return userDataService.getUserData(userId);
}
return "Data not available";
}
}
```
## Advanced Server Configuration
### Multi-Transport Server Configuration
Configure MCP server with multiple transport options:
```java
@Configuration
public class AdvancedMcpConfiguration {
@Bean
public MCPServer advancedMcpServer(
List<ToolProvider> toolProviders,
List<ResourceListProvider> resourceProviders,
List<PromptListProvider> promptProviders) {
return MCPServer.builder()
.server(new StdioServer.Builder())
.addToolProvider(toolProviders)
.addResourceProvider(resourceProviders)
.addPromptProvider(promptProviders)
.enableLogging(true)
.setLogHandler(new StructuredLogHandler())
.enableHealthChecks(true)
.setHealthCheckInterval(30) // seconds
.setMaxConcurrentRequests(100)
.setRequestTimeout(30) // seconds
.build();
}
@Bean
public HttpMcpTransport httpTransport() {
return new HttpMcpTransport.Builder()
.sseUrl("http://localhost:8080/mcp/sse")
.logRequests(true)
.logResponses(true)
.setCorsEnabled(true)
.setAllowedOrigins(List.of("http://localhost:3000"))
.build();
}
}
```
## Client Integration Patterns
### Multi-Client MCP Integration
Integrate with multiple MCP servers for comprehensive functionality:
```java
@Service
public class MultiMcpIntegrationService {
private final List<McpClient> mcpClients;
private final ChatModel chatModel;
private final McpToolProvider toolProvider;
public MultiMcpIntegrationService(List<McpClient> mcpClients, ChatModel chatModel) {
this.mcpClients = mcpClients;
this.chatModel = chatModel;
// Create tool provider with multiple MCP clients
this.toolProvider = McpToolProvider.builder()
.mcpClients(mcpClients)
.failIfOneServerFails(false) // Continue with available servers
.filter((client, tool) -> {
// Implement cross-server tool filtering
return !tool.name().startsWith("deprecated_");
})
.build();
}
public String processUserQuery(String userId, String query) {
// Create AI service with multiple MCP integrations
AIAssistant assistant = AiServices.builder(AIAssistant.class)
.chatModel(chatModel)
.toolProvider(toolProvider)
.chatMemoryProvider(memoryProvider)
.build();
return assistant.chat(userId, query);
}
public List<ToolSpecification> getAvailableTools() {
return mcpClients.stream()
.flatMap(client -> {
try {
return client.listTools().stream();
} catch (Exception e) {
log.warn("Failed to list tools from client {}: {}", client.key(), e.getMessage());
return Stream.empty();
}
})
.distinct()
.collect(Collectors.toList());
}
}
```
These comprehensive examples provide a solid foundation for implementing MCP servers with LangChain4j, covering everything from basic setup to advanced enterprise patterns.