☰
MCP服务 SSE / Streamable HTTP 两种传输机制下,如何用 http 请求查询工具列表并调用工具(TaoToken 统一通道实践)
2026/10/8 12:16:59 网站建设 项目流程

1. 从一次抓包说起:MCP 的 SSE 与 Streamable HTTP 到底差在哪

MCP(Model Context Protocol)是让大模型调用外部工具的协议,它本身不规定传输层,只规定消息格式——JSON-RPC 2.0。真正决定你 HTTP 请求怎么写、响应怎么读的,是底下那层传输机制。目前主流两种:SSE(Server-Sent Events)和 Streamable HTTP。

我最早接触时也懵:同样是 POST 一个 JSON-RPC 请求,为什么有的服务返回一坨 JSON,有的却吐出一串event: message开头的流?后来把两种都抓包对比才明白,差别集中在三处:请求头 Accept、会话标识(session id)、响应体的解析方式。

先说 SSE 模式。这是 MCP 早期最常用的传输。客户端先发一个 GET 请求建立长连接,服务端用text/event-stream持续推消息;后续的 JSON-RPC 请求通过 POST 发到同一个 endpoint,响应不一定直接回在 POST 的 body 里,而是从那条 SSE 长连接里推回来。所以你会看到 POST 返回 202 或者一个空 body,真正的结果在流里。这种模式对服务端友好(一条连接复用),但对纯 HTTP 调试不友好——你得同时维持两条通道。

Streamable HTTP 是后来演进出来的。它把请求和响应收敛到单次 HTTP 往返:你 POST 一个 JSON-RPC,服务端可以直接用application/json回你完整结果,也可以按需升级成text/event-stream流式返回。对调试者来说,绝大多数情况下一次 curl 就能拿到答案,不用再挂着长连接。这也是为什么现在很多 MCP 服务默认走 Streamable HTTP。

理解这个差异,你才能看懂为什么同一份tools/list请求,在两种模式下要配不同的 Accept 头、要不要带Mcp-Session-Id、返回的 body 该按 JSON 解析还是按 SSE 逐行解析。这篇就按「先查工具列表,再调工具」的顺序,把两种传输的 HTTP 请求都跑一遍,配置直接可复制。

适合谁看:想搞懂 MCP 底层原理、想用纯 HTTP 手搓调用、或者在做 MCP 客户端接入时被传输层卡住的开发者。核心检索词就三个——MCP、SSE、Streamable HTTP,加上 JSON-RPC 的 tools/list 和 tools/call 两个方法。

2. 前置准备:用 TaoToken 统一通道拿 Key 与 Base URL

在动手写请求前,得先有个能稳定访问的 MCP 通道。自己搭 MCP 服务、处理鉴权和网络,对只想验证协议的人来说太重。我这边用的是 TaoToken 的统一通道,它把模型对话、编码 Agent、MCP 接入收敛到一套 Base URL 和 Key 上,省去每个服务单独配鉴权的麻烦。

先拿 Key。打开控制台,登录后在 API Keys 页面创建一个新 Key。建议按用途命名,比如mcp-debug,方便后面区分。创建后立刻复制保存,页面刷新后就看不到完整 Key 了。

  • 控制台入口:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite
  • API Keys 页面:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite

拿到 Key 后,统一通道的 Base URL 是:

https://taotoken.net/api

注意这个地址不带任何查询参数,鉴权靠请求头里的Authorization: Bearer <你的Key>。MCP 的 JSON-RPC 请求就 POST 到这个 Base URL 下的对应路径。

这里有个容易踩的坑:MCP 服务和普通 REST 不一样,它的 endpoint 往往需要显式声明传输类型。在 TaoToken 通道里,你可以在路径上区分,比如走 Streamable HTTP 用/api/mcp,走 SSE 用/api/mcp/sse。具体路径以接入文档为准,别硬编码猜。

  • 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite

如果你只是想先验证模型侧能不能通,可以顺手在模型对话页发一条消息确认 Key 有效:

  • 模型对话:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=chat&utm_campaign=rewrite

Key 和 Base URL 都齐了,下面进入正题。我会先给 Streamable HTTP 的完整配置(因为它一次请求就能出结果,最适合入门),再给 SSE 的配置,最后对比两者的请求头差异。

3. 可复制配置:tools/list 与 tools/call 的完整请求

这一节给的是能直接粘贴运行的配置。先明确 JSON-RPC 2.0 的四个标准字段,这是两种传输共用的:

  • jsonrpc: "2.0":声明协议版本,固定值。
  • id:请求唯一编号,用来把响应和请求配对。数字或字符串都行,同一会话里别重复。
  • method:要执行的方法,查工具列表是tools/list,调工具是tools/call。
  • params:方法参数。tools/list传空对象{};tools/call里放name和arguments。

3.1 Streamable HTTP 模式配置

Streamable HTTP 下,一次 POST 就能拿到结果。请求头关键是Accept要同时接受 JSON 和事件流,Content-Type固定application/json。

curl --location --request POST 'https://taotoken.net/api/mcp' \ --header 'Authorization: Bearer sk-你的Key' \ --header 'Content-Type: application/json' \ --header 'Accept: application/json, text/event-stream' \ --data-raw '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} }'

如果服务端要求会话,第一次响应头里会带Mcp-Session-Id,后续请求把它带上:

curl --location --request POST 'https://taotoken.net/api/mcp' \ --header 'Authorization: Bearer sk-你的Key' \ --header 'Content-Type: application/json' \ --header 'Accept: application/json, text/event-stream' \ --header 'Mcp-Session-Id: 上一步返回的会话ID' \ --data-raw '{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "maps_weather", "arguments": { "city": "北京" } } }'

对应的客户端配置片段(以常见的 MCP 客户端 settings 为例),三件套 Base URL、Key、Model ID 都要写全:

{ "mcpServers": { "taotoken-streamable": { "type": "streamable-http", "url": "https://taotoken.net/api/mcp", "headers": { "Authorization": "Bearer sk-你的Key", "Accept": "application/json, text/event-stream" } } } }

3.2 SSE 模式配置

SSE 模式要两步。先建立事件流连接,再发 JSON-RPC 请求。第一步用 GET:

curl --location --request GET 'https://taotoken.net/api/mcp/sse' \ --header 'Authorization: Bearer sk-你的Key' \ --header 'Accept: text/event-stream'

这条连接会挂住,服务端会先推一个endpoint事件,告诉你后续 POST 往哪发。拿到 endpoint 后再发请求:

curl --location --request POST 'https://taotoken.net/api/mcp/message?sessionId=xxx' \ --header 'Authorization: Bearer sk-你的Key' \ --header 'Content-Type: application/json' \ --data-raw '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} }'

注意 SSE 模式下 POST 的响应通常是 202 Accepted,body 为空,真正的结果从那条 GET 事件流里推回来。所以调试时你得开两个终端,一个挂着 GET,一个发 POST。

对应的 settings 片段:

{ "mcpServers": { "taotoken-sse": { "type": "sse", "url": "https://taotoken.net/api/mcp/sse", "headers": { "Authorization": "Bearer sk-你的Key" } } } }

两种模式的请求头差异,用表格对照更清楚:

维度Streamable HTTPSSE
建连方式单次 POSTGET 建流 + POST 发消息
Acceptapplication/json, text/event-streamGET 用text/event-stream
会话标识响应头Mcp-Session-IdURL 参数sessionId
响应位置POST 的 bodyGET 事件流
调试难度低,一次往返高,需双通道

4. 验证请求:从返回结果确认工具列表与调用成功

配置写完,得验证真的通了。先看tools/list的返回。Streamable HTTP 模式下,如果服务端用 JSON 回,你会拿到类似这样的结构:

{ "jsonrpc": "2.0", "id": 1, "result": { "tools": [ { "name": "maps_weather", "description": "根据城市名称查询天气", "inputSchema": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } }, { "name": "maps_regeocode", "description": "根据经纬度反查地址", "inputSchema": { "type": "object", "properties": { "location": { "type": "string" } }, "required": ["location"] } } ] } }

看到result.tools数组,就说明工具列表查通了。数组里每个元素的name就是后面tools/call要用的工具名,inputSchema告诉你这个工具需要哪些参数、哪些必填。这一步很关键——很多人调工具报参数错误,就是因为没先看inputSchema就瞎传。

如果服务端用事件流回,你会看到这样的行:

event: message data: {"jsonrpc":"2.0","id":1,"result":{"tools":[...]}}

解析时按data:前缀逐行取,把后面的 JSON 拼起来解析即可。注意 SSE 的 data 可能跨多行,要按空行分隔事件块。

再看tools/call的返回。调用天气工具成功后:

{ "jsonrpc": "2.0", "id": 3, "result": { "content": [ { "type": "text", "text": "北京:晴,气温 12-24℃,东南风 3 级" } ] } }

result.content是数组,每项有type和对应内容。文本类工具返回type: "text",图片类会返回type: "image"带 base64。判断调用成功,就看有没有result字段且content非空;如果返回的是error字段,那就是失败了,往下看排障。

反查地址的工具同理,传经纬度:

curl --location --request POST 'https://taotoken.net/api/mcp' \ --header 'Authorization: Bearer sk-你的Key' \ --header 'Content-Type: application/json' \ --header 'Accept: application/json, text/event-stream' \ --data-raw '{ "jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": { "name": "maps_regeocode", "arguments": { "location": "116.397128,39.916527" } } }'

返回里content[0].text就是解析出的地址。验证动作建议按这个顺序:先tools/list确认工具名,再挑一个参数最简单的工具tools/call,最后对照inputSchema检查自己传的参数类型对不对。三步都过,说明通道和协议都没问题。

5. 常见报错排查:401、local proxy failed 与 reading choices

调试 MCP 时踩的坑基本集中在几个固定报错上,逐个对照。

401 Unauthorized。最常见,九成是 Key 的问题。检查三处:Authorization头是不是Bearer开头(注意 Bearer 后有空格);Key 有没有复制全(前后别带空格);Key 是不是被删了或过期。如果用的是 SSE 模式,GET 建流和 POST 发消息两个请求都要带 Key,漏一个就 401。

local proxy failed / connection refused。这个报错通常出现在客户端侧,不是服务端返回的。意思是客户端连不上你配的 Base URL。排查:URL 是不是写成了https://taotoken.net/api/mcp而漏了协议或路径;本地网络能不能正常访问该域名;如果客户端走本地代理,代理配置有没有把该域名排除。注意别把代理和某些网络工具混为一谈,这里说的只是常规 HTTP 代理设置。

reading choices / unexpected end of JSON input。这类是响应解析错误。Streamable HTTP 模式下,如果服务端实际返回的是事件流,而你按纯 JSON 解析,就会报这个。解决办法是看响应头Content-Type:是application/json就按 JSON 解析,是text/event-stream就按 SSE 逐行解析。别硬套一种解析方式。

OAuth / 鉴权跳转相关报错。有些 MCP 服务要求 OAuth 流程,返回 302 跳转到授权页。如果你用的是统一通道的 Key 鉴权,正常不会触发;一旦看到跳转,先确认请求头里的鉴权方式对不对,别把 Key 鉴权和 OAuth 混用。

tools/call 报 method not found 或 tool not found。多半是工具名写错了。回去跑一遍tools/list,把name字段原样复制,别自己猜。参数名也要和inputSchema.properties里的键完全一致,大小写敏感。

SSE 模式 POST 返回 202 但拿不到结果。这是正常的,结果在 GET 流里。检查你的 GET 连接是不是还活着——有些客户端会在 POST 后误关 GET 连接,导致结果推不过来。保持 GET 常驻,直到收到对应id的响应再关。

排查时有个通用技巧:加-v参数看完整请求响应头。

curl -v --location --request POST 'https://taotoken.net/api/mcp' \ --header 'Authorization: Bearer sk-你的Key' \ --header 'Content-Type: application/json' \ --header 'Accept: application/json, text/event-stream' \ --data-raw '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

响应头里的Content-Type、Mcp-Session-Id、状态码,基本能定位大部分问题。

6. 把两种传输用对场景:长期编码与 Agent 接入的选择

搞懂两种传输后,选哪个其实看场景。纯调试、写脚本、做一次性调用,Streamable HTTP 更省事,一次 POST 出结果,不用维护长连接。做长期编码 Agent、需要服务端主动推消息、或者客户端本身支持 SSE 长连接复用,那 SSE 更合适。

如果你打算把 MCP 接进编码工作流,比如让 Agent 长期挂着调用工具,建议走 Coding Plan,它把编码场景的额度和通道都配好了,不用每次手动拼请求:

  • Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite

Claude Code 这类工具接入时,配置里同样要写全三件套——Base URL、Key、Model ID,缺一个都连不上。Anthropic 兼容接入的说明在这里:

  • Claude Code 接入:https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claude-code-anthropic&utm_campaign=rewrite

最后给个实操建议:调试阶段先用 Streamable HTTP 把tools/list和tools/call跑通,确认工具名和参数都对;等逻辑没问题了,再按需切到 SSE 做长连接。别一上来就啃 SSE 的双通道,容易在解析上卡半天。工具列表和调用参数这两步验证过,后面接任何 MCP 客户端都是同一套 JSON-RPC 结构,换汤不换药。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询