ARTICLE DETAIL

资讯详情

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

AI 工具接入 MCP 的三种传输方式:stdio、SSE 与 streamable-http 怎么选

AI 工具接入 MCP 的三种传输方式:stdio、SSE 与 streamable-http 怎么选 1. 三种传输方式到底差在哪从本地脚本到远程服务的选型困惑MCPModel Context Protocol刚火起来那阵子我身边不少朋友的第一反应是「这不就是个插件协议吗」结果真上手配的时候卡在第一个问题上的不在少数配置文件里那个type字段到底该填stdio、sse还是streamable-http这三个词看着都像传输层的东西但实际用起来踩的坑完全不一样。先把概念说清楚。MCP 是让 AI 客户端比如 Claude Desktop、Cline、Cursor 这类工具去调用外部能力的一套协议而传输方式决定了「客户端怎么和 MCP 服务器说话」。你可以把它类比成打电话stdio像是两个人面对面递纸条纸条直接塞手里不经过任何中间环节sse像是你打客服电话先建立一条长连接服务器有事就顺着这条线推给你streamable-http则是更现代的做法用标准 HTTP 请求需要流式返回时就流式返回不需要就一次性给完。这三种方式适合谁简单说stdio适合本地跑的单机工具比如你自己写的一个 Python 脚本客户端直接把它当子进程拉起来sse适合早期部署在远程服务器上的服务客户端通过一个固定的 SSE 端点持续接收消息streamable-http是 MCP 官方后来主推的方案适合远程服务、需要走标准 HTTP 基础设施网关、鉴权、负载均衡的场景。我试过把同一个 MCP 服务器分别用三种方式跑起来配置文件的写法、启动命令、连通性验证步骤都不一样而且报错信息也各有各的脾气。下面我会把每种方式的配置片段、启动代码、验证方法都拆开讲最后再说说怎么用 TaoToken 统一管住 Key 和 API 通道省得每接一个服务就重新折腾一遍鉴权。2. TaoToken 前置准备统一 Key 与 API 通道别让鉴权拖后腿在讲具体配置之前得先把「鉴权」这件事理顺。MCP 服务器本身不负责管你的模型调用额度它只是个能力提供方。真正去调模型、去跑推理的还是背后的 API 通道。如果你每个 MCP 服务都单独配一套 Key时间长了就是一团乱麻这个 Key 过期了、那个 Key 额度用完了、换个模型又要改配置。TaoToken 在这里的角色就是把这些分散的鉴权收拢到一个地方。你只需要在 TaoToken 控制台生成一个 API Key然后在各个 MCP 客户端或服务器里统一引用这个 Key模型调用就走同一条通道。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 。具体操作上先去控制台创建一个 API Key路径是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 然后在 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 生成并保存好。这个 Key 后面会出现在你的 MCP 配置里作为环境变量传给服务器进程。这里有个关键点MCP 的三种传输方式鉴权的位置是不一样的。stdio方式下服务器是本地子进程Key 通常通过环境变量注入sse和streamable-http方式下服务器在远程Key 要么放在请求头里要么放在 URL 参数里具体看服务器实现。TaoToken 的好处是不管你用哪种传输方式模型调用的出口都是同一个 API 端点你只需要保证这个 Key 在服务器进程里能读到就行。如果你还没决定用哪个模型可以先到模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 试一下确认通道能通、模型能回再去配 MCP。长期做编码或 Agent 的话Coding Plan 页面 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 有更细的套餐说明这里不展开。配置文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 遇到参数不确定的时候翻一下比瞎猜快。3. 可复制配置stdio、SSE、streamable-http 三套片段这一节直接给配置。我按三种传输方式分别写你可以对照自己的场景抄。注意不同客户端的配置文件路径不一样Claude Desktop 在claude_desktop_config.jsonCline 在它自己的 MCP 设置里但字段结构大同小异。3.1 stdio 配置本地子进程方式stdio的核心是客户端把服务器当子进程启动通过标准输入输出通信。配置文件里要写command和args告诉客户端怎么把进程拉起来。{ mcpServers: { example-server02: { name: MCP 服务器2, type: stdio, isActive: true, command: uv, args: [ --directory, D:\\workspace\\mcpserver, run, main.py ], env: { TAOTOKEN_API_KEY: 你的_TaoToken_Key, TAOTOKEN_BASE_URL: https://taotoken.net/api } } } }这里command用的是uvargs里先--directory切到项目目录再run main.py。如果你不用 uv换成python也行但 uv 的好处是依赖隔离不会污染全局环境。env字段是关键TaoToken 的 Key 和 Base URL 通过环境变量传进去服务器代码里用os.environ读就行。服务器端代码用 FastMCP 写启动时指定transportstdioimport logging import os from typing import Final from mcp.server.fastmcp import FastMCP logging.basicConfig( levellogging.INFO, format%(asctime)s - %(name)s - %(levelname)s - %(message)s ) logger: Final logging.getLogger(__name__) mcp: FastMCP FastMCP(Demo, json_responseTrue) mcp.tool() def add(a: int, b: int) - int: 计算两个数相加的结果 return a b mcp.resource(greeting://{name}) def get_greeting(name: str) - str: Return a greeting message for the given name return fHello, {name}! def main(): try: logger.info(正在启动 MCP stdio 服务器...) mcp.run(transportstdio) except KeyboardInterrupt: logger.info(接收到中断信号正在关闭服务器...) except Exception as e: logger.error(f服务器运行时发生错误: {str(e)}, exc_infoTrue) raise finally: logger.info(服务器已关闭) if __name__ __main__: main()启动就是python main.py但注意stdio方式下你直接在终端跑是看不到输出的因为它等的是标准输入。要测试的话得用客户端去拉或者用echo管道模拟一条 JSON-RPC 消息。3.2 SSE 配置长连接推送方式sse方式下服务器先跑起来监听一个端口客户端通过 URL 连过去。配置里写url就行不需要command。{ mcpServers: { walkerAPI-mcp: { name: MCP SSE 服务器, url: http://127.0.0.1:8000/sse, disabled: false, autoApprove: [] } } }服务器端代码把transport改成ssedef main(): try: logger.info(正在启动 MCP SSE 服务器...) mcp.settings.host 0.0.0.0 mcp.settings.port 8000 mcp.run(transportsse) except KeyboardInterrupt: logger.info(接收到中断信号正在关闭服务器...) except Exception as e: logger.error(f服务器运行时发生错误: {str(e)}, exc_infoTrue) raise finally: logger.info(服务器已关闭)启动后服务器会在http://0.0.0.0:8000/sse上等连接。SSE 的特点是服务器可以主动推消息给客户端适合需要实时通知的场景。但它的缺点是连接容易断断了要重连而且有些网关对长连接不友好。3.3 streamable-http 配置标准 HTTP 流式方式streamable-http是 MCP 官方现在推荐的远程传输方式。配置里也是写url但路径通常是/mcp。{ mcpServers: { custom-streamable-http: { name: 自定义流式HTTP服务器, type: streamable-http, url: http://127.0.0.1:8000/mcp, autoApprove: [] } } }服务器端代码def main(): try: logger.info(正在启动 MCP streamable-http 服务器...) mcp.settings.host 0.0.0.0 mcp.settings.port 8000 mcp.run(transportstreamable-http) except KeyboardInterrupt: logger.info(接收到中断信号正在关闭服务器...) except Exception as e: logger.error(f服务器运行时发生错误: {str(e)}, exc_infoTrue) raise finally: logger.info(服务器已关闭)streamable-http的好处是它走标准 HTTP可以过网关、可以加鉴权头、可以做负载均衡。如果你要把 MCP 服务器部署到远程这是首选。三种方式的配置差异我用表格对照一下维度stdioSSEstreamable-http通信方式标准输入输出长连接推送标准 HTTP 流式服务器位置本地子进程远程或本地远程或本地配置字段command argsurlurl type鉴权方式环境变量请求头或 URL请求头适合场景单机工具实时推送远程服务4. 验证请求从启动到拿到「1加3等于4」配置写完得验证能不能通。三种方式的验证步骤不一样我一个个说。4.1 stdio 验证stdio方式下服务器是被客户端拉起来的你没法直接 curl。最简单的验证方法是写一个测试脚本用 MCP 的客户端库去连import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def test_stdio(): server_params StdioServerParameters( commanduv, args[--directory, D:\\workspace\\mcpserver, run, main.py], env{TAOTOKEN_API_KEY: 你的_TaoToken_Key} ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() result await session.call_tool(add, {a: 1, b: 3}) print(result) asyncio.run(test_stdio())跑出来应该看到4。如果卡住不动多半是服务器启动失败去看日志。4.2 SSE 验证sse方式下服务器先跑起来然后你可以用 curl 测端点curl -N http://127.0.0.1:8000/sse-N是禁用缓冲这样你能看到流式输出。如果连上了会看到服务器推过来的事件。然后在客户端里发消息「计算两个数相加的结果1加3等于几」正常的话会返回4。4.3 streamable-http 验证streamable-http用 curl 测curl -X POST http://127.0.0.1:8000/mcp \ -H Content-Type: application/json \ -H Authorization: Bearer 你的_TaoToken_Key \ -d {jsonrpc:2.0,method:tools/call,params:{name:add,arguments:{a:1,b:3}},id:1}返回的 JSON 里应该有result: 4。注意Authorization头这是 TaoToken 的 Key服务器收到后转发给模型通道。三种方式验证通过后你在客户端里发「计算两个数相加的结果1加3等于几」都应该看到思考过程和结果4。如果结果不对先检查工具注册有没有成功再看参数名对不对。5. 常见报错排查401、local proxy failed、reading choices、OAuth配 MCP 的时候报错信息往往很隐晦。我把几个高频错误列出来对照着查。401 Unauthorized这个最常见基本就是 Key 没传对。检查三件事Key 是不是复制全了有时候末尾有空格、环境变量名是不是和代码里读的一致、请求头格式对不对Bearer后面有个空格。如果是streamable-http确认Authorization头加上了如果是stdio确认env字段传进去了。local proxy failed这个通常出现在sse或streamable-http方式下客户端连不上服务器。先确认服务器进程还在跑netstat -an | grep 8000看端口有没有监听。如果服务器在远程检查防火墙和端口映射。还有一种情况是客户端配的 URL 路径不对sse是/ssestreamable-http是/mcp别写反了。reading choices 相关报错这个多半是模型返回格式和客户端预期不一致。检查 TaoToken 的 Base URL 是不是https://taotoken.net/api有些客户端要求末尾不带斜杠有些要求带试一下。另外确认模型 ID 写对了别把gpt-4写成gpt4。OAuth 报错如果你用的是 Claude Code 或类似工具可能会遇到 OAuth 流程问题。Claude Code 的配置在~/.claude/settings.json或项目里的.claude/settings.json需要写全三件套Base URL、Key、Model ID。Base URL 用https://taotoken.net/apiKey 用 TaoToken 生成的Model ID 按你实际用的填。如果 OAuth 卡住先检查网络能不能通到 TaoToken 端点再看 Key 有没有过期。还有一个坑是uv的路径问题。stdio配置里command写uv但客户端可能找不到uv的可执行文件因为 PATH 不一样。解决办法是写绝对路径比如/Users/你的用户名/.local/bin/uv或C:\\Users\\你的用户名\\.local\\bin\\uv.exe。如果报错信息里出现MCP error -32000那是连接层面的问题先确认服务器进程活着再确认传输方式选对了。stdio配成sse的 URL或者反过来都会报这个。6. 按场景选传输方式用 TaoToken 统一收口最后说说怎么选。我的经验是看三个维度服务器在哪、要不要实时推送、有没有网关需求。服务器在本地、就是个单机脚本选stdio。配置简单不用管端口进程生命周期跟着客户端走客户端关了服务器也关了干净。服务器在远程、需要服务器主动推消息选sse。但要注意长连接的稳定性网络抖动容易断断了要重连。如果你的场景对实时性要求没那么高其实streamable-http也能凑合。服务器在远程、要走标准 HTTP 基础设施选streamable-http。这是官方主推的方向能过网关、能加鉴权、能做负载均衡部署到云上最省心。不管选哪种TaoToken 的 Key 和 API 通道都是统一的。你只需要在 TaoToken 控制台生成一个 Key然后在各个 MCP 服务器的环境变量或请求头里引用它。模型调用的出口都是https://taotoken.net/api换模型、调额度都在一个地方管。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 配置片段和参数说明都有。如果你还没生成 Key去 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 创建一个。想先试试模型通不通到 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 发条消息。长期做编码或 Agent 的话https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 有套餐说明。配的时候记住一个原则先让服务器单独跑通再配客户端。服务器跑不起来客户端配得再对也没用。启动命令在终端里跑一遍看到日志输出正常再去改配置文件。这样出问题的时候你能快速定位是服务器的问题还是客户端的问题。
返回列表