Build a Streamable HTTP MCP Server with Spring AI 1.1

This article walks through creating a Java Spring Boot MCP Server that supports Streamable HTTP using the newly released Spring AI 1.1 snapshot, covering repository setup, Maven dependencies, configuration, service implementation, and verification with example code and screenshots.

Ubiquitous Tech
Ubiquitous Tech
Ubiquitous Tech
Build a Streamable HTTP MCP Server with Spring AI 1.1

This guide demonstrates how to develop a Streamable HTTP MCP Server based on Spring AI 1.1. It starts by pointing to the Spring AI GitHub repository (https://github.com/spring-projects/spring-ai/tree/main/spring-ai-spring-boot-starters) where four new Spring Boot starters for MCP Server are listed:

spring-ai-starter-mcp-server-streamable-webmvc

spring-ai-starter-mcp-server-streamable-webflux

spring-ai-starter-mcp-server-stateless-webmvc

spring-ai-starter-mcp-server-stateless-webflux

These starters enable Java developers to build MCP Servers with Streamable HTTP support.

Project Setup

Create a new Maven project and add the following dependencies to pom.xml (the essential parts are shown):

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-autoconfigure-processor</artifactId>
</dependency>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-bom</artifactId>
      <version>1.1.0-SNAPSHOT</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
  </dependency>
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.83</version>
  </dependency>
  <dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.18.3</version>
  </dependency>
  <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-io</artifactId>
    <version>1.3.2</version>
  </dependency>
  <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.17.0</version>
  </dependency>
  <dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server-streamable-webmvc</artifactId>
  </dependency>
</dependencies>

Configure the Spring snapshot repository to resolve the 1.1.0‑SNAPSHOT artifacts:

<repositories>
  <repository>
    <id>spring-snapshots</id>
    <name>Spring Snapshots</name>
    <url>https://repo.spring.io/snapshot</url>
    <releases><enabled>false</enabled></releases>
    <snapshots><enabled>true</enabled></snapshots>
  </repository>
</repositories>

Application Configuration

Add the following to src/main/resources/application.yml to enable Streamable HTTP support:

spring:
  ai:
    mcp:
      server:
        streamable-http:
          enabled: true
          name: springai-mcp-server
          version: 1.0.0
          type: ASYNC
        mcp-endpoint: /mcp
  server:
    port: 8001

The corresponding Java properties class is McpStreamableServerProperties.

Business Logic – Weibo Trending Service

The service fetches Weibo hot‑search data, filters ads, builds a list of maps, and returns a JSON string. The full source is:

@Service
@Slf4j
public class WeiboTrendingDataRequestService {
    @Tool(name = "get-weibo-trending",
          description = "获取微博热搜榜,包含时事热点、社会现象、娱乐新闻、明星动态及网络热议话题的实时热门中文资讯")
    public String getWeiboTrending() {
        String url = "https://weibo.com/ajax/side/hotSearch";
        try {
            // 1. 请求微博热搜接口(GET 请求)
            Connection.Response response = Jsoup.connect(url)
                .ignoreContentType(true)
                .timeout(10000)
                .header("referer", "https://weibo.com")
                .method(Connection.Method.GET)
                .execute();
            // 2. 判断 HTTP 状态码
            if (response.statusCode() != 200) {
                log.error("请求微博热搜失败,HTTP状态码: {}", String.valueOf(response.statusCode()));
                return "微博热搜获取失败,请稍后再试";
            }
            // 3. 解析返回的 JSON 数据
            String body = response.body();
            JSON.Object json = JSON.parseObject(body);
            if (json.getInteger("ok") != 1 || !json.containsKey("data")) {
                return "微博热搜获取失败,返回数据异常";
            }
            JSON.Array realtimeList = json.getJSONObject("data").getJSONArray("realtime");
            if (realtimeList == null || realtimeList.isEmpty()) {return "微博热搜为空";}
            // 4. 处理每一条热搜
            List<Map<String, Object>> resultList = new ArrayList<>();
            for (int i = 0; i < realtimeList.size(); i++) {
                JSON.Object item = realtimeList.getJSONObject(i);
                // 跳过广告
                if (item.getIntValue("is_ad") == 1) { continue; }
                String word = item.getString("word");
                String wordScheme = item.getString("word_scheme");
                String key = (wordScheme != null && !wordScheme.isEmpty()) ? wordScheme : "#" + word;
                // 构造链接
                String searchUrl = "https://s.weibo.com/weibo?q=" + URLEncoder.encode(key, StandardCharsets.UTF_8.toString()) + "&band_rank=1&Refer=top";
                // 封装成 map
                Map<String, Object> map = new HashMap<>();
                map.put("title", word);
                map.put("description", item.getString("note") != null ? item.getString("note") : key);
                map.put("popularity", item.getString("num"));
                map.put("link", searchUrl);
                resultList.add(map);
            }
            // 5. 转换为 JSON 字符串返回
            return JSON.toJSONString(resultList);
        } catch (Exception e) {
            log.error("工具调用异常: {}", e.getMessage(), e);
            return "工具调用失败,请稍后再试";
        }
    }
}

Main Application Class

Register the service as a tool callback and start the Spring Boot application:

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

    @Bean
    public ToolCallbackProvider applicationTools(WeiboTrendingDataRequestService weibo) {
        return MethodToolCallbackProvider.builder()
                .toolObjects(weibo)
                .build();
    }
}

Running and Testing

Start the application (default port 8001). In an MCP client, add a configuration pointing to http://localhost:8001/mcp. Send a test query; the server returns the processed Weibo hot‑search results, confirming successful integration.

Comparison of Spring AI Starters

The article notes that the two Streamable HTTP starters ( spring-ai-starter-mcp-server-streamable-webmvc and spring-ai-starter-mcp-server-streamable-webflux) internally use McpStreamableServerWebMvcAutoConfiguration (or the WebFlux counterpart) which delegates to WebMvcStreamableServerTransportProvider from the latest Java MCP Server SDK.

Conclusion

This tutorial shows how to leverage Spring AI 1.1 snapshot releases to build a Streamable HTTP MCP Server, covering repository discovery, Maven setup, configuration, service implementation, and verification steps.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

backendMCPspring-bootMCP Serverspring-aistreamable-http
Ubiquitous Tech
Written by

Ubiquitous Tech

A ubiquitous public account for pirate enthusiasts, regularly sharing curated experiences, tech learning, and growth insights. Currently publishing articles on AI RAG customer service, AI MCP technology, and open-source design. Personal free Knowledge Planet: Awakening New World Programmer.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.