【SpringAIAlibaba新手村系列】(15)MCP Client 调用本地服务

简介: 本章从 MCP Client 视角说明如何连接上一章提供的本地服务,并把远端工具接入 ChatClient。重点讲解 Streamable-HTTP 配置、ToolCallbackProvider 的注入方式,以及模型如何通过 JSON-RPC 消息完成工具调用与结果回传。

第十五章 MCP Client 调用本地服务

版本标注

  • Spring AI: 1.1.2
  • Spring AI Alibaba: 1.1.2.0

章节定位

  • 第十四章负责提供本地 MCP 服务。
  • 这一章负责连接这个服务,并把远端工具接入当前应用。

s01 > s02 > s03 > s04 > s05 > s06 > s07 > s08 > s09 > s10 > s11 > s12 > s13 > s14 > [ s15 ] s16 > s17 > s18


一、本章要做什么

上一章已经把天气能力作为 MCP Server 暴露出来,这一章的任务就是连接这个服务,并把它提供的工具注册给 ChatClient。完成后,模型在回答问题时就可以主动调用上一章中的天气工具。

这一步的重点不在服务端,而在客户端接入。

二、配置文件

本章的 application.yml 中,MCP Client 相关配置如下:

server:
  port: 8015

spring:
  application:
    name: mcp-client-demo

  ai:
    dashscope:
      api-key: ${
   DASHSCOPE_API_KEY}

    mcp:
      client:
        type: async
        request-timeout: 60s
        toolcallback:
          enabled: true

        streamable-http:
          connections:
            mcp-server1:
              url: http://localhost:8014
              endpoint: /mcp

这里的含义很直接:当前应用作为 MCP Client,通过 Streamable-HTTP 方式连接运行在 8014 端口上的本地服务。配置中的 url 是服务基础地址,endpoint 则是客户端真正连接的协议端点。它和上一章服务端配置中的 protocol: STREAMABLE 是一一对应的:服务端负责暴露 Streamable-HTTP 能力,客户端负责连接这个 Streamable-HTTP 端点。

三、配置类

最终跑通后的配置类如下:

package cn.edu.nnu.opengms.config;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SaaLLMConfig {
   

    @Bean("mcpChatClient")
    public ChatClient mcpChatClient(
            ChatModel chatModel,
            ToolCallbackProvider tools)
    {
   
        return ChatClient.builder(chatModel)
                .defaultToolCallbacks(tools.getToolCallbacks())
                .build();
    }
}

这段代码只表达一件事:把 MCP Client 发现到的远端工具回调注册给 ChatClient

这里使用的是 defaultToolCallbacks(...),因为当前注册的不是本地工具对象,而是框架已经整理好的工具回调。

四、控制器

控制器代码如下:

package cn.edu.nnu.opengms.controller;

import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@RestController
public class McpClientController {
   
    @Resource
    private ChatClient chatClient;

    @Resource
    private ChatModel chatModel;

    @GetMapping("/mcpclient/chat")
    public Flux<String> chat(@RequestParam(name = "msg", defaultValue = "北京") String msg)
    {
   
        System.out.println("使用了mcp");
        return chatClient.prompt(msg).stream().content();
    }

    @RequestMapping("/mcpclient/chat2")
    public Flux<String> chat2(@RequestParam(name = "msg", defaultValue = "北京") String msg)
    {
   
        System.out.println("未使用mcp");
        return chatModel.stream(msg);
    }
}

这里的 chatClient 实际上就是配置类中定义的 mcpChatClient Bean,因此 /mcpclient/chat 走的是带 MCP 工具能力的调用链。

/mcpclient/chat2 则直接使用 ChatModel,不会触发 MCP 工具。

如果希望代码语义更明确,也可以写成:

@Resource(name = "mcpChatClient")
private ChatClient mcpChatClient;

五、MCP Client 调用本地服务的原理

这一章真正需要理解的,不只是配置项怎么写,而是客户端和服务端到底是怎样连起来的。

Spring AI 官方对自己的定位是:把企业中的 DataAPIs 接到 AI Models 上。MCP 在这里扮演的就是标准桥梁。它不是简单的“远程调用工具”,而是把工具发现、能力协商、消息交换和调用结果回传都统一到了同一套协议里。

从 Spring AI 和 MCP Java SDK 的结构来看,这条链路可以分成三层:

  1. 客户端/服务端层
    这一层的角色分别是 McpClientMcpServer。客户端负责建立连接、初始化会话、发现服务端能力;服务端负责暴露工具、资源和提示模板,并处理客户端发来的调用请求。

  2. 会话层
    这一层由 McpSession 负责维护会话状态。客户端启动后,不是每次调用工具都重新“临时拼一个 HTTP 请求”,而是先建立 MCP 会话,再在会话中完成后续的协议交互。

  3. 传输层
    这一层负责真正的消息收发和 JSON-RPC 编解码。Spring AI 文档里明确说明,MCP 支持 STDIOSSEStreamable-HTTP 等多种传输方式。本章客户端连接的是服务端提供的 Streamable-HTTP 端点。

5.1 本章里的连接是怎么建立的

本章配置的是:

spring:
  ai:
    mcp:
      client:
        streamable-http:
          connections:
            mcp-server1:
              url: http://localhost:8014
              endpoint: /mcp

根据 Spring AI MCP Client Starter 文档,Streamable-HTTP 连接配置由两部分组成:

  1. url
    这是服务端的基础地址,例如 http://localhost:8014

  2. endpoint
    这是 Streamable-HTTP 端点路径。官方文档给出的默认值是 /mcp。如果没有显式配置,客户端会按默认值去拼接。

也就是说,本章这条配置最终连接的并不是单纯的根路径,而是基于基础地址和 Streamable-HTTP 端点拼出来的服务入口。服务端上一章显式声明了 protocol: STREAMABLE,客户端这一章再通过 endpoint: /mcp 去连接它,这样两边的配置就能完整对上。

5.2 连接成功后,客户端做了什么

客户端启动后,并不是立刻让模型开始调工具,而是会先完成一次 MCP 初始化过程。这个过程通常包括:

  1. 建立到服务端的 Streamable-HTTP 连接
  2. 完成协议初始化
  3. 进行版本和能力协商
  4. 拉取服务端已经暴露的工具列表

Spring AI 的 MCP Client Starter 在 toolcallback.enabled=true 时,会把这些发现到的远端工具整理成 ToolCallbackProvider。这也是为什么本章最终可以直接注入:

ToolCallbackProvider tools

这一步完成后,当前应用就已经知道:服务端提供了哪些工具、每个工具叫什么、需要什么参数、调用后会返回什么结果。

5.3 模型调用工具时,消息是怎样流动的

真正进入对话时,链路是这样的:

用户问题
  -> ChatClient
  -> ChatModel
  -> 模型判断需要调用远端工具
  -> ToolCallbackProvider 中对应的 MCP 工具回调
  -> MCP Client 通过会话发送 JSON-RPC 消息
  -> MCP Server 接收请求并执行本地工具方法
  -> 服务端返回工具执行结果
  -> ChatClient 将结果交回模型
  -> 模型组织最终回答

其中最关键的两个动作是:

  1. 发送消息
    客户端不会直接去调用上一章中的 Java 方法,而是把工具名称、参数等信息封装为 MCP 协议消息,通过 Streamable-HTTP 连接发给服务端。Spring AI 文档说明,底层传输层负责 JSON-RPC 消息的序列化和反序列化。

  2. 接收结果
    服务端执行完工具方法后,会把结果再按 JSON-RPC 消息返回给客户端。客户端拿到结果后,不是直接把原始数据返回给用户,而是继续交给当前对话链路中的模型,让模型基于工具结果生成最终自然语言回答。

所以从用户角度看,好像只是“模型回答了一个天气问题”;但实际内部已经发生了一次完整的 MCP 会话消息交换。

5.4 为什么这里既像远程调用,又不像普通 HTTP 接口

因为 MCP 不只是一个“请求某个 URL 然后拿 JSON”的简单接口,它本身还负责:

  • 能力发现
  • 协议初始化
  • 工具描述统一
  • 调用消息标准化
  • 结果回传

普通 HTTP 接口只解决“发请求、拿响应”,而 MCP 解决的是“AI 应用如何以统一协议理解并调用外部能力”。这也是为什么这一章里,客户端只要拿到 ToolCallbackProvider,后面的工具调用就可以直接挂到 ChatClient 上,而不需要手写一套天气接口适配逻辑。

5.5 为什么这里改用 Streamable-HTTP

这一章最开始也可以用 SSE 跑通,但最终改成 Streamable-HTTP 更合适,主要有两个原因。

第一,Spring AI 官方文档已经把 Streamable-HTTP 作为更推荐的方向来描述。它比早期的 SSE 方案更贴近 MCP 后续演进的主线,因此用它来写当前版本的笔记,稳定性和可迁移性都会更好一些。

第二,Streamable-HTTP 的配置语义更清楚。客户端配置里直接写基础地址和 endpoint,服务端则显式切到 STREAMABLE 协议,阅读成本比 SSE 场景下去理解默认 /sse 端点更低。对于这一章这种本地联调案例,这种写法更容易把“服务地址”和“协议端点”区分开。

六、测试方式

启动顺序如下:

  1. 先启动上一章中的本地 MCP 服务
  2. 再启动当前客户端应用

测试接口:

http://localhost:8015/mcpclient/chat?msg=上海天气怎么样
http://localhost:8015/mcpclient/chat2?msg=上海天气怎么样

这两条接口的差异很清楚:

  • /mcpclient/chat:带 MCP 工具能力
  • /mcpclient/chat2:只用模型本身回答

如果链路已经打通,/mcpclient/chat 的返回会带上上一章天气工具中的固定结果;如果没有调通,通常会返回“无法实时获取天气信息”这类模型自答内容。

七、本章小结

这一章的核心就是把远端 MCP 工具接到本地对话链路里。对应到代码层面,关键实现只有这一句:

.defaultToolCallbacks(tools.getToolCallbacks())

它把上一章暴露出来的工具能力真正注册给了 ChatClient。之后模型在回答问题时,就具备了调用本地 MCP 服务的能力。


本章重点

  1. 当前应用的角色是 MCP Client,不再负责定义工具。
  2. ToolCallbackProvider 提供的是远端工具回调集合。
  3. defaultToolCallbacks(...) 是当前项目最终跑通的接入方式。

下章剧透(s16):

本地 MCP 服务联通后,下一章继续扩展到第三方 MCP 服务接入。


📝 编辑者:Flittly
📅 更新时间:2026年4月
🔗 相关资源MCP 官方文档 | Spring AI MCP

目录
相关文章
|
6天前
|
人工智能 数据可视化 安全
王炸组合!阿里云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!(附带免费使用6个月服务器)
本文详解如何用阿里云Lighthouse一键部署OpenClaw,结合飞书CLI等工具,让AI真正“动手”——自动群发、生成科研日报、整理知识库。核心理念:未来软件应为AI而生,CLI即AI的“手脚”,实现高效、安全、可控的智能自动化。
26300 14
王炸组合!阿里云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!(附带免费使用6个月服务器)
|
18天前
|
人工智能 JSON 机器人
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
本文带你零成本玩转OpenClaw:学生认证白嫖6个月阿里云服务器,手把手配置飞书机器人、接入免费/高性价比AI模型(NVIDIA/通义),并打造微信公众号“全自动分身”——实时抓热榜、AI选题拆解、一键发布草稿,5分钟完成热点→文章全流程!
37463 141
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
|
7天前
|
人工智能 JSON 监控
Claude Code 源码泄露:一份价值亿元的 AI 工程公开课
我以为顶级 AI 产品的护城河是模型。读完这 51.2 万行泄露的源码,我发现自己错了。
4669 20
|
6天前
|
人工智能 API 开发者
阿里云百炼 Coding Plan 售罄、Lite 停售、Pro 抢不到?最新解决方案
阿里云百炼Coding Plan Lite已停售,Pro版每日9:30限量抢购难度大。本文解析原因,并提供两大方案:①掌握技巧抢购Pro版;②直接使用百炼平台按量付费——新用户赠100万Tokens,支持Qwen3.5-Max等满血模型,灵活低成本。
1516 3
阿里云百炼 Coding Plan 售罄、Lite 停售、Pro 抢不到?最新解决方案

热门文章

最新文章