打破版本枷锁!MCP SDK成功降级至JDK8,完美兼容老旧系统!支持StreamableHttpServerTransport!

打破版本枷锁!MCP SDK成功降级至JDK8,完美兼容老旧系统!支持StreamableHttpServerTransport!
程序员老姐姐打破版本枷锁!MCP SDK成功降级至JDK8,完美兼容老旧系统!支持StreamableHttpServerTransport!
📋 概述
官方SDK使用jdk17开发构建,为了能够使得更多使用老版本jdk的项目也能集成开发MCP功能,并且尽量避免重复造轮子,因此选择使用jdk8重构官方版本。
项目地址
重构分支项目地址:https://github.com/Lori888/mcp-java-sdk
分支0.10.0-jdk8
(基于原项目分支0.10.0 revision 6307f069
建立)
✨ 重构说明
重构原则
- 保持原项目代码中类的注释等
- 尽量和原项目代码的代码顺序保持一致,以便于修改对比
重构代码改动
主要进行了以下改动:
record
重构为static class
、添加@Value
注解(添加lombok
包依赖)sealed interface
重构为interface
并相应修改其子类List.of()
重构为Collections.emptyList()
List.of(xxx)
重构为Collections.singletonList(xxx)
和Arrays.stream(handlers).collect(Collectors.toList())
List.of(xxx, xxx)
重构为Arrays.asList(xxx, xxx)
Map.of()
重构为Collections.emptyMap()
Map.of(xxx)
重构为Collections.singletonMap(xxx)
Map.of(xxx, xxx)
重构为 jdk8 map写法stream().map(xxx).toList()
重构为stream().map(xxx).collect(Collectors.toList())
stream().toList()
重构为stream().collect(Collectors.toList())
Optional.isEmpty()
重构为== null
var
重构为具体类型instanceof Class xxx
重构为jdk8写法switch
重构为jdk8写法jakarta.servlet.*
重构为javax.servlet.*
(添加jakarta.servlet-api
包依赖)java.net.http.*
改为使用OkHttp
(添加okhttp
包依赖)
功能变更
- 在原项目代码的基础上,新增了
StreamableHttpServerTransportProvider
(复制于https://github.com/ZachGerman/mcp-java-sdk
项目分支StreamableHttpServerTransportProvider
并用jdk8重构~请给原作者1个小星星) - 修复了使用
HttpServletSseServerTransportProvider
时进行tools/call
传参中文乱码问题
🛠️ 构建项目
环境要求
- Java 8
- Maven 3.3+
构建方法
1.下载项目源码:
1 | git clone -b 0.10.0-jdk8 https://github.com/Lori888/mcp-java-sdk.git |
2.构建安装到本地maven仓库中:
1 | cd mcp-java-sdk |
🔥 使用方法
在项目中添加依赖:
1 | <dependency> |
🧪 应用示例
开发1个使用StreamableHttpTransport的MCP Server,关键步骤:
构建具体的MCP Server tools类
1
2
3
4
5
6
7
8
9
10
11
12
13
public class McpServerTool {
public String getWeather( { String city)
return String.format("%s: 晴天,温度25℃", city);
}
public String getSpeciality( { String city, String type)
return String.format("%s的%s特产是小笼包", type, city);
}
}构建MCP Server属性对象实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25private void processServerProperties() {
mcpServerEndpoint = McpServerEndpointProcessor.resolveMcpServerEndpoint(targetBean.getClass().getName());
assert mcpServerEndpoint != null;
serverProperties.setName(mcpServerEndpoint.name());
serverProperties.setVersion(mcpServerEndpoint.version());
if (McpServerProperties.ServerType.ASYNC.name().equalsIgnoreCase(mcpServerEndpoint.type())) {
serverProperties.setType(McpServerProperties.ServerType.ASYNC);
}
if (mcpServerEndpoint.transport().equalsIgnoreCase(TransportType.SSE.name())) {
serverProperties.setTransport(TransportType.SSE);
} else if (mcpServerEndpoint.transport().equalsIgnoreCase(TransportType.STDIO.name())) {
serverProperties.setTransport(TransportType.STDIO);
serverProperties.setStdio(true);
}
serverProperties.setPort(mcpServerEndpoint.port());
serverProperties.setBaseUrl(mcpServerEndpoint.baseUrl());
serverProperties.setSseEndpoint(mcpServerEndpoint.sseEndpoint());
serverProperties.setSseMessageEndpoint(mcpServerEndpoint.sseMessageEndpoint());
serverProperties.setMcpEndpoint(mcpServerEndpoint.mcpEndpoint());
serverProperties.setToolChangeNotification(mcpServerEndpoint.toolChangeNotification());
log.info("MCP Server properties: [{}]", serverProperties);
serverInfo = new McpSchema.Implementation(serverProperties.getName(), serverProperties.getVersion());
}根据MCP Server属性创建对应的
McpServerTransportProvider
实例1
2
3
4
5
6
7
8
9
10
11
12
13
14capabilitiesBuilder = McpSchema.ServerCapabilities.builder();
if (serverProperties.getTransport() == TransportType.STREAMABLE_HTTP) {
transportProvider = StreamableHttpServerTransportProvider.builder()
.withMcpEndpoint(serverProperties.getMcpEndpoint())
.build();
} else if (serverProperties.getTransport() == TransportType.SSE) {
transportProvider = HttpServletSseServerTransportProvider.builder()
.baseUrl(serverProperties.getBaseUrl())
.messageEndpoint(serverProperties.getSseMessageEndpoint())
.sseEndpoint(serverProperties.getSseEndpoint())
.build();
} else if (serverProperties.isStdio()){
transportProvider = new StdioServerTransportProvider();
}根据同步/异步类型创建MCP Server实例
1
2
3
4
5
6
7if (serverProperties.getTransport() == TransportType.STREAMABLE_HTTP) {
buildAsyncStreamableHttpServer();
} else if (serverProperties.getType() == McpServerProperties.ServerType.SYNC) {
buildSyncServer();
} else {
buildAsyncServer();
}将提供的能力(
tools/resources/prompts
)注册到MCP Server实例中1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22private void buildAsyncStreamableHttpServer() {
log.info("building async StreamableHttpServer...");
McpAsyncStreamableHttpServer.Builder serverBuilder = McpAsyncStreamableHttpServer.builder()
.serverInfo(serverInfo.getName(), serverInfo.getVersion())
.withMcpEndpoint(serverProperties.getMcpEndpoint());
// tools
List<McpServerFeatures.AsyncToolSpecification> toolSpecifications = buildAsyncToolSpecifications();
if (!toolSpecifications.isEmpty()) {
toolSpecifications.forEach(serverBuilder::withTool);
capabilitiesBuilder.tools(serverProperties.isToolChangeNotification());
}
log.info(String.format(MSG_REGISTER_TOOLS, toolSpecifications.size(), serverProperties.isToolChangeNotification()));
// TODO resources, prompts, rootsChangeConsumers
serverBuilder.serverCapabilities(capabilitiesBuilder.build());
McpAsyncStreamableHttpServer streamableHttpServer = serverBuilder.build();
transportProvider = streamableHttpServer.getTransportProvider();
}使用内嵌的
Tomcat
提供Web服务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
29private void startTomcat() throws LifecycleException {
log.info("Starting Tomcat...");
tomcat = new Tomcat();
tomcat.setPort(serverProperties.getPort());
// 设置临时目录
File baseDir = new File(System.getProperty("java.io.tmpdir"));
tomcat.setBaseDir(baseDir.getAbsolutePath());
// 添加 Web 应用(无 webapp 目录,只注册 servlet)
Context ctx = tomcat.addContext("", baseDir.getAbsolutePath());
// 注册 MCP Servlet
org.apache.catalina.Wrapper wrapper = ctx.createWrapper();
wrapper.setName(MCP_SERVLET_NAME);
wrapper.setServlet((Servlet) transportProvider);
wrapper.setLoadOnStartup(1);
wrapper.setAsyncSupported(true);
ctx.addChild(wrapper);
ctx.addServletMappingDecoded("/*", MCP_SERVLET_NAME);
tomcat.getConnector(); // 默认创建一个 HTTP connector
tomcat.start();
String endpoint = serverProperties.getTransport() == TransportType.STREAMABLE_HTTP ?
serverProperties.getMcpEndpoint() : serverProperties.getSseEndpoint();
log.info("Tomcat running on {} and mcp server path is {}", serverProperties.getPort(), endpoint);
}
完整代码详见: mcp-java-sdk-examples
📑 TODO LIST
mcp-spring-webflux
、mcp-spring-webmvc
子模块重构- 加入
HttpClientStreamableHttpTransport
- 适配Specification 2025-03-26 和 2025-06-18
- jdk8重构官方主干分支
相关链接
- 项目GitHub 分支
0.10.0-jdk8
- 示例项目GitHub
mcp-0.10.0-jdk8.jar
下载(百度网盘、夸克网盘、自建网盘)
评论
匿名评论隐私政策