Spring AI 实战:从零搭建 MCP 客户端与服务端,让大模型拥有“手脚“

一、什么是 MCP?为什么需要它?

在 AI 应用开发中,大语言模型(LLM)虽然知识丰富,但它本身只是一个"文本生成器"------它无法访问实时数据库、不能查询天气、也不能帮你操作系统里的业务数据。

为了解决这个问题,MCP(Model Context Protocol,模型上下文协议) 应运而生。

1.1 MCP 的定位

官方定义很形象:

Think of MCP like a USB-C port for AI applications.

就像 USB-C 为电子设备提供了统一的接口标准,MCP 为 AI 应用连接数据源和工具提供了标准化方式

MCP 并不是替代 Tool Calling(工具调用),而是为其提供一个统一、可扩展、跨平台的连接基础设施。可以理解为:

  • Tool Calling 是"能力":AI 可以调用外部工具
  • MCP 是"通信协议":规定如何描述工具、如何发起调用、如何传递结果、如何管理会话状态

1.2 MCP 的架构

Java MCP SDK 采用三层架构:

架构层 功能说明 比喻
Client/Server 层 McpClient 处理客户端操作,McpServer 管理服务端协议 顾客 vs 厨房
Session 层 DefaultMcpSession 管理通信模式和状态 订单管理系统
Transport 层 McpTransport 处理 JSON-RPC 消息的序列化与反序列化 外卖骑手

支持的传输方式包括:

  • Stdio:通过标准输入/输出通信,适合本地进程调用
  • SSE(Server-Sent Events):基于 HTTP 的单向推送,适合远程服务
  • Streamable HTTP:更灵活的 HTTP 流式通信

二、项目整体架构

本文将构建三个模块,组成完整的 MCP 应用体系:

复制代码
┌─────────────────────────────────────────────────┐
│                  mcp-client-demo                 │
│   (AI 客户端 + DashScope 模型 + MCP Client)       │
│        ↓ 通过 Stdio 或 SSE 连接                  │
├──────────────────┬───────────────────────────────┤
│  mcp-stdio-server-demo │  mcp-sse-server-demo   │
│  (Stdio 传输方式)       │  (SSE 传输方式)        │
│  暴露 getUserInfo 工具  │  暴露 getUserInfo 工具  │
└──────────────────┴───────────────────────────────┘
  • mcp-stdio-server-demo:以 Stdio 方式暴露工具,通过 jar 包进程调用
  • mcp-sse-server-demo:以 SSE 方式暴露工具,通过 HTTP 端点通信
  • mcp-client-demo:AI 客户端,接入通义千问(DashScope)和 MCP 服务

三、搭建 MCP Server(Stdio 方式)

3.1 创建项目与依赖

使用 Spring Boot 3.x + JDK 17,在 pom.xml 中引入核心依赖:

xml 复制代码
<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Spring AI MCP Server (Stdio) -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-server</artifactId>
    </dependency>
    
    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

<build>
    <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>

注意spring-boot-maven-pluginrepackage 目标是必须的,因为 Stdio 模式需要将 Server 打包成可执行的 jar 文件,由客户端进程启动。

3.2 配置文件

application.yml

yaml 复制代码
spring:
  ai:
    mcp:
      server:
        name: user-info
        version: 0.0.1
  main:
    web-application-type: none   # Stdio 模式不需要 Web 容器
    banner-mode: off

关键点:Stdio 模式不需要 Web 应用类型,关闭 banner 可以减少标准输出的干扰。

3.3 定义实体与服务

UserInfo.java

java 复制代码
@Data
@AllArgsConstructor
public class UserInfo {
    private String name;
    private Integer age;
    private String sex;
    private String address;
}

UserService.java

java 复制代码
@Service
public class UserService {
    
    static Map<String, UserInfo> userInfoMap = new HashMap<>();
    
    static {
        userInfoMap.put("zhangsan", new UserInfo("zhangsan", 15, "男", "北京"));
        userInfoMap.put("lisi", new UserInfo("lisi", 16, "男", "上海"));
        userInfoMap.put("wangwu", new UserInfo("wangwu", 17, "男", "广州"));
        userInfoMap.put("zhaoliu", new UserInfo("zhaoliu", 18, "女", "深圳"));
        userInfoMap.put("sunqi", new UserInfo("sunqi", 19, "女", "香港"));
        userInfoMap.put("zhaoba", new UserInfo("zhaoba", 20, "女", "澳门"));
    }
    
    @Tool(description = "根据用户的姓名, 返回用户信息")
    public String getUserInfo(@ToolParam(description = "用户的姓名") String name) {
        if (userInfoMap.containsKey(name)) {
            return userInfoMap.get(name).toString();
        }
        return "未查询到用户信息";
    }
}

这里的核心注解:

  • @Tool:标记一个方法为 MCP 工具,description 会告诉 AI 这个工具是做什么的
  • @ToolParam:描述参数的含义,帮助 AI 理解何时以及如何调用

3.4 注册工具

ToolConfig.java

java 复制代码
@Configuration
public class ToolConfig {
    
    @Bean
    public ToolCallbackProvider getUserInfo(UserService userService) {
        return MethodToolCallbackProvider.builder()
                .toolObjects(userService)
                .build();
    }
}

通过 MethodToolCallbackProvider 将带有 @Tool 注解的服务注册为 MCP 工具回调提供者。

3.5 启动类

java 复制代码
@SpringBootApplication
public class McpServerDemo {
    public static void main(String[] args) {
        SpringApplication.run(McpServerDemo.class, args);
    }
}

打包后,这个 jar 就是 MCP Server 的可执行文件。


四、搭建 MCP Server(SSE 方式)

SSE 方式与 Stdio 的核心差异在于传输层依赖选择

4.1 依赖调整

xml 复制代码
<dependencies>
    <!-- 注意:SSE 模式需要使用 webmvc 或 webflux 启动器 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

说明:Spring AI 为 MCP Server 提供了三个启动器:

  • spring-ai-starter-mcp-server:Stdio 模式
  • spring-ai-starter-mcp-server-webmvc:基于 Servlet/MVC 的 SSE 模式
  • spring-ai-starter-mcp-server-webflux:响应式 SSE 模式

选错启动器会导致 MCP 端点(如 /sse)无法正常工作。

4.2 配置文件

yaml 复制代码
server:
  port: 8088
spring:
  ai:
    mcp:
      server:
        name: user-info
        version: 0.0.1

SSE 模式需要指定端口,因为客户端将通过 HTTP 连接到这个服务。

4.3 其他代码

实体类(UserInfo)、服务类(UserService)、配置类(ToolConfig)和启动类与 Stdio 模式完全一致,无需修改。


五、搭建 MCP Client

客户端是整个系统的"大脑",负责接收用户请求、调用 AI 模型、并通过 MCP 协议调用工具。

5.1 依赖配置

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Spring AI Alibaba DashScope(通义千问) -->
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
    </dependency>
    
    <!-- Spring WebFlux(MCP Client 需要) -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webflux</artifactId>
    </dependency>
    
    <!-- Spring AI MCP Client -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-client</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-bom</artifactId>
            <version>1.0.0.2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

5.2 配置文件

application.yml

yaml 复制代码
spring:
  ai:
    dashscope:
      api-key: ${DASHSCOPE_API_KEY:your-api-key-here}
    mcp:
      client:
        request-timeout: 60000
        sse:
          connections:
            user-info:
              url: http://127.0.0.1:8088/sse

logging:
  level:
    io:
      modelcontextprotocol:
        client: DEBUG
        spec: DEBUG

这里使用 SSE 方式连接 MCP Server。如果要用 Stdio 方式,改为:

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        request-timeout: 60000
        stdio:
          servers-configuration: classpath:/mcp/mcp-servers-config.json

对应的 mcp-servers-config.json

json 复制代码
{
  "mcpServers": {
    "baidu-map": {
      "command": "npx.cmd",
      "args": ["-y", "@baidumap/mcp-server-baidu-map"],
      "env": {
        "BAIDU_MAP_API_KEY": "your-api-key"
      }
    },
    "user-info": {
      "command": "java",
      "args": [
        "-Dspring.ai.mcp.server.stdio=true",
        "-Dlogging.pattern.console=",
        "-jar",
        "D:\\code\\javacode\\spring-ai\\spring-ai-project\\mcp-stdio-server-demo\\target\\mcp-stdio-server-demo-1.0-SNAPSHOT.jar"
      ]
    }
  }
}

Windows 用户注意 :在 IDEA 中配置 MCP 服务时,需要将 npx 改为 npx.cmd,避免因扩展名缺失导致启动失败。

5.3 Chat Controller

java 复制代码
@RestController
@RequestMapping("/chat")
public class ChatController {
    
    private ChatClient chatClient;

    public ChatController(DashScopeChatModel chatModel, 
                          ToolCallbackProvider toolCallbackProvider) {
        this.chatClient = ChatClient.builder(chatModel)
                .defaultToolCallbacks(toolCallbackProvider)
                .build();
    }
    
    @RequestMapping("/generate")
    public String generate(String message) {
        return chatClient.prompt()
                .user(message)
                .call()
                .content();
    }
}

关键点在于 .defaultToolCallbacks(toolCallbackProvider) ------ 这行代码将 MCP 工具注册到 ChatClient,让 AI 在需要时可以自动发现并调用。

5.4 启动类

java 复制代码
@SpringBootApplication
public class MCPClientDemo {
    public static void main(String[] args) {
        SpringApplication.run(MCPClientDemo.class, args);
    }
}

六、测试与效果

6.1 启动服务

  1. 先启动 MCP Server (SSE 方式):运行 mcp-sse-server-demo,监听 8088 端口
  2. 再启动 MCP Client :运行 mcp-client-demo

6.2 发送请求

bash 复制代码
curl "http://localhost:8080/chat/generate?message=帮我查一下zhangsan的信息"

6.3 工作流程

当你发送请求后,整个调用链路如下:

复制代码
用户请求 → ChatClient → DashScope AI 模型
                           ↓
                    AI 判断需要调用工具
                           ↓
                    通过 MCP 协议 → MCP Server
                           ↓
                    UserService.getUserInfo("zhangsan")
                           ↓
                    返回: UserInfo{name=zhangsan, age=15, sex=男, address=北京}
                           ↓
                    AI 整合结果 → 返回给用户

客户端日志中可以看到 MCP 通信的完整 DEBUG 信息:

复制代码
io.modelcontextprotocol.spec.McpSchema : Received JSON message: {"result": {...}}

6.4 无工具 vs 有工具对比

  • 没有接入 MCP 工具时:问"zhangsan 的信息",AI 只能基于训练数据回答或表示不知道
  • 接入 MCP 工具后 :AI 自动发现 getUserInfo 工具,提取参数 zhangsan,调用后返回准确的业务数据

这就是 MCP 的价值------让 AI 从"聊天机器人"变成能操作真实业务的智能助手


七、两种传输方式的对比

特性 Stdio SSE
通信方式 标准输入/输出(进程间) HTTP Server-Sent Events
部署方式 打包为 jar,客户端进程启动 独立部署为 HTTP 服务
适用场景 本地嵌入式、IDE 插件 远程服务、微服务架构
依赖启动器 spring-ai-starter-mcp-server spring-ai-starter-mcp-server-webmvc
是否需要端口
多服务管理 通过 JSON 配置文件 通过 URL 配置

开发建议

  • 本地开发和插件化场景优先使用 Stdio
  • 需要远程部署或集成到微服务体系时使用 SSE
  • 生产环境推荐将 MCP Server 注册为微服务(Nacos/Consul/Eureka),方便服务治
相关推荐
“码”力全开1 小时前
解构企业级安防中台:基于Docker容器化与GB28181/RTSP多协议汇聚的边缘计算AI视频管理平台(全量源码交付)
人工智能·docker·边缘计算
GeeLark1 小时前
TikTok自动化 我们有在优化
人工智能
秦时星星1 小时前
Spring AI + FastMCP 跨语言集成踩坑实录
java·人工智能·spring
码农小白AI1 小时前
单据审核难度大?IACheck AI 报告审核联动全流程高效核验
人工智能
聚城云-GeecityCloud1 小时前
数字化破局|不分物业规模,皆可全新升级
大数据·人工智能
小白考证进阶中1 小时前
阿里云ACA大模型|6月15日课程和大纲大改⚠️
人工智能·阿里云·阿里云认证·阿里云acp备考·阿里云aca证书·ai证书·阿里云aca大模型
见牛羊1 小时前
docker理解
java·docker·容器
Esaka_Forever1 小时前
FAISS (Facebook AI Similarity Search)
人工智能·faiss
摄影图1 小时前
[图片素材]大模型训练开发 场景覆盖适配各类科技
人工智能·科技·aigc·贴图