大模型应用开发Spring AI实战-开发自己的MCP应用

今天这篇文章我来分享大模型应用开发Spring AI实战-开发自己的MCP服务。通过实际代码案例,逐步掌握Java生态下的AI大模型应用产品开发。

AI专栏软件环境

  • IntelliJ IDEA2024.3.5
  • JDK 17.0.13
  • Spring AI 1.0.0-SNAPSHOT
  • Spring Boot 3.4.4
  • Spring 6.2.5
  • 智谱大模型

我们先看本篇文章对应的项目结构,请看下图

text 复制代码
    spring-ai-lab07
    ├─spring-ai-mcp-client
    │  └─src
    │      ├─main
    │      │  ├─java
    │      │  │  └─cn
    │      │  │      └─itbeien
    │      │  │          └─lab07
    │      │  │              └─client
    │      │  │                  ├─config
    │      │  │                  └─controller
    │      │  └─resources
    │      └─test
    │          └─java
    └─spring-ai-mcp-server
        └─src
            ├─main
            │  ├─java
            │  │  └─cn
            │  │      └─itbeien
            │  │          └─lab07
            │  │              └─server
            │  │                  ├─config
            │  │                  └─service
            │  └─resources
            └─test
                └─java

完整代码在文章最后,如果觉得本篇文章对你有用,记得点赞、关注、收藏哦。你的支持是我持续更新的动力!

1 什么是MCP

​ MCP (Model Context Protocol)是一种开放协议,它标准化了应用程序向 LLM 提供上下文的方式。可以将 MCP 视为 AI 应用程序的 USB-C 端口。正如 USB-C 提供了一种将设备连接到各种外围设备和配件的标准化方式一样,MCP 提供了一种将 AI 模型连接到不同数据源和工具的标准化方式。MCP 是 Claude (Anthropic) 主导发布的一个开放的、通用的、有共识的协议标准。

​ MCP 可帮助用户在 LLM 之上构建代理和复杂的工作流程。LLM 经常需要与数据和工具集成,每一个环节的交互响应都需要花费时间,特别是在复杂的工作流程下,耗时更长,而 MCP 提供:

  • 越来越多的预构建集成(比如通用工具或通用的企业级业务服务),LLM 可以直接插入
  • LLM对接业务服务和工具就像使用USB集成一样简单
  • 可以使用MCP共享你的业务数据

2 MCP核心概念及架构

2.1 核心概念

  • MCP主机:像Claude Desktop、ide或AI工具这样想要通过MCP访问数据的程序
  • MCP客户端:与服务器保持1:1连接的协议客户端,比如本篇文章3.3为自定义的客户端实现
  • MCP服务器:轻量级程序,每个程序都通过标准化的模型上下文协议公开特定的功能,比如本篇文章3.2为自定义的服务端实现
  • 本地数据源:MCP服务器可以安全访问的计算机文件、数据库和服务
  • 远程服务:MCP服务器可以连接到的可通过internet(例如,通过api)访问的外部系统

2.2 MCP基础架构

2.3 MCP 与 API 快速比较

特征 MCP apI
集成工作 单一标准化集成 每个API单独集成,有各自的接入标准
实时通信 √支持 × 不支持
动态发现 √支持 × 不支持
可扩展性 简单(即插即用) 需要额外集成
安全与控制 跨工具/程序保持一致 因API而异

MCP 与传统 API 之间的主要区别在于:

  • 单一协议:MCP 充当标准化的"连接器",因此集成一个 MCP 意味着可能访问多个工具和服务,而不仅仅是一个。
  • 动态发现:MCP 允许 AI 模型动态发现可用工具并与之交互,而无需对每个集成进行硬编码。
  • 双向通信:MCP 支持持久的实时双向通信 - 类似于 WebSockets。AI 模型既可以检索信息,也可以动态触发操作。

MCP 提供实时的双向通信:

  • 拉取数据:LLM查询服务器以获取上下文→例如获取订单信息
  • 触发:LLM指示服务器采取行动→例如发起下单,退订

文章最后可以加入免费的Java&AI技术和支付系统沟通社群,一起探讨Java/你的产品如何与AI结合,请按照要求加入。在群中可以聊开发、系统设计、架构、行业趋势、AI等等话题

3 Spring AI MCP实战

3.1 MCP Java SDK 架构

3.1.1 Java MCP实现遵循三层架构

SSE协议调用为跨进程API调用,通过http进行MCP 服务端网络资源调用,Stdio为进程间调用用于访问本地数据源,Jar或网络资源。

  • Client/Server 层: McpClient处理客户端操作,而McpServer管理服务器端协议操作。两者都使用McpSession进行通信管理.
  • Session层(McpSession): 通过DefaultMcpSession实现管理通信模式和状态.
  • Transport层(McpTransport): 处理JSON-RPC消息序列化和反序列化,支持多种传输实现.

3.1.2 MCP Client

​ MCP客户端是模型上下文协议(MCP)体系结构中的关键组件,负责建立和管理与MCP服务器的连接。它实现了协议的客户端处理

3.1.3 MCP Server

​ MCP服务器是模型上下文协议(MCP)体系结构中的基础组件,为客户端提供工具、资源和功能。它实现了协议的服务器端处理

3.2 MCP Server代码实现

以下代码基于SSE实现MCP Server和MCP Client

3.2.1 pom依赖

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>cn.itbeien.ai</groupId>
        <artifactId>spring-ai-lab07</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>spring-ai-mcp-server</artifactId>

   <dependencies>
       <dependency>
           <groupId>org.projectlombok</groupId>
           <artifactId>lombok</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.ai</groupId>
           <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
       </dependency>
      <!-- <dependency>
           <groupId>org.springframework.ai</groupId>
           <artifactId>spring-ai-starter-mcp-server</artifactId>
       </dependency>-->
   </dependencies>

</project>

3.2.2 MCP服务

java 复制代码
package cn.itbeien.lab07.server.service;

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

/**
 * @author itbeien
 * 项目网站:https://www.itbeien.cn
 * 公众号:贝恩聊架构
 * 全网同名,欢迎小伙伴们关注
 * Java/AI/支付系统/SAAS多租户基础技术平台学习社群
 * Copyright© 2025 itbeien
 */
@Service
@Slf4j
public class McpService {

    @Tool(description = "获取城市的天气信息")
    public String getWeatherByCity(@ToolParam(required=true,description = "城市名称") String city) {
        log.info("获取城市天气信息:{}",city);
        return city +"天气信息:晴空万里,气温25°C";
    }
}

3.2.3 创建ToolCallbackProvider

java 复制代码
package cn.itbeien.lab07.server.config;

import cn.itbeien.lab07.server.service.McpService;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author itbeien
 * 项目网站:https://www.itbeien.cn
 * 公众号:贝恩聊架构
 * 全网同名,欢迎小伙伴们关注
 * Java/AI/支付系统/SAAS多租户基础技术平台学习社群
 * Copyright© 2025 itbeien
 */
@Configuration
public class AppConfig {
    @Bean
    public ToolCallbackProvider weatherTools(McpService mcpService) {
        return  MethodToolCallbackProvider.builder().toolObjects(mcpService).build();
    }

}

3.3 MCP Client代码实现

3.3.1 pom依赖

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>cn.itbeien.ai</groupId>
        <artifactId>spring-ai-lab07</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>spring-ai-mcp-client</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-zhipuai-spring-boot-starter</artifactId>
            <version>${springai.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-mcp</artifactId>
        </dependency>
    </dependencies>

</project>

3.3.2 设置ToolCallbackProvider

java 复制代码
package cn.itbeien.lab07.client.config;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author itbeien
 * 项目网站:https://www.itbeien.cn
 * 公众号:贝恩聊架构
 * 全网同名,欢迎小伙伴们关注
 * Java/AI/支付系统/SAAS多租户基础技术平台学习社群
 * Copyright© 2025 itbeien
 */
@Configuration
public class AppConfig {

    @Bean
    public ChatClient chatClient(ChatClient.Builder builder,ToolCallbackProvider tools) {
        return builder.defaultTools(tools).build();
    }

}

3.3.3 大模型和MCP集成

java 复制代码
package cn.itbeien.lab07.client.controller;

import io.modelcontextprotocol.client.McpAsyncClient;
import io.modelcontextprotocol.client.McpSyncClient;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @author itbeien
 * 项目网站:https://www.itbeien.cn
 * 公众号:贝恩聊架构
 * 全网同名,欢迎小伙伴们关注
 * Java/AI学习社群
 * Copyright© 2025 itbeien
 */
@RestController
@RequestMapping("/ai")
@RequiredArgsConstructor
public class AiController {

    // 自定义人设,来与用户进行角色扮演 提示词
    private final static String systemPrompt = "你是智能天气助手,请回答与天气相关的问题,用户在询问天气情况时必须要求给出哪个城市和哪一天";

    // 历史消息列表
    static List<Message> historyMessage = new ArrayList<>(List.of(new SystemMessage(systemPrompt)));

    private final ChatModel chatModel;

    private final ChatClient chatClient;

    //private final ToolCallbackProvider tools;

    // 历史消息列表的最大长度
    static int maxLen = 10;
    @GetMapping("/chat")
    String generation(@RequestParam("prompt") String userInput) {
        return this.chatModel.call(userInput);
    }


    @GetMapping("/fcChat")
    String fcChat(@RequestParam("prompt") String userInput) {
        // 用户输入的文本是UserMessage
        historyMessage.add(new UserMessage(userInput));
        // 发给AI前对历史消息对列的长度进行检查
        if(historyMessage.size() > maxLen){
            historyMessage = historyMessage.subList(historyMessage.size()-maxLen-1,historyMessage.size());
            // 确保第一个是SystemMessage
            historyMessage.add(0,new SystemMessage(systemPrompt));
        }

        Prompt prompt = new Prompt(historyMessage);
        return chatClient.prompt(prompt).call().content();
       /* return ChatClient.create(chatModel)
                .prompt(prompt)
                .tools(tools)
                .call()
                .content();*/
    }
}

3.4 单元测试

通过向大模型提问"深圳今天的天气",大模型会通过设置的tools对mcp server服务进行调用

4 源码地址

贝恩聊架构-AI专栏,SpringBoot3专栏系列文章、资料和源代码会同步到以下地址,代码和资料每周都会同步更新

该仓库地址主要用于存放贝恩聊架构-SpringBoot3专栏、贝恩聊架构-AI专栏、基于企业级支付系统学习微服务整体技术栈所有资料和源码

Gitee:gitee.com/itbeien/pro...

Github:github.com/itbeien/pro...

相关推荐
希望永不加班1 小时前
Spring AOP 代理模式:CGLIB 与 JDK 动态代理区别
java·开发语言·后端·spring·代理模式
浮游本尊2 小时前
一次合同同步背后的多阶段流水线:从外部主数据到本地歧义消解
后端
lv__pf2 小时前
springboot原理
java·spring boot·后端
段小二3 小时前
服务一重启全丢了——Spring AI Alibaba Agent 三层持久化完整方案
java·后端
UIUV3 小时前
Go语言入门到精通学习笔记
后端·go·编程语言
lizhongxuan3 小时前
开发 Agent 的坑
后端
段小二3 小时前
Agent 自动把机票改错了,推理完全正确——这才是真正的风险
java·后端
itjinyin3 小时前
ShardingSphere-jdbc 5.5.0 + spring boot 基础配置 - 实战篇
java·spring boot·后端
Victor3564 小时前
MongoDB(91)如何在MongoDB中使用TTL索引?
后端