前言
了解Model Context Protocol(MCP),首先需要了解[jsonrpc2.0]協議。MCP使用jsonrpc2.0協議實現了MCPServer和MCPClient兩者交互的數據結構。
JSONRPC2.0
在[SpringAI MCP技術試用]文中說過,MCP只是一個standardized(標準化的;規范化的)協議,而MCP協議的核心是jsonrpc2.0,具體可以參考[官方文檔]和[MCP傳輸協議文檔]
為什么用jsonrpc2.0?
0)生態完善:JSON-RPC 2.0 有豐富的庫和工具支持。
1)和開發語言無關:基本上所有開發語言都支持json協議。
2)簡單實用:結構簡單易讀性好。
3)輕量級:能大大減少數據傳輸,減少AI數據交互過程中的延遲。
MCP中jsonrpc2.0的定義
下文主要以mcp tools原語為例。

initialize
# 請求
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {
"tools": {}
},
"clientInfo": {
"name": "example-client",
"version": "1.0.0"
}
}
}
# 響應
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": {
"tools": {
"listChanged": true
},
"resources": {}
},
"serverInfo": {
"name": "example-server",
"version": "1.0.0"
}
}
}
initialized
# 請求
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}
# 響應
無
tools/list
# 請求
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list"
}
# 響應
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "com.example.calculator/arithmetic",
"title": "Calculator",
"description": "Perform mathematical calculations including basic arithmetic, trigonometric functions, and algebraic operations",
"inputSchema": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "Mathematical expression to evaluate (e.g., '2 + 3 * 4', 'sin(30)', 'sqrt(16)')"
}
},
"required": ["expression"]
}
}
]
}
}
tools/call
# 請求
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "com.example.weather/current",
"arguments": {
"location": "San Francisco",
"units": "imperial"
}
}
}
# 響應
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "Current weather in San Francisco: 68°F, partly cloudy with light winds from the west at 8 mph. Humidity: 65%"
}
]
}
}
一些說明
1)MCP官方文檔寫的非常清楚,可以參考官方文檔中的Architecture Overview->Data Layer 模塊。
2)官方文檔主要以一個地區天氣查詢MCP為例,說明了MCP從連接建立到tool調用的過程中數據以jsonrpc2.0協議傳輸的數據結構,可以看到非常的簡單明了,易于理解和實現。
Demo
這里使用java spring boot簡單模擬mcp tool/call的調用過程。
# JsonRpcServerController.java
package cn.chinatelecom.dw.user.app.jsonrpc;
import cn.chinatelecom.dw.user.app.utils.JSONUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: wanghaoguang
* @CreateTime: 2025/7/28 15:22
*/
@RestController
public class JsonRpcServerController {
private final static Logger LOG = LoggerFactory
.getLogger(JsonRpcServerController.class);
@PostMapping(value = "/jsonrpc", consumes = MediaType.APPLICATION_JSON_VALUE, produces =
MediaType.APPLICATION_JSON_VALUE)
private ResponseEntity<String> jsonrpc(@RequestBody String requestBody) {
try {
ObjectNode objNode = JSONUtils.parseObject(requestBody);
String methodName = objNode.get("method").asText();
JsonNode params = objNode.get("params");
if (params == null) {
params = JSONUtils.createObjectNode();
}
Integer requestId = objNode.get("id").asInt();
LOG.info("jsonrpc_endpoint params {}", objNode);
ObjectNode response = JSONUtils.createObjectNode();
if ("calculate".equals(methodName)) {
try {
String expression = params.get("expression").asText();
double result = safeCalculate(expression);
response.put("result", result);
} catch (Exception e) {
int code = -32603;
String message = e.getMessage();
response = buildErrObjectNode(requestId, code, message);
}
} else {
int code = -32601;
String message = "Method not found";
buildErrObjectNode(requestId, code, message);
}
return ResponseEntity.ok(JSONUtils.toJsonString(response));
} catch (Exception e) {
LOG.info("jsonrpc_endpoint Error: {}", e.getMessage());
int code = -32000;
String message = "Internal server error " + e.getMessage();
return ResponseEntity.status(500).body(JSONUtils.toJsonString(buildErrObjectNode(0, code, message)));
}
}
private ObjectNode buildErrObjectNode(int requestId, int code, String message) {
ObjectNode response = JSONUtils.createObjectNode();
response.put("id", requestId);
response.put("jsonrpc", "2.0");
ObjectNode error = JSONUtils.createObjectNode();
error.put("code", code);
error.put("message", message);
response.set("error", error);
return response;
}
private double safeCalculate(String expression) {
try {
return Double.parseDouble(String.valueOf(;
} catch (Exception e) {
throw new IllegalArgumentException("Invalid expression");
}
}
private Object {
try {
return new javax.script.ScriptEngineManager().getEngineByName("JavaScript").;
} catch (Exception e) {
throw new IllegalArgumentException("Invalid expression");
}
}
}
# JsonRpcClient.java
package cn.chinatelecom.dw.user.app.utils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
* @Author: wanghaoguang
* @CreateTime: 2025/7/28 15:35
*/
public class JsonRpcClient {
private final static Logger LOG = LoggerFactory
.getLogger(JsonRpcClient.class);
private final String serverUrl;
private int requestId = 1;
public JsonRpcClient(String serverUrl) {
this.serverUrl = serverUrl;
}
public JsonNode call(String method, JsonNode params, int timeout) {
ObjectNode payload = JSONUtils.createObjectNode();
payload.put("jsonrpc", "2.0");
payload.put("method", method);
if (params == null) {
params = JSONUtils.createObjectNode();
}
payload.set("params", params);
payload.put("id", requestId++);
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(timeout, java.util.concurrent.TimeUnit.SECONDS)
.readTimeout(timeout, java.util.concurrent.TimeUnit.SECONDS)
.build();
MediaType JSON = MediaType.get("application/json; charset=utf-8");
try {
RequestBody body = RequestBody.create(JSONUtils.toJsonString(payload), JSON);
Request request = new Request.Builder()
.url(serverUrl)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
return JSONUtils.parseObject(responseBody);
} else {
LOG.info("Request failed with code: {}", response.code());
}
}
} catch (IOException e) {
LOG.info("Error occurred while making the request: {}", e.getMessage());
}
return null;
}
public static void main(String[] args) {
JsonRpcClient client = new JsonRpcClient("//127.0.0.1:9022/jsonrpc");
ObjectNode params = JSONUtils.createObjectNode();
params.put("expression", "3+5");
JsonNode result = client.call("calculate", params, 10);
System.out.println(result);
}
}


一些說明:
1)可以看到使用java啟動一個http服務,基于jsonrpc2.0協議可以模擬mcp協議的交互流程。
2)上文主要提供java版本實現,python可以參考官方文檔。
總結
1,MCP使用jsonrpc定義了MCPServer和MCPClient之間交互的數據結構,不管是stdio、sse、streamable-http、sampling那種協議。
2,jsonrpc協議和語言無關,方便簡單易用,使用最簡單的json包處理即可,自己也可以用自己擅長的開發語言按MCP定義的交互協議編寫自己的MCPServer。