AI Agent全栈开发MCP指南

作者:技术拾光时间:2026-06-10 06:32:07浏览:203

MCP(模型上下文协议)为ToolCalling构建统一基础设施,有效解决工具接口不统一问题。通过JavaSDK支持Stdio、SSE等传输协议,实现标准化调用。SpringAI集成MCP可自动注册工具,完成动态工具组合,显著提升开发效率。

先说几个核心判断:AI应用生态发展到今天,优化提示词和Tool Calling已经帮我们突破了很多语言模型的边界。但如果仔细想想,工具一多、场景一复杂,老路子就开始吃力了——接口不统一、模型得硬编码工具定义……这些问题就像厨房里堆满了不同制式的厨具,每个都得单独学怎么用。好在,MCP(模型上下文协议)来了。

前言

如今,AI应用越来越依赖与外部系统的交互。我们从最开始的提示词工程,一步步走到Tool Calling——让模型自己决定要不要调用工具、调哪个工具。但现实是,随着工具数量的增长,传统的Tool Calling实现方式开始暴露出几个扎堆的挑战:工具接口格式不统一,模型需要硬编码工具定义……说实话,这些痛点如果不解决,后面每加一个新工具都得改代码,想想就头疼。

正是为了收拾这个烂摊子,MCP应运而生。

什么是MCP

MCP(Model Context Protocol)模型上下文协议,说白了,它不是要替代Tool Calling,而是给Tool Calling搭一个统一的、可扩展的跨平台基础设施。用一句话概括:MCP就是Tool Calling的管理者。

  • Tool Calling:模型决定要不要叫工具,叫哪个工具。
  • MCP:规定工具怎么描述、怎么发起调用、怎么传递结果。

有了MCP,AI只需学会一种通信格式,剩下的翻译工作全交给MCP Server。就像是给所有厨具统一配上了标准接口,厨房再乱也能高效运转。

MCP Java SDK架构

MCP Java SDK提供了Java端的完整实现,支持同步和异步两种通信模式,让AI模型和工具之间能按标准化方式握手。

AI Agent全栈开发MCP指南

  • Client/Server:请求的发起者和接收者,就像顾客和后厨。
  • Session:管理会话生命周期,相当于订单管理系统。
  • Transport:消息传递的方式,好比手机订餐加上骑手送餐。

Transport传输协议

MCP Java SDK支持多种“通信方式”,让AI应用(客户端)能灵活地与各种工具服务(服务器)对话。目前支持三种传输方式:

  1. 基于Stdio的进程间通信传输协议:通过标准输入/输出(stdin和stdout)在两个程序之间传消息,直接高效。
  2. 基于Java HttpClient的SSE客户端传输协议:用Java HttpClient发起HTTP请求,接收服务端持续推送的事件流。
  3. WebFlux SSE客户端传输协议:基于WebFlux的非阻塞响应式模型处理SSE流,适合高并发场景。

MCP Server

MCP Server是协议的具体服务端实现,对外提供特定功能。你可以直接去MCP Server社区查找你需要的功能——那里聚集了大量技术爱好者,资源很丰富。几个常用的社区入口:GitHub MCP Registry、MCP Flow、火山引擎MCP广场。不过要注意,这些社区里有些服务可能需要注册或API Key,具体按官方文档来。

MCP Client

有了服务端,怎么在代码里调用?这就需要MCP Client出场了。它连接开发环境和远程MCP Server,不同客户端对MCP协议的支持程度不一样,可以根据自己的需求选合适的。

MCP使用

在使用MCP Client之前,通常得先跑一个或多个MCP Server实例。很多MCP Server通过npx或uv命令启动,所以运行环境要提前配好。下面是一个典型的配置,以百度地图MCP Server为例:

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

配置好后,在Cursor里就能直接看到MCP Server的效果:
AI Agent全栈开发MCP指南

除了Cursor这类客户端,我们也能通过Spring AI代码来接入。以Spring AI Alibaba为例,先引入依赖,然后在配置文件中指定MCP Server的地址和超时时间:

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

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

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

然后在Controller里注入ToolCallbackProvider,它会自动把MCP Server的工具注册给AI模型:

@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配置进来,它就能自动调用,完美解决了传统Tool Calling中各工具接口不同的问题,实现动态工具组合。

自定义MCP Server

我们知道MCP有两种通信方式:Stdio和Streamable HTTP。早先用的是SSE,但在2025年3月26日的协议更新后,官方用更强大的Streamable HTTP取代了SSE(解决了SSE连接容易断开的痛点)。不过为了兼容旧版本,这里仍保留SSE的实现说明。

AI Agent全栈开发MCP指南

使用Stdio自定义MCP Server

AI Agent全栈开发MCP指南

先写一个天气查询服务:

@Service
@Slf4j
public class WeatherService {
    private final Map 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) {}
}

然后通过ToolConfig将其暴露给MCP Server:

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

在Stdio模式下,MCP Server是一个独立的命令行应用,不需要Web容器。配置如下:

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

打包成jar后,客户端通过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"
      ]
    }
  }
}

启动后,客户端就可以像调用本地函数一样使用天气查询工具了。
AI Agent全栈开发MCP指南
AI Agent全栈开发MCP指南

使用SSE自定义MCP Server

SSE模式的MCP Server需要运行在Web容器中。注意,不同的Starter适用于不同的角色:

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

这里有一个容易踩的坑:如果在Web项目中同时引入spring-boot-starter-web和spring-ai-starter-mcp-server-webflux,会导致MCP端点(/sse)失效。原因是两个Servlet/Reactive的Dispatcher共存时,Spring Boot默认优先使用Servlet堆栈。解决方式是在配置文件中明确指定使用Reactive:

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

pom.xml需要包含WebFlux Starter:


    org.springframework.boot
    spring-boot-starter-web


    org.springframework.ai
    spring-ai-starter-mcp-server-webflux


    org.projectlombok
    
    true


    org.springframework.boot
    spring-boot-starter-test
    test

Service和Config的代码与Stdio模式类似,这里不再重复。Service中的@Tool方法和Config中的MethodToolCallbackProvider就像“扫描器”,自动把工具注册给MCP Server。

启动SSE Server后,在Cursor中配置即可直接使用:

{
  "mcpServers": {
    "sse-server": {
      "url": "http://127.0.0.1:8081/sse"
    }
  }
}

AI Agent全栈开发MCP指南

如果想在Spring AI中作为MCP Client调用SSE Server,Controller里需要注入SyncMcpToolCallbackProvider:

@RestController
@RequestMapping("/chat")
public class ChatController {
    private final ChatClient chatClient;

    @Autowired
    public ChatController(DashScopeChatModel chatModel,
                          SyncMcpToolCallbackProvider mcpToolProvider) {
        this.chatClient = ChatClient.builder(chatModel)
                .defaultToolCallbacks(mcpToolProvider.getToolCallbacks())
                .build();
    }

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

AI Agent全栈开发MCP指南

完结撒花!

AI Agent全栈开发MCP指南

从Tool Calling到MCP,本质上是把“临时拼凑的传话筒”升级成“标准化的服务总线”。MCP的出现让AI应用和工具之间的耦合度大大降低,未来你只需要关心业务逻辑,剩下的通信细节交给协议去处理。希望这篇文章能帮你理清MCP的来龙去脉,下次写代码时,不妨试试自己搭一个自定义MCP Server玩玩。