6-MCP-让AI助手与万物互联

181 阅读6分钟

1-背景故事

前几篇通过RAG让她具备搜索私有资料库的能力,还用工具将RAG的填鸭式增强,改造成了AI主动调用工具智能增强。

但是每次对AI助手的增强,都改写AI助手的代码、并部署|重启。

这种强耦合关系,意味着每次对工具的扩展,都要依赖AI助手同样特定的语言和框架实现、运行资源。

另外互联网上有成千上万的现成工具,不可能每一个都要封装成本地工具给AI助手使用。

好在MCP协议已诞生,可以通过通用协议,将AI助手与工具解耦,同时也可以将AI助手接入万维网,与万物互联。 java-mcp-client-architecture.jpg

2-动手实践

Spring AI同样以Spring Boot的方式,为AI项目集成MCP协议提供了极大的便利。

原有Spring AI项目,只需要两处改造,即可将本地工具改为基于MCP协议的工具调用:

2.1-将工具提取为独立的MCP Server

步骤一:创建Spring Boot项目

使用Spring Initializr创建名为mcp-server的项目,并包含以下依赖:

<!-- mcp-server/pom.xml -->
<!-- ... -->
<properties>
    <java.version>21</java.version>
    <spring-ai.version>1.0.0</spring-ai.version>
</properties>
<!-- ... -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
    <version>${spring-ai.version}</version>
</dependency>
<!-- ... -->

参考:WebMVC Server Transport

步骤二:将工具代码移动到mcp-server项目中

将原助手项目中的工具代码文件移动到mcp-server项目中,也可以使用以下代码:

@Slf4j
@Component
public class DateTimeTools {
    @Tool(description = "获取当前日期时间")
    String getCurrentLocalDateTime() {
        String current = LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
        log.info("获取当前日期时间: {}", current);
        return current;
    }

    @Tool(description = "获取当前日期")
    String getCurrentLocalDate() {
        String current = LocalDate.now().toString();
        log.info("获取当前日期: {}", current);
        return current;
    }

    @Tool(description = "获取当前时间")
    String getCurrentLocalTime() {
        String current = LocalTime.now().toString();
        log.info("获取当前时间: {}", current);
        return current;
    }

    @Tool(description = "日期时间计算工具,获取某段时间前/后的日期时间非常有用")
    String getOffsetTime(@ToolParam(description = "时间差") Duration plusTime) {
        String datetime = LocalDateTime.now().plus(plusTime).atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
        log.info("当前偏移时间: {}", datetime);
        return datetime;
    }

    /**
     * tool描述最好与用户语言一致,以便大模型理解,@ToolParam不是必须的,变量名取得好,大模型就能理解
     *
     * @param atDateTime 要定时的日期
     * @param action     要执行的动作
     */
    @Tool(description = "设置一个指定日期时间的提醒")
    void setAlarm(@ToolParam(description = "ISO-8601格式的具体时间点") String atDateTime, @ToolParam(description = "要执行的动作") String action) {
        LocalDateTime alarmTime = LocalDateTime.parse(atDateTime, DateTimeFormatter.ISO_DATE_TIME);
        log.info("请在:{} {}", alarmTime, action);
    }
}

步骤三:暴露工具为mcp服务

我们只需要创建一个Spring配置类,使用生成器将工具实体导出成ToolCallbackProvider,Spring AI将自动帮我们将工具转换为MCP服务

@Configuration
public class MCPServerConfig {
    @Bean
    public ToolCallbackProvider toolCallbackProviders(final DateTimeTools dateTimeTools) {
        return MethodToolCallbackProvider.builder().toolObjects(dateTimeTools).build();
    }
}

步骤四:配置mcp-server

# 配置使用新端口,以避免与AI助手冲突
server:
  port: 7002
spring:
  ai:
    mcp:
      server:
        # 以下配置项建议配置:
        name: webmvc-mcp-server
        version: 1.0.0
        instructions: "此服务提供时间工具"
        # 以下配置项可选,使用默认值即可,此处为展示关键信息
        # MCP Server类型,Webmvc项目为SYNC,Webflux项目为ASYNC
        type: SYNC
        sse-message-endpoint: /mcp/messages
        # 开放的工具能力
        capabilities:
          tool: true

完成以上配置之后,即可启动MCP工具服务,以待AI助手调用

2.2-AI助手调用MCP工具服务

步骤一:添加MCP客户端依赖

原AI助手项目的pom.xml中添加以下依赖项:

       <!-- MCP Tools -->
       <dependency>
          <groupId>org.springframework.ai</groupId>
          <artifactId>spring-ai-starter-mcp-client</artifactId>
       </dependency>

步骤二:配置MCP工具服务地址

application.yaml中配置MCP工具服务的地址:

spring:
  ai:
    mcp:
      client:
        sse:
          connections:
            datetime-tools:
              url: http://localhost:7002

步骤三:代码中使用MCP工具

将原使用本地工具的代码,替换为使用MCP工具:

@RestController
public class MyChatController {
    private final ChatClient chatClient;

    public MyChatController(ChatClient.Builder chatClientBuilder, ChatMemoryRepository chatMemoryRepository, List<McpSyncClient> mcpSyncClients) {
        //...
        this.chatClient = chatClientBuilder
                .defaultAdvisors(new SimpleLoggerAdvisor())
                .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
                // 添加MCP工具
                .defaultToolCallbacks(McpToolUtils.getToolCallbacksFromSyncClients(mcpSyncClients))
                .build();
    }
    //...
}

2.3-测试效果

使用前面的用例测试效果:

# 发送消息:当前的日期时间
curl http://localhost:8080/ai/chat?message=%E5%BD%93%E5%89%8D%E7%9A%84%E6%97%A5%E6%9C%9F%E6%97%B6%E9%97%B4
# AI助手回复(这个时间确实是当前时间)
当前的日期时间是 2025年6月23日 15:36:23(北京时间)。
# 发送消息:10分钟后的日期时间
curl http://localhost:8080/ai/chat?message=10%E5%88%86%E9%92%9F%E5%90%8E%E7%9A%84%E6%97%A5%E6%9C%9F%E6%97%B6%E9%97%B4
# AI助手回复(这个时间确实是当前时间10分钟后的时间):
10分钟后的日期时间是 20252025年6月23日 15:47:16(北京时间)。

💡可以看到,MCP工具与本地工具效果一致——但此时我们不用修改AI助手的代码,而为AI助手添加更多工具

2.4-添加第三方MCP服务

要添加第三方工具服务,也非常简单:

步骤一:获取一个第三方MCP服务地址:

我们可以去国内的MCP市场上查找一个第三方MCP图表服务API。

通过登录/注册,,并获取MCP URL,可以得到一个类似以下的MCP Server地址: https://mcpmarket.cn/sse/xxxxxxxxxxxxxxxxxxxxx

步骤二:将第三方MCP服务引入AI助手

直接在AI助手的配置文件中添加刚获取到的MCP Server

# application.yaml
spring:
  ai:
    mcp:
      client:
        # 注意调用第三方MCP Server时适当调整请求超时时长,以避免超时失败
        request-timeout: 40s
        sse:
          connections:
            # 第三方MCP服务配置,键名可自定义
            mcp-server-chart:
              # 注意上一步获取到的MCP URL要拆分成url和sse-endpoint两部分配置
              url: "https://mcpmarket.cn"
              sse-endpoint: "/sse/xxxxxxxxxxxxxxxxxxxxx"

通过以上配置,即完成了第三方MCP服务的添加,聊天时对工具的引用前面的代码已经完成。

2.5-测试第三方MCP工具

# 发送消息:生成2000年到2010年世界人口增长折线图
curl http://localhost:8080/ai/chat?message=%E7%94%9F%E6%88%902000%E5%B9%B4%E5%88%B02010%E5%B9%B4%E4%B8%96%E7%95%8C%E4%BA%BA%E5%8F%A3%E5%A2%9E%E9%95%BF%E6%8A%98%E7%BA%BF%E5%9B%BE
# AI助手回复:
以下是2000年到2010年世界人口增长趋势的折线图:
![世界人口增长趋势 (2000-2010)](https://mdn.alipayobjects.com/one_clip/afts/img/MP3RQo5WlWAAAAAARdAAAAgAoEACAQFr/original)
从图中可以清晰地看到,世界人口从2000年的60.85亿增长到2010年的68.57亿,呈现稳步上升的趋势。

打开AI助手返回的链接,就可以看到生成的图表: world-population-growth.jpeg

3-课外拓展

  1. 尝试将上一篇的知识库工具也移动到MCP Server中;
  2. 尝试将时间工具和知识库工具工具拆分为两个独立的MCP Server并引入AI助手中;
  3. 尝试查找并接入更多第三方MCP服务。

4-参考资料