欢迎光临
我们一直在努力

【AI Agent 全栈开发】MCP

🚀 欢迎来到我的CSDN博客:Optimistic _ chen ✨ 一名热爱技术与分享的全栈开发者,在这里记录成长,专注分享编程技术与实战经验,助力你的技术成长之路,与你共同进步!


🚀我的专栏推荐:

专栏内容特色适合人群
🔥C语言从入门到精通 系统讲解基础语法、指针、内存管理、项目实战 零基础新手、考研党、复习
🔥Java基础语法 系统解释了基础语法、类与对象、继承 Java初学者
🔥Java核心技术 面向对象、集合框架、多线程、网络编程、新特性解析 有一定语法基础的开发者
🔥Java EE 进阶实战 Servlet、JSP、SpringBoot、MyBatis、项目案例拆解 想快速入门Java Web开发的同学
🔥Java数据结构与算法 图解数据结构、LeetCode刷题解析、大厂面试算法题 面试备战、算法爱好者、计算机专业学生
🔥Redis系列 从数据类型到核心特性解析 项目必备

🚀我的承诺: ✅ 文章配套代码:每篇技术文章都提供完整的可运行代码示例

✅ 持续更新:专栏内容定期更新,紧跟技术趋势

✅ 答疑交流:欢迎在文章评论区留言讨论,我会及时回复(支持互粉)


🚀 关注我,解锁更多技术干货! ⏳ 每天进步一点点,未来惊艳所有人!✍️ 持续更新中,记得⭐收藏关注⭐不迷路 ✨

📌 标签:#技术博客  #编程学习  #Java  #C语言  #算法  #程序员

文章目录

  • 前言
  • 什么是MCP
  • MCP Java SDK架构
    • Transport传输协议
    • MCP server
    • MCP Client
  • MCP使用
  • 自定义MCP Server
    • 使用Stdio自定义MCP Server
    • 使用SSE自定义MCP Server
  • 完结撒花!🎉

前言

当今快速发展的AI应用生态中,我们从优化提示词到使用Tool Calling突破大模型语言生成的界限,完成调用外部系统的实际任务。但是随着工具数量的增长和应用场景的复杂化,传统的Tool Calling实现方式暴露出一系列挑战:

  • 工具接口格式不统一
  • 模型需硬编码工具定义

为了解决这些问题,一个新的概念——MCP出现了。

什么是MCP

MCP(Model Context Protocol)模型上下文协议:事实上,MCP并不是代替Tool Calling的产物,而是为其提供一个统一、可扩展、跨平台的连接基础设施。

简单来说,MCP是Tool Calling的管理者。

  • Tool Calling:模型决定要不要调用工具,调哪个工具,
  • MCP:规定如何描述工具,如何发起调用,如何传递结果

有了MCP,AI只需要学习一种格式,MCP Server 负责翻译。

MCP Java SDK架构

MCP Java SDK提供MCP的Java实现,⽀持通过同步和异步通信模式与AI模型及⼯具进⾏标准化交互。

在这里插入图片描述

  • Client/Server分别表示请求的发起者和请求的接收者(顾客和后厨)
  • Session表示管理会话生命周期(订单管理系统)
  • Transport表示消息传递的方式(手机订餐+骑手送餐)

Transport传输协议

MCP Java SDK提供了多种"通信⽅式",让AI应⽤(客⼾端)能灵活地与各种⼯具服务(服务器)进⾏对话 目前支持三种传输方式:

  • 基于Stdio 的进程间通信传输协议 通过标准输⼊/输出(stdin和stdout)在两个程序之间传消息,⾼效直接
  • 基于Java HttpClient的SSE客户端传输协议 基于JavaHttpClient发起HTTP请求,并接收服务端持续发送的事件流
  • WebFlux SSE客户端传输协议 基于WebFlux的⾮阻塞、响应式编程模型,处理SSE流
  • MCP server

    作为MCP协议的具体服务端实现,是对外提供特定功能的服务程序,我们可以直接去MCP Server社区去查找调用你想要的功能,社区中活跃着大量技术爱好者,致力于为MCP用户提供交流、资源共享等服务。

    • GitHub MCP Registry: htttps://github.com/mcp/registry
    • MCP Flow:https://mcpflow.io/home
    • 火山引擎 MCP 广场: www.volcengine.com/mcp-marketplace

    MCP Client

    有了MCP 服务端后,如何在代码中调用这些服务,这就需要借助MCP 客户端。

    作为MCP客户端是连接本地开发环境或应用与远程MCP服务器之间的桥梁,不同客户端对MCP协议的支持程度各不相同,⽤⼾可以根据⾃⼰的需求选择合适的客⼾端。

    MCP使用

    在使⽤MCPClient之前,通常需要先运⾏⼀个或多个MCPServer实例.⽽许多MCPServer是通过npx或uv命令启动的,在开始使⽤前,必须正确配置相应的运⾏环境。 准备一个MCP Server:可以到各大网站获取相应的配置

    {
    "mcpServers": {
    "baidu-map": {
    "command": "npx",
    "args": [
    "-y",
    "@baidumap/mcp-server-baidu-map"
    ],
    "env": {
    "BAIDU_MAP_API_KEY": "xxx"
    }
    }
    }
    }

    准备好MCP Server,这里通过Cursor来展示MCP的使用:

    除了上述的客户端之外,我们也可以通过Spring AI代码来接入这些资源 首先,采用SpringAI-Alibaba来调用AI服务,引入依赖

    <?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">

    <parent>
    <artifactId>spring-ai-project</artifactId>
    <groupId>org.example</groupId>
    <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mcp-client-demo</artifactId>

    <properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    </dependency>
    <dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webflux</artifactId>
    </dependency>
    <!– 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>

    </project>

    配置文件application

    spring:
    ai:
    dashscope:
    api-key: ${DASHSCOPE_API_KEY}
    mcp:
    client:
    request-timeout: 60000
    stdio:
    servers-configuration: classpath:/mcp/mcpserversconfig.json

    同时引入百度地图的配置:mcp/mcp-servers-config.json

    {
    "mcpServers": {
    "baidu-map": {
    "command": "npx.cmd",
    "args": ["-y", "@baidumap/mcp-server-baidu-map"],
    "env": {
    "BAIDU_MAP_API_KEY": "nLpm876DutMXGl6gEwzJksuya0gbfk0B"
    }
    }
    }
    }

    在controller添加该工具

    @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();
    }
    }

    ToolCallbackProvider 是 Spring AI 中用于向 AI 模型注册和提供可用工具(MCP Server 的工具)的核心接口。所以,之后只要有MCP配置进来,ToolCallbackProvider 就可以调用,完美解决了Tool Calling中各个工具接口不同的情况,实现动态工具组合。

    自定义MCP Server

    我们知道MCP有两种通信方式:Stdio 和 Streamable HTTP 在这里插入图片描述 前面提到的两个协议是Stdio 和 SSE,但是在 2025年3月26日的协议更新后,官方已用更强大的 Streamable HTTP 取代 SSE(解决了SSE连接容易断开的痛点)

    controller/ChatController

    package com.zc.mcp.controller;

    import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
    import org.springframework.ai.chat.client.ChatClient;
    import org.springframework.ai.tool.ToolCallbackProvider;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;

    @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();
    }
    }

    application.yml

    spring:
    ai:
    dashscope:
    api-key: ${DASHSCOPE_API_KEY}
    mcp:
    client:
    request-timeout: 60000
    stdio:
    servers-configuration: classpath:/mcp/mcpserversconfig.json

    /mcp/mcp-servers-config.json

    {
    "mcpServers": {
    "stdio-server": {
    "command": "java",
    "args": [
    "-Dfile.encoding=UTF-8",
    "-Dspring.ai.mcp.server.stdio=true",
    "-Dlogging.pattern.console=",
    "-jar",
    "E:\\\\springAI\\\\mcp\\\\mcp-stdio-server\\\\target\\\\mcp-stdio-server-1.0-SNAPSHOT.jar"
    ]
    }
    }
    }

    使用Stdio自定义MCP Server

    在这里插入图片描述

    Service/WeatherService

    package com.zc.mcp.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;

    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;

    @Service
    @Slf4j
    public class WeatherService {

    private final Map<String, WeatherInfo> weatherCache = new ConcurrentHashMap<>();

    public WeatherService() {
    // 初始化天气数据
    weatherCache.put("北京", new WeatherInfo("晴转多云", "22~28", "南风2级", "78"));
    weatherCache.put("上海", new WeatherInfo("小雨", "18~24", "东风3级", "52"));
    weatherCache.put("广州", new WeatherInfo("晴朗", "25~33", "微风", "45"));
    weatherCache.put("深圳", new WeatherInfo("多云", "24~30", "东北风2级", "60"));
    }

    @Tool(description = "查询指定城市的天气信息,返回天气状况、温度范围、风力、空气质量")
    public String queryWeather(
    @ToolParam(description = "城市名称,如:北京、上海、广州、深圳") String city) {

    log.info("[HTTP MCP] queryWeather 调用,城市: {}", city);

    if (!weatherCache.containsKey(city)) {
    return String.format("未找到「%s」的天气信息,支持的城市:%s",
    city, weatherCache.keySet());
    }

    WeatherInfo info = weatherCache.get(city);
    return String.format("""
    🌍 %s天气报告
    ─────────────────
    ☁️ 天气:%s
    🌡️ 温度:%s°C
    💨 风力:%s
    🏭 AQI:%s
    ─────────────────
    🕐 更新时间:%s
    """
    ,
    city, info.weather, info.temp, info.wind, info.aqi,
    LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
    );
    }

    record WeatherInfo(String weather, String temp, String wind, String aqi) {}
    }

    config/ToolConfig

    package com.zc.mcp.config;

    import com.zc.mcp.service.WeatherService;
    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;

    @Configuration
    public class ToolConfig {
    @Bean
    public ToolCallbackProvider getWeather(WeatherService weatherService){
    return MethodToolCallbackProvider.builder()
    .toolObjects(weatherService)
    .build();
    }
    }

    application.yml

    spring:
    ai:
    mcp:
    server:
    name: stdioserver
    version: 0.0.1
    main:
    web-application-type: none
    banner-mode: off

    生成jar包 在这里插入图片描述 在这里插入图片描述

    使用SSE自定义MCP Server

    注意:使用SSE传输策略时,依赖的主要选择是取决于你是作为客户端还是服务端,以及是使用传统的同步SSE还是WebFlux响应式SSE。

    Starter角色被谁调用
    spring-ai-starter-mcp-server MCP Server 本地MCP Client(通过Stdio)
    spring-ai-starter-mcp-server-webmvc MCP Server 远程MCP Client(通过HTTP/SSE)
    spring-ai-starter-mcp-server-webflux MCP Server 远程MCP Client(通过HTTP/SSE/WebFlux)
    spring-ai-starter-mcp-client MCP Client Stdio/SSE客户端
    spring-ai-starter-mcp-client-webflux MCP Client WebFlux客户端

    在Web项目中添加spring-ai-starter-mcp-server webflux依赖会导致MCP端点(/sse)失效,这是因为项目中同时存在org.springframework.web.servlet.DispatcherServlet和org.springframework.web.reactive.DispatcherHandler。根本原因是:当DispatcherServlet(Servlet)和DispatcherHandler(Reactive)共存时,Spring Boot会默认优先使用Servlet堆栈启动Web服务。这样应用将以传统的Tomcat(或Jetty/Undertow)服务器运行,而非WebFlux所需的Netty服务器,导致专属于WebFlux的/sse端点无法正常工作。

    可以通过在配置文件中设置解决:

    server:
    port: 8081
    spring:
    ai:
    mcp:
    server:
    name: sseserver
    version: 0.0.1
    main:
    web-application-type: reactive

    SSE的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">

    <parent>
    <artifactId>mcp</artifactId>
    <groupId>org.example</groupId>
    <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mcp-sse</artifactId>

    <properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <repositories>
    <repository>
    <id>spring-milestones</id>
    <name>Spring Milestones</name>
    <url>https://repo.spring.io/milestone</url>
    </repository>
    </repositories>
    <dependencies>
    <!– Web 容器支持 –>
    <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-webflux</artifactId>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
    </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>

    service实现工具的业务逻辑,config将工具暴露给MCP Server.(代码和Stdio类似) config 中的 MethodToolCallbackProvider 就像一个"扫描器",把 @Tool 方法收集起来"交"给MCP Server.

    SSE定义MCP Server后,启动项目,在Cursor中配置好服务后,就能直接使用了。

    {
    "mcpServers": {
    "sseserver":{
    "url":"http://127.0.0.1:8081/sse"
    }
    }
    }

    在这里插入图片描述

    想要在SpringAI中作为MCP Client调用该工具,注意controller的细节

    @RestController
    @RequestMapping("/chat")
    public class ChatController {

    private final ChatClient chatClient;

    @Autowired
    public ChatController(DashScopeChatModel chatModel,
    SyncMcpToolCallbackProvider mcpToolProvider) {
    // DashScopeChatModel chatModel:阿里云通义千问的模型实例,负责实际调用大模型 API
    // SyncMcpToolCallbackProvider mcpToolProvider:MCP 工具提供者,负责将远程 MCP Server 的工具转换成 Spring AI 可用的工具
    this.chatClient = ChatClient.builder(chatModel)//告诉 ChatClient 使用哪个大模型
    .defaultToolCallbacks(mcpToolProvider.getToolCallbacks()) // 把从 MCP 工具提供者中获取所有远程工具设置为 ChatClient 的默认工具
    .build();
    }

    @RequestMapping("/generate")
    public String generate(String message) {
    return chatClient.prompt()
    .user(message)
    .call()
    .content();
    }
    }

    在这里插入图片描述

    完结撒花!🎉

    如果这篇博客对你有帮助,不妨点个赞支持一下吧!👍 你的鼓励是我创作的最大动力~

    ✨ 想获取更多干货? 欢迎关注我的专栏 → optimistic_chen 📌 收藏本文,下次需要时不迷路!

    我们下期再见!💫 持续更新中……


    悄悄说:点击主页有更多精彩内容哦~ 😊 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7471a32ba1fc4954b6ae528ef5b66475.png

    赞(0)
    未经允许不得转载:171主机测评 » 【AI Agent 全栈开发】MCP
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址