在技术选型上,Java 生态凭借其成熟的企业级能力和强大的类型系统,为构建生产就绪的 MCP 服务器提供了理想的基础。特别是 Spring AI 框架的 MCP 支持,让开发者能够基于熟悉的技术栈构建可靠、可扩展的智能服务。

在人工智能技术飞速发展的今天,大语言模型正在重塑我们与软件系统的交互方式。然而,这些强大的模型往往被困在”信息孤岛”中——它们拥有惊人的推理能力,却无法直接访问企业数据、业务系统或实时信息。这正是 Model Context Protocol (MCP) 要解决的核心问题。

MCP 正在成为连接 AI  模型与现实世界的标准化桥梁。这套专门为大语言模型设计的协议,为模型安全、一致地接入外部数据源和工具服务提供了统一的解决方案。想象一下,你的 AI 助手不仅能回答问题,还能直接查询数据库、调用业务接口、生成实时报告——这正是 MCP 带来的变革。

在技术选型上,Java 生态凭借其成熟的企业级能力和强大的类型系统,为构建生产就绪的 MCP 服务器提供了理想的基础。特别是 Spring AI 框架的 MCP 支持,让开发者能够基于熟悉的技术栈构建可靠、可扩展的智能服务。

一、深入理解 MCP 协议

MCP 不仅仅是一个技术协议,它代表了一种全新的 AI 应用架构思想。与传统的 REST API 不同,MCP 从设计之初就充分考虑了大语言模型的使用场景和特性。

协议设计的三个核心洞察:

  1. 语义化交互:MCP 使用工具(Tools)、资源(Resources)和提示模板(Prompts)这些对 AI 友好的抽象,让模型能够理解每个接口的用途和使用方式。
  2. 标准化通信:通过统一的 JSON-RPC 2. 0 协议,MCP 确保了不同系统之间的互操作性,避免了每个服务都要自定义接口的碎片化问题。
  3. 安全优先:MCP 内置了认证和授权机制,确保企业数据在 AI 交互过程中的安全性。

从技术实现视角看,MCP 的每个”能力”本质上都是一个精心设计的远程函数。开发者需要提供清晰的 Schema(定义输入输出结构)和丰富的元信息描述,让大语言模型能够理解:这个工具是做什么的?什么时候使用?需要什么参数?返回什么结果?

这种设计哲学使得 MCP 不仅是一个技术标准,更是一种促进人机协作的交互范式。它让 AI 系统从被动的问答机器转变为能够主动操作业务系统的智能助手。

二、Spring AI MCP技术优势

在技术选型过程中,我们选择了 Spring AI MCP 而非 Python 生态的 FastMCP,这背后有着深层的技术考量和企业需求分析。

为什么选择 Java + Spring AI 技术栈?

(1)类型安全的坚实保障

Java 的强类型系统在构建企业级应用时提供了无可替代的优势。编译期的类型检查能够捕获大部分潜在错误,这在处理复杂的业务逻辑和数据转换时尤为重要。想象一下,在金融或医疗等对准确性要求极高的场景中,类型安全不是可选项,而是必选项。

(2)成熟的依赖注入体系

Spring 框架的 IOC 容器让组件管理和依赖注入变得优雅而高效。这种设计模式特别适合 MCP 服务器的架构,因为工具服务通常需要依赖数据库连接、外部 API 客户端、配置管理等多个组件。

(3)企业集成的丰富生态

Spring 生态提供了与各种企业系统集成的成熟解决方案。无论是数据库访问(Spring Data)、消息队列(Spring  Integration)、安全认证(Spring Security)还是监控管理(Spring Boot  Actuator),都有现成的组件可以复用。

(4)生产环境的完备支持

从配置管理、健康检查到性能监控和日志追踪,Spring Boot 提供了一整套生产就绪的特性。这些功能对于确保 MCP 服务器在真实业务环境中的稳定运行至关重要。

(5)团队技术栈的延续性

对于已经拥有 Java 技术积累的团队,使用 Spring AI MCP 可以最大限度地利用现有知识和工具链,降低学习成本,加快项目交付速度。

三、实战演练

3.1 环境准备与项目初始化

让我们从最基础的环境搭建开始。首先确保你的开发环境满足以下要求:

  • JDK 17 或更高版本
  • Maven 3.6+ 或 Gradle 7+
  • 支持 Spring Boot 3.x 的 IDE

创建项目时,我们建议使用 Spring Initializr 生成项目骨架,确保依赖版本的一致性。在 pom.xml 中,除了基础的 Spring Boot 依赖,我们还需要添加 MCP 相关的特定依赖。

依赖选择的深层考量:

选择 spring-ai-mcp-server-spring-boot-starter 而不是基础的手动配置,是因为 starter 提供了自动配置、合理的默认值以及与 Spring 生态的无缝集成。这显著降低了配置复杂度,让开发者能够专注于业务逻辑的实现。

创建SpringBoot项目,添加如下核心依赖。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>3.2.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
        <version>1.0.0-M6</version>
    </dependency>
</dependencies>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

3.2 核心服务架构设计

在实现具体功能之前,我们需要理解 Spring AI MCP 服务器的核心架构组件:

// Application.java - 服务启动入口
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
publicclass Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public ToolCallbackProvider mathTools(MathService mathService) {
        return MethodToolCallbackProvider.builder()
                .toolObjects(mathService)
                .build();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

这个简单的启动类背后包含了 Spring AI MCP 的智能设计:

  • 自动配置机制:Spring Boot 会自动配置 MCP 服务器端点、消息处理和传输层
  • 工具发现系统:通过 ToolCallbackProvider 自动扫描和注册所有带有 @Tool 注解的方法
  • 生命周期管理:Spring 容器负责组件的创建、依赖注入和销毁

3.3 业务工具的实现

工具(Tools)是 MCP 服务器的核心能力载体。每个工具都应该设计得专注、可复用且易于理解。

// MathService.java - 数学计算工具
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;

@Service
publicclass MathService {

    @Tool(name = "add", description = "Add two integers and return the sum")
    public int add(
            @ToolParam(description = "First integer operand") int a,
            @ToolParam(description = "Second integer operand") int b) {
        // 输入验证和业务逻辑处理
        if (a < 0 || b < 0) {
            thrownew IllegalArgumentException("Negative numbers are not supported");
        }
        return a + b;
    }

    @Tool(name = "multiply", description = "Multiply two numbers and return the product")
    public double multiply(
            @ToolParam(description = "First number") double a,
            @ToolParam(description = "Second number") double b) {
        // 处理浮点数精度问题
        BigDecimal result = BigDecimal.valueOf(a).multiply(BigDecimal.valueOf(b));
        return result.doubleValue();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.

工具设计的最佳实践:

  1. 清晰的命名和描述:工具名称应该直观,描述应该准确说明功能、输入输出和可能的副作用。
  2. 完善的参数注解:每个参数都应该有详细的描述,帮助 AI 模型理解何时以及如何提供这个参数。
  3. 健壮的错误处理:工具应该能够处理各种边界情况,并提供有意义的错误信息。
  4. 性能考虑:对于可能被频繁调用的工具,要考虑性能优化和资源管理。

3.4 资源配置与管理策略

资源(Resources)在 MCP 中代表只读数据,它们可以是静态配置信息,也可以是基于参数的动态数据。

// ResourceService.java - 资源管理服务
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Service
publicclass ResourceService {

    @Tool(name = "get_version", description = "Retrieve current server version and build information")
    public Map<String, Object> getVersion() {
        return Map.of(
            "version", "1.0.0",
            "build_time", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
            "environment", "production"
        );
    }

    @Tool(name = "get_user_profile", description = "Retrieve detailed user profile information by user ID")
    public Map<String, Object> getUserProfile(
            @ToolParam(description = "Unique identifier of the user") int userId) {
        
        // 模拟从数据库或外部服务获取用户信息
        // 在实际项目中,这里会集成真实的数据源
        return Map.of(
            "user_id", userId,
            "name", "User " + userId,
            "status", "active",
            "created_at", "2024-01-01T00:00:00",
            "last_login", LocalDateTime.now().minusDays(1).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
            "permissions", new String[]{"read", "write", "execute"}
        );
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.

资源设计的关键考虑:

  1. 数据一致性:确保资源数据在不同调用之间保持一致
  2. 缓存策略:对于不经常变化的数据,考虑实现缓存机制
  3. 数据脱敏:敏感信息应该在返回前进行适当的脱敏处理
  4. 版本管理:资源结构的变化应该考虑版本兼容性

3.5 配置管理

MCP 服务器的配置管理需要平衡灵活性和严谨性。我们采用分层配置策略,适应不同环境的需求。

# application.yml - 基础配置
server:
port:8080
servlet:
    context-path:/api

spring:
application:
    name:mcp-server
ai:
    mcp:
      server:
        name:enterprise-mcp-server
        version:1.0.0
        type:ASYNC
        sse-endpoint:/sse
        sse-message-endpoint:/mcp/messages
        # 高级配置选项
        max-concurrent-requests:100
        request-timeout:30s

management:
endpoints:
    web:
      exposure:
        include:health,info,metrics,prometheus
endpoint:
    health:
      show-details:always
    metrics:
      enabled:true

logging:
level:
    org.springframework.ai:INFO
    com.yourcompany.mcp:DEBUG
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.

配置设计的工程考量:

  1. 环境隔离:使用 Spring Profile 管理不同环境的配置
  2. 安全敏感信息:密码、密钥等敏感信息应该通过环境变量或配置中心管理
  3. 性能调优参数:根据预期负载调整连接数、超时时间等参数
  4. 监控和可观测性:配置适当的日志级别和监控端点

四、高级特性与实践

4.1 上下文感知的智能工具

在复杂的业务场景中,工具往往需要访问会话上下文信息。Spring AI MCP 提供了强大的上下文支持。

// ContextAwareService.java - 上下文感知服务
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
publicclass ContextAwareService {
    
    privatefinal RestTemplate restTemplate;
    privatestaticfinal Logger logger = LoggerFactory.getLogger(ContextAwareService.class);
    
    public ContextAwareService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @Tool(name = "summarize_content", 
          description = "Fetch content from a URL and generate a concise summary")
    public String summarizeContent(
            @ToolParam(description = "URL of the content to summarize") String url) {
        
        // 记录详细的操作日志
        logger.info("Starting content summarization for URL: {}", url);
        long startTime = System.currentTimeMillis();
        
        try {
            // 验证 URL 格式
            if (!isValidUrl(url)) {
                thrownew IllegalArgumentException("Invalid URL format: " + url);
            }
            
            // 获取远程内容
            logger.debug("Fetching content from: {}", url);
            String content = fetchContentSafely(url);
            
            if (content == null || content.trim().isEmpty()) {
                return"No content available from the provided URL";
            }
            
            // 生成智能摘要
            String summary = generateIntelligentSummary(content);
            long processingTime = System.currentTimeMillis() - startTime;
            
            logger.info("Successfully summarized content in {} ms", processingTime);
            return String.format("Summary (%d chars): %s", summary.length(), summary);
            
        } catch (Exception e) {
            logger.error("Error summarizing content from URL: {}", url, e);
            return"Error processing content: " + e.getMessage();
        }
    }
    
    private boolean isValidUrl(String url) {
        return url != null && 
               (url.startsWith("http://") || url.startsWith("https://"));
    }
    
    private String fetchContentSafely(String url) {
        try {
            // 设置合理的超时时间
            return restTemplate.getForObject(url, String.class);
        } catch (Exception e) {
            logger.warn("Failed to fetch content from URL: {}", url, e);
            returnnull;
        }
    }
    
    private String generateIntelligentSummary(String content) {
        // 在实际项目中,这里可以集成 AI 摘要服务
        // 当前实现提供基础的文本处理
        String cleanContent = content.replaceAll("\\s+", " ").trim();
        
        // 智能截断,尽量在句子边界处断开
        int maxLength = 200;
        if (cleanContent.length() <= maxLength) {
            return cleanContent;
        }
        
        String truncated = cleanContent.substring(0, maxLength);
        int lastSentenceEnd = Math.max(
            truncated.lastIndexOf('.'),
            Math.max(
                truncated.lastIndexOf('!'),
                truncated.lastIndexOf('?')
            )
        );
        
        if (lastSentenceEnd > maxLength * 0.6) {
            return truncated.substring(0, lastSentenceEnd + 1) + "..";
        }
        
        return truncated + "...";
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.

4.2 安全架构与认证授权

在生产环境中,安全是不可妥协的要求。我们采用多层安全防护策略。

// SecurityConfig.java - 安全配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.config.http.SessionCreationPolicy;

@Configuration
@EnableWebSecurity
publicclass SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            // 禁用 CSRF,因为 MCP 使用无状态认证
            .csrf(csrf -> csrf.disable())
            
            // 配置会话管理为无状态
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            )
            
            // 配置请求授权
            .authorizeHttpRequests(authz -> authz
                // MCP 端点需要认证
                .requestMatchers("/mcp/**").authenticated()
                // 健康检查端点允许匿名访问
                .requestMatchers("/actuator/health").permitAll()
                // 其他 API 端点需要认证
                .requestMatchers("/api/**").authenticated()
                .anyRequest().permitAll()
            )
            
            // 配置 OAuth2 资源服务器
            .oauth2ResourceServer(oauth2 -> oauth2
                .jwt(jwt -> {
                    // JWT 配置可以在 application.yml 中指定
                })
            );
        
        return http.build();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.

安全设计的深度考量:

  1. 防御性编程:所有输入都应该验证,所有输出都应该过滤
  2. 最小权限原则:每个工具只应该拥有完成其功能所需的最小权限
  3. 审计日志:记录所有的敏感操作以便事后审计
  4. 密钥管理:使用专业的密钥管理服务,避免硬编码密钥

4.3 客户端集成与测试策略

一个完整的 MCP 解决方案需要强大的客户端支持和全面的测试覆盖。

// MCPClientService.java - 客户端服务
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
publicclass MCPClientService {
    
    privatefinal ChatClient chatClient;
    privatestaticfinal Logger logger = LoggerFactory.getLogger(MCPClientService.class);
    
    public MCPClientService(ChatClient chatClient) {
        this.chatClient = chatClient;
    }
    
    public String processNaturalLanguageQuery(String userQuery) {
        logger.info("Processing natural language query: {}", userQuery);
        
        try {
            String result = chatClient.prompt()
                    .user(userQuery)
                    .call()
                    .content();
            
            logger.debug("Successfully processed query, result length: {}", 
                        result != null ? result.length() : 0);
            return result;
            
        } catch (Exception e) {
            logger.error("Failed to process query: {}", userQuery, e);
            return"Sorry, I encountered an error while processing your request: " + 
                   e.getMessage();
        }
    }
}

// TestClient.java - 集成测试客户端
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

@Component
@Profile("dev") // 只在开发环境运行
publicclass TestClient implements CommandLineRunner {
    
    privatefinal MCPClientService clientService;
    
    public TestClient(MCPClientService clientService) {
        this.clientService = clientService;
    }
    
    @Override
    public void run(String... args) throws Exception {
        System.out.println("=== MCP Server Integration Tests ===");
        System.out.println();
        
        // 测试数学计算功能
        testMathOperations();
        
        // 测试资源访问功能  
        testResourceAccess();
        
        // 测试复杂查询处理
        testComplexQueries();
        
        System.out.println("=== All Tests Completed ===");
    }
    
    private void testMathOperations() {
        System.out.println("1. Testing Math Operations:");
        
        String[] mathQueries = {
            "Calculate 15 + 25",
            "What is 6.5 multiplied by 4.2?",
            "Add 100 and 200 together"
        };
        
        for (String query : mathQueries) {
            System.out.println("   Query: " + query);
            String result = clientService.processNaturalLanguageQuery(query);
            System.out.println("   Result: " + result);
            System.out.println();
        }
    }
    
    private void testResourceAccess() {
        System.out.println("2. Testing Resource Access:");
        
        String[] resourceQueries = {
            "What version is the server running?",
            "Get information for user ID 12345",
            "Show me the server status"
        };
        
        for (String query : resourceQueries) {
            System.out.println("   Query: " + query);
            String result = clientService.processNaturalLanguageQuery(query);
            System.out.println("   Result: " + result);
            System.out.println();
        }
    }
    
    private void testComplexQueries() {
        System.out.println("3. Testing Complex Queries:");
        
        String[] complexQueries = {
            "First add 10 and 20, then multiply the result by 3",
            "Get the server version and then show me user 999's profile"
        };
        
        for (String query : complexQueries) {
            System.out.println("   Query: " + query);
            String result = clientService.processNaturalLanguageQuery(query);
            System.out.println("   Result: " + result);
            System.out.println();
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.

4.4 与 LLM 应用集成

部署完成后,下一步是将 MCP 服务器集成到大语言模型应用中。以下示例展示如何与 OpenAI API 集成:

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.web.client.RestTemplate;
import org.springframework.stereotype.Service;

@Service
publicclass LLMIntegrationService {
    
    privatefinal ChatClient chatClient;
    privatefinal RestTemplate restTemplate;
    
    public LLMIntegrationService(ChatClient chatClient, RestTemplate restTemplate) {
        this.chatClient = chatClient;
        this.restTemplate = restTemplate;
    }
    
    public String processWithLLM(String userQuery) {
        // 使用 MCP 工具处理用户查询
        String toolResult = chatClient.prompt()
                .user(userQuery)
                .call()
                .content();
        
        // 将结果传递给 LLM 进行进一步处理
        String llmPrompt = String.format(
            "Based on the calculation result '%s', provide a user-friendly explanation of what this means in practical terms.",
            toolResult
        );
        
        // 调用外部 LLM API(示例使用模拟响应)
        return enhanceWithLLM(llmPrompt);
    }
    
    private String enhanceWithLLM(String prompt) {
        // 实际项目中这里会调用真实的 LLM API
        // 示例中使用模拟逻辑
        if (prompt.contains("calculation") || prompt.contains("result")) {
            return"The calculation has been completed successfully. This result can be used for further analysis or decision making.";
        }
        return"I've processed your request using the available tools. Is there anything else you'd like to know?";
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.

五、部署与运维

5.1 容器化与云原生部署

现代应用部署越来越倾向于容器化和云原生架构。以下是我们的 Docker 和 Kubernetes 配置实践。

Dockerfile 优化:

# 使用多阶段构建减小镜像大小
FROM eclipse-temurin:17-jdk as builder
WORKDIR /app
COPY . .
RUN ./mvnw clean package -DskipTests

# 生产阶段
FROM eclipse-temurin:17-jre
WORKDIR /app

# 创建非root用户运行应用
RUN groupadd -r spring && useradd -r -g spring spring
USER spring

# 复制构建产物
COPY --from=builder /app/target/*.jar app.jar

# 配置JVM参数
ENV JAVA_OPTS="-Xmx512m -Xms256m -XX:+UseG1GC -XX:MaxGCPauseMillis=100"

EXPOSE8080

# 使用 exec form 启动应用
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

Kubernetes 部署配置:

# deployment.yaml
apiVersion:apps/v1
kind:Deployment
metadata:
name:mcp-server
labels:
    app:mcp-server
spec:
replicas:3
selector:
    matchLabels:
      app:mcp-server
template:
    metadata:
      labels:
        app:mcp-server
      annotations:
        prometheus.io/scrape:"true"
        prometheus.io/port:"8080"
        prometheus.io/path:"/actuator/prometheus"
    spec:
      containers:
      -name:mcp-server
        image:your-registry/mcp-server:latest
        ports:
        -containerPort:8080
        env:
        -name:SPRING_PROFILES_ACTIVE
          value:"prod"
        -name:JAVA_OPTS
          value:"-Xmx512m -Xms256m"
        resources:
          requests:
            memory:"512Mi"
            cpu:"250m"
          limits:
            memory:"1Gi"
            cpu:"500m"
        livenessProbe:
          httpGet:
            path:/actuator/health
            port:8080
          initialDelaySeconds:60
          periodSeconds:10
        readinessProbe:
          httpGet:
            path:/actuator/health/readiness
            port:8080
          initialDelaySeconds:30
          periodSeconds:5
---
apiVersion:v1
kind:Service
metadata:
name:mcp-service
spec:
selector:
    app:mcp-server
ports:
-port:80
    targetPort:8080
type:ClusterIP
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.

5.2 监控与可观测性

在生产环境中,完善的监控体系是保证服务可靠性的关键。

应用监控配置:

# application-prod.yml - 生产环境监控配置
management:
endpoints:
    web:
      exposure:
        include:health,info,metrics,prometheus,loggers
endpoint:
    health:
      show-details:always
      show-components:always
    metrics:
      enabled:true
    prometheus:
      enabled:true
metrics:
    export:
      prometheus:
        enabled:true
    distribution:
      percentiles-histogram:
        "[http.server.requests]":true
    tags:
      application:${spring.application.name}
      environment:prod

logging:
level:
    org.springframework.ai:INFO
    com.yourcompany.mcp:INFO
pattern:
    level:"%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]"

# 自定义健康检查指标
endpoints:
health:
    custom:
      mcp-connection:
        enabled:true
      external-api:
        enabled:true
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.

六、总结

通过 Spring AI MCP,Java 开发者能够快速构建企业级的 MCP 服务器,为大型语言模型提供稳定可靠的外部能力接入。相比 Python 方案,Java 版本在类型安全、企业集成和生产就绪方面具有显著优势。

无论是构建内部 AI 助手还是开发面向客户的智能应用,Spring AI MCP 都提供了从概念验证到生产部署的完整技术路径。

文章来自:51CTO

Loading

作者 yinhua

发表回复