资讯动态

MCP协议规范

发布时间:2026/8/6 18:23:03 来源:尧图企业网站定制
摘要随着大语言模型LLM生态向 Agent智能体与复杂工具调用Tool Calling深度演进如何让 AI 客户端如 Claude Desktop、Cursor、VS Code与海量外部数据源、工具链无缝解耦对接成为了行业的核心痛点。由 Anthropic 主导发起的MCPModel Context Protocol模型上下文协议正在迅速成为大模型时代的“USB 接口协议”。MCP 的底层通信机制完全建立在成熟、轻量级的JSON-RPC 2.0规范之上。本文将系统拆解 MCP 协议的整体架构、JSON-RPC 2.0 报文规范、传输层映射stdio 与 SSE、初始化握手生命周期、三大核心功能原语Tools, Resources, Prompts的请求与响应映射并手把手带你使用纯 Python 从零手写一个符合规范的 MCP 服务端最后总结生产落地的核心避坑指南。一、 背景与愿景为什么需要 MCP在 MCP 出现之前大语言模型与外部工具/数据源的对接面临着经典的M×N 复杂度网状困境传统架构M×N 复杂网状连接 [ Claude Desktop ] ─── (单独开发) ─── [ PostgreSQL ] [ Cursor IDE ] ─── (单独开发) ─── [ GitHub API ] [ Custom Agent ] ─── (单独开发) ─── [ Local Files ]每一个 AI 主控端Host/Client如果要接入一个新的数据源或工具如 GitHub、PostgreSQL、本地文件系统都需要为该数据源单独编写一套适配器反之工具开发者如果希望自己的服务被多种 AI 客户端支持也必须为每一个 IDE 和聊天客户端适配 API。MCP 协议引入了类似LSPLanguage Server Protocol语言服务协议的解耦思想通过标准化的通信接口将架构简化为1N 标准拓扑MCP 架构解耦后的星型标准拓扑 [ Client: Claude Desktop ] \ / [ Server: PostgreSQL ] [ Client: Cursor IDE ] ─── (MCP Protocol) ─── [ Server: GitHub API ] [ Client: Custom Agent ] / (JSON-RPC 2.0) \ [ Server: Local Files ]为什么选择 JSON-RPC 2.0 作为底层传输规范MCP 官方选用了JSON-RPC 2.0作为其消息序列化与调用的基石。其核心原因如下极为轻量且语言无关JSON 是现代软件工程中使用最广泛的数据交换格式任何编程语言都能零门槛解析。规范定义严谨JSON-RPC 2.0 明确区分了“双向请求-响应Request-Response”与“单向通知Notification”天生具备处理复杂异步交互的能力。传输层解耦JSON-RPC 2.0 仅定义消息结构不强绑定物理传输层。这使得 MCP 可以完美运行在本地进程间通信stdio以及远程网络传输HTTP SSE之上。二、 MCP 架构总览与传输层Transport Layer在深入 JSON-RPC 2.0 报文之前我们首先需要搞清楚 MCP 的物理与逻辑架构。2.1 角色定义MCP Client客户端/主控端发起连接并管理 LLM 生命周期的应用例如 Claude Desktop、Cursor、自定义 Agent 框架。Client 负责将用户的意图转化为对 Server 的请求并决定何时将 Server 返回的上下文喂给 LLM。MCP Server服务端/上下文提供者独立的进程或远程服务负责暴露具体的工具Tools、只读资源Resources或提示词模板Prompts。LLM大语言模型位于 Client 后端的推理引擎。注意LLM 并不直接与 MCP Server 通信所有的交互均由 Client 中转和路由。┌───────────────────────────────────────────────────────────┐ │ MCP Client │ │ │ │ ┌───────────────┐ 通信中转 ┌────────────────┐ │ │ │ LLM Engine │ ───────────── │ MCP Protocol │ │ │ └───────────────┘ │ JSON-RPC 2.0 │ │ └─────────────────────────────────────└────────┬───────┘────┘ │ 物理传输通道 (stdio / SSE) │ ┌──────────────────────────────────────────────▼────────────┐ │ MCP Server │ │ │ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │ │ Tools (执行) │ │Resources(只读)│ │ Prompts(模板) │ │ │ └───────────────┘ └───────────────┘ └───────────────┘ │ └───────────────────────────────────────────────────────────┘2.2 两大传输通道实现规范MCP 官方定义了两种标准的物理传输通道1. stdio标准输入/输出通道用于本地进程间通信IPC。Client 以子进程Subprocess的形式启动 MCP Server 进程。Client - ServerClient 将 JSON-RPC 报文按行写入 Server 的stdin标准输入。Server - ClientServer 将 JSON-RPC 报文按行写入自身的stdout标准输出。规范要求每条 JSON-RPC 报文必须是压缩为单行的 JSON 文本并以换行符\n或\r\n结尾。stderr标准错误被严格保留用于输出调试日志。Server 绝不能将任何 JSON-RPC 报文发送到 stderr也决不能将普通文本日志打印到 stdout否则会导致 Client 的 JSON 解析器崩溃。2. SSEServer-Sent Events HTTP POST远程网络通道用于跨机器远程网络通信。客户端订阅通道SSEClient 向 Server 发起 HTTP GET 请求建立 SSE 长连接。Server 通过该长连接向 Client 推送 JSON-RPC 响应或通知。客户端发送通道HTTP POSTClient 向 Server 指定的端点发送 HTTP POST 请求消息体为 JSON-RPC 请求报文。三、 核心通信规范JSON-RPC 2.0 在 MCP 中的报文全解JSON-RPC 2.0 是一个无状态、轻量级的远程过程调用RPC协议。在 MCP 中所有收发的文本必须严格遵守以下四大基本消息结构。3.1 请求对象Request Object当 Client 或 Server 需要调用对方的方法并期待返回结果时发送。JSON{ jsonrpc: 2.0, id: 1001, method: tools/call, params: { name: calculate_tax, arguments: { income: 50000 } } }jsonrpc字符串必填必须准确为2.0。method字符串必填调用的 RPC 方法名称如tools/call。params对象/数组选填方法所需的参数。在 MCP 规范中params几乎总是键值对 JSON 对象。id字符串/整数必填请求的唯一标识符。接收方在处理完该请求后必须在对应的响应对象中原样返回该id。3.2 成功响应对象Response Object - Success当接收方成功处理请求后返回。{ jsonrpc: 2.0, id: 1001, result: { content: [ { type: text, text: 计算结果预扣预缴税额为 4500 元。 } ], isError: false } }jsonrpc字符串必填必须为2.0。id字符串/整数必填必须与对应 Request 中的id完全一致。result任意 JSON 类型必填调用成功时返回的数据载荷。3.3 错误响应对象Response Object - Error当请求解析失败、方法不存在、参数校验失败或执行过程中抛出异常时返回。{ jsonrpc: 2.0, id: 1001, error: { code: -32602, message: Invalid params: argument income must be a positive number., data: { field: income, expected: number 0 } } }jsonrpc字符串必填必须为2.0。id字符串/整数必填与 Request 中的id一致若请求因 JSON 解析失败无法获取id则必须返回null。error对象必填包含以下字段code整数必填错误码。message字符串必填简短的错误描述。data任意类型选填包含错误的额外调试上下文。JSON-RPC 2.0 与 MCP 错误码映射表错误码Code错误类型含义说明-32700Parse Error服务端接收到的不是合法的 JSON 文本。-32600Invalid Request发送的 JSON 不符合 JSON-RPC 2.0 请求对象结构。-32601Method Not Found调用的 MCP 方法如tools/call_wrong不存在。-32602Invalid Params方法的参数不符合 Schema 约束例如缺失必填项。-32603Internal ErrorMCP 服务端内部抛出了未捕获的运行时异常。-32000到-32099Server ErrorMCP 协议预留的服务端自定义业务错误区段。3.4 通知对象Notification Object单向发送的消息不需要也不允许接收方做出任何响应。通常用于状态变更提醒、日志推送或取消操作。{ jsonrpc: 2.0, method: notifications/resources/updated, params: { uri: file:///workspace/config.json } }核心特征绝对不包含id字段如果包含了id接收方就会将其误判为普通 Request。四、 MCP 生命周期与握手协商机制任何一个符合规范的 MCP 会话都必须经历严格的生命周期三阶段初始化握手 ➔ 正常业务交互 ➔ 优雅关闭。4.1 初始化握手时序图在连接建立之初Client 与 Server 必须通过握手确认彼此支持的协议版本与能力集Capabilities。MCP Client MCP Server │ │ ├────────── 1. initialize Request (id: 1) ───────────►│ │ (clientInfo, capabilities) │ │ │ │◄───────── 2. initialize Response (id: 1) ───────────┤ │ (serverInfo, capabilities) │ │ │ ├─────── 3. notifications/initialized Notification ───►│ │ │ │ 握手完成 │ │ │ ├────────── 4. 正常业务请求 (tools/list 等) ───────────►│4.2 握手报文实战拆解步骤 1Client 发起initialize请求{ jsonrpc: 2.0, id: 1, method: initialize, params: { protocolVersion: 2024-11-05, capabilities: { roots: { listChanged: true }, sampling: {} }, clientInfo: { name: Cursor-IDE, version: 0.42.0 } } }protocolVersionClient 支持的 MCP 协议版本号当前最新主流标准为2024-11-05。capabilities告知 Server 本 Client 支持哪些高级能力如根目录变动通知、Sampling 采样等。步骤 2Server 回复initialize响应{ jsonrpc: 2.0, id: 1, result: { protocolVersion: 2024-11-05, capabilities: { tools: { listChanged: true }, resources: { subscribe: true, listChanged: true }, prompts: { listChanged: false }, logging: {} }, serverInfo: { name: enterprise-db-mcp, version: 1.2.0 } } }Server 在响应中明确宣告自己能提供哪些功能tools支持工具调用且工具列表变更时会发出 notification。resources支持只读资源提取且支持客户端订阅变更。步骤 3Client 发送notifications/initialized确认{ jsonrpc: 2.0, method: notifications/initialized }收到此通知后 Server 方可正式开启业务请求处理。五、 MCP 三大核心功能原语及其 JSON-RPC 映射MCP 将 AI 交互的上下文能力抽象为三大核心原语Tools工具、Resources资源与Prompts提示词。下面我们逐一拆解它们的 JSON-RPC 报文映射。5.1 Tools工具原语可执行的函数调用Tools 允许 LLM 通过 MCP Server 执行具有副作用的操作例如发起 API 请求、写入文件、执行 SQL 查询。1. 获取工具列表 (tools/list)Client 请求{ jsonrpc: 2.0, id: 2, method: tools/list, params: {} }Server 响应{ jsonrpc: 2.0, id: 2, result: { tools: [ { name: execute_sql, description: 在只读副本上执行安全 SQL 查询, inputSchema: { type: object, properties: { query: { type: string, description: 标准 SQL 查询语句 }, limit: { type: integer, default: 100 } }, required: [query] } } ] } }inputSchema必须严格遵循JSON Schema (Draft-07/2020-12)规范LLM 将依据此 Schema 生成参数。2. 调用工具 (tools/call)当 LLM 决定调用该工具时Client 发起以下请求Client 请求{ jsonrpc: 2.0, id: 3, method: tools/call, params: { name: execute_sql, arguments: { query: SELECT id, name, email FROM users LIMIT 2;, limit: 2 } } }Server 响应{ jsonrpc: 2.0, id: 3, result: { content: [ { type: text, text: [{\id\: 1, \name\: \Alice\, \email\: \aliceexample.com\}, {\id\: 2, \name\: \Bob\, \email\: \bobexample.com\}] } ], isError: false } }content支持多模态可包含text、imagebase64 编码图片或嵌入的resource对象。即使工具执行业务逻辑报错例如 SQL 语法错误通常也会设置isError: true并将错误信息放在content中返回而不是直接抛出 JSON-RPC 级别的error这有助于 LLM 观察错误并进行自我纠错。5.2 Resources资源原语只读上下文数据Resources 类似于 HTTP 的GET接口用于为 LLM 提供只读的数据源如日志文件、数据库 Schema、API 挡板数据。每一个资源由一个唯一的URI标识。1. 读取具体资源 (resources/read)Client 请求{ jsonrpc: 2.0, id: 4, method: resources/read, params: { uri: postgres://main-db/schemas/public } }Server 响应{ jsonrpc: 2.0, id: 4, result: { contents: [ { uri: postgres://main-db/schemas/public, mimeType: application/json, text: {\tables\: [\users\, \orders\, \products\]} } ] } }5.3 Prompts提示词原语预定义可复用模板Prompts 允许 Server 暴露可复用的 Prompt 模版方便用户在 Client 侧一键加载特定的专业角色或工作流。1. 获取展开后的提示词 (prompts/get)Client 请求{ jsonrpc: 2.0, id: 5, method: prompts/get, params: { name: code_review, arguments: { language: python } } }Server 响应{ jsonrpc: 2.0, id: 5, result: { description: Python 代码审查模板, messages: [ { role: user, content: { type: text, text: 请作为资深 Python 专家对提交的代码进行 Clean Code 审查重点关注 PEP8 规范与异步性能问题。 } } ] } }六、 MCP 高级特性双向通信与反向采样Sampling传统的 RPC 通常是单向的“客户端请求服务端响应”。然而基于 JSON-RPC 2.0MCP 允许 Server 反向向 Client 发起请求其中最出彩的高级特性就是Sampling采样原语。6.1 什么是 Sampling有时MCP Server 在执行某个复杂任务时自身需要借助于 LLM 的能力比如把一段庞大的日志做一次预总结。通过 SamplingServer 可以向 Client 抛出sampling/createMessage请求要求 Client 调用其连接的大模型进行一次嵌套推理再将结果回复给 ServerServer Client │ │ ├─────── 1. sampling/createMessage Request ──────────►│ │ (messages, maxTokens, systemPrompt) │ │ │ 2. Client 转发给 │ │ 外部 LLM 推理 │ │ │◄────── 3. sampling/createMessage Response ──────────┤ │ (model, role: assistant, content) │6.2 Sampling 报文示例Server 发起反向请求{ jsonrpc: 2.0, id: server-req-99, method: sampling/createMessage, params: { messages: [ { role: user, content: { type: text, text: 请提取以下日志中的报错堆栈摘要\nERROR 2026-08-05 ... } } ], maxTokens: 200 } }这种机制极大提升了 Server 的智能化上限使其无需硬编码额外的 LLM API Key即可复用 Client 已有的模型推理通道。七、 实战零依赖手写 Python MCP Server为了帮助你彻底掌握底层细节下面我们不依赖任何现成的 MCP 高级 SDK仅使用 Python 原生的sys.stdin、sys.stdout和json模块手写一个完全符合 JSON-RPC 2.0 规范的本地 stdio MCP Server。7.1 Python 代码实现custom_mcp_server.pyimport sys import json import traceback def log_debug(msg: str): 注意所有日志必须写入 stderr绝对不能打到 stdout sys.stderr.write(f[MCP-SERVER-LOG] {msg}\n) sys.stderr.flush() def send_response(response_dict: dict): 将 JSON-RPC 响应打印至 stdout并紧跟换行符刷新 output json.dumps(response_dict, ensure_asciiFalse) sys.stdout.write(output \n) sys.stdout.flush() def handle_initialize(req_id, params): return { jsonrpc: 2.0, id: req_id, result: { protocolVersion: 2024-11-05, capabilities: { tools: {listChanged: False} }, serverInfo: { name: handcrafted-python-mcp, version: 1.0.0 } } } def handle_tools_list(req_id): return { jsonrpc: 2.0, id: req_id, result: { tools: [ { name: add_numbers, description: 计算两个数字的和, inputSchema: { type: object, properties: { a: {type: number, description: 第一个数字}, b: {type: number, description: 第二个数字} }, required: [a, b] } } ] } } def handle_tools_call(req_id, params): tool_name params.get(name) args params.get(arguments, {}) if tool_name add_numbers: a args.get(a, 0) b args.get(b, 0) result_val a b return { jsonrpc: 2.0, id: req_id, result: { content: [ { type: text, text: f计算结果{a} {b} {result_val} } ], isError: False } } else: return { jsonrpc: 2.0, id: req_id, error: { code: -32601, message: f未知的工具名称: {tool_name} } } def main(): log_debug(MCP Server 启动等待 stdin 报文...) for line in sys.stdin: line line.strip() if not line: continue log_debug(f收到原生报文: {line}) # 1. 尝试解析 JSON try: req json.loads(line) except json.JSONDecodeError: send_response({ jsonrpc: 2.0, id: None, error: {code: -32700, message: Parse error: 非法的 JSON 文本} }) continue # 2. 校验是否符合 JSON-RPC 2.0 请求/通知基础结构 if req.get(jsonrpc) ! 2.0: send_response({ jsonrpc: 2.0, id: req.get(id), error: {code: -32600, message: Invalid Request: jsonrpc 版本必须为 2.0} }) continue method req.get(method) req_id req.get(id) # 3. 如果是通知 (Notification)无需回复 if req_id is None and method notifications/initialized: log_debug(收到 Client 握手完成通知初始化流程就绪) continue # 4. 根据 Method 进行路由分发 try: if method initialize: resp handle_initialize(req_id, req.get(params, {})) elif method tools/list: resp handle_tools_list(req_id) elif method tools/call: resp handle_tools_call(req_id, req.get(params, {})) else: resp { jsonrpc: 2.0, id: req_id, error: {code: -32601, message: fMethod not found: {method}} } send_response(resp) except Exception as e: log_debug(f执行异常: {traceback.format_exc()}) send_response({ jsonrpc: 2.0, id: req_id, error: {code: -32603, message: fInternal error: {str(e)}} }) if __name__ __main__: main()7.2 客户端命令行模拟测试我们可以通过控制台重定向输入直接使用交互方式验证该 MCP Server 是否符合标准输入 1发送 initialize 请求{jsonrpc: 2.0, id: 1, method: initialize, params: {protocolVersion: 2024-11-05}}输出 1{jsonrpc: 2.0, id: 1, result: {protocolVersion: 2024-11-05, capabilities: {tools: {listChanged: false}}, serverInfo: {name: handcrafted-python-mcp, version: 1.0.0}}}输入 2发送 initialized 通知{jsonrpc: 2.0, method: notifications/initialized}(服务端 stderr 日志输出stdout 无响应符合规范)输入 3发送 tools/call 调用计算{jsonrpc: 2.0, id: 2, method: tools/call, params: {name: add_numbers, arguments: {a: 12, b: 30}}}输出 3{jsonrpc: 2.0, id: 2, result: {content: [{type: text, text: 计算结果12 30 42}], isError: false}}八、 生产级开发避坑指南与最佳实践在基于 JSON-RPC 2.0 开发生产级别的 MCP 服务端时以下几点是极易踩坑的“重灾区”1. Stdio 缓冲区刷新陷阱Buffer Flushing在 Python 中使用print()或sys.stdout.write()时操作系统通常默认开启行缓冲区或块缓冲区。如果你忘记调用sys.stdout.flush()消息会滞留在内存缓冲区中。客户端会以为服务端陷入挂起死锁最终触发超时报错。规避方案每次写完 stdout 后必须立即强制flush()。在 Python 中可以加上环境标识PYTHONUNBUFFERED1。2. Stdout 污染问题很多第三方 Python 库例如 PyTorch、TensorFlow 或某些日志库在 import 时会自动向stdout打印横幅或调试信息。这会破坏单行 JSON-RPC 报文结构导致 Client 端报Parse error (-32700)。规避方案任何打印调试信息的逻辑必须强行重定向到sys.stderr。3. 请求 ID 类型匹配一致性JSON-RPC 2.0 规定请求的id可以是字符串或整数。服务端在构造响应时必须保持原始类型完全一致如果请求的id是字符串abc响应的id绝对不能变成数字或被丢掉 Quotes。4. 严谨的 JSON Schema 定义tools/list暴露的参数 Schema 是 LLM 生成代码的主要参考依据。务必明确标注required数组以及属性的description。避免使用复杂且深层嵌套的多态 Schema这能大幅提升 LLM 工具调用的成功率。九、 总结MCPModel Context Protocol的出现标志着大模型应用开发正从“散兵游勇式的定制时代”迈入“标准化接口的工业化时代”。通过选择成熟稳健的JSON-RPC 2.0规范作为骨架MCP 成功兼顾了轻量性、跨语言扩展性与异步双向通信能力。理解并熟练掌握 JSON-RPC 2.0 的报文细节不仅能帮助开发者更高效地构建高质量的 MCP Server 扩展组件也为深入探索 Agent 智能体协同机制打下了坚实的工程基础。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价