首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >spring-ai 学习系列(3)-MCP(stdio)

spring-ai 学习系列(3)-MCP(stdio)

作者头像
菩提树下的杨过
发布2025-08-22 08:32:16
发布2025-08-22 08:32:16
18200
代码可运行
举报
运行总次数:0
代码可运行

使用spring-ai创建1个MCP Server很容易,下面演示MCP(stdio模式)的写法:

一、添加依赖项

代码语言:javascript
代码运行次数:0
运行
复制
1 <dependency>
2     <groupId>org.springframework.ai</groupId>
3     <artifactId>spring-ai-starter-mcp-server</artifactId>
4     <version>1.0.0</version>
5 </dependency>

二、创建1个MCP Server服务

代码语言:javascript
代码运行次数:0
运行
复制
 1 import org.springframework.ai.tool.annotation.Tool;
 2 import org.springframework.ai.tool.annotation.ToolParam;
 3 import org.springframework.stereotype.Service;
 4 
 5 /**
 6  * @author 菩提树下的杨过
 7  */
 8 @Service
 9 public class OrderService {
10 
11 
12     @Tool(name = "queryOrderStatus",
13             description = "根据订单号查询订单状态")
14     public String queryOrderStatus(@ToolParam(required = true, description = "订单号,格式为8位数字,比如:25070601") String orderNo) {
15         return switch (orderNo) {
16             case "25070601" -> "订单号:" + orderNo + ",订单状态:已发货";
17             case "25070602" -> "订单号:" + orderNo + ",订单状态:已完成";
18             case "25070603" -> "订单号:" + orderNo + ",订单状态:已取消";
19             default -> "订单号:" + orderNo + ",订单状态:未知";
20         };
21     }
22 }

可以看到,几乎跟常规的后端Service开发没区别,只是多了@Tool@ToolParam注解,是给MCP Host和大模型使用的。

三、暴露MCP服务

MCP Server必须对外暴露出来,才能被调用方发现。

代码语言:javascript
代码运行次数:0
运行
复制
 1 import com.cnblogs.yjmyzz.mcp.server.OrderService;
 2 import org.springframework.ai.tool.ToolCallbackProvider;
 3 import org.springframework.ai.tool.method.MethodToolCallbackProvider;
 4 import org.springframework.boot.SpringApplication;
 5 import org.springframework.boot.autoconfigure.SpringBootApplication;
 6 import org.springframework.context.annotation.Bean;
 7 
 8 @SpringBootApplication
 9 public class SpringAiApplication {
10 
11     public static void main(String[] args) {
12         SpringApplication.run(SpringAiApplication.class, args);
13     }
14 
15     @Bean
16     public ToolCallbackProvider orderTools(OrderService orderService) {
17         return  MethodToolCallbackProvider.builder().toolObjects(orderService).build();
18     }
19 
20 }

编译一下,会在本地生成jar包,类似D:\code\spring-ai-sample\target\spring-ai-0.0.1-SNAPSHOT.jar

四、调整yaml

代码语言:javascript
代码运行次数:0
运行
复制
spring:
  main:
    banner-mode: off

logging:
  pattern:
    console:

这一步非常重要,MCP的stdio模式,client与server通过标准输入输出(Standard Input/Output )进行通讯(通俗来说,就是控制台的输入/输出)。如果不关闭启动banner以及控制台的输出,会影响 MCP Client调用时的结果解析。

五、编写MCP Client测试

MCP Server写好了,如何验证功能正常呢,写个Client来调用一下

代码语言:javascript
代码运行次数:0
运行
复制
package com.cnblogs.yjmyzz.mcp.client;

import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.McpSyncClient;
import io.modelcontextprotocol.client.transport.ServerParameters;
import io.modelcontextprotocol.client.transport.StdioClientTransport;
import io.modelcontextprotocol.spec.McpSchema;
import org.junit.Test;

import java.util.Map;

/**
 * @author 菩提树下的杨过
 */
public class McpClientSample {

    @Test
    public void testMcpClientSample() {

        ServerParameters stdioParams = ServerParameters.builder("java")
                .args("-jar", "D:\\code\\spring-ai-sample\\target\\spring-ai-0.0.1-SNAPSHOT.jar")
                .build();

        StdioClientTransport stdioTransport = new StdioClientTransport(stdioParams);

        //创建MCP Client
        McpSyncClient mcpClient = McpClient.sync(stdioTransport).build();

        //这一步初始化执行完后,其实就是把jar中的Spring boot应用启动了(MCP Server就能对外提供服务了)
        mcpClient.initialize();

        McpSchema.ListToolsResult toolsList = mcpClient.listTools();

        //打印工具信息(即:orderService的queryOrderStatus方法信息)
        System.out.println(toolsList);

        //调用MCP Server
        McpSchema.CallToolResult orderStatus = mcpClient.callTool(
                //这里我们只有1个工具,所以直接取第一个
                new McpSchema.CallToolRequest(toolsList.tools().getFirst().name(),
                        Map.of("orderNo", "25070601")));
        //打印调用结果
        System.out.println(orderStatus);

        //关闭MCP Client
        //这里一定要记得关闭,否则MCP Server的Spring boot应用不会退出(大家可以这里打个断点,然后http://localhost:8080/api/hello 访问一下,应该能访问通)
        mcpClient.closeGracefully();
    }
}

正常的话,应该会看到以下输出:

代码语言:javascript
代码运行次数:0
运行
复制
18:59:41.289 [pool-1-thread-1] INFO io.modelcontextprotocol.client.McpAsyncClient -- Server response with Protocol: 2024-11-05, Capabilities: ServerCapabilities[completions=CompletionCapabilities[], experimental=null, logging=LoggingCapabilities[], prompts=PromptCapabilities[listChanged=true], resources=ResourceCapabilities[subscribe=false, listChanged=true], tools=ToolCapabilities[listChanged=true]], Info: Implementation[name=mcp-server, version=1.0.0] and Instructions null
ListToolsResult[tools=[Tool[name=queryOrderStatus, description=根据订单号查询订单状态, inputSchema=JsonSchema[type=object, properties={orderNo={type=string, description=订单号,格式为8位数字,比如:25070601}}, required=[orderNo], additionalProperties=false, defs=null, definitions=null]]], nextCursor=null]
CallToolResult[content=[TextContent[audience=null, priority=null, text="订单号:25070601,订单状态:已发货"]], isError=false]
18:59:41.615 [parallel-6] WARN io.modelcontextprotocol.client.transport.StdioClientTransport -- Process terminated with code 1

正好4行:

第1行,表示初始化启动成功

第2行,列出了当前应用暴露的所有工具(即:MCP Server方法)

第3行,是调用工具queryOrderStatus的结果

第4行,表示关闭Spring Boot应用(MCP Server)

如果运行失败,强烈建议先看看任务管理器里,是否有java应用占用了默认端口8080,导致MCP Server的Spring boot应用启动失败

看到这里,可能有朋友会懵,这跟大模型有什么关系 ?这不就是常规的后端开发,跟写个业务接口或SOA服务一样么?其实我刚开始接触时,也是这么认为的。

tips:前面提到了client与server是通过控制台I/O来通讯的,上述的测试过程其实也可以完全在控制台手动输入json来进行

上述测试代码其实就是发出了几条json,类似:

代码语言:javascript
代码运行次数:0
运行
复制
{"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"yjmyzz client","version":"0.0.1"}},"jsonrpc":"2.0","id":0}

{"method":"notifications/initialized","jsonrpc":"2.0"}

{"method":"ping","jsonrpc":"2.0","id":1}

{"method":"tools/list","jsonrpc":"2.0","id":1}

... 后面就不一一列举了

可以先用mvn spring-boot:run,把server启动起来,然后一条条把上面的json输入到终端里,就相当于纯手动测试了

当然,实际应用中,更通用的做法,是找1个现成的MCP Host,来承载MCP client

六、使用MCP Host

6.1 下载MCP Host

建议大家使用免费开源的 Cherry Studio,网址:https://www.cherry-ai.com/download,它能对接市面上的各大主流模型

以DeepSeek为例,我们添加api 密钥

然后发起个对话,看看deepseek是否能正常工作

显然,这个订单号deepSeek是不知道的。

6.2 添加MCP Server

参考下图:

右上角,启动保存时,如果失败,也强烈建议查看任务管理器,是否端口占用(或有其它java进程占用)。启动保存后,本质上就把这个Spring Boot应用给run起来了,跟部署到tomcat其实是类似的。

6.3 会话中启用MCP Server

再回到聊天界面,把刚才这个新加的MCP Server启用

再次来问这个订单的状态

发现大模型似乎变聪明了

静下来想想,发生了啥?

  • 模型还是那个模型,deepseek并没有改变。
  • 本地的mcp server springboot应用,也并不知道deepseek是何方大神

那么,这2个角色是怎么勾搭上的?显然是cherry studio这个媒婆(mcp host)牵线搭桥了,这个细节后面有机会咱们再分析。

文中代码:https://github.com/yjmyzz/spring-ai-sample/tree/day03

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-07-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档