1. 从 stdio 到 Streamable HTTP一个 MCP 服务到底怎么跑起来MCPModel Context Protocol说白了就是给 AI 客户端装外设的协议。你写一个 Server把本地能力查数据库、读文件、调内部 API暴露成 ToolCursor、Cline、Claude Desktop 这些 Host 就能通过统一的 JSON-RPC 调它。它解决的问题很具体以前每接一个 AI 客户端就要写一套适配现在写一次 Server多个客户端复用。这篇面向想让本地工具被 AI 客户端调用的开发者目标很明确——用官方 SDK 从零搭一个 MCP 服务先跑通 stdio再切到 Streamable HTTP最后用 Cline MCP 这类客户端连上并成功调用工具。全程给可复制的代码和配置不空谈概念。先分清三个角色不然后面配置容易懵。Host 是用户面对的应用持有模型和授权 UI比如 Cursor、Claude DesktopClient 是 Host 内部跟某一个 Server 的 1:1 连接Server 就是你要开发的那一端。模型不会直接打你的 API流程是模型想用工具 → Host 调 Client → Client 用 JSON-RPC 问 Server → 结果回给模型。Server 能提供的能力有 Tools、Resources、Prompts、Sampling、Roots多数 Server 只实现一部分就够。对 Agent 来说Tool 的 description 几乎决定它会不会被正确调用所以写清楚做什么、不做什么、何时用、参数含义比代码本身还重要。传输方式选型也简单stdio 适合本地开发和桌面/CLI标准输入输出最快上手日志只能打 stderrStreamable HTTP 适合远程、多人、生产是当前推荐的远程方案老的 HTTP SSE 已弃用新项目别用。建议路径是先做 stdio 跑通用 Inspector 测工具再切 HTTP 上线。2. 前置准备SDK 选型、环境与 TaoToken 接入动手前先把 SDK 和环境定下来。TypeScript 用modelcontextprotocol/sdk生态最全Python 用mcp加 FastMCP对数据脚本和内部工具友好。我这边用 Python 演示因为类型注解和 docstring 能自动变成 tool schema少写一堆样板。环境初始化用 uv干净利落uv init weather cd weather uv venv source .venv/bin/activate uv add mcp[cli] httpx如果你打算让 Server 内部去调大模型比如做 Sampling 或者自己封装一个智能工具这里就涉及模型接入。我用 TaoToken 做统一入口它的 API 地址是https://taotoken.net/api兼容常见调用方式Key 在控制台生成。模型对话入口在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite API Keys 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。长期跑编码类 Agent 的话Coding Plan 在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。先把 Key 放进环境变量别硬编码export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api定义工具表面这一步别跳过。先列清楚要暴露哪些 tool、名字和参数是什么、哪些只读哪些会改数据、错误时返回什么让模型能自己修正。设计完再写代码返工少一半。3. 可复制配置stdio 与 Streamable HTTP 两套写法先写最小 Server。FastMCP 的写法很直观类型注解和 docstring 直接变成 schemafrom mcp.server.fastmcp import FastMCP mcp FastMCP(weather) mcp.tool() async def get_alerts(state: str) - str: Get weather alerts for a US state. Args: state: Two-letter US state code (e.g. CA, NY) return fAlerts for {state}: ... if __name__ __main__: mcp.run() # 默认 stdiostdio 模式下客户端配置就是写启动命令。以 Cline MCP 或 Cursor 为例配置片段长这样{ mcpServers: { weather: { command: uv, args: [--directory, /绝对路径/weather, run, weather.py] } } }切到 Streamable HTTP 时Server 端改成监听端口if __name__ __main__: mcp.run(transportstreamable-http, host0.0.0.0, port8000)客户端配置随之变成 URL 形式单端点如/mcp{ mcpServers: { weather-http: { url: http://127.0.0.1:8000/mcp } } }如果你用 Codex 的auth.json或 Cline MCP 这类需要显式声明模型的地方三件套要写全Base URL 填https://taotoken.net/apiKey 填你的TAOTOKEN_API_KEYModel ID 按你选的模型填。缺一个都会在连接阶段报错。stdio 有个硬规矩绝不能污染 stdout。print()默认写 stdout会毁掉 JSON-RPCServer 会「莫名挂掉」。日志一律走 stderr 或 logging。这个坑我踩过排查了半天才发现是一行调试 print。4. 验证请求Inspector 自测与客户端调用成功结果别一上来就接 Agent先用 Inspector 自测。它能列出所有 tool、展示 schema、逐个调用比在对话里猜失败原因快得多npx modelcontextprotocol/inspector python weather.py # 或 npx modelcontextprotocol/inspector node ./dist/server.js打开 UI 后你应该能看到get_alerts这个 tool参数state是 string 类型description 就是 docstring 的内容。手动传CA调用返回Alerts for CA: ...说明 Server 本身没问题。stdio 验证通过后重启客户端Cline、Cursor 等在对话里让它调用这个 tool。成功的标志是客户端能识别到 Server 的 tools模型在需要时主动发起调用结果正确回填到对话里。如果模型不调八成是 description 太虚回去改文案。Streamable HTTP 的验证类似先确认端口通了curl -i http://127.0.0.1:8000/mcp再在客户端里用 URL 配置连接重复上面的调用流程。远程部署时记得加鉴权公开端点无鉴权等于把内部能力暴露到公网推荐 OAuth 2.1 PKCE内网可以用 Bearer 或 mTLS。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth排错时先看报错落在哪一层协议层和业务层要分开。401 Unauthorized多半是 Key 没传对或没带上。检查环境变量是否生效客户端配置里 Base URL 和 Key 是否写全。用 TaoToken 的话确认TAOTOKEN_BASE_URL是https://taotoken.net/apiKey 从 API Keys 页面重新生成一次排除复制错误。local proxy failed通常是本地端口没起来或地址写错。stdio 模式检查启动命令路径是否为绝对路径HTTP 模式确认host和port跟客户端 URL 一致防火墙别挡。reading choices类报错一般是返回结构不符合预期常见于 Server 内部调模型时响应格式没对齐。检查你解析响应的字段路径确认模型返回的是标准结构。OAuth相关失败远程端点开了鉴权但客户端没配 token或者回调地址不匹配。先在内网用 Bearer 跑通再上 OAuth 2.1 PKCE别一步到位。还有一个高频坑一个 Server 塞几十个弱相关 tool导致模型选型混乱。拆成多个聚焦 Server 更好。tool 名是公开 API可增不可乱改名重命名等于破坏性变更。6. 从玩具到生产上线前的收尾与接入入口本地跑通只是第一步。上生产要补几件事单独开/healthz做健康检查TLS 在反向代理终止打 latency 和错误率日志但慎打入参可能含敏感信息。默认做成无状态 HTTP 更易水平扩展只有需要服务端推送或断线续传时再上有状态 session。如果你要把这个 Server 接到编码类 Agent 长期跑Coding Plan 在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。需要生成和管理 Key 去 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 完整接入步骤看 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 想先验证模型效果可以直接在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 对话测试。Claude Code 相关接入参考 https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。最后提醒一句Skill 和 MCP 容易混。Skill 是 Markdown 说明书教 Agent「怎么做」MCP 是独立进程或远程服务给 Agent「能调用的真工具」。复杂场景两者一起用Skill 规定何时调用哪些 MCP tools。先把 stdio 跑通再用 Inspector 验证最后切 Streamable HTTP 上线这条路径最稳。