
1. 先把 MCP、HTTP、WebSocket 的层级关系说清楚很多人第一次配 MCP 服务时会卡在一个很基础的问题上MCP 到底是不是一种新的网络协议它和 HTTP、WebSocket 是什么关系为什么我明明写的是http://开头的地址日志里却能看到Upgrade: websocket我先把结论摆出来MCP 是应用层的协议规范它定义的是「消息长什么样、有哪些方法、怎么握手、怎么调用工具」而 HTTP 和 WebSocket 是它可以选择使用的传输通道。这三者不是竞争关系而是分层协作关系。你可以用寄快递来类比。MCP 是「包裹里装什么、面单怎么填、收件人怎么签收」这套规则HTTP 是「普通快递」一问一答送完就结束WebSocket 是「专线电话」接通之后双方可以一直聊。MCP 的包裹既可以走普通快递也可以走专线电话包裹本身的格式不变。从分层角度看大概是这样的应用层: MCP 协议 ← 定义 initialize / tools/list / tools/call 等语义 传输层: WebSocket / SSE / stdio / Streamable HTTP 网络层: TCP / IP关键点在于 MCP 设计上是「传输无关」的。同一套 MCP 消息可以走本地标准输入输出stdio可以走 SSE可以走 WebSocket也可以走 HTTP 的 POST 请求。你在settings.json里写的transport字段决定的就是「这个 MCP 服务用哪种通道」。那为什么大家总把 MCP 和 WebSocket 绑在一起讲因为 WebSocket 提供了全双工长连接服务端可以主动向客户端推送消息这对需要长时间会话、流式返回、服务端主动通知的场景很合适。而 HTTP 的初始握手那个Upgrade请求恰好是建立 WebSocket 连接的第一步所以你会看到「MCP 用 HTTP 握手然后升级成 WebSocket」这种说法。理解了这个分层后面配置settings.json时你就不会迷糊url填的是传输地址transport填的是传输类型而 MCP 的协议语义是藏在消息体里的跟传输方式无关。这一节想让你记住一句话MCP 不是替代 HTTP 的协议而是构建在 HTTP/WebSocket 之上的专门协议。想清楚这一点Nginx 能不能代理 MCP、为什么能代理也就顺理成章了。2. 接入前的准备TaoToken 的 Base URL、Key 与 Model ID在真正写settings.json之前得先把「连到哪个模型服务」这件事定下来。MCP 本身只是工具调用的协议层它需要一个能理解工具调用的大模型来驱动。我这边实测用的是 TaoToken 提供的统一接入端点它同时兼容 Anthropic 风格和 OpenAI 风格的调用配置起来比较省事。你需要准备三样东西我把它叫做「三件套」配置项说明示例值Base URL接口根地址不带具体路径https://taotoken.net/apiAPI Key身份凭证形如sk-开头sk-xxxxxxxxModel ID具体模型标识claude-sonnet-4-5等Base URL 用https://taotoken.net/api注意这里不要加多余的斜杠或路径很多客户端会自动拼接/v1/messages或/v1/chat/completions。API Key 在控制台的 API Keys 页面创建创建后只显示一次记得及时保存。如果你用的是 Claude Code 这类工具它读取的是环境变量或配置文件里的ANTHROPIC_BASE_URL和ANTHROPIC_AUTH_TOKEN如果你用的是 Cline、Roo Code 这类 VS Code 插件通常在设置界面里填 Base URL、API Key、Model ID 三个字段。不管哪种本质都是把上面三件套填进去。这里有个容易踩的坑有人把 Base URL 填成了带/v1的完整路径结果客户端又拼了一次变成/v1/v1/messages直接 404。正确做法是只填到/api这一层。准备好三件套之后先别急着配 MCP建议先用最简方式验证一下模型通道是通的。你可以打开模型对话页面发一句「你好请回复 ok」确认能正常返回。这一步能排除掉 Key 错误、额度不足、模型名写错等基础问题。等模型通道确认没问题再往上叠加 MCP 服务排障时就能快速定位是「模型层」还是「MCP 层」的问题。顺便说一句如果你打算长期跑编码类 Agent 任务可以考虑用 Coding Plan 这类套餐比按量计费更划算如果只是临时验证 MCP 连通性用按量调用就够了。两种方式共用同一套 Base URL 和 Key切换成本很低。3. settings.json 骨架http 与 websocket 两种传输怎么写这一节是重点我直接给你可复制的配置骨架。不同客户端读取的配置文件名不一样Claude Code 用的是.mcp.json或settings.json里的mcpServers字段Cline 用的是插件自己的cline_mcp_settings.json但结构大同小异核心都是command/args或url/transport这两类。先看一个本地 stdio 类型的 MCP 服务这是最常见的{ mcpServers: { filesystem: { command: npx, args: [ -y, modelcontextprotocol/server-filesystem, /Users/yourname/projects ] } } }再看远程 HTTP 类型的 MCP 服务注意transport字段{ mcpServers: { remote-tools: { url: https://mcp.example.com/mcp, transport: http, headers: { Authorization: Bearer sk-xxxxxxxx } } } }WebSocket 类型的写法{ mcpServers: { ws-tools: { url: wss://mcp.example.com/mcp/ws, transport: websocket, headers: { Authorization: Bearer sk-xxxxxxxx } } } }如果你用的是 Claude Code并且想让它同时走 TaoToken 的模型通道配置通常长这样放在~/.claude/settings.json或项目级.claude/settings.json{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: sk-xxxxxxxx, ANTHROPIC_MODEL: claude-sonnet-4-5 }, mcpServers: { remote-tools: { url: https://mcp.example.com/mcp, transport: http } } }这里要强调「三件套」的完整性Base URL、Key、Model ID 一个都不能少。我见过有人只填了 Base URL 和 Key忘了 Model ID结果客户端用了一个默认模型名报model not found。所以无论你用什么工具检查配置时先看这三项齐不齐。关于transport的取值不同客户端支持的枚举不完全一样常见的有stdio、sse、http、websocket。如果客户端不认websocket可以试试ws或者查一下该客户端的文档。配置写完后很多客户端需要重启才能加载新的 MCP 服务别改完就急着测先重启。还有一个细节headers里的Authorization是给 MCP 服务端做鉴权用的跟模型通道的 Key 是两回事。有些 MCP 服务不需要鉴权那就可以省略headers。但如果你的 MCP 服务部署在公网强烈建议加上鉴权否则任何人都能调用你的工具。4. 一次可复现的连通性验证从握手到工具调用配置写完怎么确认真的通了我给你一套可复现的验证动作分三步走。第一步验证传输层能连上。如果你配的是 WebSocket可以用wscat或websocat直接连npx wscat -c wss://mcp.example.com/mcp/ws -H Authorization: Bearer sk-xxxxxxxx连上后你会看到连接建立如果服务端有欢迎消息会直接打印。这一步只验证「通道通不通」不涉及 MCP 语义。第二步验证 MCP 握手。MCP 会话的第一步是initialize你可以手动发一条{ jsonrpc: 2.0, id: 1, method: initialize, params: { protocolVersion: 2024-11-05, capabilities: { tools: {} }, clientInfo: { name: ConnectivityCheck, version: 1.0.0 } } }正常返回会包含serverInfo和capabilities说明服务端认了这个客户端。如果返回错误通常是protocolVersion不匹配或鉴权失败。第三步列出并调用工具。发tools/list{ jsonrpc: 2.0, id: 2, method: tools/list, params: {} }返回里会有工具名和参数 schema。挑一个无副作用的工具调用比如加法{ jsonrpc: 2.0, id: 3, method: tools/call, params: { name: add, arguments: { a: 5, b: 3 } } }如果返回result.content[0].text是5 3 8恭喜整条链路通了传输层 → MCP 握手 → 工具调用 → 结果返回。如果你不想手动发 JSON也可以用 Python 脚本一次性跑完import asyncio import json import websockets async def check(): async with websockets.connect( wss://mcp.example.com/mcp/ws, extra_headers{Authorization: Bearer sk-xxxxxxxx} ) as ws: await ws.send(json.dumps({ jsonrpc: 2.0, id: 1, method: initialize, params: { protocolVersion: 2024-11-05, capabilities: {tools: {}}, clientInfo: {name: check, version: 1.0.0} } })) print(initialize:, await ws.recv()) await ws.send(json.dumps({ jsonrpc: 2.0, id: 2, method: tools/list, params: {} })) print(tools/list:, await ws.recv()) asyncio.run(check())跑通之后你再去客户端里用自然语言让模型调用工具比如「帮我算一下 5 加 3」模型会自己走 MCP 调用。这时候如果失败问题多半在模型通道或客户端的 MCP 集成层而不是 MCP 服务本身。5. 常见报错排查401、local proxy failed、reading choices、OAuth配 MCP 的过程中报错基本集中在几类。我按真实遇到的顺序列一下。401 Unauthorized最常见。先检查Authorization头有没有带、格式对不对Bearer后面有个空格。如果 MCP 服务端和模型通道用的是不同的 Key别搞混了。还有一种情况是 Key 过期或被禁用去控制台重新生成一个。local proxy failed / connection refused通常是本地 MCP 服务没启动或者端口写错了。stdio 类型的服务不需要端口如果你配了url却指向localhost:8000先确认那个端口上真的有服务在监听。用lsof -i :8000或netstat -an | grep 8000查一下。reading choices / choices 字段为空这个报错一般出现在模型返回层不是 MCP 层。说明模型通道返回的响应结构不符合客户端预期常见原因是 Base URL 填错导致请求打到了不兼容的端点或者 Model ID 写成了不存在的模型。回到三件套检查一遍特别是 Base URL 不要带/v1。OAuth 相关报错有些远程 MCP 服务用 OAuth 做鉴权客户端会弹浏览器授权。如果卡在回调或报invalid_client检查回调地址是否和 OAuth 应用注册的一致。这类问题跟 MCP 协议本身无关是鉴权流程的问题。Upgrade header 缺失 / websocket handshake failed如果你用了 Nginx 反代很可能是没配proxy_set_header Upgrade $http_upgrade;和proxy_set_header Connection upgrade;。这两行是 WebSocket 升级的关键缺了就会握手失败。tools/list 返回空数组说明服务端没注册任何工具或者工具注册代码没被执行。检查服务端启动日志确认工具注册那部分逻辑跑到了。排查时有个通用思路先分层再定位。传输层用wscat或curl单独测MCP 层用initialize和tools/list单独测模型层用一句简单对话单独测。三层都单独通了再合起来用问题就好找了。6. 把 MCP 接进日常开发流几个实用建议连通性验证通过只是开始真正用起来还有几个细节值得注意。第一MCP 服务的超时设置。WebSocket 是长连接如果中间有反向代理或负载均衡空闲连接可能被掐断。Nginx 里把proxy_read_timeout和proxy_send_timeout调大比如1d能减少断连。客户端侧也要看有没有心跳机制。第二工具命名要清晰。MCP 工具名会直接暴露给模型名字太模糊模型容易选错。比如add不如math_add明确query不如db_query_users明确。参数 schema 里写清楚description模型选工具时会参考。第三别把生产库直连暴露成 MCP 工具。MCP 工具一旦被模型调用执行的就是真实操作。涉及写操作、删除操作的工具要么加二次确认要么只读。这是安全底线。第四配置版本化。settings.json和.mcp.json建议纳入 Git 管理但 Key 不要提交用环境变量或本地覆盖文件。团队协作时别人 clone 下来只需要填自己的 Key 就能跑。第五模型通道和 MCP 通道分开排障。我习惯先确认模型能正常对话再确认 MCP 能tools/list最后才让模型调工具。这样任何一层出问题都能快速定位不会眉毛胡子一把抓。如果你还没开始配建议从本地 stdio 类型的 MCP 服务入手比如 filesystem server它不需要网络和鉴权最容易跑通。跑通之后再换成远程 HTTP 或 WebSocket逐步增加复杂度。模型通道这边Base URL 用https://taotoken.net/apiKey 在控制台创建Model ID 按需选三件套填齐基本就能跑起来。