
Langchain4j Mcp Server Patterns
- 1.6k installs
- 311 repo stars
- Updated June 22, 2026
- giuseppe-trisciuoglio/developer-kit
langchain4j-mcp-server-patterns is an agent skill that provides langchain4j patterns for implementing mcp (model context protocol) servers, creating java ai tools, exposing tool calling capabilities, and integrating mcp
About
langchain4j-mcp-server-patterns is an agent skill from giuseppe-trisciuoglio/developer-kit that provides langchain4j patterns for implementing mcp (model context protocol) servers, creating java ai tools, exposing tool calling capabilities, and integrating mcp clients with ai services. use when . # LangChain4j MCP Server Implementation Patterns ## Overview Use this skill to design and implement Model Context Protocol (MCP) integrations with LangChain4j. The main concerns are: - defining a clean tool, resource, and prompt surface - choosing the right transport and bootstrap model - filtering unsafe capabilities before exposing them to age Developers invoke langchain4j-mcp-server-patterns during build/backend work for backend & apis tasks. The skill documents triggers, prerequisites, and step-by-step workflows grounded in SKILL.md. Compatible with Claude Code, Cursor, and Codex agent runtimes that load marketplace skills. Review the Security Audits panel on this listing before installing in production environments.
- LangChain4j MCP Server Implementation Patterns
- Use this skill to design and implement Model Context Protocol (MCP) integrations with LangChain4j.
- defining a clean tool, resource, and prompt surface
- choosing the right transport and bootstrap model
- filtering unsafe capabilities before exposing them to agents or applications
Langchain4j Mcp Server Patterns by the numbers
- 1,623 all-time installs (skills.sh)
- +55 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #287 of 4,386 Backend & APIs skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
langchain4j-mcp-server-patterns capabilities & compatibility
- Capabilities
- langchain4j mcp server implementation patterns · use this skill to design and implement model con · defining a clean tool, resource, and prompt surf · choosing the right transport and bootstrap model · filtering unsafe capabilities before exposing th
- Use cases
- orchestration
What langchain4j-mcp-server-patterns says it does
Use this skill to design and implement Model Context Protocol (MCP) integrations with LangChain4j.
- defining a clean tool, resource, and prompt surface
- choosing the right transport and bootstrap model
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill langchain4j-mcp-server-patternsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.6k |
|---|---|
| repo stars | ★ 311 |
| Security audit | 2 / 3 scanners passed |
| Last updated | June 22, 2026 |
| Repository | giuseppe-trisciuoglio/developer-kit ↗ |
What it does
Provides LangChain4j patterns for implementing MCP (Model Context Protocol) servers, creating Java AI tools, exposing tool calling capabilities, and integrating MCP clients with AI services. Use when
Who is it for?
Developers working on backend & apis during build tasks.
Skip if: Tasks outside Backend & APIs scope described in SKILL.md.
When should I use this skill?
Provides LangChain4j patterns for implementing MCP (Model Context Protocol) servers, creating Java AI tools, exposing tool calling capabilities, and integrating MCP clients with AI services. Use when
What you get
Completed backend & apis workflow aligned with SKILL.md steps.
- MCP server Spring Boot project
- tool/resource/prompt provider beans
By the numbers
- Scaffolds 3 MCP provider types: tools, resources, and prompts
Files
LangChain4j MCP Server Implementation Patterns
Overview
Use this skill to design and implement Model Context Protocol (MCP) integrations with LangChain4j.
The main concerns are:
- defining a clean tool, resource, and prompt surface
- choosing the right transport and bootstrap model
- filtering unsafe capabilities before exposing them to agents or applications
Keep SKILL.md focused on the implementation flow. Use the bundled references for expanded examples and API-level detail.
When to Use
Use this skill when:
- building a Java MCP server that exposes tools, resources, or prompts
- integrating LangChain4j with one or more external MCP servers
- wiring MCP support into a Spring Boot application
- filtering available tools by tenant, user role, or runtime context
- adding observability, resilience, and safe failure handling around MCP interactions
- reviewing an MCP integration for prompt-injection and side-effect risks
Typical trigger phrases include langchain4j mcp, java mcp server, mcp tool provider, spring boot mcp, and connect langchain4j to mcp.
Instructions
1. Design the MCP surface before writing code
Decide what the server should expose:
- tools for actions with clear inputs and side effects
- resources for read-only or structured data access
- prompts only when a reusable template adds real value
Keep names stable, descriptions concrete, and schemas small enough for a client or model to understand quickly.
2. Implement providers with narrow responsibilities
Use separate classes for each concern:
- tool provider for executable functions
- resource provider for discoverable and readable data
- prompt provider for reusable prompt templates
Validate arguments before execution and return clear error messages for invalid input or unavailable dependencies.
3. Choose the transport intentionally
Use:
- stdio for local integrations, CLI tools, and sidecar processes
- HTTP or SSE for remote or shared services
Pin external server versions and document how the process is started, authenticated, and monitored.
4. Bridge MCP into LangChain4j carefully
When consuming MCP servers from LangChain4j:
- initialize clients during application startup
- cache tool lists only when stale metadata is acceptable
- filter tools by trust level, environment, or user permissions
- fail closed for dangerous tools rather than exposing everything by default
5. Add resilience and security controls
At minimum:
- bound execution time for external calls
- log server and tool identity for each failure
- sanitize content returned by external resources before using it downstream
- isolate privileged tools behind allowlists, qualifiers, or role checks
6. Validate the full workflow
Before shipping:
- verify tool discovery and invocation with a real MCP client
- test disconnected or slow server behavior
- confirm that tool filtering matches the intended authorization model
- check that prompts and resources do not leak secrets or unsafe instructions
Examples
Example 1: Minimal tool provider and stdio server bootstrap
class WeatherToolProvider implements ToolProvider {
@Override
public List<ToolSpecification> listTools() {
return List.of(
ToolSpecification.builder()
.name("get_weather")
.description("Return the current weather for a city")
.inputSchema(Map.of(
"type", "object",
"properties", Map.of(
"city", Map.of("type", "string")
),
"required", List.of("city")
))
.build()
);
}
@Override
public String executeTool(String name, String arguments) {
return weatherService.lookup(arguments);
}
}
MCPServer server = MCPServer.builder()
.server(new StdioServer.Builder())
.addToolProvider(new WeatherToolProvider())
.build();
server.start();Use this pattern for local tool execution or a sidecar process started by another application.
Example 2: Expose MCP tools to a LangChain4j AI service with filtering
McpToolProvider toolProvider = McpToolProvider.builder()
.mcpClients(mcpClients)
.failIfOneServerFails(false)
.filter((client, tool) -> !tool.name().startsWith("admin_"))
.build();
Assistant assistant = AiServices.builder(Assistant.class)
.chatModel(chatModel)
.toolProvider(toolProvider)
.build();Use this pattern when you want LangChain4j to consume external MCP servers while still enforcing trust boundaries.
Best Practices
- Keep each tool focused, deterministic, and well-described.
- Prefer explicit schemas over free-form string arguments.
- Separate read-only resources from tools with side effects.
- Filter or disable privileged tools by default.
- Pin external MCP server packages or container versions.
- Capture metrics for connection failures, invocation latency, and tool error rates.
- Store longer protocol details and framework-specific wiring in
references/instead of expandingSKILL.mdindefinitely.
Constraints and Warnings
- External MCP servers are untrusted integration boundaries and may expose malicious or misleading content.
- Do not forward raw resource content directly into autonomous tool execution without validation.
- Some LangChain4j and MCP APIs evolve quickly; adapt class names and builders to the versions already used in the project.
- Long-running or stateful tools need explicit timeout, cancellation, and cleanup behavior.
- Stdio-based servers require process lifecycle management and robust logging.
References
references/examples.mdreferences/api-reference.md
Related Skills
prompt-engineeringspring-aiclean-architecture
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);
}
}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:
// 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:
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:
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.
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.
McpTransport transport = new HttpMcpTransport.Builder()
.sseUrl("http://localhost:3001/sse")
.logRequests(true)
.logResponses(true)
.build();StreamableHttpMcpTransport.Builder
For streamable HTTP transport with enhanced performance.
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:
AIAssistant assistant = AiServices.builder(AIAssistant.class)
.chatModel(chatModel)
.toolProvider(toolProvider)
.chatMemoryProvider(memoryProvider)
.build();Error Handling and Management
Exception Handling
Handle MCP-specific exceptions gracefully:
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:
RetryTemplate retryTemplate = RetryTemplate.builder()
.maxAttempts(3)
.exponentialBackoff(1000, 2, 10000)
.build();
String result = retryTemplate.execute(context ->
mcpClient.executeTool(request));Configuration Properties
Application Configuration
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@0.6.2"]
log-events: falseSpring Boot Configuration
@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:
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:
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:
// 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:
DefaultMcpResourcesAsToolsPresenter presenter =
new DefaultMcpResourcesAsToolsPresenter();
mcpToolProvider.provideTools(presenter);
// Adds 'list_resources' and 'get_resource' tools automaticallySecurity and Filtering
Tool Filtering
Implement security-conscious tool filtering:
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:
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:
// 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:
@Bean
public Executor mcpExecutor() {
return Executors.newFixedThreadPool(10); // Dedicated thread pool
}Testing and Validation
Mock Configuration
Setup for testing:
@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:
@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:
@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:
@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:
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.
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:
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:
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:
@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:
@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:
@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:
@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:
@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:
@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:
@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.
Related skills
Forks & variants (1)
Langchain4j Mcp Server Patterns has 1 known copy in the catalog totaling 21 installs. They canonicalize to this original listing.
- giuseppe-trisciuoglio - 21 installs
FAQ
What does langchain4j-mcp-server-patterns do?
Provides LangChain4j patterns for implementing MCP (Model Context Protocol) servers, creating Java AI tools, exposing tool calling capabilities, and integrating MCP clients with AI services. Use when
When should I use langchain4j-mcp-server-patterns?
During build backend work for backend & apis.
Is langchain4j-mcp-server-patterns safe to install?
Review the Security Audits panel on this listing before production use.