背景

       因為2025年初使用Spring AI 1.0.0-M6構建智能體項目,所以版本有Bug也得踩。項目本來使用模型工具來實現“動作”,為了使得工具定義更快,先決定引入MCP的方式加速模塊化開發。官方文檔翻來覆去看了幾十遍,百度、谷歌了幾十篇文檔,甚至Gemini、ChatGPT查詢好久。僅僅找找一篇構建MCP Server的有價值的文檔。現將全部實踐做記錄。

       追加多MCP動態接入擴展。

代碼

一、MCP Server 構建

①引入依賴(不要問為什麼引入這麼多,因為這是踩過坑的)  Spring AI 1.0.0-M6

	<dependency>
	    <groupId>org.springframework.ai</groupId>
	    <artifactId>spring-ai-mcp-server-webmvc-spring-boot-starter</artifactId>
	</dependency>
	
	<dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-mcp</artifactId>
	</dependency>
	<dependency>
        <groupId>com.openai</groupId>
        <artifactId>openai-java</artifactId>
        <version>0.32.0</version>
    </dependency>
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-actuator</artifactId>
	</dependency>

②配置文件


spring.ai.mcp.server.enabled=true

spring.ai.mcp.server.name= webmvc-mcp-server
spring.ai.mcp.server.version= 1.0.0
spring.ai.mcp.server.type= SYNC
#spring.ai.mcp.server.type= ASYNC 
spring.ai.mcp.server.sse-message-endpoint=/mcp/messages

# 暴露健康检查端点
management.endpoints.web.exposure.include=health

 ③配置類

@Configuration
@EnableWebMvc
public class McpServerConfig implements WebMvcConfigurer {

    @Bean
    public ToolCallbackProvider openLibraryTools(ToolServer toolServer) {

        return MethodToolCallbackProvider.builder().toolObjects(toolServer).build();

    }

}

④模型工具

@Service
public class WeatherService {

    @Tool(description = "Get weather information by city name")
    public String getWeather(String cityName) {
        
 
        return cityName+":"+simulateTempAtTime(2.0,25.0,10.0);
    }
    
    public static BigDecimal simulateTempAtTime(double time, double baseTemp, double tempRange) {
        double amplitude = tempRange / 2.0; // 振幅

        // 1. 基礎趨勢:使用 Cos 函數模擬日溫變化
        // 這裡使用 double time 計算,曲線會更平滑,支援非整點時刻
        double trend = -Math.cos((time - 2) * Math.PI / 12);

        // 2. 隨機噪音:模擬雲層或風導致的微小波動 (-0.5 ~ 0.5 度)
        double noise = ThreadLocalRandom.current().nextDouble(-0.5, 0.5);

        // 3. 計算最終溫度並格式化
        return BigDecimal.valueOf(baseTemp + (trend * amplitude) + noise)
                .setScale(1, RoundingMode.HALF_UP);
    }
}

二、MCP Client 構建

①引入依賴 Spring AI 1.0.0-SNAPSHOT

<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
  <version>1.0.0-SNAPSHOT</version>
</dependency>

②配置文件(注意從第二個Server開始需要增加配置,sse-endpoint)

spring.ai.mcp.client.enabled=true
spring.ai.mcp.client.name=my-mcp-client
spring.ai.mcp.client.request-timeout=60s
spring.ai.mcp.client.type=SYNC
spring.ai.mcp.client.sse.connections.server1.url= http://127.0.0.1:8888
spring.ai.mcp.client.sse.connections.server2.url= http://127.0.0.1:7777
spring.ai.mcp.client.sse.connections.server2.sse-endpoint=/server2-sse

③(可選)有些模型調用需要代理

@Configuration
public class McpClientWebClientConfig {

	
    @Bean
    @Primary  
    public WebClient.Builder mcpWebClientBuilder(
            @Qualifier("mcpHttpClient") HttpClient mcpHttpClient) {

        return WebClient.builder()
                .clientConnector(
                        new ReactorClientHttpConnector(mcpHttpClient)
                );
    }
    @Bean
    @Qualifier("mcpHttpClient")
    public HttpClient mcpHttpClient() {
        return HttpClient.create()
                .noProxy(); 
    }
}

④MCP Client 調用 MCP Server

	@Autowired
	private List<McpSyncClient> mcpSyncClients;  
	@Autowired
	private SyncMcpToolCallbackProvider toolCallbackProvider;
	
	
	@PostMapping("/a/chat")
	public String chat(/* @RequestBody SearchText searchRequest */) {
		ToolCallback[] toolCallbacks = toolCallbackProvider.getToolCallbacks();
		System.out.println(mcpSyncClients.toString());
		System.out.println(toolCallbacks.toString());
		
		return chatClient
	    .prompt("查詢重慶天氣信息")
	    .tools(toolCallbacks)
	    .call()
	    .content();
    }

三、智能體(或者MCP Client)如何動態接入多個MCP Server?

1.分析源碼,根據源碼新增配置類

@Configuration
public class DbMcpClientConfiguration {

    @Bean
    public List<NamedClientMcpTransport> dbMcpClientTransports(
            ObjectMapper objectMapper) {

        List<McpClientConfig> cfgs = new ArrayList<>();
        // cfgs = repository.findEnabled();
        McpClientConfig cfg1=new McpClientConfig();
        cfg1.setBaseUrl("http://127.0.0.1:8888");
        cfg1.setName("my-mcp-client");
        cfg1.setCode("mcp001");
        cfg1.setEnabled(true);
        cfg1.setTimeout(Duration.ofSeconds(30));
        cfg1.setVersion("1.0.1");
        cfgs.add(cfg1);
        List<NamedClientMcpTransport> transports = new ArrayList<>();

        for (McpClientConfig cfg : cfgs) {

            var transport = new HttpClientSseClientTransport(
                    HttpClient.newBuilder(),
                    cfg.getBaseUrl(),
                    objectMapper
            );

            transports.add(
                    new NamedClientMcpTransport(cfg.getCode(), transport)
            );
        }

        return transports;
    }
}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐