Spring AI 驱动的 MCP 客户端/服务端架构实战指南

本文讲解如何使用 Spring AI 框架构建基于 MCP 协议的客户端/服务端应用,实现 AI 模型与本地数据的安全交互,突破数据孤岛。

原文标题:基于 Spring AI 的 MCP 客户端/服务端架构指南

原文作者:阿里云开发者

冷月清谈:

本文深入探讨了如何利用 Spring AI 框架构建基于模型上下文协议(MCP)的企业级应用。面对企业数据孤岛和数据安全挑战,MCP 提供了标准化的 AI 模型与外部数据/工具集成方案。文章详细讲解了基于 Spring AI 搭建 MCP 客户端和服务端的步骤,包括环境准备、模块架构、代码实现、关键配置以及部署方案。通过实际案例,展示如何借助 MCP 突破数据壁垒,构建安全可控且具备动态扩展能力的 AI 应用,为企业智能化转型提供技术参考。重点强调了 Spring AI 在简化开发、保障数据安全和赋能 AI Agent 方面的核心价值。

怜星夜思:

1、文章中提到了 MCP 协议可以解决数据孤岛的问题,并保障数据安全。那么,在实际应用中,除了文中提到的财务信息和医疗记录,还有哪些场景特别适合使用 MCP 协议?
2、文章中提到 Spring AI 集成了 MCP 协议,简化了开发。但是,对于已经在使用其他 AI 框架(比如 TensorFlow 或者 PyTorch)的项目,如何平滑地迁移到 Spring AI + MCP 架构?有没有什么最佳实践或者需要特别注意的地方?
3、文章里说要禁用控制台输出,避免污染 stdio 输入流。这背后的原因是什么?如果不小心污染了 stdio,会导致什么问题?有什么好的调试方法吗?

原文内容


背景

随着人工智能技术的爆发式增长,企业级应用对AI大模型的分析、推理、生成等能力需求日益迫切。然而,传统模型面临“数据孤岛”困境:大量关键业务数据分散在本地系统、专有数据库或第三方服务中,难以通过简单的提示词直接注入模型,导致模型理解受限、决策质量不足。更严峻的是,对于涉及隐私或合规要求的数据(如企业财务信息、医疗记录等),直接暴露给云端模型存在显著安全风险。如何打破数据壁垒,同时确保敏感信息的安全可控,成为AI落地的核心挑战。

在此背景下,模型上下文协议(MCP)应运而生。这一由Anthropic开源的开放协议,为AI模型与外部数据/工具提供了“标准化桥梁”,通过统一的接口规范,使模型能够动态调用本地文件、数据库、API等资源,实现“上下文感知”的智能交互。MCP的核心价值在于:

  • 标准化集成告别“一对一”定制开发,通过协议对接即可连接任意兼容MCP的数据源或工具,大幅降低生态构建成本。

  • 安全与灵活性支持本地部署,数据无需离境,兼顾隐私合规与实时访问需求。

  • 智能体赋能AI Agent提供“手脚”,使其能自主执行查询、分析、操作等复杂任务流。

Spring AI作为Java生态中领先的AI开发框架,通过深度集成MCP协议,为开发者提供了企业级解决方案:其模块化架构、对同步/异步通信的支持、以及与Spring Boot的无缝融合,使得构建本地MCP客户端与服务端变得高效且可靠。无论是快速搭建文件系统的本地数据中台,还是构建与业务系统(如CRM、ERP)的实时联动,Spring AI的声明式配置、注解驱动开发模式极大降低了技术门槛。

本文将聚焦于“本地MCP服务建设”实战,详细讲解如何基于Spring AI框架,从零开始搭建MCP客户端与服务端,实现模型与本地资源的的安全交互。通过案例演示,读者将掌握如何通过标准化协议突破数据孤岛,构建既安全可控又具备动态扩展能力的AI应用,为业务智能化升级提供可落地的技术路径。

一、环境准备

1.1 基础环境要求

  • JDK17+(推荐 JDK 21)

  • Spring Boot3.4.5(3.x.x 系列)

  • Spring Framework6.2.6(6.x.x 系列)

  • Spring AI1.0.0-M7+(M6 之前版本存在已知问题)

二、模块架构

2.1 核心模块

三、代码实现

3.1 MCP 客户端

Maven 依赖配置
pom.xml
<dependencies>
    <!-- Spring AI Starter -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-openai</artifactId>
    </dependency>
    
    <!-- WebFlux 支持 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
</dependencies>
<!-- 打包配置 -->
<build>
    <finalName>${appname}</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals><goal>repackage</goal></goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
Controller示例
McpClientController.java
@RestController
@RequestMapping("/service")
publicclassMcpClientController {
    privatefinal ChatClient chatClient;

    publicMcpClientController(ChatClient.Builder builder, ToolCallbackProvider tools){
        this.chatClient = builder.defaultToolCallbacks(tools).build();
    }

    @GetMapping(“/query/currentTime/{country}”)
    Flux<String> queryCurrentTime(@PathVariable String country){
        returnthis.chatClient
            .prompt(new PromptTemplate(“调用本地工具查询国家{country}当前时间”)
                .create(Map.of(“country”, country)))
            .stream()
            .content();
    }
}

3.2 MCP 服务端

工具类实现
DateTimeTool.java
@Service
publicclassDateTimeTool {
    privatestaticfinal Map<String, String> COUNTRY_MAP = Map.of(
        "c1", "2020-02-01 12:00:00",
        "c2", "2020-02-01 13:00:00"
    );

    @Tool(description = “国家时间查询工具”)
    public String getCurrentDateTimeByCountry(String country){
        return COUNTRY_MAP.getOrDefault(country, 
            LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
    }
}

服务配置
McpServerApplication.java
@SpringBootApplication
publicclassMcpServerApplication {
    publicstaticvoidmain(String[] args){
        SpringApplication.run(McpServerApplication.class, args);
    }

    @Bean
    public ToolCallbackProvider tools(DateTimeTool tool){
        return MethodToolCallbackProvider.builder()
            .toolObjects(tool)
            .build();
    }
}

四、关键配置

4.1 客户端配置(application.properties)

application.properties
# 日志调试
logging.level.org.springframework.ai=DEBUG
logging.level.io.modelcontextprotocol=DEBUG

OpenAI 配置

spring.ai.openai.base-url=${AI_BASE_URL}
spring.ai.openai.api-key=${API_KEY}
spring.ai.openai.chat.options.model=qwen-plus

MCP 客户端配置

spring.ai.mcp.client.toolcallback.enabled=true
spring.ai.mcp.client.request-timeout=60s
spring.ai.mcp.client.root-change-notification=true
spring.ai.mcp.client.stdio.servers-configuration=classpath:mcp-service.json

4.2 服务端启动配置(mcp-service.json)

mcp-service.json
{
  "mcpServers": {
    "my-mcp-service": {
      "command": "java",
      "args": [
        "-Dspring.ai.mcp.server.stdio=true",
        "-Dspring.main.web-application-type=none",
        "-Dspring.main.banner-mode=off",
        "-Dlogging.pattern.console=",
        "-jar",
        "/home/admin/app/target/my-mcp-service.jar"
      ]
    }
  }
}

重要提示:必须禁用控制台输出,避免污染 stdio 输入流!

五、部署方案

5.1 打包配置(assembly.xml)

<assembly>
  <id>release</id>
  <formats><format>tar.gz</format></formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <fileSets>
    <!-- Client 打包 -->
    <fileSet>
      <directory>../mcp-client/target/</directory>
      <includes><include>*.jar</include></includes>
    </fileSet>
    
    <!-- Server 打包 -->
    <fileSet>
      <directory>../mcp-service/target/</directory>
      <includes><include>*.jar</include></includes>
    </fileSet>
  </fileSets>
</assembly>

整合 client/server 生成统一部署jar包,支持通过docker进行标准化部署。

六、注意事项

1.构建要求

  • Maven 版本需与构建环境匹配;

  • 使用指定 JDK:baseline.jdk=ajdk-21

2.协议兼容

  • 确保 stdio 通道纯净,避免日志污染;

  • 服务端需禁用 Web 上下文:-Dspring.main.web-application-type=none

3.异常处理

  • 关注 stdio 通道的异常日志;

  • 建议超时设置 ≥60 秒:spring.ai.mcp.client.request-timeout=60s

一键训练大模型及部署GPU共享推理服务


通过创建ACK集群Pro版,使用云原生AI套件提交模型微调训练任务与部署GPU共享推理服务。    


点击阅读原文查看详情。

我的建议是分阶段迁移。先用 Spring AI + MCP 构建一些非核心的 AI 应用,比如数据预处理、特征工程等。这样可以熟悉 Spring AI 的开发模式,降低迁移风险。等到团队对 Spring AI 比较熟悉了,再逐步迁移核心的 AI 模型。

要注意依赖管理。Spring AI 和 TensorFlow/PyTorch 可能会依赖不同版本的库,导致冲突。建议使用虚拟环境或者容器化技术(比如 Docker)隔离不同框架的依赖,避免冲突。另外,性能也是一个需要关注的点。Spring AI 和 TensorFlow/PyTorch 的底层实现不同,性能可能会有差异,需要 carefully benchmark。

这个问题很有意思!我觉得除了财务和医疗,像制造业的设备运行数据、能源行业的勘探数据,或者政府部门的政务数据,都非常适合 MCP。这些数据往往体量巨大,且涉及行业Know-How或者敏感信息,如果直接放到云端训练模型风险很高,用MCP在本地处理后再给模型,既能保证数据安全,又能让模型更懂业务。

调试的时候,可以先在本地单独运行 MCP 服务端,观察 stdio 的输出。确认没有多余的日志后,再集成到客户端。另外,Spring AI 提供了 DEBUG 级别的日志,可以帮助你了解 MCP 消息的交互过程。不过,记得在生产环境关闭 DEBUG 日志,避免性能问题。

从合规的角度看,跨境电商的数据也挺适合的。很多国家对数据出境有严格的规定,如果用 MCP 在本地搭建服务,就可以避免数据跨境传输,满足当地的合规要求。而且,不同国家/地区可以配置不同的数据源和工具,更加灵活。

我从技术的角度补充一下,MCP 还可以用在边缘计算场景。比如,在工厂车间部署 AI 模型,实时分析传感器数据,预测设备故障。由于网络不稳定、带宽有限等问题,数据很难全部上传到云端。这时,使用 MCP 协议,将模型部署在本地,直接读取本地数据,可以大大提高响应速度和可靠性。

这个坑我踩过!MCP 客户端和服务端之间通过 stdio 进行通信,如果服务端有日志输出到控制台,客户端会把这些日志当成是 MCP 消息,导致解析失败,甚至整个程序崩溃。所以,一定要保证 stdio 通道的纯净。

如果实在找不到问题,可以尝试抓包。用 Wireshark 或者 tcpdump 抓取客户端和服务端之间的 TCP 通信,分析 MCP 消息的内容。虽然比较底层,但是可以帮助你定位问题。总而言之,要保证客户端可以正确的解析服务端返回的内容,否则就会出现各种问题。

迁移嘛,肯定要评估成本。如果现有的 TensorFlow/PyTorch 模型已经训练得很好了,可以考虑保留模型,然后用 Spring AI + MCP 搭建一个“桥梁”,负责数据交互和模型调用。 Spring AI 提供了很多集成工具,可以简化这个过程。关键是要搞清楚现有模型的输入输出格式,以及 MCP 协议的要求,做好适配。