1. 为什么 MCP 的底层值得单独聊一次
MCP(Model Context Protocol,模型上下文协议)这两年被讨论得很多,但大多数文章停在“它能接工具、能读文件”这一层。真正动手写一个 MCP Server,或者想搞清楚 Cline、Claude Code 这类客户端到底怎么和外部能力对话时,绕不开一个更底层的东西:JSON-RPC 2.0。
MCP 的所有传输机制,无论是 stdio 还是 HTTP 流式,交换的消息都是 JSON-RPC 2.0 格式。也就是说,你看到的“工具调用”“资源读取”“提示模板”,在协议层都是一条条method+params+id的 JSON 消息。理解了这个骨架,你排查 MCP 连接失败、工具不显示、initialize 超时这些问题时,就不会只盯着客户端界面发呆。
这篇是番外篇,不讲 MCP 的宏大叙事,只做三件事:拆开 JSON-RPC 2.0 的消息结构,给出在 Cline 里配置settings.json的可复制骨架,然后用一次真实的initialize请求验证整条链路是否通。适合已经在用 Cline、想自己接 MCP Server、或者被 JSON-RPC 报错卡住的人。如果你还没配过统一 Key 通道,下面会顺带把 TaoToken 的接入方式串进去,让请求真正发得出去。
2. JSON-RPC 2.0 消息骨架拆解
JSON-RPC 2.0 的设计目标就四个字:简单、无状态。它用 JSON 当数据格式,几乎任何语言都能解析,所以 MCP 选它做消息层并不意外。一条请求消息的核心字段只有四个。
jsonrpc固定是字符串"2.0",写错版本号服务器会直接判无效请求。method是要调用的方法名,MCP 里常见的有initialize、tools/list、tools/call、resources/list。params是参数,可以是数组也可以是对象,MCP 基本都用对象。id是请求标识,字符串或数字都行,服务器响应时会原样带回,用来配对请求和响应。
请求长这样:
{ "jsonrpc": "2.0", "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": { "name": "cline", "version": "1.0.0" } }, "id": 1 }成功响应只多一个result字段,id保持一致:
{ "jsonrpc": "2.0", "result": { "protocolVersion": "2024-11-05", "capabilities": { "tools": {} }, "serverInfo": { "name": "demo-server", "version": "0.1.0" } }, "id": 1 }出错时result换成error,里面带code和message:
{ "jsonrpc": "2.0", "error": { "code": -32601, "message": "Method not found" }, "id": 1 }标准错误码记住几个就够用:-32700解析错误、-32600无效请求、-32601方法未找到、-32602参数无效、-32603内部错误。MCP 场景里最常见的是-32601,通常意味着你调的方法名拼错了,或者 Server 根本没注册这个方法。
注意:JSON-RPC 2.0 是无状态的,每条消息独立。MCP 的会话状态是靠
initialize握手后在双方内存里维护的,不是靠协议本身。
3. TaoToken 前置:把统一 Key 通道准备好
MCP Server 本身不负责模型推理,但很多 MCP 工作流最终要调用大模型。为了让请求有统一的出口,我习惯先把 TaoToken 的 Key 通道配好,这样 Cline 里的模型调用和 MCP 工具调用走同一套凭证,排查问题时变量更少。
先去控制台创建一个 API Key。地址是https://taotoken.net/console,登录后在 API Keys 页面新建,复制出来的 Key 形如sk-开头的一串字符,只显示一次,记得存好。
TaoToken 的 API 入口是https://taotoken.net/api,兼容 OpenAI 风格的调用方式。也就是说,任何支持自定义 base_url 的客户端,把地址填成这个,Key 填刚生成的,就能通。Cline 里配置模型时也是这个逻辑。
如果你更想先验证模型通道是否正常,可以打开模型对话页面直接发一句话测试:https://taotoken.net/model-chat。这一步不是必须的,但能帮你区分“是模型通道不通”还是“是 MCP 配置有问题”,排障时非常省时间。
长期跑编码任务或者 Agent 工作流的话,Coding Plan 会更划算,入口在https://taotoken.net/coding-plan。这篇的重点是 MCP 配置,所以 Key 准备好就够,下面直接进 Cline。
4. Cline settings.json 可复制配置骨架
Cline 的 MCP 配置写在settings.json里,不同系统路径不一样。macOS 一般在~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json,Windows 在%APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json。文件名可能因版本略有差异,认准cline_mcp_settings.json这个关键词。
一个最小可用的骨架长这样:
{ "mcpServers": { "demo-stdio": { "command": "node", "args": ["/absolute/path/to/demo-server/index.js"], "env": { "TAOTOKEN_API_KEY": "sk-你的Key", "TAOTOKEN_BASE_URL": "https://taotoken.net/api" }, "disabled": false, "autoApprove": [] } } }几个字段说明一下。command是启动 Server 的可执行程序,Node 写的 Server 就填node,Python 的填python3。args是参数数组,第一个通常是 Server 入口文件的绝对路径,相对路径容易踩坑,建议一律用绝对路径。env是注入给 Server 进程的环境变量,把 TaoToken 的 Key 和 base_url 放这里,Server 内部调用模型时直接读环境变量,不用硬编码。
disabled设为false表示启用。autoApprove是自动批准的工具列表,初期建议留空,等确认工具行为安全后再加,避免误操作。
如果你用的是 HTTP 类型的 MCP Server,配置换成url字段:
{ "mcpServers": { "demo-http": { "url": "http://127.0.0.1:3000/mcp", "env": { "TAOTOKEN_API_KEY": "sk-你的Key" }, "disabled": false } } }改完保存,Cline 会自动重载 MCP 配置。如果没重载,重启一下 VS Code 窗口。这时候在 Cline 的 MCP 面板里应该能看到demo-stdio这个 Server,状态是连接中或已连接。
5. 发送 initialize 请求验证连通性
配置好之后,最关键的一步是确认握手成功。MCP 规定客户端连接后第一条消息必须是initialize,Server 返回能力清单,双方才算建立会话。
如果你有 Server 的源码,可以在处理initialize的地方打一行日志,把收到的 params 打印出来。然后回到 Cline,触发一次 MCP 连接。观察日志,应该能看到类似这样的请求进来:
{ "jsonrpc": "2.0", "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": { "roots": { "listChanged": true } }, "clientInfo": { "name": "cline", "version": "3.x" } }, "id": 0 }Server 要回一条结构完整的响应,id必须和请求一致:
{ "jsonrpc": "2.0", "result": { "protocolVersion": "2024-11-05", "capabilities": { "tools": { "listChanged": true } }, "serverInfo": { "name": "demo-server", "version": "0.1.0" } }, "id": 0 }如果 Cline 面板里 Server 状态变成已连接,并且能看到工具列表,说明整条链路通了。想更直接一点,可以手动用 curl 对 HTTP 类型的 Server 发一条 initialize:
curl -X POST http://127.0.0.1:3000/mcp \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "curl", "version": "1.0"} }, "id": 1 }'返回里能看到result.serverInfo就说明 Server 活着且协议实现正确。这一步能过,后面tools/list、tools/call基本不会有大问题。
6. 本篇常见错误排查
连接一直转圈或超时。先看command和args路径对不对,绝对路径写错是最常见的原因。Node Server 还要确认node在系统 PATH 里,Cline 启动子进程时环境变量可能和终端不一样。可以在终端手动跑一遍node /path/to/index.js,看能不能正常启动。
报 -32601 Method not found。方法名拼错了,或者 Server 没实现initialize。MCP 要求 Server 必须实现initialize,如果连这个都返回 -32601,说明 Server 的协议层没写对,检查路由分发逻辑。
报 -32700 Parse error。发出去的 JSON 格式有问题,常见于手动 curl 时引号转义错误,或者 Server 读 stdin 时没按行分割。stdio 传输要求每条消息一行,换行符处理不当就会解析失败。
工具列表为空。initialize成功了但tools/list返回空数组,检查 Server 是否在capabilities里声明了tools,以及工具注册代码是否在握手之后才执行。
环境变量读不到。env里配的TAOTOKEN_API_KEY在 Server 里读出来是 undefined,多半是 Cline 版本对env字段的支持差异,可以改成在args里传参,或者用 Server 自己的配置文件。实测下来,把 Key 放在env里在多数版本是有效的,但值得用一行日志确认。
改了配置不生效。Cline 有时不会自动重载,手动重启 VS Code 窗口最稳。另外确认改的是cline_mcp_settings.json,不是 VS Code 自己的settings.json,两个文件容易混。
7. 继续往下走
把initialize跑通之后,下一步就是发tools/list看 Server 暴露了哪些工具,再发tools/call实际调一次。这时候如果模型调用也要走统一通道,记得 Key 和 base_url 已经在env里配好了,Server 内部直接读环境变量即可。
需要新建或轮换 Key 的时候,去https://taotoken.net/api-keys操作。接入细节和字段说明在文档里:https://taotoken.net/doc。如果你更想先确认模型通道本身没问题,模型对话页面https://taotoken.net/model-chat发一句话最快。长期跑编码和 Agent 任务,Coding Plan 入口在https://taotoken.net/coding-plan,按需选就行。
JSON-RPC 2.0 这套骨架不复杂,难的是把每一层都验证到位。我自己的习惯是每加一个 MCP Server,先手动 curl 一条 initialize,确认协议层通了再交给 Cline,这样出问题时能立刻定位是配置层还是协议层。