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,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)

View File

@@ -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);
}
}

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.