原生Java SDK实现MCP Server(基于Servlet的SSE通信方式)

前言

目前MCP官方已经使用五种编程语言实现了MCP协议,其中就包括java。为了能够更深入地了解MCP,我们接下来就将使用最原生的方式在我们的应用程序中实现MCP Server。

环境要求

工具 版本
JDK 17或以上
SpringBoot 3.0或以上
Tomcat 10或以上
Maven 3.8.3+,最好是3.9.x

引入依赖

首先我们先创建一个最基本的springBoot项目,不需要其他复杂的依赖,然后新增下面的MCP Java SDK(截止2025-04-29,MCP Java SDK最高版本是0.9.0):

xml 复制代码
<dependencyManagement>  
    <dependencies>  
        <dependency>  
            <groupId>io.modelcontextprotocol.sdk</groupId>  
            <artifactId>mcp-bom</artifactId>  
	        <version>0.9.0</version>  
	        <type>pom</type>  
	        <scope>import</scope>  
	    </dependency>  
    </dependencies>  
</dependencyManagement>

<dependencies>
    <dependency>  
	    <groupId>io.modelcontextprotocol.sdk</groupId>  
		<artifactId>mcp</artifactId>  
	</dependency>
</dependencies>

新增依赖后记得reload maven project,避免依赖未导入;

编写MCP Server业务代码

因为我们本小节最重要的不是业务代码怎么写,所以我们就写一个相对简单的,就以通过订单号获取订单详情为例:

java 复制代码
import org.springframework.stereotype.Service;

@Service
public class OrderService {

	public OrderDetail getOrderDetail(String orderId) {  
		OrderDetail orderDetail = new OrderDetail();  
		orderDetail.setOrderId(orderId);
		orderDetail.setDetail("订单详情");
		return orderDetail;  
	}

	public static class OrderDetail {  
		private String orderId;  
		  
		private String detail;  
		  
		public void setOrderId(String orderId) {  
			this.orderId = orderId;  
		}  
		  
		public String getOrderId() {  
			return this.orderId;  
		}  
		  
		public void setDetail(String detail) {  
			this.detail = detail;  
		}  
		  
		public String getDetail() {  
			return this.detail;  
		}  
		@Override  
		public String toString() {  
			return "{\"orderId\":\"" + this.orderId + "\",\"detail\":\"" + this.detail+ "\"}";  
		}
	}
}

编写MCP Server配置

这一部分是本小节最重要的部分,我们需要做两件事情:

  1. 配置SSE请求入口
java 复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import io.modelcontextprotocol.server.transport.HttpServletSseServerTransportProvider;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.web.servlet.config.annotation.EnableWebMvc;  
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration  
@EnableWebMvc  
public class McpServerConfig implements WebMvcConfigurer {
	@Bean  
	public HttpServletSseServerTransportProvider  servletSseServerTransportProvider() {  
		return new HttpServletSseServerTransportProvider(new ObjectMapper(), "/mcp/message");  
	}  
	  
	@Bean  
	public ServletRegistrationBean customServletBean(HttpServletSseServerTransportProvider transportProvider) {  
	return new ServletRegistrationBean(transportProvider, "/mcp/message", "/sse");  
	}
}

首先我们通过注入HttpServletSseServerTransportProvider对象开启SSE的通信方式,并通过ServletRegistrationBean把/sse、/mcp/message请求接管到HttpServletSseServerTransportProvider来处理;

注意: 此处有一点细节需要说明一下,如果按照官方文档中直接创建ServletRegistrationBean对象,不配置urlMappings,那么项目中的所有请求都将被HttpServletSseServerTransportProvider接管,这可能会导致项目中已有的restful api访问报404错误;

  1. 配置业务代码为Tools
java 复制代码
@Bean(destroyMethod = "close")  
public McpSyncServer mcpSyncServer(HttpServletSseServerTransportProvider transportProvider,  
OrderService orderService) {  
	McpSyncServer mcpSyncServer = McpServer.sync(transportProvider) 
	.serverInfo("my-server", "1.0.0")  
	.capabilities(McpSchema.ServerCapabilities.builder()  
		.tools(true)
		.logging()  
		.build())  
	.build();

	String jsonSchema = """  
	{  
		"type":"object",  
		"properties":{  
			"orderId" : {  
				"type": "string",  
				"description": "订单号"  
			}  
		},  
		"required":[  
			"orderId"  
		],  
		"additionalProperties":false  
	}  
	""";  
	// 方法的描述  
	McpSchema.Tool tool = new McpSchema.Tool("getOrderDetail", "通过订单号获取订单详情信息", jsonSchema);  
	// 方法描述对应的执行逻辑  
	BiFunction<McpSyncServerExchange, Map<String, Object>, McpSchema.CallToolResult> call = (exchange, arguments) -> {  
	OrderService.OrderDetail result = orderService.getOrderDetail(String.valueOf(arguments.get("orderId")));  
	return new McpSchema.CallToolResult(result.toString(), false);  
	};  
	// 绑定描述和执行逻辑  
	McpServerFeatures.SyncToolSpecification toolHandler = new McpServerFeatures.SyncToolSpecification(tool, call);  
	  
	// 添加到工具集中  
	mcpSyncServer.addTool(toolHandler);

	return mcpSyncServer;  
}

我们需要把需要暴露的业务方法通过上面的配置暴露给MCP Client。上面的代码看上去挺多,但是仔细看一下,其实可以拆解成两部分: 1、首先是创建一个McpSyncServer Bean对象,并配置一些基本属性,包括Server的名称等; 2、其次就是把我们需要暴露的业务方法整理成JsonSchema,并添加到McpSyncServer对象的工具集中;

测试

上面的工作都做完后,我们可以启动项目,为了能够测试我们的MCP Server是否可用,我们可以下载安装cherry studio用来作为MCP Client。可按照以下图示进行配置:

如果按照上述图示配置没有异常,那么说明MCP Server启动成功,且能正常提供服务,并且可在工具栏看到我们暴露出来的接口:

相关推荐
2601_962106646 小时前
【Java Set综合实战】商品管理系统 + 图书收藏系统|Product、Book自定义类全套代码
java
RuoyiOffice7 小时前
SpringBoot+Vue3 凭证生命周期设计:审核、过账、冲销与反过账怎样保持账目一致
java·spring boot·事务·springboot3·财务系统·会计凭证·ruoyi office
2601_962106648 小时前
HashMap入门|工号-姓名键值存储、两种遍历方式、根据key/value查
java
杨凯凡8 小时前
Spring Framework 7 API 版本管理实战:请求头路由、兼容迁移与废弃策略
java·rest api·springframework·spring boot 4·api版本管理
T_Wizard8 小时前
同一个问题写了 4 遍:官方 SDK / HTTP / Spring AI / LangChain4j,到底该选哪个
java·ai编程
hai_android9 小时前
AudioTrack 深度解析:从原理到实战
android·java·kotlin
斯维赤9 小时前
限流、熔断、降级,你真的分得清吗?
java·后端·架构
誰在花里胡哨12 小时前
Qoder + Blender MCP:对话建模到网页渲染
ai编程·three.js·mcp
aiks_yuan12 小时前
Java CPU 100% 怎么排查:JDK 11 起 jstack 自带线程 CPU 时间,不用再 top -H 换算十六进制(JDK 8、11、17 实测)
java
Flynn Liang13 小时前
AiServices 源码级拆解:一个接口如何变成 RAG Agent
java·langchain·源码分析·rag·langchain4j·aiservices