searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

【MCP-05】Java MCP StreamableHTTP方式调用Demo

2025-08-19 10:32:01
2
0

前言

上文[【MCP-04】Golang MCP StreamableHTTP方式调用Demo]和[【MCP-03】一次完整的MCP和LLM交互流程]已经使用PythonSDK和MCP-go实现了LLM使用MCP StreamableHTTP的交互,由于MCP-Java SDK版本对StreamableHTTP协议支持较慢,SpringAI到当前为止还只整合了StreamableHTTP mcp-client部分,这里参考官方Demo,使用MCP-Java SDK原生代码的方式编写一个Java版本的MCP StreamableHTTP和LLM交互Demo。

Demo

同Golang版本只实现走FunctionCall的方式,走系统提示词(system prompt)参考[Python版本]。java的MCPServer参考的[examples]。MCPClient参考[examples]。

JShMcpServer

# 依赖
<properties>
    <java.version>17</java.version>
    <spring-ai.version>1.1.0-SNAPSHOT</spring-ai.version><!--1.0.0-M6-->
    <guava.version>31.1-jre</guava.version>
    <mcp.version>0.11.2</mcp.version>
</properties>
 
<dependencies>
    # java mcp-sdk并不提供服务容器,因此要单独引入一个webflux
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
     
    # 由于这里还是要用到@Tool注解等SpringAI的方法,这里还是要引入spring-ai-mcp
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-mcp</artifactId>
        <exclusions>
            <exclusion>
                <groupId>io.modelcontextprotocol.sdk</groupId>
                <artifactId>mcp-spring-webflux</artifactId>
            </exclusion>
            <exclusion>
                <groupId>io.modelcontextprotocol.sdk</groupId>
                <artifactId>mcp</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
 
    <dependency>
        <groupId>io.modelcontextprotocol.sdk</groupId>
        <artifactId>mcp-spring-webflux</artifactId>
        <version>${mcp.version}</version>
        <scope>compile</scope>
    </dependency>
</dependencies>
 
<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>
 
# 配置文件
spring.application.name=mcpv2
 
server.port=8210
 
# spring.main.web-application-type=none
 
# NOTE: You must disable the banner and the console logging
# to allow the STDIO transport to work !!!
#spring.main.banner-mode=off
#logging.pattern.console=
 
# transport.mode=stdio
#transport.mode=sse
#transport.mode=stateless
# 这里开启streamable http
transport.mode=streamable
 
logging.file.name=mcp.tooldemo.log
logging.level.root=info
 
# 配置类
/**
 * @Author: wanghaoguang
 * @CreateTime: 2025/8/14 10:01
 */
@Configuration
public class McpServerStreamableConfig {
 
    /**********************streamable************************/
    @Bean
    @ConditionalOnProperty(prefix = "transport", name = "mode", havingValue = "streamable")
    public WebFluxStreamableServerTransportProvider webFluxStreamableProvider() {
        return WebFluxStreamableServerTransportProvider.builder()
                .messageEndpoint("/mcp")
                .objectMapper(new ObjectMapper())
                .build();
    }
 
    @Bean
    @ConditionalOnProperty(prefix = "transport", name = "mode", havingValue = "streamable")
    public RouterFunction<?> webfluxMcpStreamableRouterFunction(
            WebFluxStreamableServerTransportProvider webFluxStreamableProvider) {
        return webFluxStreamableProvider.getRouterFunction();
    }
     
    @Bean
    public CalculateService calculateService() {
        return new CalculateService();
    }
 
    @Bean
    public McpSyncServer mcpServer(WebFluxStreamableServerTransportProvider webFluxStreamableProvider, CalculateService calculateService) {
        var capabilities = McpSchema.ServerCapabilities.builder()
                .tools(true)
                .logging()
                .build();
        McpSyncServer server = McpServer.sync(webFluxStreamableProvider)
                .serverInfo("MCP Demo Calculate Server", "1.0.0")
                .capabilities(capabilities)
                .tools(McpToolUtils.toSyncToolSpecifications(ToolCallbacks.from(calculateService)))
                .build();
        return server;
    }
}
 
# tool工具类
public class CalculateService {
 
    @Tool(description = "对两个数字进行加法")
    public float add(float number1, float number2) {
        System.out.println("Add number1 = " + number1 + " number2 = " + number2);
        return number1 + number2;
    }
 
    @Tool(description = "对两个数字进行减法")
    public float subtract(float number1, float number2) {
        System.out.println("Subtract number1 = " + number1 + " number2 = " + number2);
        return number1 - number2;
    }
 
 
    @Tool(description = "对两个数字进行乘法")
    public float multiply(float number1, float number2) {
        System.out.println("Multiply number1 = " + number1 + " number2 = " + number2);
        return number1 * number2;
    }
 
    @Tool(description = "对两个数字进行除法")
    public float divide(float number1, float number2) {
        System.out.println("Divide number1 = " + number1 + " number2 = " + number2);
        return number1 / number2;
    }
 
}

JShMCPClient

# 依赖
<properties>
    <java.version>17</java.version>
    <spring-ai.version>1.1.0-SNAPSHOT</spring-ai.version><!--1.0.0-M6-->
    <guava.version>31.1-jre</guava.version>
    <mcp.version>0.11.2</mcp.version>
</properties>
 
<dependencies>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
  </dependency>
 
  <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
  </dependency>
 
  <dependency>
      <groupId>io.modelcontextprotocol.sdk</groupId>
      <artifactId>mcp</artifactId>
      <version>${mcp.version}</version>
  </dependency>
 
  <dependency>
      <groupId>io.modelcontextprotocol.sdk</groupId>
      <artifactId>mcp-spring-webflux</artifactId>
      <version>${mcp.version}</version>
  </dependency>
 
  <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-model-openai</artifactId>
  </dependency>
</dependencies>
 
<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>
</dependencyManagement>
 
# 配置文件
spring.application.name=mcpv2client
server.port=8211
 
spring.main.web-application-type=reactive
 
spring.ai.openai.base-url=api.deepseek.com
spring.ai.openai.api-key=xxxxxxx
spring.ai.openai.chat.options.model=deepseek-chat
 
spring.ai.mcp.client.toolcallback.enabled=true
spring.ai.mcp.client.streamable-http.connections.server1.url=127.0.0.1:8210
 
# Controller
/**
 * @Author: wanghaoguang
 * @CreateTime: 2025/8/14 17:28
 */
@RestController
@RequestMapping("/test")
public class ChatController {
    private final ChatClient chatClient;
    public ChatController(ChatClient.Builder chatClientBuilder, ToolCallbackProvider tools) {
        this.chatClient = chatClientBuilder.defaultToolCallbacks(tools)
                .build();
    }
 
    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> chatWithStream(@RequestParam String message) {
        System.out.println("\n>>> QUESTION: " + message);
        Flux<String> rt = chatClient.prompt()
                .user(message)
                .stream()
                .content();
        System.out.println("\n>>> ASSISTANT: " + rt);
        return rt;
    }
}

企业微信截图_722ea486-b979-4ece-8532-94186841b3b1.png

企业微信截图_d3943d86-349a-42c1-a6aa-ff7f5b6583f8.png

企业微信截图_858fc551-6c69-46e1-acc6-deb063a05881.png

总结

0,同PythonSDK,所有语言的MCP-SDK均参考官方规划文档编写,从源码来看,大体思路和使用方式都差不多。
1,Java MCP-SDK相对PythonSDK和MCP-go更新迭代慢,相对于SpringAI MCP技术试用的SpringAI的方法,最好使用官方原生MCP-SDK+自定义运行容器的方式,这样也比较灵活,官方Java MCP-SDK代码更新也较快。
2,同样Java MCP-SDK有提供Last-Event-ID机制和stateless,不过stateless方式暂时测试还有一些问题。
3,为了保证使用到最新的版本和支持最新的协议,以及生态支持上,推荐还是使用PythonSDK。

0条评论
0 / 1000
wanghg11
21文章数
3粉丝数
wanghg11
21 文章 | 3 粉丝
原创

【MCP-05】Java MCP StreamableHTTP方式调用Demo

2025-08-19 10:32:01
2
0

前言

上文[【MCP-04】Golang MCP StreamableHTTP方式调用Demo]和[【MCP-03】一次完整的MCP和LLM交互流程]已经使用PythonSDK和MCP-go实现了LLM使用MCP StreamableHTTP的交互,由于MCP-Java SDK版本对StreamableHTTP协议支持较慢,SpringAI到当前为止还只整合了StreamableHTTP mcp-client部分,这里参考官方Demo,使用MCP-Java SDK原生代码的方式编写一个Java版本的MCP StreamableHTTP和LLM交互Demo。

Demo

同Golang版本只实现走FunctionCall的方式,走系统提示词(system prompt)参考[Python版本]。java的MCPServer参考的[examples]。MCPClient参考[examples]。

JShMcpServer

# 依赖
<properties>
    <java.version>17</java.version>
    <spring-ai.version>1.1.0-SNAPSHOT</spring-ai.version><!--1.0.0-M6-->
    <guava.version>31.1-jre</guava.version>
    <mcp.version>0.11.2</mcp.version>
</properties>
 
<dependencies>
    # java mcp-sdk并不提供服务容器,因此要单独引入一个webflux
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
     
    # 由于这里还是要用到@Tool注解等SpringAI的方法,这里还是要引入spring-ai-mcp
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-mcp</artifactId>
        <exclusions>
            <exclusion>
                <groupId>io.modelcontextprotocol.sdk</groupId>
                <artifactId>mcp-spring-webflux</artifactId>
            </exclusion>
            <exclusion>
                <groupId>io.modelcontextprotocol.sdk</groupId>
                <artifactId>mcp</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
 
    <dependency>
        <groupId>io.modelcontextprotocol.sdk</groupId>
        <artifactId>mcp-spring-webflux</artifactId>
        <version>${mcp.version}</version>
        <scope>compile</scope>
    </dependency>
</dependencies>
 
<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>
 
# 配置文件
spring.application.name=mcpv2
 
server.port=8210
 
# spring.main.web-application-type=none
 
# NOTE: You must disable the banner and the console logging
# to allow the STDIO transport to work !!!
#spring.main.banner-mode=off
#logging.pattern.console=
 
# transport.mode=stdio
#transport.mode=sse
#transport.mode=stateless
# 这里开启streamable http
transport.mode=streamable
 
logging.file.name=mcp.tooldemo.log
logging.level.root=info
 
# 配置类
/**
 * @Author: wanghaoguang
 * @CreateTime: 2025/8/14 10:01
 */
@Configuration
public class McpServerStreamableConfig {
 
    /**********************streamable************************/
    @Bean
    @ConditionalOnProperty(prefix = "transport", name = "mode", havingValue = "streamable")
    public WebFluxStreamableServerTransportProvider webFluxStreamableProvider() {
        return WebFluxStreamableServerTransportProvider.builder()
                .messageEndpoint("/mcp")
                .objectMapper(new ObjectMapper())
                .build();
    }
 
    @Bean
    @ConditionalOnProperty(prefix = "transport", name = "mode", havingValue = "streamable")
    public RouterFunction<?> webfluxMcpStreamableRouterFunction(
            WebFluxStreamableServerTransportProvider webFluxStreamableProvider) {
        return webFluxStreamableProvider.getRouterFunction();
    }
     
    @Bean
    public CalculateService calculateService() {
        return new CalculateService();
    }
 
    @Bean
    public McpSyncServer mcpServer(WebFluxStreamableServerTransportProvider webFluxStreamableProvider, CalculateService calculateService) {
        var capabilities = McpSchema.ServerCapabilities.builder()
                .tools(true)
                .logging()
                .build();
        McpSyncServer server = McpServer.sync(webFluxStreamableProvider)
                .serverInfo("MCP Demo Calculate Server", "1.0.0")
                .capabilities(capabilities)
                .tools(McpToolUtils.toSyncToolSpecifications(ToolCallbacks.from(calculateService)))
                .build();
        return server;
    }
}
 
# tool工具类
public class CalculateService {
 
    @Tool(description = "对两个数字进行加法")
    public float add(float number1, float number2) {
        System.out.println("Add number1 = " + number1 + " number2 = " + number2);
        return number1 + number2;
    }
 
    @Tool(description = "对两个数字进行减法")
    public float subtract(float number1, float number2) {
        System.out.println("Subtract number1 = " + number1 + " number2 = " + number2);
        return number1 - number2;
    }
 
 
    @Tool(description = "对两个数字进行乘法")
    public float multiply(float number1, float number2) {
        System.out.println("Multiply number1 = " + number1 + " number2 = " + number2);
        return number1 * number2;
    }
 
    @Tool(description = "对两个数字进行除法")
    public float divide(float number1, float number2) {
        System.out.println("Divide number1 = " + number1 + " number2 = " + number2);
        return number1 / number2;
    }
 
}

JShMCPClient

# 依赖
<properties>
    <java.version>17</java.version>
    <spring-ai.version>1.1.0-SNAPSHOT</spring-ai.version><!--1.0.0-M6-->
    <guava.version>31.1-jre</guava.version>
    <mcp.version>0.11.2</mcp.version>
</properties>
 
<dependencies>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
  </dependency>
 
  <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
  </dependency>
 
  <dependency>
      <groupId>io.modelcontextprotocol.sdk</groupId>
      <artifactId>mcp</artifactId>
      <version>${mcp.version}</version>
  </dependency>
 
  <dependency>
      <groupId>io.modelcontextprotocol.sdk</groupId>
      <artifactId>mcp-spring-webflux</artifactId>
      <version>${mcp.version}</version>
  </dependency>
 
  <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-model-openai</artifactId>
  </dependency>
</dependencies>
 
<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>
</dependencyManagement>
 
# 配置文件
spring.application.name=mcpv2client
server.port=8211
 
spring.main.web-application-type=reactive
 
spring.ai.openai.base-url=api.deepseek.com
spring.ai.openai.api-key=xxxxxxx
spring.ai.openai.chat.options.model=deepseek-chat
 
spring.ai.mcp.client.toolcallback.enabled=true
spring.ai.mcp.client.streamable-http.connections.server1.url=127.0.0.1:8210
 
# Controller
/**
 * @Author: wanghaoguang
 * @CreateTime: 2025/8/14 17:28
 */
@RestController
@RequestMapping("/test")
public class ChatController {
    private final ChatClient chatClient;
    public ChatController(ChatClient.Builder chatClientBuilder, ToolCallbackProvider tools) {
        this.chatClient = chatClientBuilder.defaultToolCallbacks(tools)
                .build();
    }
 
    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> chatWithStream(@RequestParam String message) {
        System.out.println("\n>>> QUESTION: " + message);
        Flux<String> rt = chatClient.prompt()
                .user(message)
                .stream()
                .content();
        System.out.println("\n>>> ASSISTANT: " + rt);
        return rt;
    }
}

企业微信截图_722ea486-b979-4ece-8532-94186841b3b1.png

企业微信截图_d3943d86-349a-42c1-a6aa-ff7f5b6583f8.png

企业微信截图_858fc551-6c69-46e1-acc6-deb063a05881.png

总结

0,同PythonSDK,所有语言的MCP-SDK均参考官方规划文档编写,从源码来看,大体思路和使用方式都差不多。
1,Java MCP-SDK相对PythonSDK和MCP-go更新迭代慢,相对于SpringAI MCP技术试用的SpringAI的方法,最好使用官方原生MCP-SDK+自定义运行容器的方式,这样也比较灵活,官方Java MCP-SDK代码更新也较快。
2,同样Java MCP-SDK有提供Last-Event-ID机制和stateless,不过stateless方式暂时测试还有一些问题。
3,为了保证使用到最新的版本和支持最新的协议,以及生态支持上,推荐还是使用PythonSDK。

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0