MCP is very popular. Let’s see how we can directly add an MCP to the backend management system?

Written by
Audrey Miles
Updated on:July-09th-2025
Recommendation

Explore how the MCP protocol revolutionizes the data interaction mode of the backend management system.

Core content:
1. The MCP protocol and its importance in AI programming
2. Actual case: How to connect the ERP system and AI model through the MCP protocol
3. The architecture design and application prospects of the MCP protocol

Yang Fangxian
Founder of 53AI/Most Valuable Expert of Tencent Cloud (TVP)

What is MCP

Let me quote some official introduction:

Model Context Protocol (MCP) is an open protocol that enables LLM Seamless integration between applications and external data sources and tools is possible. Whether you are building an AI-driven IDE, improving chat interactions, or building custom AI workflows, MCP provides a standardized way to connect LLMs with the context they need.

Dabaihua is an application protocol for data communication, which stipulates how to transfer data between applications and large models for seamless connection.

"This article mainly talks about MCP of SSE+HTTP Method of use.

Let’s take lychee as an example :)


Current context

  1. Server via Ollama Some messy models were deployed for use by friends within the company.
  2. On another server there is an internal ERP The system manages a large amount of data information of the company.
  3. You heard  the concept of "MCP" from the neighboring community  .

So what can we do in this context?

First look at the screenshots:


The client we use is  "CherryStudio" , on the left is our ERP System, on the right is Ollama A small  "7B"  Tongyi Qianwen open source model.

We directly through  the "CherryStudio  " MCP Protocol access function, direct and ERP The system communicates to achieve ERP System data query and operation.

If we  replace "CherryStudio" with "Siri"  on our mobile phones  , what about Xiao Ai around us?

Siri can complete it through shortcut commands, and Xiao Ai can complete it through Xiao Ai skills. Of course, the experience is definitely not as fast and good as directly building in MCP.


Start analysis

First, let’s take a look at  the MCP  architecture design sequence diagram:

CherryStudio: **SSE** bro, let's chat Server--)CherryStudio: **SSE** Ok, if you have anything, POST this address (endpoint) CherryStudio-->>Server: **POST** bro, introduce yourself (initalize) Server--)CherryStudio: **SSE** Ok, here is my basic information (serverInfo) CherryStudio-->>Server: **POST** Bro, I got it, I'm ready (initialized) CherryStudio-->>Server: POST: Bro, do you have MCP tools (tools/list) Server--)CherryStudio: **SSE** I provide several tools (tools) User->>CherryStudio: Input: Disable Zhang San's account CherryStudio->>Ollama: POST: Call `Disable Zhang San's account` with the tool Ollama-)CherryStudio: Intent recognition: {tool: disable account, parameter: Zhang San} CherryStudio-->>Server: **POST** Request to send {tool: disable account, parameter: Zhang San} Server-->>CherryStudio: Execute the tool and **SSE** push the result CherryStudio->>Ollama: Organize the received results Ollama-)CherryStudio: Return the processed result CherryStudio-)User: Display it to the user


Start developing

With the architecture diagram, it is not difficult to develop:

Of course, you can use some "SDK" provided by the official website   to do it, but there are many problems. You can try it first and discuss it in the comment area~ . . .

We won’t consider using  the “SDK”  and will just work on the project!


「Project Technology Stack」

  • Runtime: "Java17"
  • Framework:  "SpringBoot"
  • ORM:  "JPA"

Come on, let's get started.


 Basic data structure of MCP


Infrastructure

ounter(lineounter(lineounter(lineounter(line{ "id": 0, "jsonrpc": "2.0"}


Request structure extends the infrastructure

All requests sent to  the "MCP"  server have this structure:

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineinterface  Request  {  // Request ID  id: number
  // The requested protocol is fixed to 2.0  jsonrpc:  "2.0" ;
  // Request method  method:  string ;
  // Request parameters  params ?: { ... };}

For example, the method initalize The request structure is:

{ "id": 0, "jsonrpc": "2.0", "method": "initalize", "params": { // Some capabilities of the client "capabilities": {}, "clientInfo": { // Some client information, such as name, version, etc. } }}

Another example is the request structure of a function call

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line{ "id": 1, "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "disableUserByName", "arguments": { "name": "Zhang San" } }}


The response structure extends the basic structure

All   responses pushed to the client via "SSE" have this structure:

interface Response { id: 0; jsonrpc: "2.0"; result: { // some data information }; error: { // some error information };}


SSE Services

 It is very simple to start an "SSE" service under SpringBoot  :

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(linepublic  final  static  ConcurrentHashMap<String, SseEmitter> 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);
    // You can add some heartbeats
    emitter.onCompletion(() -> EMITTERS.remove(uuid));    emitter.onTimeout(() -> EMITTERS.remove(uuid));    return  emitter;    return  sseEmitter;}

It should be noted here that "MCP"  requires that a message must be sent once the connection is established, and the content is  the URL used by the "MCP"  service to accept  "POST"  requests.

OK, now that we have this service, the client can use this service to receive the messages we want to send.


Message POST API

Next, let's implement this more complex  "POST"  request:

ounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter ( lineounter (line@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" :        // This request is an initialization request and needs to return some server information to the client        break ;      case  "tools/call" :        // This request is a tool call request and needs to return the execution result to the client        break ;      case  "tools/list" :        // This request is a tool list request, and some tool lists need to be returned to the client        break ;      default :    }}

Please note that all requests are not direct HTTP responses, but   are pushed back through the "SSE" channel just now.


1. Initialize

The initialization request needs to respond to the client with some basic information from the server:

{ id: id, jsonrpc: "2.0", result: { // Some service capabilities capabilities: {}, serverInfo: { name: "Server name", version: "1.0.0" } }}

At this point, the client can already display the basic information of the server.


2. Request Tool List

After the "SSE"  server receives the request, it needs to respond to the client with a list of tools:

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line{ "id": 0, "jsonrpc": "2.0", "result": { "tools": [ { "name": "disableUserByName", "description": "Disable a user's account", "inputSchema": { "type": "object", "properties": { "nickname": { "type": "string", "description": "name" } }, "required": ["nickname"] } } ] }}


3. Execution Tools

When the "SSE"  server needs to execute the tool, it will get this structure:

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line{ "id": 1, "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "disableUserByName", "arguments": { "name": "Zhang San" } }}

You can return the following structure after executing some code:

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line{ "id": 1, "jsonrpc": "2.0", "result": { "content": [ { "type": "text", "text": "Okay, I killed Zhang San" } ] }}

At this point, the entire process is almost complete.


Annotation-based encapsulation

Because we use  "Java"  and  "SpringBoot" , we use @McpMethod Annotation fit Reflections To implement the automatic registration tool.

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line@McpMethod("modifyEmailByName")@Description("modify user new email by name")public String modifyEmailByName( @Description("the name of user, eg Ling Xiaoyun") String name, @Description("the new email of user, eg example@domain.com") String email) { List<UserEntity> userList = filter(new UserEntity().setNickname(name)); DATA_NOT_FOUND.when(userList.isEmpty(), "There is no user named " + name + ""); userList.forEach(user -> { updateToDatabase(get(user.getId()).setEmail(email)); }); return "The email addresses of " + userList.size() + " users named " + name + " have been changed to " + email;}

Just mark @McpMethod annotation, MCP The server will automatically register this method.

Then you can   call this method through tools such as "CherryStudio" .

Things that move your mouth


Summarize

We have completed an "MCP" service through the above method   , and it can also be expanded for some of our other systems, using large models to transform the way these systems are used. It's great.

Of course, there are still many problems we need to solve here, such as permission control.