【MCP】使用SpringBoot基于Streamable-HTTP构建MCP-Client

【MCP】使用SpringBoot基于Streamable-HTTP构建MCP-Client

MCP实现原理

先来看看大语言模型工具调用的时序图

MCP(模型上下文协议,Model Context Protocol),通常更广义地理解为基于上下文的工具使用(Context-based Tool Usage) 或 提示工程中的工具使用(Tool Use via Prompt Engineering)。它的核心原理是将工具的描述、使用说明和示例直接作为上下文(Prompt)的一部分,输入给大模型。模型不"调用"工具,而是根据其通用语言能力,"理解"并"生成"使用工具所需的指令或参数。

Function Calling不同,MCP模式下,大模型本身并不直接生成可执行的函数调用对象。它更像是一个"聪明的指令遵循者":你告诉它有哪些工具,每个工具能做什么,以及如何使用它们。当用户提出需求时,模型会根据这些上下文信息,生成一个符合预设格式的文本输出,这个输出指示了外部系统应该如何操作。

MCPclient端和server端通讯的协议也在逐步演进,一开始主流的是SSE协议,随后又诞生了Streamable-HTTP协议,用于取代SSE协议。

本文将介绍如何使用SpringBoot基于Streamable-HTTP构建MCP-Client客户端。

想了解如何构建MCP-Server,可以查看这篇文章:
【MCP】使用SpringBoot基于Streamable-HTTP构建MCP-Server.md

本文开发环境介绍

开发依赖 版本
Spring Boot 4.0.1
spring-ai-bom 2.0.0-M1
spring-ai-starter-mcp-server-webflux 2.0.0-M1

pom核心依赖

xml 复制代码
<dependencyManagement>
  <dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-bom</artifactId>
    <version>${spring-ai.version}</version>
    <type>pom</type>
    <scope>import</scope>
  </dependency>
</dependencyManagement>

<!--<dependency>-->
<!--  <groupId>org.springframework.ai</groupId>-->
<!--  <artifactId>spring-ai-starter-mcp-client</artifactId>-->
<!--</dependency>-->
<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-starter-model-anthropic</artifactId>
</dependency>

spring-ai-starter-mcp-client-webfluxspring-ai-starter-mcp-client都可以,一种是响应式架构,一种是非响应式架构,两者只能二选一。

创建启动类

创建Spring Boot应用的启动类

java 复制代码
package com.wen3.demo.ai.mcp.client;


import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tools.jackson.databind.ObjectMapper;

/**
 * @author tangheng
 */
@Slf4j
@SpringBootApplication
public class McpClientApplication{

    @Resource
    private ToolCallbackProvider tools;
    @Resource
    ObjectMapper objectMapper;

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

配置文件

yaml 复制代码
server:
  port: 9091

spring.ai:
  #  openai:
  #    base-url: https://api.scnet.cn/api/llm
  #    api-key: xxx
  #    chat:
  #      options:
  #        model: DeepSeek-R1-Distill-Qwen-7B
  #        #model: DeepSeek-R1-Distill-Qwen-32B
  #        #model: QwQ-32B
  #        temperature: 0.7
  anthropic:
    api-key: xxx

  mcp:
    client:
      enabled: true
      name: demo-mcp-client
      version: 1.0.0
      request-timeout: 30s
      type: ASYNC
      streamable-http:
        connections:
          server1:
            url: http://localhost:9090
          server2:
            url: http://localhost:9090
            endpoint: /mcp
      toolcallback:
        enabled: true

相关配置类

  • org.springframework.ai.mcp.client.common.autoconfigure.properties.McpClientCommonProperties 前缀为spring.ai.mcp.client的配置项
  • org.springframework.ai.mcp.client.common.autoconfigure.annotations.McpClientAnnotationScannerProperties 前缀为spring.ai.mcp.client.annotation-scanner的配置项,默认为扫描@McpTool注解进行工具的注册
  • org.springframework.ai.mcp.client.common.autoconfigure.properties.McpStreamableHttpClientProperties 前缀为spring.ai.mcp.client.streamable-http的配置项,请求端点默认是/mcp

Junit单元测试

  • 先单独调用MCP-Server进行测试
java 复制代码
package com.wen3.demo.ai.mcp.client.tools;


import com.wen3.demo.ai.mcp.client.McpClientSpringbootTestBase;
import io.modelcontextprotocol.client.McpAsyncClient;
import io.modelcontextprotocol.spec.McpSchema.CallToolRequest;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
import io.modelcontextprotocol.spec.McpSchema.ListToolsResult;
import io.modelcontextprotocol.spec.McpSchema.Tool;
import jakarta.annotation.Resource;
import lombok.AccessLevel;
import lombok.SneakyThrows;
import lombok.experimental.FieldDefaults;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.Map;

/**
 * @author tangheng
 */
@FieldDefaults(level = AccessLevel.PROTECTED)
public class DemoToolTest extends McpClientSpringbootTestBase {

    @Resource
    List<McpAsyncClient> mcpAsyncClients;

    @SneakyThrows
    @Test
    void mcpClient() {
        log.info("mcpAsyncClients: {}", mcpAsyncClients);
        McpAsyncClient client = mcpAsyncClients.getFirst();

        client.initialize();

        client.ping();

        // List and demonstrate tools
        ListToolsResult toolsList = client.listTools().block();
        System.out.println("Available Tools = " + toolsList);

        for (Tool tool : toolsList.tools()) {
            log.info("{}", objectMapper.writeValueAsString(tool));
        }

        CallToolResult callToolResult = client.callTool(new CallToolRequest("hello", Map.of("city", "北京"))).block();
        log.info("工具调用结果: {}", objectMapper.writeValueAsString(callToolResult.content()));

        CallToolResult callToolResult2 = client.callTool(new CallToolRequest("helloWithName", Map.of("name", "小花"))).block();
        log.info("工具调用结果: {}", objectMapper.writeValueAsString(callToolResult2.content()));

        client.closeGracefully();
    }
}
  • 单元测试控制台输出截图
  • 结合大语言模型进行工具调用测试
java 复制代码
package com.wen3.demo.ai.mcp.client.tools;


import com.wen3.demo.ai.mcp.client.McpClientSpringbootTestBase;
import io.modelcontextprotocol.client.McpAsyncClient;
import io.modelcontextprotocol.spec.McpSchema.CallToolRequest;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
import io.modelcontextprotocol.spec.McpSchema.ListToolsResult;
import io.modelcontextprotocol.spec.McpSchema.Tool;
import jakarta.annotation.Resource;
import lombok.AccessLevel;
import lombok.SneakyThrows;
import lombok.experimental.FieldDefaults;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.context.ConfigurableApplicationContext;

import java.util.List;
import java.util.Map;

/**
 * @author tangheng
 */
@FieldDefaults(level = AccessLevel.PROTECTED)
public class DemoToolTest extends McpClientSpringbootTestBase {

    @Resource
    List<McpAsyncClient> mcpAsyncClients;
    @Resource
    ChatClient.Builder chatClientBuilder;
    @Resource
    ToolCallbackProvider tools;
    @Resource
    ConfigurableApplicationContext context;

    @SneakyThrows
    @Test
    void mcpClient() {
        log.info("mcpAsyncClients: {}", mcpAsyncClients);
        McpAsyncClient client = mcpAsyncClients.getFirst();

        client.initialize();

        client.ping();

        // List and demonstrate tools
        ListToolsResult toolsList = client.listTools().block();
        System.out.println("Available Tools = " + toolsList);

        for (Tool tool : toolsList.tools()) {
            log.info("{}", objectMapper.writeValueAsString(tool));
        }

        CallToolResult callToolResult = client.callTool(new CallToolRequest("hello", Map.of("city", "北京"))).block();
        log.info("工具调用结果: {}", objectMapper.writeValueAsString(callToolResult.content()));

        CallToolResult callToolResult2 = client.callTool(new CallToolRequest("helloWithName", Map.of("name", "小花"))).block();
        log.info("工具调用结果: {}", objectMapper.writeValueAsString(callToolResult2.content()));

        client.closeGracefully();
    }

    @Test
    void chat() {
        var chatClient = chatClientBuilder
                .defaultToolCallbacks(tools)
                .build();

        String userInput = "What tools are available?";

        System.out.println("\n>>> QUESTION: " + userInput);
        System.out.println("\n>>> ASSISTANT: " + chatClient.prompt(userInput).call().content());

        context.close();
    }
}
相关推荐
RANCE_atttackkk几秒前
Springboot+langchain4j的RAG检索增强生成
java·开发语言·spring boot·后端·spring·ai·ai编程
CoderJia程序员甲28 分钟前
GitHub 热榜项目 - 日榜(2026-01-31)
ai·开源·大模型·github·ai教程
孟秋与你1 小时前
【openclaw】centos9安装oepnclaw教程 解决安装期间的报错
ai
好好研究2 小时前
Spring Boot - Thymeleaf模板引擎
java·spring boot·后端·thymeleaf
她说..2 小时前
策略模式+工厂模式实现单接口适配多审核节点
java·spring boot·后端·spring·简单工厂模式·策略模式
m0_603888712 小时前
FineInstructions Scaling Synthetic Instructions to Pre-Training Scale
人工智能·深度学习·机器学习·ai·论文速览
像少年啦飞驰点、2 小时前
零基础入门 Spring Boot:从“Hello World”到可部署微服务的完整学习路径
java·spring boot·微服务·编程入门·后端开发
爬台阶的蚂蚁2 小时前
RAG概念和使用
ai·rag
undsky_2 小时前
【RuoYi-SpringBoot3-Pro】:将 AI 编程融入传统 java 开发
java·人工智能·spring boot·ai·ai编程
AI应用开发实战派3 小时前
AI人工智能中Bard的智能电子商务优化
人工智能·ai·bard