大模型开发 - SpringAI之MCP Client开发:让Agent动态调用远程工具服务

文章目录

  • 引言
  • 一、MCP协议概念:标准化的工具连接
  • 二、MCP架构设计:Client-Server通信模式
    • [2.1 整体架构图](#2.1 整体架构图)
    • [2.2 通信流程](#2.2 通信流程)
    • 阶段1:初始化与发现(Startup)
    • [阶段2:工具调用(Tool Calling)](#阶段2:工具调用(Tool Calling))
    • [2.3 ToolCallbackProvider的职责](#2.3 ToolCallbackProvider的职责)
  • 三、依赖引入与项目配置
    • [3.1 添加MCP Client依赖](#3.1 添加MCP Client依赖)
    • [3.2 MCP Server端配置](#3.2 MCP Server端配置)
    • [3.3 MCP Client端配置](#3.3 MCP Client端配置)
  • [四、MCP Server端实现详解](#四、MCP Server端实现详解)
    • [4.1 WeatherService:工具提供者](#4.1 WeatherService:工具提供者)
    • [@McpTool - 可调用的函数工具](#@McpTool - 可调用的函数工具)
    • [@McpResource - 只读数据资源](#@McpResource - 只读数据资源)
    • [@McpPrompt - 预设提示词模板](#@McpPrompt - 预设提示词模板)
    • [4.2 MCP Server的启动配置](#4.2 MCP Server的启动配置)
  • [五、MCP Client端实现详解](#五、MCP Client端实现详解)
    • [5.1 McpController:工具调用的入口](#5.1 McpController:工具调用的入口)
    • [5.2 实际测试](#5.2 实际测试)
  • [六、MCP vs 直接Tool Calling:架构对比](#六、MCP vs 直接Tool Calling:架构对比)
    • [6.1 直接Tool Calling方式(之前的做法)](#6.1 直接Tool Calling方式(之前的做法))
    • [6.2 MCP Client方式(新做法)](#6.2 MCP Client方式(新做法))
    • [6.3 对比表](#6.3 对比表)
    • [6.4 选择策略](#6.4 选择策略)
  • 七、MCP协议深度探讨
    • [7.1 MCP的Request-Response模式](#7.1 MCP的Request-Response模式)
    • Request格式
    • Response格式
    • [7.2 参数自动映射](#7.2 参数自动映射)
    • [7.3 连接池与健康检查](#7.3 连接池与健康检查)
  • 八、生产环保的最佳实践
    • [8.1 错误处理](#8.1 错误处理)
    • [8.2 日志与监控](#8.2 日志与监控)
    • [8.3 版本兼容性](#8.3 版本兼容性)
    • [8.4 安全性考虑](#8.4 安全性考虑)
    • 认证与授权
    • 速率限制
  • 九、实战案例:多Agent系统架构
  • 十、常见问题与故障排查
    • [10.1 "Tool not found" 错误](#10.1 "Tool not found" 错误)
    • [10.2 网络延迟](#10.2 网络延迟)
    • [10.3 Server宕机处理](#10.3 Server宕机处理)
  • 十一、总结与展望
    • [11.1 MCP Client的核心价值](#11.1 MCP Client的核心价值)
    • [11.2 MCP的未来](#11.2 MCP的未来)
    • [11.3 学习路线](#11.3 学习路线)
    • [11.4 与我们之前学到的内容的联系](#11.4 与我们之前学到的内容的联系)
  • 总结

引言

当我们的AI Agent功能足够丰富时,一个新的问题浮现出来:如何让多个独立的Agent系统共享工具能力?

考虑这样的场景:

  • 一个天气查询服务单独部署在8082端口,提供"获取天气"工具
  • 一个医疗咨询Agent部署在8081端口,需要调用天气工具
  • 两个系统怎样才能优雅地协作,而不是把工具代码重复写一遍?

MCP(Model Context Protocol)协议 应运而生。它是Anthropic定义的一套标准化协议,用于AI模型与外部工具服务进行通信。Spring AI从1.1.0版本开始原生支持MCP Client,让我们可以:

  1. 动态发现远程MCP Server提供的所有工具
  2. 跨进程调用这些工具,就像本地工具一样自然
  3. 简化部署------工具无需重复编码,可以被多个Agent共享

本文将深入讲解MCP协议的设计理念、Spring AI的实现方式,以及如何通过仅仅几行配置,让你的Agent获得访问远程工具服务的能力。


一、MCP协议概念:标准化的工具连接

1.1 为什么需要MCP?

在MCP出现之前,工具调用是这样的:

java 复制代码
┌─────────────────────────┐
│      Agent 1 (8081)     │
│  ├─ Tool A              │
│  ├─ Tool B              │
│  └─ Tool C              │
└─────────────────────────┘

┌─────────────────────────┐
│      Agent 2 (8082)     │
│  ├─ Tool A  (重复)      │
│  ├─ Tool B  (重复)      │
│  └─ Tool D              │
└─────────────────────────┘

问题多多

  • 工具代码重复维护
  • 工具版本不一致
  • 扩展新工具需要修改多处代码
  • 微服务之间缺乏标准的工具调用协议

MCP的出现改变了这一切:

java 复制代码
┌──────────────────────┐
│   Agent Client       │
│   (8081)             │
│  ToolCallbackProvider│────┐
└──────────────────────┘    │
                            │ MCP Protocol
                            │ (HTTP/WebSocket)
                            ▼
┌──────────────────────┐
│   MCP Server         │
│   (8082)             │
│  ├─ Weather Tool     │
│  ├─ Config Resource  │
│  └─ Greeting Prompt  │
└──────────────────────┘

1.2 MCP的三大核心概念

工具(Tools)

MCP Server暴露的可执行函数,Client可以通过标准协议调用。

比如WeatherService的getWeather方法:

java 复制代码
@McpTool(description = "获取指定城市的天气")
public String getWeather(String cityName) {
    // ... 实现
}

资源(Resources)

MCP Server暴露的数据资源,可以被Client读取。用于传输静态配置、模板等。

java 复制代码
@McpResource(uri = "config://{key}", name = "configuration")
public String getConfig(String key) {
    return environment.getProperty(key, "123");
}

提示词(Prompts)

MCP Server定义的预设提示模板,Client可以请求并使用这些模板。

java 复制代码
@McpPrompt(name = "greeting", description = "欢迎语")
public McpSchema.GetPromptResult greeting(@McpArg(name = "name") String name) {
    String message = "你好, " + name + "! 有什么可以帮您?";
    return new McpSchema.GetPromptResult(...);
}

1.3 MCP的设计哲学

标准化:所有MCP Server都遵循同一套接口规范,Client无需关心具体实现。

解耦:Server和Client独立部署、独立升级,通过协议通信。

动态发现:Client启动时自动探测Server的所有能力(tools、resources、prompts),不需要硬编码工具列表。

协议中立:MCP本身与传输层无关,可以用HTTP、WebSocket、stdio等多种方式实现。


二、MCP架构设计:Client-Server通信模式

2.1 整体架构图

java 复制代码
┌─────────────────────────────────────────────────────────────┐
│                    Spring AI Application                      │
│                                                               │
│  ┌──────────────────────────────────────────────────────┐   │
│  │                  ChatClient                            │   │
│  │  (负责与大模型交互)                                    │   │
│  └──────────────────────────────────────────────────────┘   │
│                         ▲                                     │
│                         │                                     │
│  ┌──────────────────────┴──────────────────────────────┐   │
│  │                                                       │   │
│  │  ToolCallbackProvider.getToolCallbacks()            │   │
│  │  (动态加载MCP Server的工具)                          │   │
│  │                                                       │   │
│  └──────────────────────┬──────────────────────────────┘   │
└─────────────────────────┼──────────────────────────────────┘
                          │
                ┌─────────┴─────────┐
                │  MCP HTTP Client   │
                │  Connection Pool   │
                └─────────┬─────────┘
                          │
                  MCP Protocol (HTTP)
                  streamable-http://
                          │
                ┌─────────▼─────────┐
                │  MCP Server       │
                │  (8082)           │
                │                   │
                │ ┌──────────────┐  │
                │ │ WeatherTool  │  │
                │ │ ConfigResource   │
                │ │ GreetingPrompt   │
                │ └──────────────┘  │
                └───────────────────┘

2.2 通信流程

阶段1:初始化与发现(Startup)

  1. MCP Client启动时,连接到Server
  2. 发送initialize请求,告诉Server客户端信息
  3. Server响应,返回自己支持的协议版本
  4. Client发送list-tools请求,获取所有可用工具
  5. Server返回工具列表,包含工具名、描述、参数schema
java 复制代码
Client                           Server
  │                              │
  ├──────── initialize ─────────►│
  │                              │
  │◄─── initialize response ─────┤
  │                              │
  ├──────── list-tools ─────────►│
  │                              │
  │◄─── [getWeather, ...] ───────┤

阶段2:工具调用(Tool Calling)

当大模型决定调用工具时:

java 复制代码
┌─ ChatClient ──────────────────────────────┐
│  prompt: "上海天气怎样?"                   │
│  tools: [getWeather, ...]                 │
│  (tools来自MCP Server)                    │
└────────────┬──────────────────────────────┘
             │
             ▼
┌─ LLM Response ────────────────┐
│  {                             │
│    "tool_calls": [             │
│      {                         │
│        "id": "call_123",       │
│        "function": {           │
│          "name": "getWeather", │
│          "arguments": {        │
│            "cityName": "上海"  │
│          }                     │
│        }                       │
│      }                         │
│    ]                           │
│  }                             │
└────────────┬──────────────────┘
             │
             ▼
┌─ ToolCallbackProvider ────────────────────┐
│  1. 识别工具名: getWeather                 │
│  2. 从MCP Server动态调用                  │
│  3. 返回结果: "天晴"                      │
└────────────┬──────────────────────────────┘
             │
             ▼
┌─ ChatClient ──────────────────────────────┐
│  添加tool message到memory                 │
│  继续与LLM交互                            │
└────────────────────────────────────────────┘

2.3 ToolCallbackProvider的职责

ToolCallbackProvider是Spring AI中的关键接口,负责:

  1. 工具发现:启动时连接MCP Server,获取所有工具定义
  2. 生成Callbacks:为每个工具创建可调用的Callback对象
  3. 动态绑定:大模型调用工具时,动态找到对应Callback并执行

伪代码如下:

java 复制代码
public class McpToolCallbackProvider implements ToolCallbackProvider {

    private final MCP_CLIENT mcpClient;  // MCP HTTP客户端

    public List<ToolCallback> getToolCallbacks() {
        // 1. 从MCP Server发送list-tools请求
        List<Tool> tools = mcpClient.listTools();

        // 2. 为每个工具创建动态Callback
        return tools.stream()
            .map(tool -> createCallback(tool))
            .toList();
    }

    private ToolCallback createCallback(Tool tool) {
        return new ToolCallback() {
            @Override
            public String getName() {
                return tool.getName();
            }

            @Override
            public String getDescription() {
                return tool.getDescription();
            }

            @Override
            public String call(String arguments) {
                // 3. 实际调用:远程调用MCP Server的工具
                return mcpClient.callTool(tool.getName(), arguments);
            }
        };
    }
}

三、依赖引入与项目配置

3.1 添加MCP Client依赖

spring-ai-demo/pom.xml中,与其他Spring AI依赖并列添加:

xml 复制代码
<dependencies>
    <!-- 现有依赖... -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-client</artifactId>
    </dependency>
</dependencies>

这个依赖包含:

  • MCP Client核心库
  • HTTP连接器(streamable-http)
  • ToolCallbackProvider实现

3.2 MCP Server端配置

spring-ai-mcp-server-demo/src/main/resources/application.yml中:

yaml 复制代码
spring:
  ai:
    mcp:
      server:
        name: weather-mcp-server        # Server名称
        protocol: streamable             # 使用HTTP协议

server:
  port: 8082                             # 独立端口

关键点

  • protocol: streamable表示使用HTTP SSE(Server-Sent Events)方式
  • 端口8082与Client的配置相对应

3.3 MCP Client端配置

spring-ai-demo/src/main/resources/application.yml中:

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        name: spring-ai-mcp-client-demo     # Client名称,标识自己
        streamable-http:                     # HTTP连接方式
          connections:
            server1:                         # 连接名(任意)
              url: http://localhost:8082    # MCP Server地址

重要参数说明

参数 说明 示例
name 当前应用在MCP中的标识 spring-ai-mcp-client-demo
connections 可以连接多个MCP Server 下例支持多Server
url MCP Server的HTTP入口 http://localhost:8082

多Server配置示例

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        streamable-http:
          connections:
            weather-server:
              url: http://localhost:8082
            config-server:
              url: http://config-server:9000
            search-server:
              url: http://search-server:9001

此时Client会自动发现三个Server的所有工具。


四、MCP Server端实现详解

4.1 WeatherService:工具提供者

MCP Server通过@McpTool注解声明工具:

java 复制代码
@Service
@Log4j2
public class WeatherService {

    @Autowired
    private Environment environment;

    // 工具1:获取天气
    @McpTool(description = "获取指定城市的天气")
    public String getWeather(String cityName) {
        log.info("正在获取天气信息...");
        if (cityName.equals("上海")) {
            return "天晴";
        } else if (cityName.equals("北京")) {
            return "下雨";
        }
        return "不知道";
    }

    // 工具2:问候提示词
    @McpPrompt(name = "greeting", description = "欢迎语")
    public McpSchema.GetPromptResult greeting(@McpArg(name = "name") String name) {
        String message = "你好, " + name + "! 有什么可以帮您?";
        return new McpSchema.GetPromptResult(
            "Greeting",
            List.of(new McpSchema.PromptMessage(
                McpSchema.Role.ASSISTANT,
                new McpSchema.TextContent(message)
            ))
        );
    }

    // 工具3:配置资源
    @McpResource(uri = "config://{key}", name = "configuration")
    public String getConfig(String key) {
        return environment.getProperty(key, "123");
    }
}

三种能力详解

@McpTool - 可调用的函数工具

java 复制代码
@McpTool(description = "获取指定城市的天气")
public String getWeather(String cityName) { ... }
  • 可被Client动态调用
  • 参数自动序列化为JSON Schema
  • 返回值作为工具执行结果

当Client调用时,MCP协议自动处理:

json 复制代码
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "getWeather",
    "arguments": {
      "cityName": "上海"
    }
  }
}

@McpResource - 只读数据资源

java 复制代码
@McpResource(uri = "config://{key}", name = "configuration")
public String getConfig(String key) { ... }
  • URI模板:支持参数化读取
  • 读取示例config://spring.datasource.url → 返回数据库地址
  • 用途:共享配置、常量、模板等静态资源

@McpPrompt - 预设提示词模板

java 复制代码
@McpPrompt(name = "greeting", description = "欢迎语")
public McpSchema.GetPromptResult greeting(@McpArg(name = "name") String name) { ... }
  • 提供预编写的提示词
  • 支持参数化(如用户名)
  • 用途:系统级别的提示词模板共享

4.2 MCP Server的启动配置

java 复制代码
@SpringBootApplication
public class McpServerApplication {

    // 注意:不需要手动配置ToolCallbackProvider
    // Spring AI会自动扫描@McpTool @McpResource @McpPrompt注解
    // 并通过MCP协议暴露这些能力

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

重要:Spring AI自动检测并注册所有带MCP注解的Bean,无需手动配置。


五、MCP Client端实现详解

5.1 McpController:工具调用的入口

java 复制代码
@RestController
public class McpController {

    @Autowired
    private ChatClient chatClient;

    @Autowired
    private ToolCallbackProvider toolCallbackProvider;

    @GetMapping("/mcp")
    public String mcp(String message) {
        return chatClient
                .prompt()
                .user(message)
                .toolCallbacks(toolCallbackProvider.getToolCallbacks())
                .call()
                .content();
    }
}

逐行解析

  1. ToolCallbackProvider toolCallbackProvider

    • Spring AI自动注入
    • 负责从MCP Server动态加载工具
  2. toolCallbackProvider.getToolCallbacks()

    • 返回所有可用工具的Callback列表
    • 这些Callback会被传给大模型
    • 大模型可以选择调用其中任何一个
  3. .toolCallbacks(...)

    • 将MCP Server的工具注入到ChatClient
    • 大模型现在可以使用这些工具
  4. 完整执行流

java 复制代码
GET /mcp?message=上海天气怎样?
         │
         ▼
User: "上海天气怎样?"
Tools: [getWeather (from MCP Server)]  ◄── 动态加载
         │
         ▼
LLM Response: tool_calls=[getWeather(cityName="上海")]
         │
         ▼
ToolCallbackProvider.call("getWeather", {...})
         │
         ▼
MCP Client → HTTP → MCP Server
              tools/call getWeather
         │
         ▼
MCP Server: "天晴"
         │
         ▼
LLM: "根据天气工具的反馈,上海天晴"
         │
         ▼
返回给用户

5.2 实际测试

启动两个应用后,测试MCP调用:

bash 复制代码
# MCP Server启动在8082
cd spring-ai-mcp-server-demo
mvn spring-boot:run

# MCP Client启动在8081
cd spring-ai-demo
mvn spring-boot:run

# 测试调用
curl "http://localhost:8081/mcp?message=上海天气怎样?"

预期输出

java 复制代码
根据我获取的天气信息,上海天晴。

背后的调用链

  1. Client的ChatClient收到请求
  2. 向大模型提交用户问题 + MCP Server暴露的工具列表
  3. 大模型选择调用getWeather("上海")
  4. ToolCallbackProvider通过MCP协议远程调用
  5. 得到"天晴"的结果
  6. 反馈给大模型继续推理
  7. 大模型生成最终回复

六、MCP vs 直接Tool Calling:架构对比

6.1 直接Tool Calling方式(之前的做法)

java 复制代码
@Configuration
public class ToolConfig {

    @Bean
    public ToolCallbackProvider localTools(WeatherService weatherService) {
        // 把WeatherService的方法注册为本地工具
        return MethodToolCallbackProvider.builder()
            .toolObjects(weatherService)
            .build();
    }
}

@RestController
public class ChatController {

    @GetMapping("/chat")
    public String chat(String message) {
        return chatClient.prompt()
            .user(message)
            .toolCallbacks(localTools.getToolCallbacks())  // 本地工具
            .call()
            .content();
    }
}

特点

  • 工具与Agent紧密耦合
  • 工具代码必须与Agent在同一进程
  • 工具更新需要重启Agent应用

6.2 MCP Client方式(新做法)

yaml 复制代码
# 仅需配置,无需代码
spring:
  ai:
    mcp:
      client:
        streamable-http:
          connections:
            server1:
              url: http://localhost:8082
java 复制代码
@RestController
public class McpController {

    @GetMapping("/mcp")
    public String mcp(String message) {
        return chatClient.prompt()
            .user(message)
            .toolCallbacks(toolCallbackProvider.getToolCallbacks())  // 远程工具
            .call()
            .content();
    }
}

特点

  • 工具独立部署
  • Agent与工具解耦
  • 动态发现,无需硬编码
  • 工具更新无需重启Agent

6.3 对比表

维度 直接Tool Calling MCP Client
部署方式 单一进程 多进程
通信方式 方法调用 HTTP/WebSocket RPC
工具发现 硬编码注册 动态发现
工具复用 重复编码 一次部署,多处使用
更新影响 需重启Agent 仅Server重启
网络延迟 有(毫秒级)
扩展性 中等
适用场景 小型单体应用 微服务、多Agent系统

6.4 选择策略

选用直接Tool Calling

  • Agent数量少(1-2个)
  • 工具相对稳定,不常更新
  • 工具逻辑简单,计算量小
  • 无网络延迟要求

选用MCP Client

  • Agent数量多(3个以上)
  • 工具经常更新迭代
  • 多个Agent共享相同工具
  • 工具可能部署在不同机器/容器
  • 需要微服务架构

七、MCP协议深度探讨

7.1 MCP的Request-Response模式

所有通信都遵循JSON-RPC 2.0标准:

Request格式

json 复制代码
{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "tools/call",
  "params": {
    "name": "getWeather",
    "arguments": {
      "cityName": "上海"
    }
  }
}

Response格式

json 复制代码
{
  "jsonrpc": "2.0",
  "id": "1",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "天晴"
      }
    ]
  }
}

或错误响应:

json 复制代码
{
  "jsonrpc": "2.0",
  "id": "1",
  "error": {
    "code": -32600,
    "message": "Invalid Request",
    "data": {
      "details": "city not found"
    }
  }
}

7.2 参数自动映射

MCP Server会自动将Java方法签名转换为JSON Schema,供Client理解:

java 复制代码
@McpTool(description = "获取指定城市的天气")
public String getWeather(String cityName) { ... }

自动生成的Schema:

json 复制代码
{
  "name": "getWeather",
  "description": "获取指定城市的天气",
  "inputSchema": {
    "type": "object",
    "properties": {
      "cityName": {
        "type": "string",
        "description": "城市名称"
      }
    },
    "required": ["cityName"]
  }
}

LLM看到这个Schema,就知道如何调用这个工具。

7.3 连接池与健康检查

Spring AI MCP Client维护HTTP连接池,定期检查Server健康状态:

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        streamable-http:
          connections:
            server1:
              url: http://localhost:8082
              # 可选:配置连接超时
              timeout: 30s
              # 可选:配置心跳间隔
              heartbeat-interval: 60s

如果Server不可用,Client会:

  1. 记录日志
  2. 标记连接为"不可用"
  3. 继续尝试重连
  4. 大模型无法使用该Server的工具(但不会崩溃)

八、生产环保的最佳实践

8.1 错误处理

MCP工具执行失败时,大模型应该收到错误信息:

java 复制代码
@McpTool(description = "获取指定城市的天气")
public String getWeather(String cityName) {
    try {
        // 调用天气API
        WeatherData data = weatherApi.fetch(cityName);
        return data.getDescription();
    } catch (CityNotFoundException e) {
        // 返回有意义的错误信息
        return "Error: 城市 " + cityName + " 不存在";
    } catch (ApiTimeoutException e) {
        return "Error: 天气服务暂时不可用,请稍后重试";
    }
}

大模型会收到这个错误信息,并可能:

  • 重新尝试
  • 使用备选方案
  • 向用户解释为什么无法获取信息

8.2 日志与监控

在Server端详细记录所有工具调用:

java 复制代码
@McpTool(description = "获取指定城市的天气")
public String getWeather(String cityName) {
    log.info("MCP Tool called: getWeather, cityName={}", cityName);
    long startTime = System.currentTimeMillis();

    try {
        String result = fetchWeather(cityName);
        long elapsed = System.currentTimeMillis() - startTime;
        log.info("MCP Tool success: getWeather, cityName={}, elapsed={}ms",
                 cityName, elapsed);
        return result;
    } catch (Exception e) {
        log.error("MCP Tool error: getWeather, cityName={}", cityName, e);
        throw e;
    }
}

关键指标:

  • 工具调用次数
  • 调用延迟(网络+执行)
  • 错误率
  • Server连接状态

8.3 版本兼容性

Server和Client的版本可以不同步,但要保持兼容:

java 复制代码
// Server更新添加新参数时
@McpTool(description = "获取天气")
public String getWeather(
    String cityName,
    @McpArg(required = false) String timestamp  // 新参数,但可选
) {
    // 旧Client发送的请求不包含timestamp,也能正常工作
}

8.4 安全性考虑

认证与授权

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        streamable-http:
          connections:
            secure-server:
              url: https://secure-server:8082
              auth:
                type: bearer
                token: ${MCP_SERVER_TOKEN}  # 环境变量

速率限制

java 复制代码
@McpTool(description = "获取天气")
@RateLimit(requestsPerMinute = 60)
public String getWeather(String cityName) { ... }

九、实战案例:多Agent系统架构

假设你要构建一个企业级AI系统,包含三个独立Agent:

java 复制代码
┌─────────────────────┐
│  ChatBot Agent      │ 8081
│  (对话机器人)       │
└──────────┬──────────┘
           │ MCP
           ├─────────┬─────────┬──────────┐
           │         │         │          │
    ┌──────▼───┐ ┌───▼────┐ ┌─▼──────┐ ┌▼────────┐
    │ Weather  │ │ Config │ │ Search │ │Database │
    │ Service  │ │Service │ │Service │ │Service  │
    │  8082    │ │ 8083   │ │  8084  │ │  8085   │
    └──────────┘ └────────┘ └────────┘ └─────────┘

在ChatBot Agent的配置中:

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        name: chatbot-mcp-client
        streamable-http:
          connections:
            weather:
              url: http://localhost:8082
            config:
              url: http://localhost:8083
            search:
              url: http://localhost:8084
            database:
              url: http://localhost:8085

现在ChatBot Agent可以:

  • 调用WeatherService获取天气
  • 调用ConfigService查询配置
  • 调用SearchService搜索网络
  • 调用DatabaseService查询数据库

这些服务可以独立部署、独立更新、独立扩展,ChatBot完全无感知。


十、常见问题与故障排查

10.1 "Tool not found" 错误

现象:大模型要调用某个工具,但系统报错"Tool not found"

原因

  1. MCP Server未启动
  2. Server地址配置错误
  3. 工具定义有问题

排查步骤

bash 复制代码
# 1. 检查Server是否在线
curl http://localhost:8082/health  # 如果有health endpoint

# 2. 检查Client日志
# 查看是否有"Connected to MCP Server"的日志

# 3. 手动测试工具列表
# 在Client启动日志中应该看到工具列表被加载

# 4. 验证工具名称拼写
# 确保Client请求的工具名与Server定义的完全相同

10.2 网络延迟

现象:工具调用很慢

原因

  • HTTP连接开销
  • 网络距离远
  • Server处理慢

优化方案

yaml 复制代码
# 1. 启用连接复用
spring:
  ai:
    mcp:
      client:
        streamable-http:
          connections:
            server1:
              url: http://localhost:8082
              keep-alive: true
              connection-timeout: 5s

# 2. 部署Server靠近Client
# 使用容器编排工具(Docker, K8s)确保网络延迟<10ms

# 3. 考虑使用WebSocket而非HTTP
# WebSocket长连接开销更小(未来版本)

10.3 Server宕机处理

现象:Server无响应,Client应用停滞

原因:Client等待Server响应超时

解决方案

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        streamable-http:
          connections:
            server1:
              url: http://localhost:8082
              timeout: 10s  # 设置合理超时
              retry:
                max-attempts: 3
                backoff: exponential

此时大模型仍可用,只是无法调用该Server的工具。


十一、总结与展望

11.1 MCP Client的核心价值

能力 收益
动态工具发现 无需硬编码工具列表
工具共享 一个工具,多个Agent使用
独立演进 Server和Client独立开发
微服务支持 适配容器化部署
协议标准化 与Anthropic官方工具无缝对接

11.2 MCP的未来

Anthropic宣布MCP成为AI Agent的通用标准

  1. 语言无关:Java、Python、Node.js都有SDK
  2. AI模型无关:Claude、GPT、开源模型都支持
  3. 工具市场:未来可能出现MCP工具市场,类似npm
  4. IDE集成:开发工具将内置MCP支持

11.3 学习路线

java 复制代码
基础 → 进阶 → 生产
 │      │      │
 ├─────┴──────┴──────────────────────┐
 │                                   │
 ▼                                   ▼
单Server工具调用              多Server容器化部署
  ↓                                  ↓
本地测试                        Kubernetes编排
  ↓                                  ↓
性能优化                       工具市场集成

11.4 与我们之前学到的内容的联系

java 复制代码
Spring AI学习路线:

  第1步: Tool Calling基础     (直接调用本地工具)
    ↓
  第2步: RAG + Memory         (增强知识库与记忆)
    ↓
  第3步: MCP Client(本文)   (远程工具调用)
    ↓
  第4步: 多Agent系统         (多个Agent协作)
    ↓
  第5步: 生产化部署          (容器、监控、高可用)

本文介绍的MCP Client正是从单Agent应用到多Agent系统的关键桥梁。


总结

通过MCP(Model Context Protocol),我们打破了Agent与工具的紧耦合关系:

  1. 工具变成了独立服务,可以单独部署和演进
  2. 大模型获得了远程工具调用的能力,就像使用本地工具一样自然
  3. 多个Agent可以共享同一套工具,避免代码重复
  4. 系统整体的扩展性和灵活性得到了质的提升

MCP的出现,标志着AI Agent从"单体应用"走向"分布式系统"的开始。

在下一篇文章中,我们将深入多Agent系统的设计与实现------如何让多个Agent之间互相通信、协作完成复杂任务。

相关推荐
FliPPeDround4 小时前
微信小程序自动化的 AI 新时代:wechat-devtools-mcp 智能方案
微信小程序·ai编程·mcp
killer_queen48048 小时前
AI_agent(三) MCP协议(二)
c++·agent·mcp·a2a
无人装备硬件开发爱好者8 小时前
硬核技术解析|MCP 协议实现语音 AI 与 ESP32 软 / 硬件的标准化对接:从火山引擎豆包认证到全链路落地——上
人工智能·esp32·火山引擎·mcp
带刺的坐椅9 小时前
Solon AI v3.9.4 发布(智能体开发框架,支持 Java8 到 Java25)
ai·llm·agent·solon·mcp·tool-call·skills
jerrywus1 天前
告别手动调试!用 Flutter MCP 让 AI 直接操控你的 App
前端·claude·mcp
zhangshuang-peta1 天前
基于人工智能的客户支持,配备安全人工智能客服机器人
人工智能·安全·机器人·ai agent·mcp·peta
小璐乱撞1 天前
Serena MCP:给 AI 装上工程级导航,告别迷路式编程
人工智能·ai编程·mcp
有点心急10211 天前
图表展示 MCP 工具
python·aigc·mcp
zhangshuang-peta1 天前
为何MCP采用受阻(及如何解决)
人工智能·ai agent·mcp·peta