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

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
What is MCP
❓
Let me quote some official introduction:
❝❞
Model Context Protocol
(MCP
) is an open protocol that enablesLLM
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
Server via Ollama
Some messy models were deployed for use by friends within the company.On another server there is an internal ERP
The system manages a large amount of data information of the company.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 isOllama
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(line
interface 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(line
public 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
"messages" )
(public Json messages ( HttpServletRequest request, 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.