Kevin's blog Kevin's blog
首页
  • AI基础
  • RAG技术
  • 提示词工程
  • Wireshark抓包
  • 常见问题
  • 数据库
  • 代码技巧
  • 浏览器
  • 手册教程
  • 技术应用
  • 流程规范
  • github技巧
  • git笔记
  • vpn笔记
  • 知识概念
  • 学习笔记
  • 环境搭建
  • linux&运维
  • 微服务
  • 经验技巧
  • 实用手册
  • arthas常用
  • spring应用
  • javaAgent技术
  • 网站
友情链接
  • 分类
  • 标签
  • 归档

Kevin

你可以迷茫,但不可以虚度
首页
  • AI基础
  • RAG技术
  • 提示词工程
  • Wireshark抓包
  • 常见问题
  • 数据库
  • 代码技巧
  • 浏览器
  • 手册教程
  • 技术应用
  • 流程规范
  • github技巧
  • git笔记
  • vpn笔记
  • 知识概念
  • 学习笔记
  • 环境搭建
  • linux&运维
  • 微服务
  • 经验技巧
  • 实用手册
  • arthas常用
  • spring应用
  • javaAgent技术
  • 网站
友情链接
  • 分类
  • 标签
  • 归档
  • AI基础

  • 提示词

  • RAG技术

  • MCP技术

  • SpringAI

    • mcp

      • SpringAI-MCP-Server
      • Spring AI MCP 依赖配置指南
      • Spring AI MCP 完全开发指南
        • 🏗️ 项目架构概览
        • 📦 1. 项目初始化
          • 创建MCP服务器项目
          • 创建MCP客户端项目
        • 🔧 2. MCP服务器开发
          • 2.1 基础配置
          • 2.2 工具开发
          • 方式1:使用@Tool注解 (推荐)
          • 方式2:ToolCallbackProvider注册
          • 2.3 启动类
        • 🔌 3. MCP客户端开发
          • 3.1 基础配置
          • 3.2 自动Bean注入
          • 3.3 与ChatClient集成
          • 3.4 启动类
        • 🎯 4. 高级功能开发
          • 4.1 自定义客户端配置
          • 4.2 资源管理
          • 4.3 提示模板管理
        • 🚀 5. 部署与运行
          • 5.1 本地开发
          • 5.2 测试验证
          • 5.3 Docker部署
        • 📊 6. 监控与调试
          • 6.1 健康检查
          • 6.2 监控端点
        • 🎯 7. 最佳实践
          • 7.1 错误处理
          • 7.2 参数验证
          • 7.3 性能优化
        • 🔗 参考资源
  • AI
  • SpringAI
  • mcp
kevin
2025-06-06
目录

Spring AI MCP 完全开发指南

# Spring AI MCP 完全开发指南

官方标准实现 - 基于Spring AI官方文档 (opens new window)的最佳实践

# 🏗️ 项目架构概览

image-20250606112529297

graph TB
    subgraph "MCP生态系统"
        Client[MCP客户端<br/>spring-ai-starter-mcp-client]
        Server[MCP服务器<br/>spring-ai-starter-mcp-server-webmvc]
        
        Client -->|SSE连接| Server
        Client -->|工具调用| Server
        Server -->|工具响应| Client
    end
    
    subgraph "Spring AI集成"
        ChatClient[ChatClient]
        ToolCallbacks[ToolCallbacks]
        
        Client --> ToolCallbacks
        ToolCallbacks --> ChatClient
    end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 📦 1. 项目初始化

# 创建MCP服务器项目

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.4</version>
        <relativePath/>
    </parent>
    
    <groupId>com.example</groupId>
    <artifactId>mcp-server-demo</artifactId>
    <version>1.0.0</version>
    <name>MCP Server Demo</name>
    
    <properties>
        <java.version>17</java.version>
        <spring-ai.version>1.1.0-SNAPSHOT</spring-ai.version>
    </properties>
    
    <dependencies>
        <!-- MCP服务器 WebMVC Starter -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>
    </dependencies>
</project>
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

# 创建MCP客户端项目

<dependencies>
    <!-- Web支持 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- MCP客户端 Starter -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-client</artifactId>
        <version>${spring-ai.version}</version>
    </dependency>
    
    <!-- Spring AI Chat (可选 - 用于LLM集成) -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
        <version>${spring-ai.version}</version>
    </dependency>
</dependencies>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 🔧 2. MCP服务器开发

# 2.1 基础配置

# application.yml
spring:
  ai:
    mcp:
      server:
        name: demo-server
        version: 1.0.0
        instructions: "这是一个演示服务器,提供计算和文本处理工具"
        
        # SSE端点配置 (自动配置,可自定义)
        sse-endpoint: /sse
        sse-message-endpoint: /mcp/message
        
        # 能力配置
        capabilities:
          tool: true
          resource: true
          prompt: true
          completion: true

# 服务器端口
server:
  port: 9099
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 2.2 工具开发

# 方式1:使用@Tool注解 (推荐)

@Service
public class CalculatorService {
    
    @Tool(description = "计算两个数字的和")
    public double add(
        @Parameter(description = "第一个数字") double a,
        @Parameter(description = "第二个数字") double b) {
        return a + b;
    }
    
    @Tool(description = "计算数字的幂运算")
    public double power(
        @Parameter(description = "底数") double base,
        @Parameter(description = "指数") double exponent) {
        return Math.pow(base, exponent);
    }
}

@Service  
public class TextService {
    
    @Tool(description = "将文本转换为大写")
    public String uppercase(@Parameter(description = "要转换的文本") String text) {
        return text.toUpperCase();
    }
    
    @Tool(description = "分析文本,返回字符数、单词数等统计信息") 
    public String analyzeText(@Parameter(description = "要分析的文本") String text) {
        long charCount = text.length();
        long wordCount = text.trim().isEmpty() ? 0 : text.trim().split("\\s+").length;
        long lineCount = text.split("\n").length;
        
        return String.format("文本分析结果:\n- 字符数: %d\n- 单词数: %d\n- 行数: %d\n- 是否为空: %s\n",
            charCount, wordCount, lineCount, text.trim().isEmpty() ? "是" : "否");
    }
}
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

# 方式2:ToolCallbackProvider注册

@Configuration
public class McpToolsConfiguration {
    
    @Bean
    public ToolCallbackProvider calculatorTools(CalculatorService calculatorService) {
        return MethodToolCallbackProvider.builder()
            .toolObjects(calculatorService)
            .build();
    }
    
    @Bean
    public ToolCallbackProvider textTools(TextService textService) {
        return MethodToolCallbackProvider.builder()
            .toolObjects(textService)
            .build();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 2.3 启动类

@SpringBootApplication
public class McpServerDemoApplication {
    
    private static final Logger logger = LoggerFactory.getLogger(McpServerDemoApplication.class);
    
    public static void main(String[] args) {
        SpringApplication.run(McpServerDemoApplication.class, args);
        logger.info("🚀 MCP服务器已启动 - 端口: 9099");
        logger.info("📡 SSE端点: http://localhost:9099/sse");
        logger.info("💬 消息端点: http://localhost:9099/mcp/message");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 🔌 3. MCP客户端开发

# 3.1 基础配置

# application.yml
spring:
  ai:
    mcp:
      client:
        # 基础配置
        name: demo-client
        type: SYNC
        request-timeout: 30s
        
        # 工具集成 (自动启用)
        toolcallback:
          enabled: true
        
        # SSE连接配置
        sse:
          connections:
            demo-server:
              url: http://localhost:9099
              sse-endpoint: /sse

# 客户端端口
server:
  port: 8080

# OpenAI配置 (可选)
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
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

# 3.2 自动Bean注入

@RestController
@RequestMapping("/api/mcp")
public class McpController {
    
    // 自动注入MCP客户端
    @Autowired
    private List<McpSyncClient> mcpClients;
    
    // 自动注入工具提供者
    @Autowired
    private SyncMcpToolCallbackProvider toolCallbackProvider;
    
    /**
     * 获取可用工具列表
     */
    @GetMapping("/tools")
    public Map<String, Object> getTools() {
        ToolCallback[] tools = toolCallbackProvider.getToolCallbacks();
        
        return Map.of(
            "toolCount", tools.length,
            "tools", Arrays.stream(tools)
                .map(tool -> Map.of(
                    "name", tool.getToolDefinition().name(),
                    "description", tool.getToolDefinition().description()
                ))
                .toList()
        );
    }
    
    /**
     * 调用MCP工具
     */
    @PostMapping("/call/{toolName}")
    public Map<String, Object> callTool(
            @PathVariable String toolName,
            @RequestBody Map<String, Object> arguments) {
        
        try {
            ToolCallback[] tools = toolCallbackProvider.getToolCallbacks();
            
            for (ToolCallback tool : tools) {
                if (tool.getToolDefinition().name().equals(toolName)) {
                    String result = tool.call(new ObjectMapper().writeValueAsString(arguments));
                    return Map.of("success", true, "result", result);
                }
            }
            
            return Map.of("success", false, "error", "工具不存在: " + toolName);
            
        } catch (Exception e) {
            return Map.of("success", false, "error", e.getMessage());
        }
    }
}
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

# 3.3 与ChatClient集成

@Service
public class ChatService {
    
    private final ChatClient chatClient;
    
    public ChatService(ChatClient.Builder chatClientBuilder, 
                      SyncMcpToolCallbackProvider toolCallbackProvider) {
        // 自动集成MCP工具到ChatClient
        this.chatClient = chatClientBuilder
            .defaultToolCallbacks(toolCallbackProvider.getToolCallbacks())
            .build();
    }
    
    public String chat(String message) {
        return chatClient.prompt()
            .user(message)
            .call()
            .content();
    }
}

@RestController
@RequestMapping("/api/chat")
public class ChatController {
    
    @Autowired
    private ChatService chatService;
    
    @PostMapping
    public Map<String, String> chat(@RequestBody Map<String, String> request) {
        String response = chatService.chat(request.get("message"));
        return Map.of("response", response);
    }
}
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

# 3.4 启动类

@SpringBootApplication
public class McpClientDemoApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(McpClientDemoApplication.class, args);
    }
}
1
2
3
4
5
6
7

# 🎯 4. 高级功能开发

# 4.1 自定义客户端配置

@Component
public class CustomMcpClientCustomizer implements McpSyncClientCustomizer {
    
    @Override
    public void customize(String serverConfigurationName, McpClient.SyncSpec spec) {
        
        // 自定义请求超时
        spec.requestTimeout(Duration.ofSeconds(30));
        
        // 工具变更通知
        spec.toolsChangeConsumer(tools -> {
            log.info("🔧 服务器 {} 工具列表已更新,共 {} 个工具", 
                serverConfigurationName, tools.size());
        });
        
        // 资源变更通知
        spec.resourcesChangeConsumer(resources -> {
            log.info("📁 服务器 {} 资源列表已更新,共 {} 个资源", 
                serverConfigurationName, resources.size());
        });
        
        // 日志处理
        spec.loggingConsumer(logNotification -> {
            log.info("📝 来自服务器 {} 的日志: [{}] {}", 
                serverConfigurationName, 
                logNotification.level(), 
                logNotification.data());
        });
    }
}
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

# 4.2 资源管理

@Configuration
public class McpResourcesConfiguration {
    
    @Bean
    public List<McpServerFeatures.SyncResourceSpecification> systemResources() {
        var systemInfoResource = new McpSchema.Resource(
            "system://info",
            "系统信息",
            "获取当前系统的基本信息",
            "application/json"
        );
        
        var resourceSpec = new McpServerFeatures.SyncResourceSpecification(
            systemInfoResource, 
            (exchange, request) -> {
                var systemInfo = Map.of(
                    "timestamp", Instant.now().toString(),
                    "javaVersion", System.getProperty("java.version"),
                    "osName", System.getProperty("os.name"),
                    "availableProcessors", Runtime.getRuntime().availableProcessors(),
                    "maxMemory", Runtime.getRuntime().maxMemory()
                );
                
                String jsonContent = new ObjectMapper().writeValueAsString(systemInfo);
                return new McpSchema.ReadResourceResult(List.of(
                    new McpSchema.TextResourceContents(request.uri(), "application/json", jsonContent)
                ));
            }
        );
        
        return List.of(resourceSpec);
    }
}
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

# 4.3 提示模板管理

@Configuration  
public class McpPromptsConfiguration {
    
    @Bean
    public List<McpServerFeatures.SyncPromptSpecification> greetingPrompts() {
        var prompt = new McpSchema.Prompt(
            "greeting",
            "友好问候提示模板",
            List.of(new McpSchema.PromptArgument("name", "要问候的姓名", true))
        );
        
        var promptSpec = new McpServerFeatures.SyncPromptSpecification(
            prompt,
            (exchange, request) -> {
                String name = (String) request.arguments().get("name");
                if (name == null) name = "朋友";
                
                var message = new PromptMessage(
                    Role.USER, 
                    new TextContent("你好 " + name + "!今天我可以为您做些什么?")
                );
                
                return new GetPromptResult("个性化问候消息", List.of(message));
            }
        );
        
        return List.of(promptSpec);
    }
}
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

# 🚀 5. 部署与运行

# 5.1 本地开发

# 启动服务器
cd mcp-server-demo
mvn spring-boot:run

# 启动客户端 (新终端)
cd mcp-client-demo  
mvn spring-boot:run
1
2
3
4
5
6
7

# 5.2 测试验证

# 检查工具列表
curl http://localhost:8080/api/mcp/tools

# 调用计算工具
curl -X POST http://localhost:8080/api/mcp/call/add \
  -H "Content-Type: application/json" \
  -d '{"a": 15, "b": 25}'

# 调用文本工具
curl -X POST http://localhost:8080/api/mcp/call/uppercase \
  -H "Content-Type: application/json" \
  -d '{"text": "hello world"}'

# 测试AI聊天 (如果配置了LLM)
curl -X POST http://localhost:8080/api/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "请计算15加25等于多少"}'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 5.3 Docker部署

Dockerfile (服务器):

FROM openjdk:17-jre-slim
COPY target/mcp-server-demo-1.0.0.jar app.jar
EXPOSE 9099
ENTRYPOINT ["java", "-jar", "/app.jar"]
1
2
3
4

docker-compose.yml:

version: '3.8'
services:
  mcp-server:
    build: ./mcp-server-demo
    ports:
      - "9099:9099"
    environment:
      - SPRING_PROFILES_ACTIVE=docker
      
  mcp-client:
    build: ./mcp-client-demo
    ports:
      - "8080:8080"
    depends_on:
      - mcp-server
    environment:
      - SPRING_AI_MCP_CLIENT_SSE_CONNECTIONS_DEMO-SERVER_URL=http://mcp-server:9099
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 📊 6. 监控与调试

# 6.1 健康检查

@Component
public class McpHealthIndicator implements HealthIndicator {
    
    @Autowired
    private List<McpSyncClient> mcpClients;
    
    @Override
    public Health health() {
        try {
            boolean allHealthy = mcpClients.stream()
                .allMatch(client -> {
                    // 检查客户端连接状态
                    return true; // 实际实现中检查连接状态
                });
                
            return allHealthy ? 
                Health.up().withDetail("clients", mcpClients.size()).build() :
                Health.down().withDetail("issue", "某些MCP客户端连接异常").build();
                
        } catch (Exception e) {
            return Health.down().withException(e).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

# 6.2 监控端点

# 启用监控端点
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,mcptools
  endpoint:
    health:
      show-details: always
1
2
3
4
5
6
7
8
9

# 🎯 7. 最佳实践

# 7.1 错误处理

@Tool(description = "安全的除法运算")
public double divide(
    @Parameter(description = "被除数") double dividend,
    @Parameter(description = "除数") double divisor) {
    
    if (divisor == 0) {
        throw new IllegalArgumentException("除数不能为零");
    }
    
    return dividend / divisor;
}
1
2
3
4
5
6
7
8
9
10
11

# 7.2 参数验证

@Tool(description = "验证邮箱格式")
public String validateEmail(@Parameter(description = "邮箱地址") String email) {
    if (email == null || email.trim().isEmpty()) {
        return "邮箱地址不能为空";
    }
    
    String emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$";
    if (email.matches(emailRegex)) {
        return "邮箱格式正确: " + email;
    } else {
        return "邮箱格式错误: " + email;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 7.3 性能优化

// 异步工具执行
@Tool(description = "大文件处理")
public CompletableFuture<String> processLargeFile(
    @Parameter(description = "文件路径") String filePath) {
    
    return CompletableFuture.supplyAsync(() -> {
        // 耗时处理逻辑
        return "文件处理完成: " + filePath;
    });
}
1
2
3
4
5
6
7
8
9
10

# 🔗 参考资源

  • Spring AI MCP官方文档 (opens new window)
  • MCP协议规范 (opens new window)
  • Spring Boot自动配置指南 (opens new window)
  • Spring AI工具调用文档 (opens new window)
上次更新: 2025/06/06, 11:28:26
Spring AI MCP 依赖配置指南

← Spring AI MCP 依赖配置指南

最近更新
01
AI是如何学习的
06-06
02
提示词工程实践指南
06-06
03
chatGpt提示原则
06-06
更多文章>
| Copyright © 2022-2025 Kevin | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式