掘金 人工智能 05月31日 21:03
原生Java SDK实现MCP Server(基于Servlet的SSE通信方式)
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文介绍了如何使用Java以最原生方式实现MCP Server。首先,需要满足JDK17+、SpringBoot3.0+等环境要求,并引入MCP Java SDK依赖。接着,编写简单的订单服务业务代码,以通过订单号获取订单详情为例。最重要的是MCP Server配置,包括配置SSE请求入口,通过HttpServletSseServerTransportProvider对象开启SSE通信,并配置业务代码为Tools,将业务方法整理成JsonSchema添加到McpSyncServer对象的工具集中。最后,使用Cherry Studio作为MCP Client进行测试,验证MCP Server是否可用。

🛠️ **环境配置与依赖引入**: 搭建MCP Server需JDK17+、SpringBoot3.0+等环境,并引入MCP Java SDK(0.9.0版本),通过Maven进行依赖管理,确保项目能正确识别和使用MCP相关类库。

📡 **SSE通信配置**: 通过HttpServletSseServerTransportProvider对象开启SSE(Server-Sent Events)通信方式,并利用ServletRegistrationBean将/sse和/mcp/message请求映射到该Provider处理,这是MCP Server与Client实时通信的基础。

⚙️ **业务方法暴露为Tool**: 将需要暴露的Java业务方法,如订单详情查询,整理成符合MCP协议的JsonSchema格式,并通过McpSyncServer的addTool方法添加到工具集中,使得MCP Client能够发现并调用这些服务。

🧪 **Cherry Studio测试验证**: 使用Cherry Studio作为MCP Client,配置连接到刚搭建的MCP Server,验证服务是否启动成功,以及暴露的接口是否能够正常提供服务,确保整个MCP通信链路畅通。

前言

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

环境要求

工具版本
JDK17或以上
SpringBoot3.0或以上
Tomcat10或以上
Maven3.8.3+,最好是3.9.x

引入依赖

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

<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业务代码

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

import org.springframework.stereotype.Service;@Servicepublic 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配置

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

    配置SSE请求入口
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错误;

    配置业务代码为Tools
@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启动成功,且能正常提供服务,并且可在工具栏看到我们暴露出来的接口:

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

MCP Server Java SSE通信 JsonSchema Cherry Studio
相关文章