Backend Development 11 min read

Implementing Model Context Protocol (MCP) with SSE and HTTP in SpringBoot

This article explains the Model Context Protocol (MCP) for seamless LLM integration, describes its background, presents a sequence diagram of its architecture, and provides step‑by‑step Java SpringBoot code for SSE streaming, HTTP POST handling, and annotation‑based tool registration.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Implementing Model Context Protocol (MCP) with SSE and HTTP in SpringBoot

The Model Context Protocol (MCP) is an open protocol that enables large language model (LLM) applications to integrate smoothly with external data sources and tools, allowing AI‑driven IDEs, chat interactions, or custom AI workflows to connect LLMs with required context.

In simple terms, MCP is a data‑communication protocol that defines how applications and large models exchange data for seamless connection.

The article focuses on using MCP with the SSE+HTTP approach, illustrating a practical scenario where a server runs various models via Ollama, an internal ERP system manages data, and developers want to connect these using MCP.

Background

Server A deploys models with Ollama for internal use.

Server B runs an ERP system handling company data.

The concept of MCP is introduced as a solution.

A visual example (image) shows the client CherryStudio communicating with the ERP system on the left and the Ollama‑hosted 7B model on the right.

Architecture Design (Sequence Diagram)

sequenceDiagram
    participant User as User
    participant CherryStudio as CherryStudio
    participant Server as Server
    participant Ollama as Ollama
    User->>CherryStudio: 打开软件
    CherryStudio-->>Server: **SSE** 兄弟,我们聊会
    Server--)CherryStudio: **SSE** 好,你有事的话 POST 这个地址(endpoint)
    CherryStudio-->>Server: **POST** 兄弟,自我介绍一下(initalize)
    Server--)CherryStudio: **SSE** 好,这是我的基本信息(serverInfo)
    CherryStudio-->>Server: **POST** 兄弟,我收到了,我准备好了(initialized)
    CherryStudio-->>Server: POST: 兄弟,你有MCP的工具吗(tools/list)
    Server--)CherryStudio: **SSE** 我提供了几个工具(tools)
    User->>CherryStudio: 输入: 禁用张三的账号
    CherryStudio->>Ollama: POST: 带工具调用 `禁用张三的账号`
    Ollama-)CherryStudio: 意图识别: {工具:禁用账号,参数:张三}
    CherryStudio-->>Server: **POST** 请求发送 {工具:禁用账号,参数:张三}
    Server-->>CherryStudio: 执行工具并 **SSE** 推送结果
    CherryStudio->>Ollama: 整理下收到的结果
    Ollama-)CherryStudio: 返回处理后的结果
    CherryStudio-)User: 显示给用户看

Starting Development

The project uses Java 17, SpringBoot, and JPA as its technology stack.

Basic Data Structures

{
  "id": 0,
  "jsonrpc": "2.0"
}

Request Structure (extends basic structure)

interface Request {
  // 请求的ID
  id: number

  // 请求的协议 固定2.0
  jsonrpc: "2.0";

  // 请求的方法
  method: string;

  // 请求的参数
  params?: { ... };
}

Example initalize request:

{
  "id": 0,
  "jsonrpc": "2.0",
  "method": "initalize",
  "params": {
    "capabilities": {},
    "clientInfo": {}
  }
}

Example tool‑call request:

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "disableUserByName",
    "arguments": { "name": "张三" }
  }
}

Response Structure (extends basic structure)

interface Response {
  id: 0;
  jsonrpc: "2.0";
  result: { /* data */ };
  error: { /* error info */ };
}

SSE Service in SpringBoot

public final static ConcurrentHashMap
EMITTERS = new ConcurrentHashMap<>();

@GetMapping(value = "sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter connect() throws IOException {
    String uuid = UUID.randomUUID().toString();
    SseEmitter emitter = new SseEmitter();
    sseEmitter.send(SseEmitter.event()
            .name("endpoint")
            .data("/mcp/messages?sessionId=" + uuid)
            .build());
    EMITTERS.put(uuid, emitter);
    emitter.onCompletion(() -> EMITTERS.remove(uuid));
    emitter.onTimeout(() -> EMITTERS.remove(uuid));
    return emitter;
}

Note: After establishing the connection, the client must send an initial message containing the URL for POST requests.

Message POST API

@PostMapping("messages")
public Json messages(HttpServletRequest request, @RequestBody McpRequest mcpRequest) {
    String uuid = request.getParameter("sessionId");
    if (Objects.isNull(uuid)) {
        return Json.error("sessionId is required");
    }
    String method = mcpRequest.getMethod();
    switch(method){
        case "initalize":
            // handle initialization
            break;
        case "tools/call":
            // handle tool call
            break;
        case "tools/list":
            // handle tool list
            break;
        default:
    }
}

All responses are pushed back to the client via the SSE channel, not as direct HTTP responses.

Tool Registration via Annotations

@McpMethod("modifyEmailByName")
@Description("modify user new email by name")
public String modifyEmailByName(
        @Description("the name of user, e.g. 凌小云") String name,
        @Description("the new email of user, e.g. [email protected]") String email) {
    List
userList = filter(new UserEntity().setNickname(name));
    DATA_NOT_FOUND.when(userList.isEmpty(), "没有叫 " + name + " 的用户");
    userList.forEach(user -> {
        updateToDatabase(get(user.getId()).setEmail(email));
    });
    return "已经将 " + userList.size() + " 个叫 " + name + " 的用户邮箱修改为 " + email;
}

Methods annotated with @McpMethod are automatically registered by the MCP server, allowing clients like CherryStudio to invoke them.

Conclusion

The article demonstrates how to build an MCP service using Java, SpringBoot, SSE, and HTTP, enabling LLM‑driven extensions for internal systems such as ERP, while noting future considerations like permission control.

BackendJavaLLMMCPSpringBootprotocolSSE
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

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