1、程序中使用 MCP

1.1、安装依赖

<!-- https://mvnrepository.com/artifact/org.springframework.ai/spring-ai-mcp-client-spring-boot-starter -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
            <version>1.0.0-M6</version>
        </dependency>

1.2、编写配置

先到 MCP 市场 找到 高德地图 MCP

其次申请一个key。
在这里插入图片描述

之后在 resources 目录下新建 mcp-servers.json 配置,定义需要用到的 MCP 服务:

{
  "mcpServers": {
    "amap-maps": {
      "command": "npx",
      "args": [
        "-y",
        "@amap/amap-maps-mcp-server"
      ],
      "env": {
        "AMAP_MAPS_API_KEY": "自己的API Key"
      }
    }
  }
}

特别注意:在 Windows 环境下,命令配置需要添加 .cmd 后缀(如 npx.cmd),否则会报找不到命令的错误。

因为调用MCP 服务的本质是在启动项目的过程中,单独开一个子进程,运行 npx @amap/amap-maps-mcp-server 命令,来启动 MCP 服务。当关闭程序时,子进程也关闭,所以我们需要提供 window 上能运行的命令。

1.3、编写 MCP 客户端配置

修改 Spr‏ing 配置文件,编写 MCP؜ 客户端配置。由于是本地运行 ​MCP 服务,所以使用 std‌io 模式,并且要指定 MCP‏ 服务配置文件的位置。

spring:
    ai:
      mcp:
        client:
          stdio:
            servers-configuration: classpath:mcp-servers.json

1.4、修改 LoveApp 的代码,

新增一个利用 MCP 完成对话的方法。通过自动注入的 ToolCallbackProvider 获取到配置中定义的 MCP 服务提供的 所有工具,并提供给 ChatClient。代码如下:

@Resource
private ToolCallbackProvider toolCallbackProvider;

public String doChatWithMcp(String message, String chatId) {
    ChatResponse response = chatClient
            .prompt()
            .user(message)
            .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                    .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
            // 开启日志,便于观察效果
            .advisors(new MyLoggerAdvisor())
            .tools(toolCallbackProvider)
            .call()
            .chatResponse();
    String content = response.getResult().getOutput().getText();
    log.info("content: {}", content);
    return content;
}

private ToolCallbackProvider toolCallbackProvider; Spring AI在启动的时候,会自动读取 mcp-servers.json 配置文件,从中找到所有的工具,自动注入到工具提供者类(ToolCallbackProvider)上

MCP 调用的本质就是类似工具调用,并不是让 AI 服务器主动去调用 MCP 服务,而是告诉 AI “MCP 服务提供了哪些工具”,如果 AI 想要使用这些工具完成任务,就会告诉我们的后端程序,后端程序在执行工具后将结果返回给 AI,最后由 AI 总结并回复。

1.5、测试运行

@Test
void doChatWithMcp() {
    String chatId = UUID.randomUUID().toString();
    // 测试地图 MCP
    String message = "我的另一半居住在西安雁塔区,请帮我找到 5 公里内合适的约会地点";
    String answer =  loveApp.doChatWithMcp(message, chatId);
}

debug 查看
在这里插入图片描述

MCP底层 可以理解为 工具调用,Spring AI 没有单独针对 MCP 开发一套机制,而是把 MCP 转化为 工具,把 MCP 中的 工具 提取出来,从而复用 tools 能力。

结果显示👇
在这里插入图片描述

2、MCP 服务端开发

可参照官网进行开发。

2.1、先在 Pexels 网站生成 API Key:

在这里插入图片描述

2.2、新建 mo؜dule

在项目‏根目录下新建 mo؜dule,名称为 ​yuAn-image-‌search-mc‏p-server:
在这里插入图片描述

2.3、引入依赖

引入必‏要的依赖,包括 L؜ombok、hut​ool 工具库和 ‌Spring AI‏ MCP 服务端依赖。

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-server-webmvc-spring-boot-starter</artifactId>
    <version>1.0.0-M6</version>
</dependency>

2.4、编写两套配置服务文件

在 re‏sources 目录下؜编写两套服务端配置文件,分别实现 stdio‏ 和 SSE 模式的传输。

1、配置文件 application-stdio.yml

spring:
  ai:
    mcp:
      server:
        name: yuAn-image-search-mcp-server
        version: 0.0.1
        type: SYNC
        # stdio
        stdio: true
  # stdio
  main:
    web-application-type: none
    banner-mode: off

2、配置文件application-sse.yml

spring:
  ai:
    mcp:
      server:
        name: yuAn-image-search-mcp-server
        version: 0.0.1
        type: SYNC
        # sse
        stdio: false

3、编写主配置文件 application.yml,可以灵活指定激活哪套配置

spring:
  application:
    name: yuAn-image-search-mcp-server
  profiles:
    active: stdio
server:
  port: 8127

2.5、服务类开发

编写图片搜索服务类,在 tools 包下新建 ImageSearchTool,使用 @Tool 注解标注方法,作为 MCP 服务提供的工具。

@Service
public class ImageSearchTool {

    // 替换为你的 Pexels API 密钥(需从官网申请)
    private static final String API_KEY = "2.1节申请的 API Key";

    // Pexels 常规搜索接口(请以文档为准)
    private static final String API_URL = "https://api.pexels.com/v1/search";

    @Tool(description = "search image from web")
    public String searchImage(@ToolParam(description = "Search query keyword") String query) {
        try {
            return String.join(",", searchMediumImages(query));
        } catch (Exception e) {
            return "Error search image: " + e.getMessage();
        }
    }

    /**
     * 搜索中等尺寸的图片列表
     *
     * @param query
     * @return
     */
    public List<String> searchMediumImages(String query) {
        // 设置请求头(包含API密钥)
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", API_KEY);

        // 设置请求参数(仅包含query,可根据文档补充page、per_page等参数)
        Map<String, Object> params = new HashMap<>();
        params.put("query", query);

        // 发送 GET 请求
        String response = HttpUtil.createGet(API_URL)
                .addHeaders(headers)
                .form(params)
                .execute()
                .body();

        // 解析响应JSON(假设响应结构包含"photos"数组,每个元素包含"medium"字段)
        return JSONUtil.parseObj(response)
                .getJSONArray("photos")
                .stream()
                .map(photoObj -> (JSONObject) photoObj)
                .map(photoObj -> photoObj.getJSONObject("src"))
                .map(photo -> photo.getStr("medium"))
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.toList());
    }
}

编写这种代码要多看 pexels官网 给的例子,借助官网和大模型生成。

2.6、测试

debug 模式下结果如下
在这里插入图片描述
我们随便打开一个网址,在网页中输入,显示如下:
在这里插入图片描述
MCP服务开发成功!!!

2.6、在主类注册工具

在主类中通过定义 ToolCallbackProvider Bean 来注册工具

@SpringBootApplication
public class YuAnImageSearchMcpServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(YuAnImageSearchMcpServerApplication.class, args);
    }

    @Bean
    public ToolCallbackProvider imageSearchTools(ImageSearchTool imageSearchTool){
        return MethodToolCallbackProvider.builder()
                .toolObjects(imageSearchTool)
                .build();
    }

}

3、客户端开发

3.1、先引入必要的 MCP 客户端依赖

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
    <version>1.0.0-M6</version>
</dependency>

3.2、测试stdio 传输方式

先测试 stdio 传输方式。在 mcp-servers.json 配置文件中新增 MCP Server 的配置,通过 java 命令执行我们刚刚打包好的 jar 包。

{
  "mcpServers": {
    "amap-maps": {
      "command": "npx.cmd",
      "args": [
        "-y",
        "@amap/amap-maps-mcp-server"
      ],
      "env": {
        "AMAP_MAPS_API_KEY": "你自己申请的 API"
      }
    },
    "yuAn-image-search-mcp-server": {
      "command": "java",
      "args": [
        "-Dspring.ai.mcp.server.stdio=true",
        "-Dspring.main.web-application-type=none",
        "-Dlogging.pattern.console=",
        "-jar",
        "yuAn-image-search-mcp-server/target/yuAn-image-search-mcp-server-0.0.1-SNAPSHOT.jar"
      ],
      "env": {}
    }
  }
}

3.3、测试运行。

编写单元测试代码:

@Test
void doChatWithMcp() {
    // 测试图片搜索 MCP
    String message = "帮我搜索一些哄另一半开心的图片";
    String answer =  loveApp.doChatWithMcp(message, chatId);
    Assertions.assertNotNull(answer);
}

结果返回
在这里插入图片描述
我们点击看一下
在这里插入图片描述

(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)(⊙﹏⊙)

还行吧

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐