發(fā) MCP 服務(wù):從 stdio 到 Streamable HTTP 的 SDK 實(shí)戰(zhàn)大綱)
1. 從 stdio 到 Streamable HTTP一個(gè) MCP 服務(wù)到底怎么跑起來(lái)MCPModel Context Protocol說(shuō)白了就是給 AI 客戶端裝外設(shè)的協(xié)議。你寫一個(gè) Server把本地能力查數(shù)據(jù)庫(kù)、讀文件、調(diào)內(nèi)部 API暴露成 ToolCursor、Cline、Claude Desktop 這些 Host 就能通過(guò)統(tǒng)一的 JSON-RPC 調(diào)它。它解決的問(wèn)題很具體以前每接一個(gè) AI 客戶端就要寫一套適配現(xiàn)在寫一次 Server多個(gè)客戶端復(fù)用。這篇面向想讓本地工具被 AI 客戶端調(diào)用的開(kāi)發(fā)者目標(biāo)很明確——用官方 SDK 從零搭一個(gè) MCP 服務(wù)先跑通 stdio再切到 Streamable HTTP最后用 Cline MCP 這類客戶端連上并成功調(diào)用工具。全程給可復(fù)制的代碼和配置不空談概念。先分清三個(gè)角色不然后面配置容易懵。Host 是用戶面對(duì)的應(yīng)用持有模型和授權(quán) UI比如 Cursor、Claude DesktopClient 是 Host 內(nèi)部跟某一個(gè) Server 的 1:1 連接Server 就是你要開(kāi)發(fā)的那一端。模型不會(huì)直接打你的 API流程是模型想用工具 → Host 調(diào) Client → Client 用 JSON-RPC 問(wèn) Server → 結(jié)果回給模型。Server 能提供的能力有 Tools、Resources、Prompts、Sampling、Roots多數(shù) Server 只實(shí)現(xiàn)一部分就夠。對(duì) Agent 來(lái)說(shuō)Tool 的 description 幾乎決定它會(huì)不會(huì)被正確調(diào)用所以寫清楚做什么、不做什么、何時(shí)用、參數(shù)含義比代碼本身還重要。傳輸方式選型也簡(jiǎn)單stdio 適合本地開(kāi)發(fā)和桌面/CLI標(biāo)準(zhǔn)輸入輸出最快上手日志只能打 stderrStreamable HTTP 適合遠(yuǎn)程、多人、生產(chǎn)是當(dāng)前推薦的遠(yuǎn)程方案老的 HTTP SSE 已棄用新項(xiàng)目別用。建議路徑是先做 stdio 跑通用 Inspector 測(cè)工具再切 HTTP 上線。2. 前置準(zhǔn)備SDK 選型、環(huán)境與 TaoToken 接入動(dòng)手前先把 SDK 和環(huán)境定下來(lái)。TypeScript 用modelcontextprotocol/sdk生態(tài)最全Python 用mcp加 FastMCP對(duì)數(shù)據(jù)腳本和內(nèi)部工具友好。我這邊用 Python 演示因?yàn)轭愋妥⒔夂?docstring 能自動(dòng)變成 tool schema少寫一堆樣板。環(huán)境初始化用 uv干凈利落uv init weather cd weather uv venv source .venv/bin/activate uv add mcp[cli] httpx如果你打算讓 Server 內(nèi)部去調(diào)大模型比如做 Sampling 或者自己封裝一個(gè)智能工具這里就涉及模型接入。我用 TaoToken 做統(tǒng)一入口它的 API 地址是https://taotoken.net/api兼容常見(jiàn)調(diào)用方式Key 在控制臺(tái)生成。模型對(duì)話入口在 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 。長(zhǎng)期跑編碼類 Agent 的話Coding Plan 在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。先把 Key 放進(jìn)環(huán)境變量別硬編碼export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api定義工具表面這一步別跳過(guò)。先列清楚要暴露哪些 tool、名字和參數(shù)是什么、哪些只讀哪些會(huì)改數(shù)據(jù)、錯(cuò)誤時(shí)返回什么讓模型能自己修正。設(shè)計(jì)完再寫代碼返工少一半。3. 可復(fù)制配置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() # 默認(rèn) stdiostdio 模式下客戶端配置就是寫啟動(dòng)命令。以 Cline MCP 或 Cursor 為例配置片段長(zhǎng)這樣{ mcpServers: { weather: { command: uv, args: [--directory, /絕對(duì)路徑/weather, run, weather.py] } } }切到 Streamable HTTP 時(shí)Server 端改成監(jiān)聽(tīng)端口if __name__ __main__: mcp.run(transportstreamable-http, host0.0.0.0, port8000)客戶端配置隨之變成 URL 形式單端點(diǎn)如/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 按你選的模型填。缺一個(gè)都會(huì)在連接階段報(bào)錯(cuò)。stdio 有個(gè)硬規(guī)矩絕不能污染 stdout。print()默認(rèn)寫 stdout會(huì)毀掉 JSON-RPCServer 會(huì)「莫名掛掉」。日志一律走 stderr 或 logging。這個(gè)坑我踩過(guò)排查了半天才發(fā)現(xiàn)是一行調(diào)試 print。4. 驗(yàn)證請(qǐng)求Inspector 自測(cè)與客戶端調(diào)用成功結(jié)果別一上來(lái)就接 Agent先用 Inspector 自測(cè)。它能列出所有 tool、展示 schema、逐個(gè)調(diào)用比在對(duì)話里猜失敗原因快得多npx modelcontextprotocol/inspector python weather.py # 或 npx modelcontextprotocol/inspector node ./dist/server.js打開(kāi) UI 后你應(yīng)該能看到get_alerts這個(gè) tool參數(shù)state是 string 類型description 就是 docstring 的內(nèi)容。手動(dòng)傳CA調(diào)用返回Alerts for CA: ...說(shuō)明 Server 本身沒(méi)問(wèn)題。stdio 驗(yàn)證通過(guò)后重啟客戶端Cline、Cursor 等在對(duì)話里讓它調(diào)用這個(gè) tool。成功的標(biāo)志是客戶端能識(shí)別到 Server 的 tools模型在需要時(shí)主動(dòng)發(fā)起調(diào)用結(jié)果正確回填到對(duì)話里。如果模型不調(diào)八成是 description 太虛回去改文案。Streamable HTTP 的驗(yàn)證類似先確認(rèn)端口通了curl -i http://127.0.0.1:8000/mcp再在客戶端里用 URL 配置連接重復(fù)上面的調(diào)用流程。遠(yuǎn)程部署時(shí)記得加鑒權(quán)公開(kāi)端點(diǎn)無(wú)鑒權(quán)等于把內(nèi)部能力暴露到公網(wǎng)推薦 OAuth 2.1 PKCE內(nèi)網(wǎng)可以用 Bearer 或 mTLS。5. 本篇常見(jiàn)錯(cuò)排查401、local proxy failed、reading choices、OAuth排錯(cuò)時(shí)先看報(bào)錯(cuò)落在哪一層協(xié)議層和業(yè)務(wù)層要分開(kāi)。401 Unauthorized多半是 Key 沒(méi)傳對(duì)或沒(méi)帶上。檢查環(huán)境變量是否生效客戶端配置里 Base URL 和 Key 是否寫全。用 TaoToken 的話確認(rèn)TAOTOKEN_BASE_URL是https://taotoken.net/apiKey 從 API Keys 頁(yè)面重新生成一次排除復(fù)制錯(cuò)誤。local proxy failed通常是本地端口沒(méi)起來(lái)或地址寫錯(cuò)。stdio 模式檢查啟動(dòng)命令路徑是否為絕對(duì)路徑HTTP 模式確認(rèn)host和port跟客戶端 URL 一致防火墻別擋。reading choices類報(bào)錯(cuò)一般是返回結(jié)構(gòu)不符合預(yù)期常見(jiàn)于 Server 內(nèi)部調(diào)模型時(shí)響應(yīng)格式?jīng)]對(duì)齊。檢查你解析響應(yīng)的字段路徑確認(rèn)模型返回的是標(biāo)準(zhǔn)結(jié)構(gòu)。OAuth相關(guān)失敗遠(yuǎn)程端點(diǎn)開(kāi)了鑒權(quán)但客戶端沒(méi)配 token或者回調(diào)地址不匹配。先在內(nèi)網(wǎng)用 Bearer 跑通再上 OAuth 2.1 PKCE別一步到位。還有一個(gè)高頻坑一個(gè) Server 塞幾十個(gè)弱相關(guān) tool導(dǎo)致模型選型混亂。拆成多個(gè)聚焦 Server 更好。tool 名是公開(kāi) API可增不可亂改名重命名等于破壞性變更。6. 從玩具到生產(chǎn)上線前的收尾與接入入口本地跑通只是第一步。上生產(chǎn)要補(bǔ)幾件事單獨(dú)開(kāi)/healthz做健康檢查TLS 在反向代理終止打 latency 和錯(cuò)誤率日志但慎打入?yún)⒖赡芎舾行畔?。默認(rèn)做成無(wú)狀態(tài) HTTP 更易水平擴(kuò)展只有需要服務(wù)端推送或斷線續(xù)傳時(shí)再上有狀態(tài) session。如果你要把這個(gè) Server 接到編碼類 Agent 長(zhǎng)期跑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 想先驗(yàn)證模型效果可以直接在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 對(duì)話測(cè)試。Claude Code 相關(guān)接入?yún)⒖?https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。最后提醒一句Skill 和 MCP 容易混。Skill 是 Markdown 說(shuō)明書教 Agent「怎么做」MCP 是獨(dú)立進(jìn)程或遠(yuǎn)程服務(wù)給 Agent「能調(diào)用的真工具」。復(fù)雜場(chǎng)景兩者一起用Skill 規(guī)定何時(shí)調(diào)用哪些 MCP tools。先把 stdio 跑通再用 Inspector 驗(yàn)證最后切 Streamable HTTP 上線這條路徑最穩(wěn)。