Initial commit
This commit is contained in:
393
skills/langchain4j/langchain4j-mcp-server-patterns/SKILL.md
Normal file
393
skills/langchain4j/langchain4j-mcp-server-patterns/SKILL.md
Normal file
@@ -0,0 +1,393 @@
|
||||
---
|
||||
name: langchain4j-mcp-server-patterns
|
||||
description: Model Context Protocol (MCP) server implementation patterns with LangChain4j. Use when building MCP servers to extend AI capabilities with custom tools, resources, and prompt templates.
|
||||
category: ai-integration
|
||||
tags: [langchain4j, mcp, model-context-protocol, tools, resources, prompts, ai-services, java, spring-boot, enterprise]
|
||||
version: 1.1.0
|
||||
allowed-tools: Read, Write, Bash, WebFetch
|
||||
---
|
||||
|
||||
# LangChain4j MCP Server Implementation Patterns
|
||||
|
||||
Implement Model Context Protocol (MCP) servers with LangChain4j to extend AI capabilities with standardized tools, resources, and prompt templates.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when building:
|
||||
- AI applications requiring external tool integration
|
||||
- Enterprise MCP servers with multi-domain support (GitHub, databases, APIs)
|
||||
- Dynamic tool providers with context-aware filtering
|
||||
- Resource-based data access systems for AI models
|
||||
- Prompt template servers for standardized AI interactions
|
||||
- Scalable AI agents with resilient tool execution
|
||||
- Multi-modal AI applications with diverse data sources
|
||||
- Spring Boot applications with MCP integration
|
||||
- Production-ready MCP servers with security and monitoring
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Basic MCP Server
|
||||
|
||||
Create a simple MCP server with one tool:
|
||||
|
||||
```java
|
||||
MCPServer server = MCPServer.builder()
|
||||
.server(new StdioServer.Builder())
|
||||
.addToolProvider(new SimpleWeatherToolProvider())
|
||||
.build();
|
||||
|
||||
server.start();
|
||||
```
|
||||
|
||||
### Spring Boot Integration
|
||||
|
||||
Configure MCP server in Spring Boot:
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public MCPSpringConfig mcpServer(List<ToolProvider> tools) {
|
||||
return MCPSpringConfig.builder()
|
||||
.tools(tools)
|
||||
.server(new StdioServer.Builder())
|
||||
.build();
|
||||
}
|
||||
```
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### MCP Architecture
|
||||
|
||||
MCP standardizes AI application connections:
|
||||
- **Tools**: Executable functions (database queries, API calls)
|
||||
- **Resources**: Data sources (files, schemas, documentation)
|
||||
- **Prompts**: Pre-configured templates for tasks
|
||||
- **Transport**: Communication layer (stdio, HTTP, WebSocket)
|
||||
|
||||
```
|
||||
AI Application ←→ MCP Client ←→ Transport ←→ MCP Server ←→ External Service
|
||||
```
|
||||
|
||||
### Key Components
|
||||
|
||||
- **MCPServer**: Main server instance with configuration
|
||||
- **ToolProvider**: Tool specification and execution interface
|
||||
- **ResourceListProvider/ResourceReadHandler**: Resource access
|
||||
- **PromptListProvider/PromptGetHandler**: Template management
|
||||
- **Transport**: Communication mechanisms (stdio, HTTP)
|
||||
|
||||
## Implementation Patterns
|
||||
|
||||
### Tool Provider Pattern
|
||||
|
||||
Create tools with proper schema validation:
|
||||
|
||||
```java
|
||||
class WeatherToolProvider implements ToolProvider {
|
||||
|
||||
@Override
|
||||
public List<ToolSpecification> listTools() {
|
||||
return List.of(ToolSpecification.builder()
|
||||
.name("get_weather")
|
||||
.description("Get weather for a city")
|
||||
.inputSchema(Map.of(
|
||||
"type", "object",
|
||||
"properties", Map.of(
|
||||
"city", Map.of("type", "string", "description", "City name")
|
||||
),
|
||||
"required", List.of("city")
|
||||
))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String executeTool(String name, String arguments) {
|
||||
// Parse arguments and execute tool logic
|
||||
return "Weather data result";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Resource Provider Pattern
|
||||
|
||||
Provide static and dynamic resources:
|
||||
|
||||
```java
|
||||
class CompanyResourceProvider
|
||||
implements ResourceListProvider, ResourceReadHandler {
|
||||
|
||||
@Override
|
||||
public List<McpResource> listResources() {
|
||||
return List.of(
|
||||
McpResource.builder()
|
||||
.uri("policies")
|
||||
.name("Company Policies")
|
||||
.mimeType("text/plain")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readResource(String uri) {
|
||||
return loadResourceContent(uri);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Prompt Template Pattern
|
||||
|
||||
Create reusable prompt templates:
|
||||
|
||||
```java
|
||||
class PromptTemplateProvider
|
||||
implements PromptListProvider, PromptGetHandler {
|
||||
|
||||
@Override
|
||||
public List<Prompt> listPrompts() {
|
||||
return List.of(
|
||||
Prompt.builder()
|
||||
.name("code-review")
|
||||
.description("Review code for quality")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrompt(String name, Map<String, String> args) {
|
||||
return applyTemplate(name, args);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Transport Configuration
|
||||
|
||||
### Stdio Transport
|
||||
|
||||
Local process communication:
|
||||
|
||||
```java
|
||||
McpTransport transport = new StdioMcpTransport.Builder()
|
||||
.command(List.of("npm", "exec", "@modelcontextprotocol/server-everything"))
|
||||
.logEvents(true)
|
||||
.build();
|
||||
```
|
||||
|
||||
### HTTP Transport
|
||||
|
||||
Remote server communication:
|
||||
|
||||
```java
|
||||
McpTransport transport = new HttpMcpTransport.Builder()
|
||||
.sseUrl("http://localhost:3001/sse")
|
||||
.logRequests(true)
|
||||
.logResponses(true)
|
||||
.build();
|
||||
```
|
||||
|
||||
## Client Integration
|
||||
|
||||
### MCP Client Setup
|
||||
|
||||
Connect to MCP servers:
|
||||
|
||||
```java
|
||||
McpClient client = new DefaultMcpClient.Builder()
|
||||
.key("my-client")
|
||||
.transport(transport)
|
||||
.cacheToolList(true)
|
||||
.build();
|
||||
|
||||
// List available tools
|
||||
List<ToolSpecification> tools = client.listTools();
|
||||
```
|
||||
|
||||
### Tool Provider Integration
|
||||
|
||||
Bridge MCP servers to LangChain4j AI services:
|
||||
|
||||
```java
|
||||
McpToolProvider provider = McpToolProvider.builder()
|
||||
.mcpClients(mcpClient)
|
||||
.failIfOneServerFails(false)
|
||||
.filter((client, tool) -> filterByPermissions(tool))
|
||||
.build();
|
||||
|
||||
// Integrate with AI service
|
||||
AIAssistant assistant = AiServices.builder(AIAssistant.class)
|
||||
.chatModel(chatModel)
|
||||
.toolProvider(provider)
|
||||
.build();
|
||||
```
|
||||
|
||||
## Security & Best Practices
|
||||
|
||||
### Tool Security
|
||||
|
||||
Implement secure tool filtering:
|
||||
|
||||
```java
|
||||
McpToolProvider secureProvider = McpToolProvider.builder()
|
||||
.mcpClients(mcpClient)
|
||||
.filter((client, tool) -> {
|
||||
if (tool.name().startsWith("admin_") && !isAdmin()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.build();
|
||||
```
|
||||
|
||||
### Resource Security
|
||||
|
||||
Apply access controls to resources:
|
||||
|
||||
```java
|
||||
public boolean canAccessResource(String uri, User user) {
|
||||
return resourceService.hasAccess(uri, user);
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
Implement robust error handling:
|
||||
|
||||
```java
|
||||
try {
|
||||
String result = mcpClient.executeTool(request);
|
||||
} catch (McpException e) {
|
||||
log.error("MCP execution failed: {}", e.getMessage());
|
||||
return fallbackResult();
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced Patterns
|
||||
|
||||
### Multi-Server Configuration
|
||||
|
||||
Configure multiple MCP servers:
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public List<McpClient> mcpClients(List<ServerConfig> configs) {
|
||||
return configs.stream()
|
||||
.map(this::createMcpClient)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public McpToolProvider multiServerProvider(List<McpClient> clients) {
|
||||
return McpToolProvider.builder()
|
||||
.mcpClients(clients)
|
||||
.failIfOneServerFails(false)
|
||||
.build();
|
||||
}
|
||||
```
|
||||
|
||||
### Dynamic Tool Discovery
|
||||
|
||||
Runtime tool filtering based on context:
|
||||
|
||||
```java
|
||||
McpToolProvider contextualProvider = McpToolProvider.builder()
|
||||
.mcpClients(clients)
|
||||
.filter((client, tool) -> isToolAllowed(user, tool, context))
|
||||
.build();
|
||||
```
|
||||
|
||||
### Health Monitoring
|
||||
|
||||
Monitor MCP server health:
|
||||
|
||||
```java
|
||||
@Component
|
||||
public class McpHealthChecker {
|
||||
|
||||
@Scheduled(fixedRate = 30000) // 30 seconds
|
||||
public void checkServers() {
|
||||
mcpClients.forEach(client -> {
|
||||
try {
|
||||
client.listTools();
|
||||
markHealthy(client.key());
|
||||
} catch (Exception e) {
|
||||
markUnhealthy(client.key(), e.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Application Properties
|
||||
|
||||
Configure MCP servers in application.yml:
|
||||
|
||||
```yaml
|
||||
mcp:
|
||||
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
|
||||
|
||||
Configure MCP with Spring Boot:
|
||||
|
||||
```java
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(McpProperties.class)
|
||||
public class McpConfiguration {
|
||||
|
||||
@Bean
|
||||
public MCPServer mcpServer(List<ToolProvider> providers) {
|
||||
return MCPServer.builder()
|
||||
.server(new StdioServer.Builder())
|
||||
.addToolProvider(providers)
|
||||
.enableLogging(true)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Refer to [examples.md](./references/examples.md) for comprehensive implementation examples including:
|
||||
- Basic MCP server setup
|
||||
- Multi-tool enterprise servers
|
||||
- Resource and prompt providers
|
||||
- Spring Boot integration
|
||||
- Error handling patterns
|
||||
- Security implementations
|
||||
|
||||
## API Reference
|
||||
|
||||
Complete API documentation is available in [api-reference.md](./references/api-reference.md) covering:
|
||||
- Core MCP classes and interfaces
|
||||
- Transport configuration
|
||||
- Client and server patterns
|
||||
- Error handling strategies
|
||||
- Configuration management
|
||||
- Testing and validation
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Resource Management**: Always close MCP clients properly using try-with-resources
|
||||
2. **Error Handling**: Implement graceful degradation when servers fail
|
||||
3. **Security**: Use tool filtering and resource access controls
|
||||
4. **Performance**: Enable caching and optimize tool execution
|
||||
5. **Monitoring**: Implement health checks and observability
|
||||
6. **Testing**: Create comprehensive test suites with mocks
|
||||
7. **Documentation**: Document tools, resources, and prompts clearly
|
||||
8. **Configuration**: Use structured configuration for maintainability
|
||||
|
||||
## References
|
||||
|
||||
- [LangChain4j Documentation](https://langchain4j.com/docs/)
|
||||
- [Model Context Protocol Specification](https://modelcontextprotocol.org/)
|
||||
- [API Reference](./references/api-reference.md)
|
||||
- [Examples](./references/examples.md)
|
||||
@@ -0,0 +1,315 @@
|
||||
package com.example.mcp;
|
||||
|
||||
import dev.langchain4j.mcp.*;
|
||||
import dev.langchain4j.mcp.transport.*;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// Helper imports
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Template for creating MCP servers with LangChain4j.
|
||||
*
|
||||
* This template provides a starting point for building MCP servers with:
|
||||
* - Tool providers
|
||||
* - Resource providers
|
||||
* - Prompt providers
|
||||
* - Spring Boot integration
|
||||
* - Configuration management
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class MCPServerTemplate {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MCPServerTemplate.class, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure and build the main MCP server instance.
|
||||
*/
|
||||
@Bean
|
||||
public MCPServer mcpServer(
|
||||
List<ToolProvider> toolProviders,
|
||||
List<ResourceListProvider> resourceProviders,
|
||||
List<PromptListProvider> promptProviders) {
|
||||
|
||||
return MCPServer.builder()
|
||||
.server(new StdioServer.Builder())
|
||||
.addToolProvider(toolProviders)
|
||||
.addResourceProvider(resourceProviders)
|
||||
.addPromptProvider(promptProviders)
|
||||
.enableLogging(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure MCP clients for connecting to external MCP servers.
|
||||
*/
|
||||
@Bean
|
||||
public McpClient mcpClient() {
|
||||
StdioMcpTransport transport = new StdioMcpTransport.Builder()
|
||||
.command(List.of("npm", "exec", "@modelcontextprotocol/server-everything@0.6.2"))
|
||||
.logEvents(true)
|
||||
.build();
|
||||
|
||||
return new DefaultMcpClient.Builder()
|
||||
.key("template-client")
|
||||
.transport(transport)
|
||||
.cacheToolList(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure MCP tool provider for AI services integration.
|
||||
*/
|
||||
@Bean
|
||||
public McpToolProvider mcpToolProvider(McpClient mcpClient) {
|
||||
return McpToolProvider.builder()
|
||||
.mcpClients(mcpClient)
|
||||
.failIfOneServerFails(false)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example tool provider implementing a simple calculator.
|
||||
*/
|
||||
class CalculatorToolProvider implements ToolProvider {
|
||||
|
||||
@Override
|
||||
public List<ToolSpecification> listTools() {
|
||||
return List.of(
|
||||
ToolSpecification.builder()
|
||||
.name("add")
|
||||
.description("Add two numbers")
|
||||
.inputSchema(Map.of(
|
||||
"type", "object",
|
||||
"properties", Map.of(
|
||||
"a", Map.of("type", "number", "description", "First number"),
|
||||
"b", Map.of("type", "number", "description", "Second number")
|
||||
),
|
||||
"required", List.of("a", "b")
|
||||
))
|
||||
.build(),
|
||||
ToolSpecification.builder()
|
||||
.name("multiply")
|
||||
.description("Multiply two numbers")
|
||||
.inputSchema(Map.of(
|
||||
"type", "object",
|
||||
"properties", Map.of(
|
||||
"a", Map.of("type", "number", "description", "First number"),
|
||||
"b", Map.of("type", "number", "description", "Second number")
|
||||
),
|
||||
"required", List.of("a", "b")
|
||||
))
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String executeTool(String name, String arguments) {
|
||||
try {
|
||||
// Parse JSON arguments
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode argsNode = mapper.readTree(arguments);
|
||||
double a = argsNode.get("a").asDouble();
|
||||
double b = argsNode.get("b").asDouble();
|
||||
|
||||
switch (name) {
|
||||
case "add":
|
||||
return String.valueOf(a + b);
|
||||
case "multiply":
|
||||
return String.valueOf(a * b);
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown tool: " + name);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return "Error executing tool: " + e.getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example resource provider for static company information.
|
||||
*/
|
||||
class CompanyResourceProvider implements ResourceListProvider, ResourceReadHandler {
|
||||
|
||||
@Override
|
||||
public List<McpResource> listResources() {
|
||||
return List.of(
|
||||
McpResource.builder()
|
||||
.uri("company-info")
|
||||
.name("Company Information")
|
||||
.description("Basic company details and contact information")
|
||||
.mimeType("text/plain")
|
||||
.build(),
|
||||
McpResource.builder()
|
||||
.uri("policies")
|
||||
.name("Company Policies")
|
||||
.description("Company policies and procedures")
|
||||
.mimeType("text/markdown")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readResource(String uri) {
|
||||
switch (uri) {
|
||||
case "company-info":
|
||||
return loadCompanyInfo();
|
||||
case "policies":
|
||||
return loadPolicies();
|
||||
default:
|
||||
throw new ResourceNotFoundException("Resource not found: " + uri);
|
||||
}
|
||||
}
|
||||
|
||||
private String loadCompanyInfo() {
|
||||
return """
|
||||
Company Information:
|
||||
===================
|
||||
|
||||
Name: Example Corporation
|
||||
Founded: 2020
|
||||
Industry: Technology
|
||||
Employees: 100+
|
||||
|
||||
Contact:
|
||||
- Email: info@example.com
|
||||
- Phone: +1-555-0123
|
||||
- Website: https://example.com
|
||||
|
||||
Mission: To deliver innovative AI solutions
|
||||
""";
|
||||
}
|
||||
|
||||
private String loadPolicies() {
|
||||
return """
|
||||
Company Policies:
|
||||
=================
|
||||
|
||||
1. Code of Conduct
|
||||
- Treat all team members with respect
|
||||
- Maintain professional communication
|
||||
- Report any concerns to management
|
||||
|
||||
2. Security Policy
|
||||
- Use strong passwords
|
||||
- Enable 2FA when available
|
||||
- Report security incidents immediately
|
||||
|
||||
3. Work Environment
|
||||
- Flexible working hours
|
||||
- Remote work options
|
||||
- Support for continuous learning
|
||||
""";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example prompt template provider for common AI tasks.
|
||||
*/
|
||||
class PromptTemplateProvider implements PromptListProvider, PromptGetHandler {
|
||||
|
||||
@Override
|
||||
public List<Prompt> listPrompts() {
|
||||
return List.of(
|
||||
Prompt.builder()
|
||||
.name("code-review")
|
||||
.description("Review code for quality, security, and best practices")
|
||||
.build(),
|
||||
Prompt.builder()
|
||||
.name("documentation-generation")
|
||||
.description("Generate technical documentation from code")
|
||||
.build(),
|
||||
Prompt.builder()
|
||||
.name("bug-analysis")
|
||||
.description("Analyze and explain potential bugs in code")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrompt(String name, Map<String, String> arguments) {
|
||||
switch (name) {
|
||||
case "code-review":
|
||||
return createCodeReviewPrompt(arguments);
|
||||
case "documentation-generation":
|
||||
return createDocumentationPrompt(arguments);
|
||||
case "bug-analysis":
|
||||
return createBugAnalysisPrompt(arguments);
|
||||
default:
|
||||
throw new PromptNotFoundException("Prompt not found: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
private String createCodeReviewPrompt(Map<String, String> args) {
|
||||
String code = args.getOrDefault("code", "");
|
||||
String language = args.getOrDefault("language", "unknown");
|
||||
|
||||
return String.format("""
|
||||
Review the following %s code for quality, security, and best practices:
|
||||
|
||||
```%s
|
||||
%s
|
||||
```
|
||||
|
||||
Please analyze:
|
||||
1. Code quality and readability
|
||||
2. Security vulnerabilities
|
||||
3. Performance optimizations
|
||||
4. Best practices compliance
|
||||
5. Error handling
|
||||
|
||||
Provide specific recommendations for improvements.
|
||||
""", language, language, code);
|
||||
}
|
||||
|
||||
private String createDocumentationPrompt(Map<String, String> args) {
|
||||
String code = args.getOrDefault("code", "");
|
||||
String component = args.getOrDefault("component", "function");
|
||||
|
||||
return String.format("""
|
||||
Generate comprehensive documentation for the following %s:
|
||||
|
||||
```%s
|
||||
%s
|
||||
```
|
||||
|
||||
Include:
|
||||
1. Function/method signatures
|
||||
2. Parameters and return values
|
||||
3. Purpose and usage examples
|
||||
4. Dependencies and requirements
|
||||
5. Error conditions and handling
|
||||
""", component, "java", code);
|
||||
}
|
||||
|
||||
private String createBugAnalysisPrompt(Map<String, String> args) {
|
||||
String code = args.getOrDefault("code", "");
|
||||
|
||||
return String.format("""
|
||||
Analyze the following code for potential bugs and issues:
|
||||
|
||||
```java
|
||||
%s
|
||||
```
|
||||
|
||||
Look for:
|
||||
1. Null pointer exceptions
|
||||
2. Logic errors
|
||||
3. Resource leaks
|
||||
4. Race conditions
|
||||
5. Edge cases
|
||||
6. Type mismatches
|
||||
|
||||
Explain each issue found and suggest fixes.
|
||||
""", code);
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user