> 技术文档 > SpringAI实现MCP示例

SpringAI实现MCP示例

本文章主要记录个人在使用SrpingAI搭建MCP的服务端和客户端的过程。

MCP官网链接:https://modelcontextprotocol.io/introduction

SpringAI-MCP文档链接: 模型上下文协议(MCP) :: Spring AI Reference(中文版)

开发环境准备: JDK17+

一、McpServer实现

此处创建Maven项目的过程省略。

1、mcp-server相关pom依赖引入

  org.springframework.ai spring-ai-starter-mcp-server-webflux 1.0.0 

也可以创建一个父模块进行BOM清单进行统一管理然后在server服务中引入上面的依赖:

   org.springframework.ai spring-ai-bom 1.0.0 pom import 

2、mcp-server相关参数配置

server: port: 11001spring: ai: mcp: server: # base-url: /api/v1 # URL前缀 目前已验证改配置无效 name: mcp-server-demo # mcp 服务名称 enabled: true # mcp 开启状态 stdio: false # stdio 模式开启 sse-endpoint: /mcp/demo # web传输的SSE终端节点路径 sse-message-endpoint: /mcp/message # 客户端用于发消息的WEB传输的自定义SSE消息终端节点 version: 1.0.0 # 服务器版本 type: ASYNC # 同步/异步 SYNC/ASYNC resource-change-notification: true # 启用资源更改通知 prompt-change-notification: true # 启用提示词更改通知 tool-change-notification: true # 启用工具更改通知

3、编写具体工具类(这里我只展示其中一个简单的当前时间工具类)

@Servicepublic class TimeService { Logger logger = LoggerFactory.getLogger(TimeService.class); @Tool(description = \"这是返回当前时间的工具.\") public String nowTime () { logger.info(\"开始请求时间工具.\"); SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\"); return sdf.format(new Date()); }}

description 部分可以根据不同的工具进行不同的描述,合理的描述可以让模型更好的正确匹配到你发布的工具。

4、注入工具类到容器

@Configurationpublic class McpServerConfig { @Bean public ToolCallbackProvider timeTools(TimeService timeService) { return MethodToolCallbackProvider.builder().toolObjects(timeService).build(); }}

5、启动mcp-server服务

启动成功日志

启动成功后,控制台会提示成功注册的工具数量。

二、McpClient实现

项目集成的大模型:DeepSeek官方API。

DeepSeek官网API地址:DeepSeek

注册账号并充值(充10元就够用很久)完成后创建对应的key:

1、mcp-client相关依赖引入

  org.springframework.boot spring-boot-starter-webflux 3.4.4   org.springframework.ai spring-ai-starter-mcp-client-webflux 1.0.0   org.springframework.ai spring-ai-starter-model-deepseek 1.0.0   com.google.code.gson gson 2.13.1  

2、mcp-client相关参数配置

server: port: 11000spring: ai: mcp: client: name: mcp-client-demo # mcp 服务名称 enabled: true # mcp 开启状态 version: 1.0.0 # 客户端版本 initialized: true # 是否在创建时初始化客户端 # request-timeout: 20 # MCP 客户端请求的超时持续时间 type: ASYNC # 同步/异步 SYNC/ASYNC root-change-notification: true # 为所有客户端启用/禁用 root 更改通知 toolcallback: enabled: true # 启用/禁用 MCP 工具回调与 Spring AI 的工具执行框架的集成 sse: connections: mcp-demo:  url: http://127.0.0.1:11001/  sse-endpoint: /mcp/demo retry: max-attempts: 3 # 最大重试尝试次数 backoff: initial-interval: 2 # 指数回退策略的初始休眠持续时间。 multiplier: 5 # Backoff interval 乘数。 max-interval: 3 # 最大回退持续时间。 on-client-errors: true # 如果为 false,则抛出 NonTransientAiException,并且不尝试重试4xx客户端错误代码 #exclude-on-http-codes: 不应触发重试的 HTTP 状态代码列表(例如,引发 NonTransientAiException)。 #on-http-codes: 应触发重试的 HTTP 状态代码列表(例如,引发 TransientAiException)。 deepseek: base-url: https://api.deepseek.com/ api-key: 填写个人申请的apikey chat: enabled: true base-url: https://api.deepseek.com/ apiKey: 填写个人申请的apikey completions-path: /chat/completions # 聊天完成端点的路径 beta-prefix-path: /beta/chat/completions # beta 功能终端节点的前缀路径 options: model: deepseek-chat # 要使用的模型的 ID。您可以使用 deepseek-coder 或 deepseek-chat frequencyPenalty: 0.0 # 介于 -2.0 和 2.0 之间的数字。正值会根据新标记到目前为止在文本中的现有频率来惩罚新标记,从而降低模型逐字重复同一行的可能性。 maxTokens: 2000 # 在聊天完成中生成的最大令牌数。输入标记和生成的标记的总长度受模型的上下文长度限制。 presencePenalty: 0.0 # 介于 -2.0 和 2.0 之间的数字。正值根据新标记到目前为止是否出现在文本中来惩罚新标记,从而增加模型讨论新主题的可能性。 # stop: 最多 4 个序列,API 将在其中停止生成更多令牌。 temperature: 1.0F # 要使用的采样温度,介于 0 和 2 之间。较高的值(如 0.8)将使输出更加随机,而较低的值(如 0.2)将使其更加集中和确定。我们通常建议更改此项或top_p,但不能同时更改两者。 topP: 0.1F # 使用温度进行采样的替代方法,称为核抽样,其中模型考虑具有top_p概率质量的标记的结果。所以 0.1 意味着只考虑包含前 10% 概率质量的 token。我们通常建议更改此温度或温度,但不能同时更改两者。 #logprobs: #topLogprobs:logging.level.org.springframework.ai: DEBUG

3、chat-client注入并设置服务端工具

@Componentpublic class AiConfig { private final static Logger logger = LoggerFactory.getLogger(AiConfig.class); @Resource DeepSeekChatModel chatModel; @Resource private ToolCallbackProvider toolCallbackProvider; private static final Gson GSON = new GsonBuilder() .create(); @Bean public ChatClient chatClient() { logger.info(\"客户端开始加载...\"); ToolCallback[] tools = toolCallbackProvider.getToolCallbacks(); for (ToolCallback t : tools) { logger.info(\"客户端加载工具: {}\", GSON.toJson(t.getToolDefinition())); } return ChatClient.builder(chatModel).defaultToolCallbacks(tools).build(); }}

4、编写测试接口

@RestController@RequestMapping(\"/mcp/client\")public class ChatController { @Resource private ChatClient chatClient; private final static Logger logger = LoggerFactory.getLogger(ChatController.class); @RequestMapping(value = \"/send_stream\", method = RequestMethod.GET) public Flux generateStream(@RequestParam(\"prompt\") String prompt) { logger.info(\"用户向deepseek模型询问了如下问题:{}\", prompt); Flux responseFlux = this.chatClient.prompt(prompt) .stream() .chatResponse(); return responseFlux.map(chatResponse -> chatResponse.getResult().getOutput().getText()).doOnComplete(() -> { logger.info(\"调用完成...\"); }); }}

5、启动mcp-client服务

启动成功并打印从服务端获取到的工具列表。

6、使用第三方API接口调用工具进行接口验证

总结:以上成功完成SpringAI-MCP客户端到服务端的实现,目前通过MCP的sdk源码看,服务端的base-url应该是没有真正使用到,所以即使配置了也不会生效。也可以只实现MCP-Server然后通过其他客户端工具如:cherrystudio进行工具的集成与使用。后面有时间了会再记录下nacos3.x的集成实现。