人工智能(八)- Spring AI 开发MCP Server(Streamable HTTP)完整开发与测试

0 阅读6分钟

人工智能(七)- RAG 搭建企业知识库问答机器人

一、MCP 介绍

MCP(Model Context Protocol,即模型上下文协议)是由 Anthropic(Claude 的母公司)于 2024年11月 开源发布。MCP 可帮助大模型使用外部工具与数据,相比 Function Calling,MCP 更灵活且易于使用。

MCP 是一种开放协议,它标准化了应用程序如何向大模型提供上下文的方式。它本身并不提供什么服务,只是定义好了一套规范,让服务提供者和服务使用者去遵守。

MCP 就是对以前的 Function Calling 进行标准化,早期大模型支持 FunctionCall 都是自家按照自己的路线走,导致不能用,自己家有自己家的标准,导致对接多家 Function Calling 模型麻烦,Claude 发布了 MCP 协议,类似于 jdbc 标准,大家都按照统一的协议进行传输,大家一起开发 MCP 服务供大家使用。

MCP采用JSON-RPC 2.0作为消息格式,支持主要的传输方式:

  • 标准输入输出(stdio):STDIO方式是基于进程间通信,MCP Client和MCP Server运行在同一主机,适用本地 MCP 客户端/IDE 接入、命令行工具以及简单的进程间通信场景。依赖:spring-ai-starter-mcp-server
  • SSE 流式传输:SSE方式是基于HTTP协议,MCP Client远程调用MCP Server提供的SSE服务。实现客户端和服务端远程通信。依赖:spring-ai-starter-mcp-server-webflux
  • Streamable HTTP 传输:。依赖:spring-ai-starter-mcp-server-webmvc
stdio、SSE、Streamable HTTP 的区别

stdio

  • 本地进程通信
  • 适合 IDE 直接拉起本地 MCP Server
  • 最常见于本地工具接入

SSE

  • 早期/过渡型的 HTTP 流式方案
  • 能让服务端持续推送事件
  • 但通信模型相对没那么统一,工程上会稍显别扭

Streamable HTTP

  • 现在更推荐
  • 也是 HTTP 方案,但比 SSE 方式更适合 MCP 的现代实现
  • 很多新版本客户端/服务端都更偏向它
MCP 核心概念

很多同学以为 MCP 协议就只能提供工具给别人调用,但实际上,MCP 协议的本领可大着呢!按照官方的说法,总共有 6 大核心概念:

  • Resources 资源:让服务端向客户端提供各种数据,比如文本、文件、数据库记录、API 响应等,客户端可以决定什么时候使用这些资源。使 AI 能够访问最新信息和外部知识,为模型提供更丰富的上下文。
  • Prompts 提示词:服务端可以定义可复用的提示词模板和工作流,供客户端和用户直接使用。它的作用是标准化常见的 AI 交互模式,比如能作为 UI 元素(如斜杠命令、快捷操作)呈现给用户,从而简化用户与 LLM 的交互过程。
  • Tools 工具:MCP 中最实用的特性,服务端可以提供给客户端可调用的函数,使 AI 模型能够执行计算、查询信息或者和外部系统交互,极大扩展了 AI 的能力范围。
  • Sampling 采样:允许服务端通过客户端向大模型发送生成内容的请求(反向请求)。使 MCP 服务能够实现复杂的智能代理行为,同时保持用户对整个过程的控制和数据隐私保护。
  • Roots 根目录:MCP 协议的安全机制,定义了服务器可以访问的文件系统位置,限制访问范围,为 - MCP 服务提供安全边界,防止恶意文件访问。
  • Transports 传输:定义客户端和服务器间的通信方式,包括 Stdio(本地进程间通信)和 SSE(网络实时通信),确保不同环境下的可靠信息交换。
MCP 服务市场

目前已经有很多 MCP 服务市场,开发者可以在这些平台上找到各种现成的 MCP 服务:

  • MCP.so:较为主流,提供丰富的 MCP 服务目录
  • GitHub Awesome MCP Servers:开源 MCP 服务集合
  • 阿里云百炼 MCP 服务市场
  • Spring AI Alibaba 的 MCP 服务市场
  • Glama.ai MCP 服务

二、工程搭建:基于 Spring Boot 的后端开发

2.1 创建Maven工程

使用IntelliJ IDEA创建一个Maven工程,完成工程初始化。

2.2 引入核心 pom 依赖
<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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.13</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>org.devpotato</groupId>
    <artifactId>java-mcp-server-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>java-mcp-server-demo</name>
    <description>Minimal Java MCP Server demo based on Spring AI</description>

    <packaging>jar</packaging>

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

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <spring-ai.version>1.1.4</spring-ai.version>
    </properties>

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

    <dependencies>
        <!--        spring-boot        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- MCP Server(STDIO 模式) -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server</artifactId>
        </dependency>

        <!-- MCP Server(Streamable HTTP 模式) -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <release>${java.version}</release>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.2.5</version>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
2.3 工程配置文件

在src/main/resources目录下创建application.yml文件

spring:
  application:
    name: java-mcp-server-demo
  profiles:
    active: http
  ai:
    mcp:
      server:
        name: java-mcp-server-demo  # 服务名
        version: 0.0.1  # 版本号
        type: SYNC
        instructions: |
          This server provides demo tools for Java MCP development.
          Use getCityTime for timezone lookup, sumNumbers for calculation,
          and projectSummary for quick project scaffolding summaries.

application-http.yml文件

spring:
  config:
    activate:
      on-profile: http
  main:
    web-application-type: servlet # 启用Web
  ai:
    mcp:
      server:
        protocol: STREAMABLE
        streamable-http:
          mcp-endpoint: /mcp
server:
  port: 8080

application-stdio.yml文件

spring:
  config:
    activate:
      on-profile: stdio
  main:
    web-application-type: none  # STDIO必须禁用web应用类型
    banner-mode: off           # STDIO禁用banner
  ai:
    mcp:
      server:
        stdio: true # 启用stdio模式
2.4 MCP工具类
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;

/**
 * 天气服务
 * MCP 核心是暴露工具(Tool),供 AI 客户端调用
 * @Tool:标记方法为 MCP 工具,description描述工具功能(AI 理解用)
 * @ToolParam:标记参数,description描述参数含义
 * 方法返回值:支持String、Map、List、自定义对象等
 * 支持同步 / 异步:异步返回Mono/Flux(Reactor)
 */
@Service
public class WeatherService {

    /**
     * 根据城市查询天气(MCP工具)
     *
     * @param city 城市名
     * @return 天气信息
     */
    @Tool(name = "getWeather", description = "根据城市名称获取天气信息")
    public String getWeather(@ToolParam(description = "城市名称", required = true) String city) {
        // 业务逻辑:调用天气 API
        return "城市: " + city + ", 温度: 25°C, 天气: 晴";
    }

    /**
     * 根据经纬度查询天气(MCP工具)
     *
     * @param latitude  纬度
     * @param longitude 经度
     * @return 天气信息
     */
    @Tool(name = "getWeatherByLocation", description = "根据经纬度获取天气预报")
    public String getWeatherByLocation(
            @ToolParam(description = "纬度") double latitude,
            @ToolParam(description = "经度") double longitude) {
        return "纬度: " + latitude + ", 经度: " + longitude + ", 温度: 22°C";
    }
}
2.5 工具配置类
package org.devpotato.config;

import org.devpotato.mcp.WeatherService;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 将 WeatherService 中的 @Tool 方法注册为 MCP 工具
 */
@Configuration
public class ToolRegistrationConfiguration {

    @Autowired
    private WeatherService weatherService;

    @Bean
    public ToolCallbackProvider toolCallbackProvider() {
        return MethodToolCallbackProvider.builder()
                .toolObjects(new Object[]{weatherService})
                .build();
    }
}
2.6 启动类开发
package org.devpotato;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration;

@SpringBootApplication(exclude = {
        ContextFunctionCatalogAutoConfiguration.class
})
public class StartServer {

    public static void main(String[] args) {
        SpringApplication.run(StartServer.class, args);

        System.out.println(">>> start");
    }
}

三、运行测试

3.1 使用 Postman 测试

创建一个 MCP 请求 创建一个 MCP 请求

点击右侧 Connect 按钮,查看 MCP 工具列表 点击右侧 Connect 按钮,查看 MCP 工具列表

发起 MCP 请求 发起 MCP 请求

3.2 使用 Cursor 接入本地 MCP Server

Cursor 是一款 AI 编辑器和编码智能体。用它来理解你的代码库、规划和构建功能、修复错误、审查更改,以及配合你已在使用的工具工作。

打开 Cursor -> Settings -> Tools & MCPs -> New MCP Server New MCP Server

填入相关信息 mcp.json

在聊天中使用 MCP 智能体会在相关时自动使用 Available Tools 下列出的 MCP 工具。你可以直接说出特定工具的名称,或描述你的需求。也可以在设置中启用或禁用工具。 企业微信20260410-143748@2x.png

工具批准 默认情况下,智能体在使用 MCP 工具前会请求批准。点击工具名称旁的箭头可查看参数。

自动运行 启用自动运行后,智能体无需询问即可使用 MCP 工具。其工作方式与终端命令类似。有关自动运行设置的更多信息,请参阅此处

如需预先配置哪些 MCP 工具可在不通过设置 UI 的情况下自动运行,请将它们添加到

~/.cursor/permissions.json