Spring AI Alibaba 1.x 系列【72】集成 MCP 客户端

文章目录

  • [1. 项目概述](#1. 项目概述)
  • [2. 环境准备](#2. 环境准备)
    • [2.1 前置条件](#2.1 前置条件)
    • [2.2 设置环境变量(可选)](#2.2 设置环境变量(可选))
  • [3. 创建项目](#3. 创建项目)
    • [3.1 目录结构](#3.1 目录结构)
  • [4. pom.xml ------ 依赖管理](#4. pom.xml —— 依赖管理)
    • [4.1 完整配置](#4.1 完整配置)
    • [4.2 依赖关系图](#4.2 依赖关系图)
  • [5. application.yml ------ 应用配置](#5. application.yml —— 应用配置)
    • [5.1 关键配置项说明](#5.1 关键配置项说明)
    • [5.2 MCP 工具自动发现流程](#5.2 MCP 工具自动发现流程)
  • [6. 核心代码实现](#6. 核心代码实现)
    • [6.1 启动类](#6.1 启动类)
    • [6.2 McpClientToolCallbackProvider ------ MCP 工具提供器](#6.2 McpClientToolCallbackProvider —— MCP 工具提供器)
    • [6.3 McpNode ------ MCP 图节点](#6.3 McpNode —— MCP 图节点)
    • [6.4 GraphMcpConfig ------ StateGraph 配置](#6.4 GraphMcpConfig —— StateGraph 配置)
      • [6.4.1 状态键策略](#6.4.1 状态键策略)
      • [6.4.2 图结构](#6.4.2 图结构)
    • [6.5 ReactAgentMcpConfig ------ ReactAgent 配置](#6.5 ReactAgentMcpConfig —— ReactAgent 配置)
      • [6.5.1 ReactAgent 执行流程(ReAct 循环)](#6.5.1 ReactAgent 执行流程(ReAct 循环))
      • [6.5.2 MemorySaver 的作用](#6.5.2 MemorySaver 的作用)
    • [6.6 Controller 层](#6.6 Controller 层)
      • [6.6.1 GraphMcpController](#6.6.1 GraphMcpController)
      • [6.6.2 AgentMcpController](#6.6.2 AgentMcpController)
  • [7. 两种 MCP 集成模式对比](#7. 两种 MCP 集成模式对比)
  • [8. 编译与运行](#8. 编译与运行)
    • [8.1 编译](#8.1 编译)
    • [8.2 打包](#8.2 打包)
    • [8.3 启动](#8.3 启动)
    • [8.4 调用接口](#8.4 调用接口)
      • [8.4.1 Graph 模式](#8.4.1 Graph 模式)
      • [8.4.2 ReactAgent 模式](#8.4.2 ReactAgent 模式)
  • [9. 扩展:多 MCP Server 按节点分配](#9. 扩展:多 MCP Server 按节点分配)

1. 项目概述

本项目演示两种在 Spring AI Alibaba 中集成 MCP(Model Context Protocol) 工具的方式:

模式 说明 端点
StateGraph + MCP 节点 在 StateGraph 工作流节点中,通过 ChatClient 注入 MCP 工具 /graph/mcp/call
ReactAgent + MCP 工具 在 ReactAgent 推理循环中,直接注册 MCP 工具参与 ReAct 过程 /agent/mcp/call

MCP Server 对接的是高德地图https://mcp.amap.com),提供地理编码、天气查询、路线规划等工具。

技术栈:

组件 版本
Spring Boot 3.5.11
Spring AI BOM 1.1.4
Spring AI Alibaba BOM 1.1.2.2
JDK 17
模型 DashScope qwen-plus
MCP 传输 streamable-http(SYNC)

2. 环境准备

2.1 前置条件

  • JDK 17+
  • Maven 3.6+
  • 阿里云 DashScope API Key申请地址
  • 高德地图 API Key申请地址,用于 MCP Server 认证)

2.2 设置环境变量(可选)

bash 复制代码
# 不设置则使用 application.yml 中内置的默认值
export DASHSCOPE_API_KEY=sk-your-dashscope-key
export AMAP_API_KEY=your-amap-key

3. 创建项目

3.1 目录结构

复制代码
spring-ai-alibaba-mcp-demo/
├── pom.xml
├── src/main/java/com/example/mcpdemo/
│   ├── McpDemoApplication.java              # Spring Boot 启动类
│   ├── config/
│   │   ├── GraphMcpConfig.java              # StateGraph + MCP 节点配置
│   │   └── ReactAgentMcpConfig.java         # ReactAgent + MCP 工具配置
│   ├── graph/
│   │   ├── McpNode.java                     # MCP 图节点(NodeAction 实现)
│   │   └── McpClientToolCallbackProvider.java  # MCP 工具回调提供器
│   └── controller/
│       ├── GraphMcpController.java          # Graph 模式 REST 端点
│       └── AgentMcpController.java          # ReactAgent 模式 REST 端点
└── src/main/resources/
    └── application.yml                      # 应用配置

4. pom.xml ------ 依赖管理

4.1 完整配置

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.11</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>spring-ai-alibaba-mcp-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>17</java.version>
        <spring-ai.version>1.1.4</spring-ai.version>
        <spring-ai-alibaba.version>1.1.2.2</spring-ai-alibaba.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- Spring AI BOM:管理 ChatClient、MCP Client 等版本 -->
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- Spring AI Alibaba BOM:管理 Graph、Agent 等版本 -->
            <dependency>
                <groupId>com.alibaba.cloud.ai</groupId>
                <artifactId>spring-ai-alibaba-bom</artifactId>
                <version>${spring-ai-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

        <!-- Spring AI Alibaba Graph Core(StateGraph 工作流引擎) -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-graph-core</artifactId>
            <version>${spring-ai-alibaba.version}</version>
        </dependency>

        <!-- Spring AI Alibaba Agent Framework(ReactAgent) -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-agent-framework</artifactId>
            <version>${spring-ai-alibaba.version}</version>
        </dependency>

        <!-- DashScope 模型 Starter(通义千问) -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
            <version>${spring-ai-alibaba.version}</version>
        </dependency>

        <!-- 测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

4.2 依赖关系图

复制代码
spring-boot-starter-parent (3.5.11)
    │
    ├── spring-ai-bom (1.1.4) ───────── spring-ai-starter-mcp-client
    │                                         └── MCP 客户端自动配置、ToolCallbackProvider
    │
    └── spring-ai-alibaba-bom (1.1.2.2)
            ├── spring-ai-alibaba-graph-core
            │       └── StateGraph、CompiledGraph、KeyStrategy
            ├── spring-ai-alibaba-agent-framework
            │       └── ReactAgent、MemorySaver
            └── spring-ai-alibaba-starter-dashscope
                    └── DashScope ChatModel 自动配置

注意spring-ai-alibaba-graph-corespring-ai-alibaba-agent-frameworkspring-ai-alibaba-starter-dashscope 需要显式指定版本号 ,因为它们不在 Spring AI BOM 的管理范围内,而 spring-ai-alibaba-bom 的版本管理可能不完整。


5. application.yml ------ 应用配置

yaml 复制代码
server:
  port: 8087

spring:
  application:
    name: spring-ai-alibaba-mcp-demo
  ai:
    # DashScope 模型配置
    dashscope:
      api-key: ${DASHSCOPE_API_KEY:sk-3d56ec506a8943d0b39f58f306438260}
      chat:
        options:
          model: qwen-plus
          temperature: 0.7

    # MCP 客户端配置
    mcp:
      client:
        enabled: true
        name: amap-maps-mcp-client
        version: 1.0.0
        request-timeout: 60s
        type: SYNC                          # 同步客户端
        streamable-http:                    # 使用 Streamable HTTP 传输
          connections:
            amap-maps:                      # 连接名(后续可据此过滤工具)
              url: https://mcp.amap.com
              endpoint: /mcp?key=${AMAP_API_KEY:0d29df51457fd82f93ac8db8c9b2be9b}
        toolcallback:
          enabled: true                     # 自动创建 ToolCallbackProvider Bean

5.1 关键配置项说明

配置项 说明
spring.ai.mcp.client.type SYNC 同步模式,适用于 WebMVC;若用 WebFlux 则选 ASYNC
spring.ai.mcp.client.streamable-http.connections 定义 MCP Server 连接,支持多个连接
spring.ai.mcp.client.toolcallback.enabled 设为 true 后,Spring AI 自动将所有 MCP 连接发现的工具包装为 ToolCallbackProvider Bean
endpoint 中带 ?key= 高德 MCP Server 通过查询参数传递 API Key 进行认证

5.2 MCP 工具自动发现流程

复制代码
application.yml 配置
        │
        ▼
spring-ai-starter-mcp-client 自动配置
        │
        ├── 为每个 connection 创建 McpSyncClient
        ├── client.initialize() 获取工具列表
        │
        ▼
toolcallback.enabled: true
        │
        ▼
SyncMcpToolCallbackProvider Bean
  (实现 ToolCallbackProvider 接口)
        │
        ▼
getToolCallbacks() → ToolCallback[]
  └── 每个 MCP 工具被包装为 ToolCallback

6. 核心代码实现

6.1 启动类

java 复制代码
package com.example.mcpdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

@SpringBootApplication 会触发:

  • spring-ai-starter-mcp-clientMCP 客户端自动配置
  • spring-ai-alibaba-starter-dashscopeDashScope 模型自动配置
  • 组件扫描(@Component@Configuration@RestController

6.2 McpClientToolCallbackProvider ------ MCP 工具提供器

java 复制代码
package com.example.mcpdemo.graph;

import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.definition.ToolDefinition;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

@Component
public class McpClientToolCallbackProvider {

    private final ToolCallbackProvider toolCallbackProvider;

    public McpClientToolCallbackProvider(ToolCallbackProvider toolCallbackProvider) {
        this.toolCallbackProvider = toolCallbackProvider;
    }

    /**
     * 获取所有 MCP 工具回调
     */
    public Set<ToolCallback> getAllToolCallbacks() {
        Set<ToolCallback> result = new HashSet<>();
        ToolCallback[] callbacks = toolCallbackProvider.getToolCallbacks();
        for (ToolCallback callback : callbacks) {
            result.add(callback);
        }
        return result;
    }

    /**
     * 根据连接名过滤工具(按需分配工具给不同节点)
     */
    public Set<ToolCallback> findToolCallbacksByConnection(String connectionName) {
        Set<ToolCallback> result = new HashSet<>();
        ToolCallback[] callbacks = toolCallbackProvider.getToolCallbacks();
        for (ToolCallback callback : callbacks) {
            ToolDefinition definition = callback.getToolDefinition();
            if (definition.name() != null
                    && definition.name().toLowerCase().contains(connectionName.toLowerCase())) {
                result.add(callback);
            }
        }
        return result;
    }
}

设计要点

  • 注入 ToolCallbackProviderSpring AI 自动配置创建的 Bean,包含所有 MCP 连接发现的所有工具
  • getAllToolCallbacks():返回全部 MCP 工具,适用于简单场景
  • findToolCallbacksByConnection(connectionName):按连接名过滤,适用于多 MCP Server 场景 ------不同 Graph 节点可分配不同的 MCP 工具集

6.3 McpNode ------ MCP 图节点

java 复制代码
package com.example.mcpdemo.graph;

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallback;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import reactor.core.publisher.Flux;

public class McpNode implements NodeAction {

    private final ChatClient chatClient;

    public McpNode(ChatClient.Builder chatClientBuilder, Set<ToolCallback> toolCallbacks) {
        this.chatClient = chatClientBuilder
                .defaultToolCallbacks(toolCallbacks.toArray(ToolCallback[]::new))
                .build();
    }

    @Override
    public Map<String, Object> apply(OverAllState state) {
        String query = state.value("query", "");

        // 流式调用 LLM,LLM 自动决定是否调用 MCP 工具
        Flux<String> streamResult = chatClient.prompt(query).stream().content();
        String result = streamResult.reduce("", (acc, item) -> acc + item).block();

        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("mcpcontent", result);
        return resultMap;
    }
}

执行流程

复制代码
StateGraph 调度到 McpNode
        │
        ▼
从 OverAllState 读取 "query" 字段
        │
        ▼
ChatClient.prompt(query).stream().content()
        │
        ├── LLM 分析用户意图
        ├── 需要工具?→ 调用 defaultToolCallbacks 中的 MCP 工具
        │       └── McpSyncClient.callTool() → MCP Server
        ├── 工具结果返回给 LLM
        └── LLM 生成最终回复
        │
        ▼
结果写入 OverAllState["mcpcontent"]

NodeAction 是函数式接口,apply(OverAllState) 的返回值会被合并回图状态。


6.4 GraphMcpConfig ------ StateGraph 配置

java 复制代码
package com.example.mcpdemo.config;

import com.alibaba.cloud.ai.graph.GraphRepresentation;
import com.alibaba.cloud.ai.graph.KeyStrategy;
import com.alibaba.cloud.ai.graph.KeyStrategyFactory;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.exception.GraphStateException;
import com.alibaba.cloud.ai.graph.state.strategy.ReplaceStrategy;
import com.example.mcpdemo.graph.McpClientToolCallbackProvider;
import com.example.mcpdemo.graph.McpNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Set;

import static com.alibaba.cloud.ai.graph.action.AsyncNodeAction.node_async;

@Configuration
public class GraphMcpConfig {

    private static final Logger logger = LoggerFactory.getLogger(GraphMcpConfig.class);

    @Bean("mcpGraph")
    public StateGraph mcpGraph(ChatClient.Builder chatClientBuilder,
                               McpClientToolCallbackProvider mcpToolProvider)
            throws GraphStateException {

        // 1. 获取 MCP 工具
        Set<ToolCallback> mcpToolCallbacks = mcpToolProvider.getAllToolCallbacks();
        logger.info("MCP Graph: loaded {} tool callbacks", mcpToolCallbacks.size());

        // 2. 定义状态键策略(ReplaceStrategy = 每次覆盖)
        KeyStrategyFactory keyStrategyFactory = () -> {
            HashMap<String, KeyStrategy> strategies = new HashMap<>();
            strategies.put("query", new ReplaceStrategy());
            strategies.put("mcpcontent", new ReplaceStrategy());
            return strategies;
        };

        // 3. 构建 StateGraph
        StateGraph stateGraph = new StateGraph("mcp_graph", keyStrategyFactory)
                .addNode("mcp", node_async(
                        new McpNode(chatClientBuilder, mcpToolCallbacks)))
                .addEdge(StateGraph.START, "mcp")
                .addEdge("mcp", StateGraph.END);

        // 4. 打印 PlantUML 图结构
        GraphRepresentation representation = stateGraph.getGraph(
                GraphRepresentation.Type.PLANTUML, "MCP Flow");
        logger.info("\n=== MCP Graph UML ===\n{}\n====================",
                representation.content());

        return stateGraph;
    }
}

6.4.1 状态键策略

策略 说明
query ReplaceStrategy 每次调用覆盖旧值
mcpcontent ReplaceStrategy 每次调用覆盖旧结果

6.4.2 图结构

复制代码
START ──→ [mcp] ──→ END

单节点线性工作流,mcp 节点内执行 LLM + MCP 工具调用。


6.5 ReactAgentMcpConfig ------ ReactAgent 配置

java 复制代码
package com.example.mcpdemo.config;

import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver;
import com.example.mcpdemo.graph.McpClientToolCallbackProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Set;

@Configuration
public class ReactAgentMcpConfig {

    private static final Logger logger = LoggerFactory.getLogger(ReactAgentMcpConfig.class);

    @Bean("mcpReactAgent")
    public ReactAgent mcpReactAgent(ChatModel chatModel,
                                    McpClientToolCallbackProvider mcpToolProvider) {

        Set<ToolCallback> mcpToolCallbacks = mcpToolProvider.getAllToolCallbacks();
        ToolCallback[] toolArray = mcpToolCallbacks.toArray(ToolCallback[]::new);

        logger.info("ReactAgent MCP: loaded {} MCP tools", toolArray.length);

        return ReactAgent.builder()
                .name("mcp-react-agent")
                .description("AI 助手,可调用高德地图 MCP 工具")
                .model(chatModel)
                .systemPrompt("你是一个有帮助的 AI 助手,可以调用高德地图提供的工具来查询地理位置、天气、路线等信息。")
                .tools(toolArray)          // 直接注入 MCP 工具
                .saver(new MemorySaver())   // 内存检查点,支持多轮对话
                .enableLogging(true)        // 控制台打印工具调用过程
                .build();
    }
}

6.5.1 ReactAgent 执行流程(ReAct 循环)

复制代码
用户输入: "查询北京的天气"
        │
        ▼
[Think] LLM 分析:需要调用天气查询工具
        │
        ▼
[Act] 调用 MCP 工具 ToolCallback
        │   └── McpSyncClient.callTool("weather", {city: "北京"})
        │
        ▼
[Observe] 工具返回: {temperature: 25°C, condition: "晴"}
        │
        ▼
[Think] LLM 整合结果 → 生成自然语言回复
        │
        ▼
输出: "北京当前天气晴朗,气温 25°C"

6.5.2 MemorySaver 的作用

java 复制代码
// 多轮对话示例
RunnableConfig config = RunnableConfig.builder()
        .threadId("user-123")   // 同一 threadId 共享对话历史
        .build();

agent.call("我叫张三", config);        // 第1轮
agent.call("帮我查一下杭州天气", config);  // 第2轮 → 记住"张三"
agent.call("我之前叫什么名字?", config);   // 第3轮 → 能回答"张三"

6.6 Controller 层

6.6.1 GraphMcpController

java 复制代码
@RestController
@RequestMapping("/graph/mcp")
public class GraphMcpController {

    private final CompiledGraph compiledGraph;

    public GraphMcpController(@Qualifier("mcpGraph") StateGraph stateGraph)
            throws GraphStateException {
        this.compiledGraph = stateGraph.compile();   // 编译 StateGraph
    }

    @GetMapping("/call")
    public Map<String, Object> call(
            @RequestParam(defaultValue = "北京时间现在几点钟") String query,
            @RequestParam(defaultValue = "demo-user") String threadId) {

        RunnableConfig config = RunnableConfig.builder()
                .threadId(threadId).build();
        Map<String, Object> inputs = new HashMap<>();
        inputs.put("query", query);

        Optional<OverAllState> result = compiledGraph.invoke(inputs, config);
        return result.map(OverAllState::data).orElseGet(HashMap::new);
    }
}

6.6.2 AgentMcpController

java 复制代码
@RestController
@RequestMapping("/agent/mcp")
public class AgentMcpController {

    private final ReactAgent agent;

    public AgentMcpController(@Qualifier("mcpReactAgent") ReactAgent agent) {
        this.agent = agent;
    }

    @GetMapping("/call")
    public Map<String, Object> call(
            @RequestParam(defaultValue = "查询北京市朝阳区的天气") String query,
            @RequestParam(defaultValue = "demo-user") String threadId) {

        RunnableConfig config = RunnableConfig.builder()
                .threadId(threadId).build();

        String result;
        try {
            result = agent.call(query, config).getText();
        } catch (GraphRunnerException e) {
            result = "Error: " + e.getMessage();
        }

        Map<String, Object> response = new HashMap<>();
        response.put("query", query);
        response.put("threadId", threadId);
        response.put("result", result);
        return response;
    }
}

7. 两种 MCP 集成模式对比

复制代码
┌──────────────────────────────────────────────────┐
│               StateGraph + MCP 节点                │
│                                                    │
│   REST ──→ StateGraph ──→ [McpNode]                │
│                              │                     │
│                      ChatClient                     │
│                   .defaultToolCallbacks(MCP工具)     │
│                              │                     │
│                       LLM + MCP工具                 │
│                              │                     │
│                      返回结果 ←─────────────────────│
│                                                    │
│   适用场景:                                       │
│   · 需要多节点编排(条件路由/并行/人机协同)         │
│   · 不同节点分配不同的 MCP 工具集                  │
│   · 需要图可视化(PlantUML/Mermaid)               │
└──────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────┐
│               ReactAgent + MCP 工具                │
│                                                    │
│   REST ──→ ReactAgent                              │
│              │                                     │
│         ReAct 循环 (Think → Act → Observe)         │
│              │                                     │
│         .tools(MCP工具数组)                         │
│              │                                     │
│         LLM 自主决定调用哪些工具                    │
│              │                                     │
│         返回文本结果                                │
│                                                    │
│   适用场景:                                       │
│   · 自由对话式 AI 助手                             │
│   · LLM 自主推理 + 工具调用                        │
│   · 多轮对话(MemorySaver 持久化上下文)           │
└──────────────────────────────────────────────────┘

8. 编译与运行

8.1 编译

bash 复制代码
cd spring-ai-alibaba-mcp-demo
mvn clean compile

8.2 打包

bash 复制代码
mvn clean install -DskipTests

8.3 启动

bash 复制代码
mvn spring-boot:run

启动日志关键输出:

复制代码
MCP Graph: loaded 5 tool callbacks       ← MCP Server 返回的工具数
  Tool: amap-maps-mcp-client_geoCode     ← 地理编码
  Tool: amap-maps-mcp-client_regeoCode   ← 逆地理编码
  Tool: amap-maps-mcp-client_weather     ← 天气查询
  ...

ReactAgent MCP: loaded 5 MCP tools       ← ReactAgent 也加载了同样工具

=== MCP Graph UML ===                    ← PlantUML 图输出
@startuml
...
@enduml
================================

8.4 调用接口

8.4.1 Graph 模式

bash 复制代码
# 时间查询
curl "http://localhost:8087/graph/mcp/call?query=北京时间现在几点钟"

# 天气查询
curl "http://localhost:8087/graph/mcp/call?query=查询杭州市的天气"

# 地理编码
curl "http://localhost:8087/graph/mcp/call?query=北京市朝阳区的地理坐标是什么"

8.4.2 ReactAgent 模式

bash 复制代码
# 天气查询
curl "http://localhost:8087/agent/mcp/call?query=查询北京市朝阳区的天气"

# 多轮对话(相同 threadId 保持上下文)
curl "http://localhost:8087/agent/mcp/call?query=我叫张三&threadid=user-001"
curl "http://localhost:8087/agent/mcp/call?query=帮我查上海天气&threadid=user-001"
curl "http://localhost:8087/agent/mcp/call?query=我是谁&threadid=user-001"
# → 返回: "你是张三"

9. 扩展:多 MCP Server 按节点分配

如果对接多个 MCP Server,可按节点分配不同的工具集:

yaml 复制代码
spring.ai.mcp.client.streamable-http.connections:
  amap-maps:
    url: https://mcp.amap.com
    endpoint: /mcp?key=${AMAP_API_KEY}
  weather-service:
    url: https://weather.example.com
    endpoint: /mcp?key=${WEATHER_API_KEY}
java 复制代码
// 节点1: 只用高德地图工具
Set<ToolCallback> amapTools = provider.findToolCallbacksByConnection("amap-maps");
// 节点2: 只用天气服务工具
Set<ToolCallback> weatherTools = provider.findToolCallbacksByConnection("weather-service");

StateGraph graph = new StateGraph("workflow", keyFactory)
    .addNode("geo_node", node_async(new McpNode(chatBuilder, amapTools)))
    .addNode("weather_node", node_async(new McpNode(chatBuilder, weatherTools)))
    // ...

相关推荐
填满你的记忆1 小时前
MCP协议是什么?为什么它被称为AI时代的“USB接口”?
java·人工智能·agent·mcp
ZHW_AI课题组1 小时前
利用DeepLab在PascalVOC数据集中实现简单物体的多类别分割
人工智能·计算机视觉
直接冲冲冲1 小时前
pytorch-深度学习-引言
人工智能·pytorch·深度学习
SilentSamsara1 小时前
MLflow 实验追踪与模型注册:从实验到生产的可复现工作流
开发语言·人工智能·pytorch·python·青少年编程
SAP上海工博云署1 小时前
生产采购财务一体化ERP选型指南(中小制造/工贸企业适用)
大数据·人工智能·信息可视化·制造·信息与通信
装不满的克莱因瓶1 小时前
掌握多头自注意力机制(Multi-Head Self-Attention)——Transformer 强大表达能力的核心来源
人工智能·python·深度学习·数学·ai·transformer
花间相见1 小时前
【AI工作流搭建n8n】—— Docker + PostgreSQL 生产环境部署全攻略:MCP 集成与 Skills 技能实战
人工智能·docker·postgresql
独隅1 小时前
Visual Studio Code 和 Visual Studio 2026 两大开发工具的核心差异
java·vscode·visual studio
我登哥MVP1 小时前
SpringCloud 核心组件解析:服务注册与发现
java·spring boot·后端·spring·spring cloud·java-ee·maven