主要观点总结
本文介绍了Java开发者在MCP(Model Context Protocol)生态中的实践路径,从背景调研到技术验证,从Spring AI的局限性到原生MCP SDK的深度整合,实现了Java客户端与Python服务端的无缝协作。证明了MCP协议的跨语言通用性,为企业级Java应用对接主流AI工具链提供了可复用的解决方案。未来展望包括解决Spring AI的兼容性问题,标准化各语言SDK,以及社区共建与工具链完善。
关键观点总结
关键观点1: 背景调研与技术验证
文章通过调研发现Java与MCP结合的资料很少,决定探索Java开发者使用MCP的路径,并验证其可行性。
关键观点2: Spring AI的局限性
文章发现Spring AI对MCP的封装存在兼容性问题,导致Java客户端与Python服务端通信时出现问题。
关键观点3: 原生MCP SDK的深度整合
文章通过使用原生MCP SDK和OpenAI Java SDK实现了Java客户端与Python服务端的无缝协作,验证了MCP协议的跨语言通用性。
关键观点4: 企业级应用扩展
文章讨论了未来企业级应用扩展的可能性,包括性能优化、安全增强、可观测性,以及社区共建与工具链完善。
正文
longitude) {
return
"当前位置(纬度:"
+ latitude +
",经度:"
+ longitude +
")的空气质量:\n"
+
"- PM2.5: 15 μg/m³ (优)\n"
+
"- PM10: 28 μg/m³ (良)\n"
+
"- 空气质量指数(AQI): 42 (优)\n"
+
"- 主要污染物: 无"
;
}
}
启动类:
package com.alibaba.damo.mcpserver;
import com.alibaba.damo.mcpserver.service.OpenMeteoService;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.reactive.function.client.WebClient;
@SpringBootApplication
publicclassMcpServerApplication {
publicstaticvoidmain(String[] args){
SpringApplication.run(McpServerApplication.class, args);
}
@Bean
public ToolCallbackProvider weatherTools(OpenMeteoService openMeteoService){
return MethodToolCallbackProvider.builder()
.toolObjects(openMeteoService)
.build();
}
@Bean
public WebClient.Builder webClientBuilder(){
return WebClient.builder();
}
}
配置文件:
server.port=8080
spring.ai.mcp.server.name=my-weather-server
spring.ai.mcp.server.version=0.0.1
依赖:
"1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.alibaba.damogroupId>
<artifactId>mcp-serverartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>mcp-servername>
<description>mcp-serverdescription>
<properties>
<java.version>17java.version>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<spring-boot.version>3.0.2spring-boot.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.aigroupId>
<artifactId
>spring-ai-starter-mcp-server-webfluxartifactId>
<version>1.0.0-M7version>
dependency>
<dependency>
<groupId>io.nettygroupId>
<artifactId>netty-resolver-dns-native-macosartifactId>
<version>4.1.79.Finalversion>
<scope>runtimescope>
<classifier>osx-aarch_64classifier>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.1version>
<configuration>
<source>17source>
<target>17target>
<encoding>UTF-8encoding>
configuration>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>${spring-boot.version}version>
<configuration>
<mainClass>com.alibaba.damo.mcpserver.McpServerApplicationmainClass>
<skip>trueskip>
configuration>
<executions>
<execution>
<id>repackageid>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
plugin>
plugins>
build>
project>
启动日志:
2025-04-29T20:09:07.153+08:00 INFO 51478 --- [ main] c.a.damo.mcpserver.McpServerApplication : Starting McpServerApplication using Java 17.0.15 with PID 51478 (/Users/clong/IdeaProjects/mcp-server/target/classes started by clong in /Users/clong/IdeaProjects/mcp-server)
2025-04-29T20:09:07.154+08:00 INFO 51478 --- [ main] c.a.damo.mcpserver.McpServerApplication : No active profile set, falling back to 1default profile: "default"
2025-04-29
T20:09:07.561+08:00 INFO 51478 --- [ main] o.s.a.m.s.a.McpServerAutoConfiguration : Registered tools: 2, notification: true
2025-04-29T20:09:07.609+08:00 INFO 51478 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port 8080
2025-04-29T20:09:07.612+08:00 INFO 51478 --- [ main] c.a.damo.mcpserver.McpServerApplication : Started McpServerApplication in 0.572 seconds (process running for0.765)
2025-04-29T20:10:18.812+08:00 INFO 51478 --- [ctor-http-nio-3] i.m.server.McpAsyncServer : Client initialize request - Protocol: 2024-11-05, Capabilities: ClientCapabilities[experimental=null, roots=null, sampling=null], Info: Implementation[name=spring-ai-mcp-client - server1, version=1.0.0]
client
客户端只需要在启动类中构建ChatClient并注入MCP工具即可。
package com.alibaba.damo.mcpclient;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import java.util.Arrays;
@SpringBootApplication
publicclassMcpClientApplication {
publicstaticvoidmain(String[] args){
SpringApplication.run(McpClientApplication.class, args);
}
@Bean
public CommandLineRunner predefinedQuestions(
ChatClient.Builder chatClientBuilder,
ToolCallbackProvider tools,
ConfigurableApplicationContext context) {
return args -> {
var chatClient = chatClientBuilder
.defaultTools(tools)
.build();
String userInput = "杭州今天天气如何?";
System.out.println("\n>>> QUESTION: " + userInput);
System.out.println("\n>>> ASSISTANT: " +
chatClient.prompt(userInput).call().content());
context.close();
};
}
}
阿里云百炼平台提供各大模型百万token免费体验,可以直接去平台申请即可获取对应的sk。
https://bailian.console.aliyun.com/console?tab=api#/api
spring.ai.openai.api-key=sk-xxx
spring.ai.openai.base-url=https://dashscope.aliyuncs.com/compatible-mode/v1
spring.ai.openai.chat.options.model=qwen-max
spring.ai.mcp.client.toolcallback.enabled=true
spring.ai.mcp.client.sse.connections.server1.url=http://localhost:8080
spring.main.web-application-type=none
依赖中需要添加spring-ai-starter-mcp-client依赖:
"1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.alibaba.damogroupId>
<artifactId>mcp-clientartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>mcp-clientname>
<description>mcp-clientdescription>
<properties>
<java.version>17java.version>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<spring-boot.version>3.4.0spring-boot.version>
<mcp.version>0.9.0mcp.version
>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.aigroupId>
<artifactId>spring-ai-starter-mcp-clientartifactId>
<version>1.0.0-M7version>
dependency>
<dependency>
<groupId>org.springframework.aigroupId>
<artifactId>spring-ai-starter-model-openaiartifactId>
<version>1.0.0-M7version>
dependency>
<dependency>
<groupId>io.modelcontextprotocol.sdkgroupId>
<artifactId>mcpartifactId>
<version>0.9.0version>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.aigroupId>
<artifactId>spring-ai-bomartifactId>
<version>1.0.0-M7version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>io.modelcontextprotocol.sdkgroupId>
<artifactId>mcp-bomartifactId>
<version>${mcp.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.1version>
<configuration>
<source>17source>
<target>17target>
<encoding>UTF-8encoding>
configuration>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>${spring-boot.version}version>
<configuration>
<mainClass>com.alibaba.damo.mcpclient.McpClientApplicationmainClass>
<skip>trueskip>
configuration>
<executions>
<execution>
<id>repackageid>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
plugin>
plugins>
build>
project>
客户端调用日志如下:
2025-04-29T20:10:18.302+08:00 INFO 51843 --- [ main] c.a.damo.mcpclient.McpClientApplication : Starting McpClientApplication using Java 17.0.15 with PID 51843 (/Users/clong/IdeaProjects/mcp-client/target/classes started by clong in /Users/clong/IdeaProjects/mcp-client)
2025-04-29T20:10:18.303+08:00 INFO 51843 --- [ main] c.a.damo.mcpclient.McpClientApplication : No active profile set, falling back to 1default profile: "default"
2025-04-29T20:10:18.846+08:00 INFO 51843 --- [ient-1-Worker-0] i.m.client.McpAsyncClient : Server response with Protocol: 2024-11-05, Capabilities: ServerCapabilities[experimental=null, logging=LoggingCapabilities[], prompts=null, resources=null, tools=ToolCapabilities[listChanged=true]], Info: Implementation[name=my-weather-server, version=0.0.1] and Instructions null
2025-04-29T20:10:19.018+08:00 INFO 51843 --- [ main] c.a.damo.mcpclient.McpClientApplication : Started McpClientApplication in 0.842 seconds (process running for1.083)
>>> QUESTION: 杭州今天天气如何?
>>> ASSISTANT: 杭州当前的天气信息如下:
- 温度:24.4°C
- 风速:3.4 km/h
请注意,这些信息是基于当前时间的实时数据。
server
与SSE模式相比,服务端只需要修改配置文件即可。由于是通过标准输入输出的方式提供服务,服务端不需要开放端口,因此注释掉端口号。同时需要修改web应用类型为none,禁掉banner输出(原因后面会讲)。配置MCP server的类型为stdio,服务名称和版本号,以供客户端发现。
spring.main.web-application-type=none
spring.main.banner-mode=off
spring.ai.mcp.server.stdio=true
spring.ai.mcp.server.name=my-weather-server
spring.ai.mcp.server.version=0.0.1
修改完之后通过maven package打包成jar文件。
client
客户端增加mcp-servers-config.json配置路径,启用toolcallback,注释掉sse连接。