Spring AI (5) : MCP 深度实战:从工具抽取到鉴权,SSE 与 STDIO

目录:

  • [一、为什么需要 MCP?](#一、为什么需要 MCP?)
  • [二、MCP 的两种通信方式](#二、MCP 的两种通信方式)
  • [三、STDIO 方式详解](#三、STDIO 方式详解)
    • [1. MCP Server(服务端)](#1. MCP Server(服务端))
      • [① 使用现成的公共 MCP Server](#① 使用现成的公共 MCP Server)
      • [② 自定义 STDIO MCP Server](#② 自定义 STDIO MCP Server)
    • [2. MCP Client(客户端)调用 STDIO](#2. MCP Client(客户端)调用 STDIO)

一、为什么需要 MCP?

在 AI 应用爆发式增长的今天,我们常常面临两个痛点:

  1. 服务商想开放工具:比如高德地图提供位置查询、百度提供联网搜索,但每个服务商都有自己的 API 格式,调用方式千差万别。
  2. 企业内部多应用共享工具:多个智能应用都想使用同一套内部工具(如订单查询、用户画像),如果每个应用各自接入,重复造轮子且维护成本极高。

解决方案很简单:把 Tools 单独抽取出来,由应用程序统一读取外部 Tools。

但问题随之而来------怎么读?怎么解析?

如果每个提供商各用一套规则,想象一下对接几十个不同 API 的混乱场面......

于是 MCP(Model Context Protocol) 应运而生。

MCP 指定了 标准通信规则,以 JSON‑RPC 2.0 格式进行交互,彻底统一了 Tools 的暴露与调用方式。

二、MCP 的两种通信方式

MCP 官方提供了两种主流传输方式:

三、STDIO 方式详解

1. MCP Server(服务端)

① 使用现成的公共 MCP Server

网上已有大量现成的 MCP 服务,例如:

  • MCP Server 聚合站 提供了百度地图、文件系统、天气查询等众多 MCP Server。

② 自定义 STDIO MCP Server

下面我们用 Spring AI 创建一个自定义的 STDIO MCP Server。

第一步:添加依赖(pom.xml)

yaml 复制代码
<!-- MCP Server 依赖 -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server</artifactId>
</dependency>

<!-- Spring AI BOM 管理 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>${spring-ai.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- 打包插件(用于生成可执行 jar) -->
<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>

第二步:编写 Tool 服务

java 复制代码
@Service
public class UserToolService {

    Map<String, Double> userScore = Map.of(
        "xushu", 99.0,
        "zhangsan", 2.0,
        "lisi", 3.0
    );

    @Tool(description = "获取用户分数")
    public String getScore(String username) {
        if (userScore.containsKey(username)) {
            return userScore.get(username).toString();
        }
        return "未检索到当前用户 " + username;
    }
}

第三步:暴露 Tool

java 复制代码
@Bean
public ToolCallbackProvider weatherTools(UserToolService userToolService) {
    return MethodToolCallbackProvider.builder()
            .toolObjects(userToolService)
            .build();
}

第四步:配置文件(application.yml)

yaml 复制代码
spring:
  main:
    banner-mode: off   # 必须关闭横幅,否则影响 STDIO 通信
  ai:
    mcp:
      server:
        name: my-weather-server
        version: 0.0.1

⚠️ 注意:必须禁用横幅和控制台日志,否则会污染标准输入输出流,导致 MCP 通信失败。

第五步:打包

执行 mvn package,在 target/ 下生成可执行 jar 包。

2. MCP Client(客户端)调用 STDIO

第一步:依赖

yaml 复制代码
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
</dependency>

第二步:配置 application.yml

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        request-timeout: 60000
        stdio:
          servers-configuration: classpath:/mcp-servers-config.json
          connections:
            server1:
              command: /path/to/server
              args:
                - --port=8080
                - --mode=production
              env:
                API_KEY: your-api-key
                DEBUG: "true"

第三步:mcp-servers-config.json(放在 resources 下)

yaml 复制代码
{
    "mcpServers": {
        "baidu-map": {
            "command": "cmd",
            "args": ["/c", "npx", "-y", "@baidumap/mcp-server-baidu-map"],
            "env": {
                "BAIDU_MAP_API_KEY": "你的百度地图Key"
            }
        },
        "mcp-server-weather": {
            "command": "java",
            "args": [
                "-Dspring.ai.mcp.server.stdio=true",
                "-Dlogging.pattern.console=",
                "-jar",
                "D:\\xxx\\target\\mcp-stdio-server.jar"
            ]
        }
    }
}

第四步:绑定到 ChatClient

java 复制代码
@RestController
public class OpenAiController {

    private final ChatClient chatClient;

    public OpenAiController(DashScopeChatModel dashScopeChatModel,
                            ToolCallbackProvider mcpTools) {
        this.chatClient = ChatClient.builder(dashScopeChatModel)
                .defaultToolCallbacks(mcpTools)
                .build();
    }

    @GetMapping(value = "/ai/generateStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> generateStream(@RequestParam String message) {
        return chatClient.prompt()
                .user(message)
                .stream()
                .content();
    }
}

待完善。。。。。。

相关推荐
richard_yuu3 小时前
OpenCV 实战第 8 篇:几何测量算子族,从 boundingRect 到亚像素定位
人工智能·opencv·计算机视觉
2601_956743683 小时前
上海GEO营销公司技术评估方法|以盾码无界公开产品路线为例,拆解企业知识库语义检索、资料版本核验、内容人工审核与大模型监测复测的验证要点及适用边界
人工智能·geo·上海·企业服务
中伟视界3 小时前
AI视频监控矿山落地实践:从算法部署到误报调优全流程
人工智能
打工仔折腾 AI3 小时前
FaceFusion本地换脸实战:Windows整合包、模型选择与遮罩调参记录
人工智能·windows·后端·python·深度学习·性能优化·ai agent 实战
DeviceHub3 小时前
AI服务器电源设计进阶:TLVR电感的应用解析与选型验证指南
运维·服务器·人工智能
阿明副业观察3 小时前
AI视频生成工具功能与作用全面解析:赋能高效内容创作
大数据·人工智能·aigc·音视频·ai写作
且随疾风前行.3 小时前
UI核心 - 绘制流程(测量、布局、绘制)
ui·dubbo
Nebula_g4 小时前
JavaSE拓展:工具类Executors
java·开发语言·后端·spring·基础·javase
数智工坊4 小时前
视觉SLAM第5讲|相机成像模型:针孔投影、畸变修正与深度感知全拆解
人工智能·深度学习·数码相机·机器人