Skip to content

2.2 MCP 通信基础:JSON-RPC

MCP 使用 JSON-RPC 作为客户端与服务器的通信基础。在介绍 JSON-RPC 之前,我们先来了解一下 JSON 和 RPC。

2.2.1 什么是 JSON

JSON (JavaScript Object Notation,JavaScript 对象表示法) 是一种轻量级的数据交换格式,易于人阅读和编写,也易于机器解析和生成。它基于 JavaScript 编程语言的一个子集,但是独立于编程语言。

JSON 主要有以下特点:

  • 使用简单的文本格式,易于传输和存储
  • 支持嵌套数据结构,可以表示复杂的数据
  • 数据类型包括:对象、数组、字符串、数字、布尔值和 null
  • 已成为许多 Web API 和配置文件的标准格式

JSON 的语法简洁明了,使用键值对组织数据,非常适合作为不同系统间的通用数据交换格式。

一个用 JSON 表示的数据结构示例:

{
"name": "张三",
"age": 30,
"isStudent": false,
"hobbies": ["读书", "旅游", "编程"],
"address": {
"city": "北京",
"postcode": "100000"
},
"phoneNumbers": [
{
"type": "家庭",
"number": "010-12345678"
},
{
"type": "工作",
"number": "138XXXXXXXX"
}
],
"spouse": null
}

2.2.2 什么是 RPC

RPC (Remote Procedure Call,远程过程调用) 是一种计算机通信协议,它允许程序调用另一台计算机上的子程序,而程序员无需额外编写网络交互代码。

RPC 的主要特点:

  • 分布式系统通信的基础机制
  • 使远程调用在代码层面表现得与本地调用相似
  • 隐藏了底层网络通信的复杂性
  • 支持不同编程语言和平台之间的互操作性
  • 常见 RPC 框架包括 gRPC、Thrift、Dubbo 等

RPC 系统通常包含两个关键组件:客户端和服务器。客户端发起请求调用远程服务器上的程序,服务器执行请求的操作并返回结果。RPC 通信流程如图所示:

可以看到,RPC 通信核心要做的两件事:

  1. 选择一种消息格式,对请求参数和响应参数进行序列化和反序列化
  2. 选择一种传输协议,传递和接收数据

2.2.3 什么是 JSON-RPC

JSON-RPC 是一种基于 JSON 的轻量级 RPC 协议。它定义了一种数据格式和处理规则,允许在不同系统之间进行远程方法调用。

主要特点:

  • 使用 JSON 作为消息格式
  • 支持请求-响应模式
  • 简单易用,不依赖特定编程语言
  • 可以通过 HTTP / HTTPS 或其他传输协议传输
  • 标准的 JSON-RPC 请求包含:方法名、参数和请求 ID。响应包含:结果或错误信息,以及与请求相匹配的 ID。

当前最新的 JSON-RPC 协议版本是 2.0。MCP 选择了 JSON-RPC 2.0 协议作为通信基础。

2.2.4 JSON-RPC 2.0 协议规范

一、请求对象

JSON-RPC 2.0 的请求对象包含以下成员:

  • jsonrpc:字符串,指定 JSON-RPC 协议的版本,必须精确地为 “2.0”
  • method:字符串,包含要调用的方法名称
  • params:对象或数组,包含传递给方法的参数(可选)
  • id:字符串、数字或 null,用于将请求与响应关联起来

请求对象主要有两类:

  1. 通知请求

通知请求不带 id 参数,不关心响应内容,只用于单方面传递信息给服务端,而无需等待和理解服务端的响应内容。

通知请求示例:

{
"method": "notifications/initialized",
"jsonrpc": "2.0"
}
  1. 待响应请求

待响应请求,需要带上 id 参数,等待服务端的响应内容。服务端必须返回跟请求 id 匹配的响应内容。

待响应请求示例:

{
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "mcp-client",
"version": "1.0.0"
}
},
"jsonrpc": "2.0",
"id": 0
}

二、响应对象

当接收到 RPC 调用时,服务器必须回复一个响应对象,但通知请求除外。响应对象包含以下成员:

  • jsonrpc:字符串,指定 JSON-RPC 协议的版本,必须精确地为 “2.0”
  • result:成功时必须包含此成员,包含方法调用的结果
  • error:出错时必须包含此成员,包含错误信息
  • id:必须包含此成员,必须与请求对象中的 id 值相同

响应对象中的 resulterror 成员必须且只能包含其中一个。

  1. 成功响应

服务端处理请求成功,返回一个成功响应,响应的 id 与请求的 id 保持一致。在 result 里面返回请求的结果数据。

成功响应示例:

{
"jsonrpc": "2.0",
"id": 0,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {}
},
"serverInfo": {
"name": "mcp-server",
"version": "0.0.3"
}
}
}
  1. 失败响应

服务端处理请求失败,通过 error 字段返回错误对象。返回的 id 也需要跟请求的 id 保持一致。

{
"jsonrpc": "2.0",
"error": {
"code": -32602,
"message": "Invalid params "
},
"id": 0
}

三、错误对象

当 RPC 调用遇到错误时,响应对象必须包含一个 error 成员,其值是一个具有以下成员的对象:

  • code:错误码,表示错误类型的数字,必须是整数
  • message:错误消息,简短描述错误的字符串
  • data:包含关于错误的附加信息(可选)

JSON-RPC 2.0 预定义了一批错误码,如下:

错误码消息含义
-32700Parse error服务器收到无效的 JSON
-32600Invalid Request发送的 JSON 不是有效的请求对象
-32601Method not found方法不存在或不可用
-32602Invalid params无效的方法参数
-32603Internal errorJSON-RPC 内部错误
-32000 到 -32099Server error保留给实现定义的服务器错误

四、批处理

客户端可以同时发送多个请求对象,将它们放在一个数组中。服务器应该用一个包含相应响应对象的数组来响应,但对于通知请求不应该有响应对象。

批处理请求示例

[
{ "jsonrpc": "2.0", "method": "sum", "params": [1, 2, 4], "id": "1" },
{ "jsonrpc": "2.0", "method": "notify_hello", "params": [7] },
{ "jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": "2" }
]

批处理响应示例

[
{ "jsonrpc": "2.0", "result": 7, "id": "1" },
{ "jsonrpc": "2.0", "result": 19, "id": "2" }
]