AI 互動教室 ‹ 學 LLM 應用開發
下載 .py 開啟實戰 notebook ↗ 留言回報
FASTMCP 4 · 補充 D · MCP ECOSYSTEM

常見 MCP 服務:接上別人的伺服器,再合成一台

前面每一課都在自己蓋 MCP 伺服器。但 MCP 的價值在生態系:查時區、抓網頁、讀檔案、操作 git、翻最新文件、開瀏覽器…… 這些別人寫好了、上千個客戶端在用。這堂課反過來——接上別人蓋好的,最後把它們跟你的工具合成一台,給 Claude 用。 選一台伺服器,看它怎麼接、實測拿到什麼(內容是 notebook 的實測紀錄):

本課需要網路uvx 下載伺服器套件、連兩台公開的遠端伺服器),molab 免費 CPU 環境即可。 生態系資料 2026-08-20 查證;用 fastmcp==4.0.0b1

01 · 生態系地圖

兩種接法、七個官方參考伺服器、一串要 OAuth 的遠端

MCP 伺服器只有兩種接法:stdio——客戶端把伺服器當子行程拉起來、用管線講 JSON-RPC(uvx …npx -y …,跑在你機器上); HTTP——給你一個網址,多半要 OAuth。官方 modelcontextprotocol/servers 目前維護 7 個參考伺服器:

名稱做什麼怎麼跑
time查時區、換算時間uvx mcp-server-time
fetch抓網頁轉 markdown 給模型讀uvx mcp-server-fetch
git讀/搜尋/操作 git repouvx mcp-server-git --repository …
filesystem受控目錄內的檔案讀寫npx -y @modelcontextprotocol/server-filesystem …
memorysequentialthinkingeverything知識圖譜記憶/分步推理/協定測試npx -y @modelcontextprotocol/server-*
GitHub、Slack、PostgreSQL、SQLite、Puppeteer…已封存到 servers-archived(GitHub 改官方版、Slack 由 Zencoder 接手)網路教學還在教的 server-github 已不更新

第三方:DeepWikiContext7、Cloudflare Docs 是公開免 token 的 HTTP 伺服器;GitHub 官方(api.githubcopilot.com/mcp/)、Notion、Linear、Sentry、Stripe 對沒帶 token 的請求一律回 401resource_metadata——就是補充課 A 那套 OAuth 發現流程; Playwright(npx @playwright/mcp@latest)讓模型操作真的瀏覽器。完整表在 notebook。

到 notebook 的 1️⃣ 節:完整生態系表(含要不要 token、查證方式)
02 · stdio 與 mcp.json

一個 dict 拉起子行程——這就是 Claude Desktop 的設定檔格式

SERVERS = {"mcpServers": { "time": {"command": "uvx", "args": ["mcp-server-time"]}, "fetch": {"command": "uvx", "args": ["mcp-server-fetch"]}, }} async with Client(SERVERS) as c: print(c.protocol_version) # 2025-11-25 ← 老伺服器只會握手協定,client 自動退回 print([t.name for t in await c.list_tools()]) # ['time_get_current_time', 'time_convert_time', 'fetch_fetch'] await c.call_tool("time_get_current_time", {"timezone": "Asia/Taipei"})

Client(設定) 自己把子行程拉起來、用完關掉,你不用開終端機、不用管 port。多台時工具自動加伺服器名前綴time_fetch_),一台時不加。 兩件 stdio 特有的事:子行程只繼承一小份環境變數白名單(HOMEPATH…),API key 要用 "env" 明傳; 首次 uvx 要下載套件,多等 10–40 秒。實測連線含子行程啟動 0.5–7 秒(看有沒有快取)。

protocol_version:這些官方伺服器是 MCP Python SDK v1 寫的,只會 2025-11-25。FastMCP 4 的 client 先用新協定探一次,老伺服器在 stderr 抱怨一串 pydantic 警告,client 就自動退回握手協定——那串警告是正常的

到 notebook 的 2️⃣–3️⃣ 節:time、fetch、工具前綴
03 · 遠端 HTTP

一個網址就好——而且你正看著協定過渡期

伺服器網址實測 protocol_version工具
DeepWiki(問任何公開 GitHub repo)https://mcp.deepwiki.com/mcp2025-11-25(握手協定)read_wiki_structureread_wiki_contentsask_question
Context7(查套件最新版文件)https://mcp.context7.com/mcp2026-07-28(無狀態協定)resolve-library-idquery-docs

同一行 Client("https://…/mcp"),一台還是舊協定、一台已經是第 3 課學的新協定——這就是 FastMCP 4「一個客戶端同時服務兩個協定時代」的意義。 Context7 解的是模型記錯 API 版本的老問題:先 resolve-library-id("fastmcp") 對應成 /prefecthq/fastmcp,再用自然語言 query-docs,回來的是帶原始碼連結的最新文件片段。 遠端服務會變,notebook 這格包了 try/except:連不上會顯示說明而不是炸掉。

到 notebook 的 4️⃣–5️⃣ 節:DeepWiki、Context7、npx filesystem
04 · 合成一台

自己的工具+time+Context7,mount 成一個網址

hub = FastMCP("我的工具 hub") @hub.tool def hello(name: str) -> str: ... hub.mount(create_proxy({"mcpServers": {"default": TIME_SERVER}}, mode="legacy"), namespace="time") hub.mount(create_proxy("https://mcp.context7.com/mcp"), namespace="c7") # 客戶端連 hub 看到:['hello', 'time_get_current_time', 'time_convert_time', 'c7_resolve-library-id', 'c7_query-docs']

create_proxy(目標) 把任何 MCP 伺服器(網址、設定 dict、檔案路徑)變成可 mount 的代理,namespace 決定前綴 (tool → ns_tool、resource → data://ns/…)。這同時是 stdio → HTTP 橋接:原本只能被本機子行程拉起來的 mcp-server-time,經過 hub 後任何遠端客戶端都用得到。

實測踩到的坑:hub 對外是新協定,proxy 預設會「鏡像」客戶端的協定時代去連後端——新協定客戶端 → proxy 用新協定敲 mcp-server-time → 老伺服器不會 → 工具清單裡它整個消失。 只會握手協定的老伺服器要 create_proxy(…, mode="legacy") 釘住;Context7 本身是新協定,不用釘。

到 notebook 的 6️⃣ 節:起 hub、三個來源的工具一次列出
05 · 接給 Claude

一行 CLI,或一段 JSON

claude mcp add --transport http hub http://localhost:8000/mcp # 接 HTTP 的 hub claude mcp add time -- uvx mcp-server-time # 直接接一台 stdio 伺服器 claude mcp add playwright -- npx @playwright/mcp@latest # 讓 Claude 操作瀏覽器 fastmcp install claude-code hub.py:hub # FastMCP CLI 幫你跑 claude mcp add fastmcp install claude-desktop hub.py:hub # 寫進 claude_desktop_config.json fastmcp list http://localhost:8000/mcp # 不寫程式就看一台伺服器有哪些工具

Claude Desktop(claude_desktop_config.json)與 Cursor(.cursor/mcp.json)吃的就是第 02 節那個 mcpServers dict。 接上後對 Claude 說「東京現在幾點」它自己呼叫 time_get_current_time;問「Qdrant 的 python client 怎麼建 collection」它先 c7_resolve-library-idc7_query-docs——你一個 agent 迴圈都沒寫。 安全常識:stdio 伺服器=在你機器上跑別人的程式,只裝信得過的;filesystem 永遠限制目錄;hub 對外前掛上補充課 A 的認證。

到 notebook 的 7️⃣ 節:Claude Code/Desktop/Cursor 設定與 fastmcp CLI
06 · 實戰

換你動手

LEVEL 1

在設定加第三台官方伺服器 git(先 git init 一個暫存目錄並 commit),看多出哪 12 個 git_git_* 工具,用 git_git_log 讀出那個 commit。

LEVEL 2

用設定檔的 "tools" 區塊改造工具:把 get_current_time 改名 nowtimezone 預設 Asia/Taipei 並隱藏——模型看到的是零參數的 now()

LEVEL 3

hub 掛上補充課 A 的 StaticTokenVerifier:沒 token 連不上、帶 team-token 才看得到 c7_*。Context7 不要 token,你的 hub 卻要——「在 hub 層加門」還能加什麼?

卡住了?每一題在 notebook 末節都有折疊解答——先自己做,再打開對照。

07 · 驗收

情境測驗

離開前試試看:下面的情境都真的會遇到。每題選一個你認為的最佳做法,選了馬上看得到解釋。

Q1 情境題

你想讓模型讀 GitHub 的 repo 與 issue,網路教學說裝 @modelcontextprotocol/server-github。2026 年的今天,最佳做法是?

官方參考的 server-github 已封存到 servers-archived、不再更新——GitHub 的 MCP 伺服器改由 GitHub 官方維護(api.githubcopilot.com/mcp/,OAuth/PAT)。A 抓得到套件,但那是不再修 bug 的殭屍,「網路教學還在教」正是本課點名的坑;B 把別人封存的包袱背回家,沒必要;D 誤解了 401——帶 resource_metadata 的 401 是標準 OAuth 發現流程的第一步(補充課 A),意思是「要登入」,不是壞了。

Q2 錯誤診斷

首次用 uvx 連官方 mcp-server-time,stderr 湧出一串 pydantic validation 警告,但工具照常列出、呼叫也成功。最可能的原因是?

async with Client({"mcpServers": {"time": {"command": "uvx", "args": ["mcp-server-time"]}}}) as c: … # stderr:一長串 pydantic validation 警告 # 但 protocol_version = '2025-11-25',list_tools() 與 call_tool() 都正常

FastMCP 4 的 client 會先用 2026-07-28 新協定探一次(server/discover),這些用 MCP Python SDK v1 寫的官方伺服器不認得、在 stderr 抱怨一串 pydantic 警告,client 就自動退回握手協定 2025-11-25——一切照常,那串警告不是錯誤。A、B 症狀相似但可排除:真的壞掉或不相容,list_tools() 不會成功;C 無關——mcp-server-time 根本不需要 API key。判斷準則:看結果(工具列得出、呼叫成功),不是看 stderr 的音量。

Q3 情境題

你請模型寫 FastMCP 程式,它一直用記憶裡的舊版 API,一跑就報錯。想用本課接過的伺服器解決,最佳做法是?

「模型記錯 API 版本」正是 Context7 要解的老問題:resolve-library-idquery-docs 回來的是帶原始碼連結的最新文件片段,直接對到正確版本。A 看起來可行,但 DeepWiki 的強項是 repo 結構與內容導覽,查即時 API 細節不如專做文件檢索的 Context7 對口;C 是常見誤解——模型大小改不了知識截止日;D 能動但你得自己猜對網址、抓回整頁再讓模型撈重點,繞遠路。

Q4 錯誤診斷

你把自己的工具、mcp-server-time、Context7 mount 成一台 hub。客戶端連上後 time_* 整組消失、也沒有任何報錯。最可能的原因是?

hub.mount(create_proxy({"mcpServers": {"default": TIME_SERVER}}), namespace="time") hub.mount(create_proxy("https://mcp.context7.com/mcp"), namespace="c7") # 客戶端連 hub 後: # list_tools() → ['hello', 'c7_resolve-library-id', 'c7_query-docs']

這是本課實測踩到的坑:hub 對外是新協定,proxy 預設「鏡像」客戶端的協定時代去連後端——新協定敲到只會 2025-11-25 握手協定的 mcp-server-timetools/list 拿不到東西,工具靜默消失。修法:對老伺服器釘 create_proxy(…, mode="legacy");Context7 本身是新協定不用釘(D 剛好反了——而且 c7_* 明明活得好好的)。B 不成立,兩個 namespace 前綴不同不會撞名;C 症狀相似但原因不同——下載中會表現成連線慢或逾時,不是連上了卻少一組工具。

Q5 情境題

hub 已經在 http://localhost:8000/mcp 跑起來了,你想在 Claude Code 裡用它的工具。應該怎麼做?

Claude Code 接 HTTP 伺服器就是 CLI 一行 claude mcp add --transport httpfastmcp install claude-code 就是幫你跑這行)。接上後說「東京現在幾點」它自己呼叫 time_get_current_time——你一個 agent 迴圈都不用寫,A 是在土砲客戶端已經幫你做掉的事;B 接錯客戶端:claude_desktop_config.json 是 Claude Desktop 的設定檔,Claude Code 不讀它;D 的 transport 搞混了——hub.py 結尾跑的是 HTTP transport,被當 stdio 子行程拉起來根本講不上話。

HANDS-ON · MOLAB

實作在 molab 跑(免費)

molab 的登入狀態進不了內嵌框架(瀏覽器的跨站 cookie 保護), 所以 notebook 要在新分頁執行——把它跟本頁並排開,左邊教學照樣對照。

  1. 登入 molab(GitHub / Google)
  2. 開啟課程 notebook,Fork 成自己的副本即可編輯
  3. 從第一格往下全部執行(首次 uvx 下載伺服器套件約 10–40 秒)——免費 CPU 環境即可,需要網路、不需要 GPU

不想用 molab?下載 mcp-servers_ext.py 後在自己電腦 uvx marimo edit --sandbox mcp-servers_ext.py,依賴會自動安裝。