首页 > 编程笔记 > 通用技能 阅读:19

JSON-RPC 2.0消息协议简介(附带实例)

JSON-RPC 2.0 是一种轻量级的、用于远程过程调用(Remote Procedure Call,RPC)的消息协议,其使用 JSON 作为数据格式。

注意,JSON-RPC 2.0 不是一个底层传输协议,只是一种应用层的消息格式标准。形象地说,就像两个人需要交换包裹,它规定了包裹应该如何打包、如何在内部分区、如何贴标签等,但并不规定如何运送。

比如,你需要调用远程 MCP 服务端上的一个计算器函数来计算“5+3”。这是一次远程过程调用。JSON-RPC 2.0 规定了你发送给 MCP 服务端的请求(Request)消息需要遵循类似这样的格式:
{
  "jsonrpc": "2.0", // 协议版本,固定为“2.0”
  "method": "calculate", // 要调用的方法(工具)名
  "params": {
    // 方法参数,可以是对象或数组
    "expression": "5+3"
  },
  "id": 1 // 请求标识符,用于匹配响应
}

在 MCP 服务端处理完后,JSON-RPC 2.0 又规定了 MCP 服务端的响应(Response)消息必须类似于:
{
  "jsonrpc": "2.0", // 协议版本
  "result": 8, // 调用结果
  "id": 1 // 对应请求的标识符
}

如果 MCP 服务端在处理时发生了异常(比如,你要求调用一个不存在的方法),那么你会收到这样的响应消息:
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32601,
    "message": "请求的方法不存在"
  },
  "id": 1
}

还有一种情况,当 MCP 服务端需要向客户端发送一个通知(Notification)消息时,需使用以下格式:
{
  "jsonrpc": "2.0",
  "method": "notifications",
  "params": {
    "message": "This is a message from server..."
  }
}

因为这是一种单向的通知,不需要对方回复,所以不携带请求标识符(id)。

所以,有了这样的消息协议做约定,通信双方就可以非常顺畅地完成请求与响应过程。上述的请求消息、响应消息、通知消息也是目前 MCP 规范所定义的 3 种基础消息类型,并对部分内部字段进行了必要的扩充。

很显然,这种消息协议的优势如下:

基于JSON-RPC 2.0的远程过程调用

一旦确定了消息的标准,选择了一种传输模式,我们就能轻松地模拟MCP的远程过程调用流程。

你可能会首先想到易于使用的 HTTP,下面编写简易的 MCP 服务端代码(这段代码存储于名为“mcp_server_raw.py”的文件中)来模拟处理上述请求:
......
app = FastAPI()  # 使用FastAPI快速开发一个MCP服务端

# 可调用的工具
def calculate(expression: str) -> float:
    ......

@app.post('/jsonrpc')
async def jsonrpc_endpoint(request: Request):
    """处理所有JSON-RPC请求的FastAPI端点"""
    try:
        content = await request.json()
        # 解析请求与参数
        method_name = content.get("method")
        params = content.get("params", {})
        request_id = content.get("id", None)

        if method_name == "calculate":
            try:
                expression = params.get("expression", "")
                result = calculate(expression)
                response = {
                    "jsonrpc": "2.0",
                    "result": result,
                    "id": request_id
                }
            except ValueError as ve:
                response = {
                    "jsonrpc": "2.0",
                    "error": {"code": -32603, "message": str(ve)},
                    "id": request_id
                }
        else:
            # 处理其他错误...
        return JSONResponse(content=response)
    except Exception as e:
    # 处理其他异常
    ......
对这段代码的解释如下:
1) 在实现这个模拟 MCP 服务端时,使用 HTTP 端点 /jsonrpc 提供一个 MCP 服务端的“工具”(calculate)的调用接口。这个接口需要使用 HTTP POST 方法来访问。

2) 此处的“calculate”工具仅为模拟演示,实际上 MCP 服务端的工具调用会通过统一的 tools/call 方法实现。

3) 然后,使用以下代码创建一个客户端来模拟调用 MCP 服务端的“工具”(这段代码存储于名为“mcp_client_raw.py”的文件中):
......
class McpClient:
    ......
    def call(self, method, params=None, timeout=10):
        """调用远程方法"""
        # 注意这里的请求格式,遵循JSON-RPC 2.0
        payload = {
            "jsonrpc": "2.0",
            "method": method,
            "params": params if params is not None else {},
            "id": self.request_id
        }
        self.request_id += 1

        headers = {'Content-Type': 'application/json'}

        try:
            response = requests.post(
                self.server_url,
                data=json.dumps(payload),
                headers=headers,
                timeout=timeout
            )
            response.raise_for_status()
            return response.json()
        except Exception as e:
            ......

......client.call("calculate", {"expression": "3+5"})
这样就模拟了一个基于 JSON-RPC 2.0 的客户端与 MCP 服务端交互的原型:
JSON-RPC 2.0 是一种专为网络环境设计的用于远程过程调用的消息协议。它能够与多种消息传输协议协同工作,以实现请求与响应的交互模式。

相关文章