SpringAI + MCP 案例实现


MCP 的全称是 Model Context Protocol。它是由 Anthropic 公司推出的一项开放协议,旨在解决大语言模型应用中的一个核心问题:如何让 AI 模型安全、标准化地连接和使用外部工具、数据源和 API。
下面,我们基于SpringAI 去实现一个MCP使用案例。
MCP分为服务端和客户端。服务端提供agent能力,客户端调用服务接口能力在结合模型提供对外服务。


1. 前置条件

  • deepseek 等线上模型或本地安装模型
  • Springboot 3.5.9 +
  • jdk 17 +

我以本地模型示【基于vllm搭建的qwen8b】,jdk21, Springboot 3.5.9,SpringAI 1.1.2版本演示代码。并且基于SSE传输设置MCP协议访问

2. 服务端代码

pom.xml 核心依赖。客户端与服务端依赖类似,唯一区别在于mcp-server和mcp-client

        <!-- mcp 服务端 webflux SSE 传输-->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
        </dependency>
        ......
      <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>
配置代码如下
    /**
     * mcp 工具,将该方法暴露给客户端
     *
     * @param toolService toolService
     * @return ToolCallbackProvider
     */
    @Bean
    public ToolCallbackProvider toolCallbackProvider(ToolService toolService) {
        return MethodToolCallbackProvider.builder()
                .toolObjects(toolService)
                .build();
    }

该处代码用于将工具服务暴露出去,供客户端调用

    @Bean
    public ChatClient chatClient(ChatModel chatModel, ChatMemory chatMemory, ToolService toolService) {
        return ChatClient.builder(chatModel)
                .defaultSystem("你作为一名专业的AI助手,请根据用户提示信息回答问题。再根据用户信息,自定判断是否需要调用工具")
                .defaultAdvisors(MessageChatMemoryAdvisor
                        .builder(chatMemory).build())
                // 自定义工具类型
                .defaultTools(toolService)
                .build();
    }
    /**
     * 聊天配置基于jdbc 存储于 MySQL 数据库中
     */
    @Bean
    public ChatMemory chatMemory(JdbcChatMemoryRepository repository) {
        return MessageWindowChatMemory.builder()
                .chatMemoryRepository(repository)
                .maxMessages(200)
                .build();
    }

上述代码一方面配置自定义工具的使用,另一方面设置可以将聊天存进历史中。我这里是将历史信息存于MySQL数据库中。默认是存于内存中

@Slf4j
@Component
public class ToolService {

    RestTemplate restTemplate = new RestTemplate();

    @Tool(name = "getLocalOilPrice", description = "根据省份获取当地油价信息")
    public String getLocalOilPrice(@ToolParam(description = "要查询的油价的省份名称") String province) {
        log.info("调用获取当地油价工具,省份:{}", province);
        String format = String.format("https://shanhe.kim/api/youjia/youjia.php?province=%s", province);
        return restTemplate.getForObject(format, String.class);
    }
}

这里定义自己的服务能力,根据自己实际业务来即可

application.yml如下
spring:
  application:
    name: sjjai
  ai:
    chat:
      memory:
        repository:
          jdbc:
            initialize-schema: always
            # mysql mariadb
            plateform: mysql
    openai:
      # https://api.deepseek.com
      base-url: http://192.168.10.102:6006/
      api-key: sk-aaacczxc
      chat:
        options:
          model: qwen3-8b

  datasource:
    url: jdbc:mysql://192.168.47.130:3306/sjj-ai?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      connection-init-sql: SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;

logging:
  file:
    name: D:/code/sjjai/sjjai.log
server:
  port: 8082

上述为服务端代码案例

客户端代码

pom依赖项

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
        </dependency>

        <!-- 引入MCP客户端 webflux SSE -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
        </dependency>

config配置项

    /**
     * 用户发现服务端mcp 服务(自动集成暴露的工具到client中)
     *
     * @return SyncMcpToolCallback
     */
    @Bean
    public SyncMcpToolCallbackProvider toolCallback(List<McpSyncClient> mcpClients) {
        return new SyncMcpToolCallbackProvider(mcpClients);
    }

    @Bean
    public ChatClient chatClient(ChatModel chatModel, SyncMcpToolCallbackProvider toolCallback) {
        return ChatClient.builder(chatModel)
                .defaultSystem("你是一个专业的助手")
                .defaultToolCallbacks(toolCallback)
                .build();
    }

客户端测试代码

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

    final ChatClient chatClient;

    @GetMapping(value = "question/{question}")
    public Flux<String> chat(@PathVariable String question, HttpServletResponse response) {
        response.setCharacterEncoding("utf-8");
        return chatClient.prompt("请回答用户问题")
                .system("你作为一名专业的AI助手,请根据用户提示信息回答问题。")
                .user(question)
                .stream()
                .content();
    }
}

客户端application.yml

spring:
  ai:
    openai:
      # https://api.deepseek.com
      base-url: http://192.168.10.102:6006
      api-key: sk-6f14d95e96bf46c6aa67983e5b9138bf
      chat:
        options:
          model: qwen3-8b
    mcp:
      client:
        sse:
          connections:
            server1:
              url: http://127.0.0.1:8082
  application:
    name: shujunjun-ai-test-client
server:
  port: 8083

请注意,在服务端因为已经依赖了webflux + Netty 因此不能再使用tomcat,否则客户端在尝试使用sse连接服务端时,会报错404
启动项目后,访问 http://127.0.0.1:8083/chat/question/江苏油价

调用效果

客户端代码:https://gitee.com/JustNickNameWSH/springai-mcp-client
服务端代码:https://gitee.com/JustNickNameWSH/sjjai-server

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容