ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

JSON-RPC 2.0:MCP通信的底层语言

JSON-RPC 2.0:MCP通信的底层语言 摘要MCP协议基于JSON-RPC 2.0进行通信本文详解JSON-RPC消息格式、请求响应模型、批量调用、错误码定义以及MCP如何在此基础上扩展出初始化握手和能力协商机制。JSON-RPC 2.0 MCP通信的底层语言我第一次抓包看MCP的通信内容时有点懵消息里全是jsonrpc、method、params这些字段看起来跟HTTP API完全不一样。后来才知道MCP底层用的是JSON-RPC 2.0协议一个比我预想中更简洁的RPC规范。搞懂JSON-RPC 2.0之后再看MCP的消息流就豁然开朗了所有工具调用、资源读取、能力协商的本质都是JSON-RPC消息的收发。这篇文章把JSON-RPC 2.0的规范和MCP的使用方式完整讲清楚配上真实的消息示例。JSON-RPC 2.0是什么JSON-RPC 2.0是一个无状态的轻量级远程过程调用协议2010年发布用JSON作为数据格式。它的核心思想很简单客户端发一个JSON对象描述要调用什么方法、传什么参数服务端返回一个JSON对象包含执行结果。它跟HTTP API的区别在于传输无关。JSON-RPC不绑定任何传输协议可以在同一个进程内用可以通过socket用可以通过HTTP用也可以通过标准输入输出用。MCP正是利用了这个特性在stdio和Streamable HTTP两种传输上跑同一套JSON-RPC消息。JSON-RPC 2.0跟1.0版本的区别也很好区分。2.0的消息里一定有个jsonrpc: 2.0字段1.0没有。三种消息格式JSON-RPC 2.0定义了三种消息类型请求、响应和通知。我逐个讲。请求 Request请求是客户端发给服务端的消息期望得到响应。它有四个字段。{jsonrpc:2.0,id:1,method:tools/call,params:{name:add_note,arguments:{title:测试笔记,content:这是内容}}}jsonrpc字段固定为2.0标识协议版本。id字段是客户端生成的唯一标识符可以是数字或字符串服务端响应时必须返回相同的id客户端据此匹配请求和响应。method是要调用的方法名。params是方法参数可以按位置传数组或按名称传对象MCP统一用按名称传。id的值有几个注意事项。不建议用Null因为Null在响应里表示无法识别请求id。不建议用带小数的数字因为浮点数精度可能导致匹配失败。响应 Response响应是服务端对请求的回复。成功和失败有两种不同的结构。成功响应。{jsonrpc:2.0,id:1,result:{content:[{type:text,text:笔记创建成功ID为 1}]}}错误响应。{jsonrpc:2.0,id:1,error:{code:-32602,message:Invalid params,data:{detail:title字段不能为空}}}响应的规则很严格。result和error字段不能同时出现成功时只有result失败时只有error。id必须跟请求的id一致。如果请求解析失败无法识别id响应的id为Null。错误对象有三个字段。code是整数错误码。message是简短错误描述。data是可选的附加信息可以是任意类型。通知 Notification通知是一种特殊的请求没有id字段服务端不需要回复。{jsonrpc:2.0,method:notifications/initialized}通知的用途是告诉对方某件事发生了但不关心结果。MCP里大量使用通知比如initialized通知、取消通知、进度通知、日志通知、列表变更通知。通知的不可靠性在于没有响应发送方无法知道对方是否收到或处理成功。如果你需要确认就得用请求而不是通知。错误码体系JSON-RPC 2.0预留了-32768到-32000的范围给预定义错误。错误码名称含义-32700Parse error服务端解析JSON文本失败-32600Invalid Request发送的JSON不是合法的请求对象-32601Method not found方法不存在或不可用-32602Invalid params方法参数无效-32603Internal error服务端内部错误-32000到-32099Server error预留给实现自定义的服务端错误MCP在这个体系上扩展了自己的语义。比如-32602在MCP里经常出现能力协商不匹配、参数格式错误、不支持的能力请求都会返回这个码。-32000到-32099的范围可以给MCP Server存自定义的业务错误码。MCP还定义了一些特定的错误情况。协议版本不匹配时Server返回-32602data字段里带上支持的版本列表和请求的版本。这比单纯返回一个错误消息有用得多。MCP如何使用JSON-RPCMCP在JSON-RPC 2.0之上定义了自己的方法集和消息语义。我把MCP用到的方法分几类。生命周期方法。initialize是握手请求Client发给Server协商版本和能力。notifications/initialized是握手完成通知。这两个方法是MCP运行的基础。工具方法。tools/list请求获取工具列表。tools/call请求调用某个工具。notifications/tools/list_changed通知告诉Client工具列表变了让Client重新拉取。资源方法。resources/list列出资源。resources/read读取资源内容。resources/subscribe订阅资源变更。resources/unsubscribe取消订阅。notifications/resources/updated通知资源已更新。Prompt方法。prompts/list列出模板。prompts/get获取生成的消息。notifications/prompts/list_changed通知模板列表变更。实用方法。ping心跳检测。logging/setLevel设置日志级别。Client侧方法。sampling/createMessage由Server发请求让Client用LLM生成文本。elicitation/create由Server发请求让Client向用户提问。所有这些方法的底层都是JSON-RPC的请求、响应或通知。MCP的精巧之处在于它没有发明新的序列化格式或传输协议完全复用JSON-RPC 2.0的消息结构只是定义了method的命名空间和params的schema。真实MCP通信消息示例下面是一个完整的MCP通信流程从握手到工具调用到关闭。我用笔记管理Server做例子展示每一步的真实JSON-RPC消息。// 第1步 Client发送initialize请求 {jsonrpc:2.0,id:1,method:initialize,params:{protocolVersion:2025-06-18,capabilities:{roots:{listChanged:true},sampling:{}},clientInfo:{name:example-client,version:1.0.0}}}// 第2步 Server返回initialize响应 {jsonrpc:2.0,id:1,result:{protocolVersion:2025-06-18,capabilities:{tools:{listChanged:true},resources:{subscribe:true,listChanged:true},prompts:{listChanged:true},logging:{}},serverInfo:{name:mcp-notes-server,version:1.0.0}}}// 第3步 Client发送initialized通知 // 通知没有id字段Server不会回复{jsonrpc:2.0,method:notifications/initialized}// 第4步 Client请求工具列表 {jsonrpc:2.0,id:2,method:tools/list}// 第5步 Server返回工具列表 {jsonrpc:2.0,id:2,result:{tools:[{name:add_note,description:添加一条新笔记返回新笔记的ID,inputSchema:{type:object,properties:{title:{type:string,description:笔记标题},content:{type:string,description:笔记正文},tags:{type:array,items:{type:string},description:标签列表可选}},required:[title,content]}},{name:list_notes,description:列出所有笔记的摘要信息,inputSchema:{type:object,properties:{}}}]}}// 第6步 Client调用add_note工具 {jsonrpc:2.0,id:3,method:tools/call,params:{name:add_note,arguments:{title:学习MCP,content:今天学习了JSON-RPC 2.0协议,tags:[MCP,协议]}}}// 第7步 Server返回工具执行结果 {jsonrpc:2.0,id:3,result:{content:[{type:text,text:笔记创建成功ID为 1\n标题 学习MCP\n时间 2025-06-18T10:30:00.000Z}]}}// 第8步 Server发送日志通知 // Server可以主动发通知不需要Client先发请求{jsonrpc:2.0,method:notifications/message,params:{level:info,logger:mcp-notes-server,data:新笔记已创建当前共1条笔记}}上面这8条消息覆盖了MCP通信的核心模式。握手三步走步骤1到3请求-响应对步骤4到5、步骤6到7服务端主动通知步骤8。与REST和gRPC的对比MCP选择JSON-RPC而不是REST或gRPC是有道理的。我从几个维度对比。对比维度JSON-RPC 2.0RESTgRPC数据格式JSONJSON/XML/任意Protobuf二进制传输层任意HTTPHTTP/2双向通信原生支持需WebSocket原生支持流式传输需扩展需SSE/WebSocket原生支持消息大小中等中等小二进制编码可读性高纯JSON高低需解码浏览器支持好好差需gRPC-Web工具链简单成熟复杂需proto编译状态管理无状态无状态支持有状态流MCP选JSON-RPC的原因我分析有三个。第一JSON-RPC传输无关stdio和HTTP都能跑符合MCP同时支持本地和远程的设计目标。gRPC绑定HTTP/2stdio模式跑不了。第二JSON可读性好调试时直接看消息内容就行不用proto解码。第三JSON-RPC原生支持双向通信Server可以主动发请求和通知REST做不到这点得靠WebSocket或SSE补充。代价是JSON的序列化效率不如Protobuf大消息场景下性能差一些。但MCP的消息通常很小工具参数和返回值这个开销可以接受。批处理JSON-RPC 2.0支持批处理客户端可以一次发一个数组包含多个请求。服务端处理完后返回一个响应数组。// 批量请求一次发两个工具调用[{jsonrpc:2.0,id:1,method:tools/call,params:{name:add_note,arguments:{title:笔记A,content:内容A}}},{jsonrpc:2.0,id:2,method:tools/call,params:{name:add_note,arguments:{title:笔记B,content:内容B}}}]// 批量响应顺序不保证靠id匹配[{jsonrpc:2.0,id:2,result:{content:[{type:text,text:笔记创建成功ID为 2}]}},{jsonrpc:2.0,id:1,result:{content:[{type:text,text:笔记创建成功ID为 1}]}}]批处理里的通知不会有对应响应。如果整个批处理都是通知服务端不返回任何内容。不过MCP协议规范没有明确要求实现批处理目前大部分MCP SDK和客户端都是一条一条发消息。了解这个特性有助于理解JSON-RPC的完整能力但实际开发中你可能用不到。常见问题与避坑第一个坑id用浮点数。JSON-RPC规范说id不建议包含小数部分。我见过有人用时间戳做id时间戳带了毫秒小数结果JavaScript的浮点精度问题导致请求和响应的id对不上客户端一直超时。用整数或字符串做id最安全。第二个坑请求和通知搞混。有id的是请求没id的是通知。我写Server时把通知当请求处理了处理完还发了个响应回去客户端收到多余的响应消息直接报错。区分方法很简单看消息里有没有id字段。有id的才需要回复。第三个坑错误响应里带了result字段。JSON-RPC规范要求result和error不能同时存在。我见过有人写了{ result: null, error: {...} }虽然语义上是错误响应但带了result字段导致一些严格的客户端解析失败。记住错误响应只有error成功响应只有result。第四个坑消息里嵌了原始换行符。stdio传输按换行符分隔消息。如果你手动拼JSON字符串没正确转义换行符一条消息会被截成两条。永远用JSON.stringify或json.dumps序列化它们会自动把\n转义成\\n。第五个坑method名大小写敏感。JSON-RPC规范说method名是大小写敏感的。tools/List和tools/list是两个不同的方法。MCP的method名全用小写加斜线分隔写代码时注意别手滑大写了。这类错误最恶心的是不报method not found因为有些Server的实现用了不区分大小写的匹配换一个Server就挂了。小结JSON-RPC 2.0是MCP通信的底层协议定义了请求、响应、通知三种消息格式和一套错误码体系。MCP在JSON-RPC之上定义了initialize、tools、resources、prompts等方法集所有MCP功能本质上都是JSON-RPC消息的收发。理解JSON-RPC的关键是区分请求有id需响应和通知无id不响应确保result和error互斥用JSON.stringify序列化避免换行符问题。MCP选JSON-RPC而不是REST或gRPC核心原因是传输无关性和原生双向通信能力。相关推荐MCP协议全景Host、Client、Server架构详解Tools原语深度解析从定义到调用全流程Completions与通知机制自动补全、进度上报与状态通知
返回列表