Spring AI Alibaba MCP协议实战:模型上下文协议集成与工具调用

Spring AI Alibaba MCP协议实战:模型上下文协议集成与工具调用

导读:MCP(Model Context Protocol,模型上下文协议)是 Anthropic 于 2024 年末发布的开放标准,旨在解决 AI 工具调用的碎片化问题。Spring AI Alibaba 1.1 版对 MCP 提供了完整支持。本文深入讲解 MCP 的三层架构、服务端开发、客户端接入,以及与 Python MCP Server 的跨语言互通。


一、MCP 的诞生背景

在 MCP 出现之前,每个 AI 应用都需要为自己的工具调用写一套独立的集成代码。你用的是通义千问,我用的是 GPT,他用的是 Claude,各自的工具接口不通,无法复用------这就是 AI 工具生态碎片化的现状。

MCP 的价值在于定义了一套统一的工具调用协议,类似于 REST API 之于 Web 服务的地位:

复制代码
没有 MCP(碎片化):
    Application A ←→ 自定义集成 ←→ Tool 1
    Application B ←→ 自定义集成 ←→ Tool 2
    Application C ←→ 自定义集成 ←→ Tool 3

有了 MCP(标准化):
    Application A ──┐
    Application B ──┤←→ MCP Protocol ←→ MCP Server(Tool 1 + Tool 2 + Tool 3)
    Application C ──┘

二、MCP 三层架构

复制代码
+-------------------+         MCP Protocol          +------------------+
|   Host(宿主层)  |   ←←←←←←←←←←←←←←←←←←   |  Server(服务层)  |
|                   |   →→→→→→→→→→→→→→→→→→   |                  |
| - AI 应用         |                               | - 工具实现       |
| - 管理 Client     |      +---------------+        | - 资源暴露       |
+-------------------+      |   Client(客户层)|    | - Prompt 模板    |
         |                  | - 工具发现    |        +------------------+
         +--→ 创建 Client → | - 工具调用    |
                             | - 资源访问   |
                             +---------------+

传输协议:
    Stdio(标准输入输出):本地进程通信,适合本地工具
    SSE(Server-Sent Events):HTTP 长连接,适合远程服务
    WebSocket:双向通信,适合高频实时交互

三种能力类型(MCP Server 可以暴露)

  • Tool:可调用的函数(最常用);
  • Resource:可读取的资源(如文件、数据库);
  • Prompt:预定义的提示模板(如角色扮演模板)。

三、依赖配置

3.1 Server 端依赖

xml 复制代码
<!-- Spring AI MCP Server(提供工具服务)-->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
</dependency>

<!-- SSE 传输模式需要 Web 支持 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

3.2 Client 端依赖

xml 复制代码
<!-- Spring AI MCP Client(消费工具服务)-->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
</dependency>

<!-- DashScope 模型 -->
<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>

四、MCP Server 开发

4.1 基于 SSE 传输的 MCP Server

java 复制代码
package com.example.mcp.server;

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;

/**
 * 天气查询 MCP 工具
 * 通过 MCP 协议暴露给任何兼容的 AI 应用
 */
@Slf4j
@Component
public class WeatherMcpTool {

    /**
     * 获取城市天气
     * @Tool 注解的方法会自动通过 MCP 协议暴露为工具
     */
    @Tool(description = "获取指定城市的实时天气信息,包括温度、天气状况、湿度、风力等")
    public WeatherInfo getWeather(
            @ToolParam(description = "城市名称,支持中文,如:北京、上海") String city) {

        log.info("[MCP Tool] 天气查询:{}", city);
        // 实际项目:调用真实天气 API(和风天气、高德天气等)
        return new WeatherInfo(city, "晴转多云", 22.5, 68, "东南风 3级");
    }

    /**
     * 获取天气预报(未来 N 天)
     */
    @Tool(description = "获取城市未来几天的天气预报,最多7天")
    public String getWeatherForecast(
            @ToolParam(description = "城市名称") String city,
            @ToolParam(description = "预报天数,1-7之间") int days) {

        log.info("[MCP Tool] 天气预报查询:{} 未来{}天", city, days);
        StringBuilder sb = new StringBuilder(city).append(" 未来").append(days).append("天预报:\n");
        String[] conditions = {"晴", "多云", "阴", "小雨", "晴", "多云", "晴"};
        int[] temps = {22, 20, 18, 16, 19, 21, 23};

        for (int i = 0; i < Math.min(days, 7); i++) {
            sb.append(String.format("第%d天:%s,气温约%d°C\n", i + 1, conditions[i], temps[i]));
        }
        return sb.toString();
    }

    public record WeatherInfo(
            String city,
            String condition,
            double temperature,
            int humidity,
            String wind
    ) {}
}
java 复制代码
/**
 * 数据库查询 MCP 工具
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DatabaseMcpTool {

    private final UserRepository userRepository;
    private final OrderRepository orderRepository;

    @Tool(description = "根据用户ID查询用户基本信息")
    public String getUserInfo(@ToolParam(description = "用户ID") String userId) {
        return userRepository.findById(userId)
                .map(u -> String.format("用户:%s, 邮箱:%s, 注册时间:%s",
                        u.getName(), u.getEmail(), u.getCreatedAt()))
                .orElse("用户 " + userId + " 不存在");
    }

    @Tool(description = "查询用户最近的订单记录")
    public String getRecentOrders(
            @ToolParam(description = "用户ID") String userId,
            @ToolParam(description = "查询条数,1-20之间") int limit) {
        List<Order> orders = orderRepository.findByUserIdOrderByCreatedAtDesc(
                userId, PageRequest.of(0, Math.min(limit, 20)));
        if (orders.isEmpty()) return "暂无订单记录";

        return orders.stream()
                .map(o -> String.format("订单%s:%s ¥%.2f [%s]",
                        o.getId(), o.getProductName(), o.getAmount(), o.getStatus()))
                .collect(Collectors.joining("\n"));
    }
}

4.2 Server 配置

yaml 复制代码
# application.yml(MCP Server 端)
spring:
  application:
    name: mcp-weather-server
  ai:
    mcp:
      server:
        # 服务名称(客户端用于标识此 Server)
        name: weather-and-database-tools
        # 版本
        version: 1.0.0
        # 传输模式:SSE(HTTP) 或 STDIO(标准输入输出)
        transport: SSE
        # 服务描述
        description: "提供天气查询和数据库查询能力的 MCP Server"

server:
  port: 8090

启动后,MCP Server 会自动在以下端点暴露工具信息:

  • GET /mcp/tools - 查询可用工具列表
  • POST /mcp/call - 调用工具

五、MCP Client 接入

5.1 配置 MCP Client

yaml 复制代码
# application.yml(MCP Client 端)
spring:
  ai:
    mcp:
      client:
        # 配置多个 MCP Server
        servers:
          # 本地天气服务(SSE 模式)
          weather-server:
            transport: SSE
            url: http://localhost:8090
            # 超时配置
            connection-timeout: 5s
            request-timeout: 30s

          # 远程数据分析服务(SSE 模式)
          analytics-server:
            transport: SSE
            url: https://analytics.internal.company.com/mcp

          # 本地 Python MCP Server(Stdio 模式)
          python-tools:
            transport: STDIO
            command: python
            args: ["-m", "my_mcp_server"]

5.2 在 ChatClient 中使用 MCP 工具

java 复制代码
@Service
@RequiredArgsConstructor
@Slf4j
public class McpChatService {

    private final ChatClient chatClient;
    // Spring AI 自动注入所有已配置的 MCP 工具
    private final List<McpSyncClient> mcpClients;

    /**
     * 使用 MCP 工具的智能对话
     * Spring AI 自动处理 MCP 工具的发现和调用
     */
    public String chatWithMcpTools(String message) {
        log.info("使用 MCP 工具处理消息:{}", message);

        // 获取所有 MCP 工具的 ToolCallbackProvider
        List<ToolCallback> mcpToolCallbacks = mcpClients.stream()
                .flatMap(client -> {
                    // 工具发现:获取 Server 暴露的所有工具
                    var toolsResult = client.listTools();
                    return toolsResult.tools().stream()
                            .map(tool -> McpFunctionCallback.builder()
                                    .mcpClient(client)
                                    .tool(tool)
                                    .build());
                })
                .collect(Collectors.toList());

        return chatClient.prompt()
                .user(message)
                .tools(mcpToolCallbacks.toArray(new ToolCallback[0]))
                .call()
                .content();
    }

    /**
     * 动态工具发现:运行时查询 MCP Server 可用工具
     */
    public List<String> discoverTools() {
        return mcpClients.stream()
                .flatMap(client -> {
                    String serverName = client.getServerInfo().name();
                    return client.listTools().tools().stream()
                            .map(tool -> serverName + "/" + tool.name() +
                                    ":" + tool.description());
                })
                .collect(Collectors.toList());
    }
}

六、与 Python MCP Server 跨语言互通

MCP 的一大优势是语言无关性。Python 社区有大量优秀的 MCP Server 实现(如代码执行、数据分析等),可以直接从 Java 侧接入:

yaml 复制代码
# 接入 Python MCP Server(Stdio 模式)
spring:
  ai:
    mcp:
      client:
        servers:
          python-analyzer:
            transport: STDIO
            # 启动 Python MCP Server 进程
            command: /usr/bin/python3
            args: ["/opt/mcp-servers/data-analyzer/main.py"]
            # 环境变量(传入数据库连接等配置)
            environment:
              DB_HOST: "localhost"
              DB_PORT: "5432"

Python 侧 MCP Server 示例(仅供理解协议,不做重点展开):

python 复制代码
# main.py - Python MCP Server 示例结构
from mcp.server import Server
from mcp.server.stdio import stdio_server

app = Server("data-analyzer")

@app.call_tool()
async def analyze_data(name: str, arguments: dict) -> list:
    if name == "run_sql":
        query = arguments["query"]
        # 执行 SQL 并返回结果
        return [{"type": "text", "text": f"查询结果: {execute_sql(query)}"}]

async def main():
    async with stdio_server() as streams:
        await app.run(*streams, app.create_initialization_options())

Java 侧通过 Stdio 模式调用 Python Server,完全透明。


七、安全机制

7.1 Server 端安全隔离

yaml 复制代码
spring:
  ai:
    mcp:
      server:
        # 启用工具白名单(只允许调用指定工具)
        tool-whitelist:
          - getWeather
          - getWeatherForecast
          - getUserInfo
          # 不在列表中的工具不对外暴露

        # 启用请求鉴权
        security:
          enabled: true
          api-key: ${MCP_SERVER_API_KEY}

7.2 Client 端权限控制

java 复制代码
@Configuration
public class McpSecurityConfig {

    /**
     * MCP Client 请求拦截器:添加认证头
     */
    @Bean
    public McpClientCustomizer mcpClientCustomizer() {
        return (clientBuilder) -> clientBuilder
                // 为每个 MCP 请求添加认证 Header
                .requestInterceptor(request -> {
                    request.headers().add("X-MCP-API-Key",
                            System.getenv("MCP_SERVER_API_KEY"));
                    return request;
                })
                // 请求超时
                .requestTimeout(Duration.ofSeconds(30));
    }
}

八、企业内部 MCP Registry

大型企业可以构建内部的 MCP 工具注册中心,统一管理所有 MCP Server:

java 复制代码
/**
 * MCP Registry:企业内部工具注册中心
 */
@RestController
@RequestMapping("/api/mcp/registry")
@RequiredArgsConstructor
public class McpRegistryController {

    private final McpRegistryService registryService;

    /**
     * 注册新的 MCP Server
     */
    @PostMapping("/register")
    public ResponseEntity<McpServerInfo> register(
            @RequestBody McpServerRegistration registration) {
        McpServerInfo info = registryService.register(registration);
        return ResponseEntity.ok(info);
    }

    /**
     * 查询所有可用的 MCP Server 和工具
     */
    @GetMapping("/discover")
    public ResponseEntity<List<McpServerInfo>> discover(
            @RequestParam(required = false) String category,
            @RequestParam(required = false) String keyword) {
        return ResponseEntity.ok(registryService.discover(category, keyword));
    }

    /**
     * 健康检查:验证所有注册的 MCP Server 是否在线
     */
    @GetMapping("/health")
    public ResponseEntity<Map<String, String>> healthCheck() {
        return ResponseEntity.ok(registryService.checkAllHealth());
    }
}

九、总结

MCP 正在成为 AI 工具生态的"通用插座",本文的核心收获:

  1. MCP 三层架构:Host(宿主)→ Client(客户端)→ Server(工具服务);
  2. 传输协议:Stdio 适合本地进程,SSE 适合远程 HTTP 服务;
  3. 三种能力:Tool(可调用函数)、Resource(可读资源)、Prompt(模板);
  4. Server 开发@Tool 注解 + Spring Boot,几行代码构建 MCP Server;
  5. 跨语言互通:通过 Stdio 模式接入 Python、Node.js 等语言的 MCP Server;
  6. 安全机制:工具白名单 + API Key 认证,防止未授权访问。

下一篇将进入 Deep Research 自动化调研领域,探讨如何利用 Spring AI Alibaba 1.1 的推理模式实现多步骤深度研究报告自动生成。


参考资料

相关推荐
superior tigre2 小时前
为WSL2 ubuntu20.04安装cuDNN 9.2
人工智能
前端不太难2 小时前
如何设计 AI Native 鸿蒙应用架构
人工智能·架构·harmonyos
Via_Neo2 小时前
JAVA中对数的表达,将浮点数转为保留指定位数的字符串
java·开发语言
呆呆敲代码的小Y2 小时前
Unity+AI 用一句话制作完整小游戏:飞翔的牛马【AI纯添加-0手工代码】
人工智能·游戏·unity·游戏引擎·游戏制作·unityai·一句话制作游戏
左左右右左右摇晃2 小时前
String、StringBuffer、StringBuilder的区别
java·笔记
ada0_ada12 小时前
产生式表示法
人工智能
yuezhilangniao2 小时前
大白话AI运维K8S整体思路和相关名词-结合腾讯云
运维·人工智能·kubernetes
cxr8282 小时前
视频工业化制作体系的专业AI多智能体虚拟制作团队构建分析
人工智能·架构·ai智能体
前端摸鱼匠2 小时前
面试题2:Transformer的Encoder、Decoder结构分别包含哪些核心组件?
人工智能·深度学习·ai·面试·职场和发展·transformer