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

打破版本枷锁!MCP SDK成功降级至JDK8,完美兼容老旧系统!StreamableHttpServer/Client 全支持!
程序员老姐姐打破版本枷锁!MCP SDK成功降级至JDK8,完美兼容老旧系统!StreamableHttpServer/Client 全支持!
📋 概述
官方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()重构为== nullvar重构为具体类型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> |
🧪 应用示例
构建StreamableHttpTransport MCP Server
开发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
构建StreamableHttpTransport MCP Client
前面已经构建了StreamableHttpTransport的MCP Server,接下来使用MCP Client代码连接服务并调用tool、resource、prompt:
1 | package org.cafe.example.mcp; |
完整代码详见: mcp-java-sdk-examples
📑 TODO LIST
-
mcp-spring-webflux、mcp-spring-webmvc子模块重构 - 加入
HttpClientStreamableHttpTransport2025-07-21 已完成 - 适配Specification 2025-03-26 和 2025-06-18
- jdk8重构官方主干分支
相关链接
- 项目GitHub 分支
0.10.0-jdk8 - 示例项目GitHub
mcp-0.10.0-jdk8.jar下载(百度网盘、夸克网盘、自建网盘)
评论
匿名评论隐私政策












