把 Python 函式變成 AI 能力:FastMCP 如何縮短 MCP Server 的實作距離
MCP 的價值不只在於讓模型呼叫工具,更在於把工具、資料與可重用的互動介面接到同一套協定。FastMCP 以 Python decorator、型別註記與現成的 server/client API,讓團隊能從一個可驗證的小型 MCP Server 開始,再逐步處理傳輸、部署、授權與治理。
把 Python 函式變成 AI 能力:FastMCP 如何縮短 MCP Server 的實作距離
我認為,Model Context Protocol(MCP)真正難的地方,從來不是把一個 API endpoint 寫出來,而是讓模型、工具、資料與互動流程能以一致的方式被發現、描述、驗證與呼叫。當團隊開始把內部搜尋、資料庫查詢、檔案操作或第三方服務交給 AI agent 使用,最先遇到的通常不是模型不夠聰明,而是每個工具都用不同的包裝方式:有的靠自訂 JSON,有的塞在 prompt,有的直接把業務邏輯綁死在某個聊天產品。
FastMCP 是我這次挑出的實作型開源專案。它不是一份 MCP 伺服器清單,也不是只講概念的教學集合,而是一套以 Python 為核心的 MCP application framework,涵蓋 server、client 與互動式應用程式。它最吸引人的地方,是把「讓普通 Python 函式成為模型可呼叫的能力」縮短成幾個清楚的步驟,同時保留往正式部署演進時需要的傳輸、驗證與組合空間。
先講結論:FastMCP 解決的是協定落差,不是替你完成治理
如果你的團隊已經有 Python 函式、資料服務或內部 API,想快速做出一個能被 MCP client 使用的工具層,FastMCP 很值得先試。它透過 @mcp.tool 把函式註冊成工具,依照函式簽名與型別註記產生輸入 schema,再把執行結果交回 client;同一個 server 也能用 @mcp.resource 提供只讀資料,或用 @mcp.prompt 暴露可重用的訊息模板。
但我不會把它描述成「加一個 decorator 就完成 AI production」。真正上線仍然要處理權限、祕密管理、輸入驗證、網路邊界、日誌、速率限制與工具副作用。FastMCP 降低的是 MCP application 的起始成本,讓工程團隊可以先把協定邊界做對,再針對風險補上治理。
為什麼 MCP Server 的第一版常常做得太重?
傳統做法很容易從框架、路由、資料模型、錯誤格式與部署設定全部開始設計。這在一般服務開發不一定錯,但對 MCP 工具來說,第一個問題通常只是:「模型能不能可靠地呼叫這個能力?」如果還沒驗證使用者場景,就先建立一整套客製協定,最後往往得到一個只有自己家 client 能理解的整合層。
FastMCP 的設計把第一個可驗證任務放在很前面:建立 FastMCP 實例、用 decorator 登錄能力、啟動 server。這個路徑很適合把現有 Python 程式逐步包裝,而不是一次重寫整個後端。從架構角度看,它將幾個層次分開:
- Tool 是可執行能力,例如查詢資料、呼叫 API 或計算結果。
- Resource 是 client 可以讀取的資料或檔案,也可以由 URI template 動態產生。
- Prompt 是可重用、可參數化的訊息模板,用來引導一致的模型互動。
- Transport 決定 client 如何連到 server,例如本機 stdio 或遠端 HTTP。
這個分層很重要。若把所有東西都做成 tool,模型可能會把原本只需要讀取的資料操作成具有副作用的動作;若把所有提示都硬編碼在 client,server 端的領域知識又難以重用。
從一個可驗證的 Tool 開始
官方 quickstart 的最小路徑很直白。我會先準備 Python 3.10 以上的環境,再安裝 FastMCP。專案的 pyproject.toml 將最低 Python 版本設為 3.10,並以 Apache License 2.0 發布。使用 uv 時,可以在自己的專案中執行:
uv add fastmcp接著建立 my_server.py:
from fastmcp import FastMCP
mcp = FastMCP("My MCP Server")
@mcp.tool
def greet(name: str) -> str:
"""Return a greeting for a person."""
return f"Hello, {name}!"
if __name__ == "__main__":
mcp.run()這段程式的重點不在問候語,而在於函式簽名成為協定的一部分。name: str 提供輸入型別資訊,docstring 則能成為工具描述的一部分。實務上我會把型別註記寫完整,把會影響模型選擇的限制放進 docstring,並避免讓一個 tool 同時包住太多不相關的副作用。
啟動後,stdio 是適合本機 client 的預設路徑。如果希望以 HTTP 提供遠端連線,官方 quickstart 示範的是:
if __name__ == "__main__":
mcp.run(transport="http", port=8000)這不代表把 stdio 改成 http 就完成了遠端服務。HTTP 會把認證、反向代理、TLS、網路存取控制與觀測性問題一起帶進來,所以我會先在本機確認工具契約,再把 HTTP 當成部署階段的明確決策。
Tool、Resource、Prompt:三種能力不要混在一起
FastMCP 的另一個價值,是讓 MCP 的語義能直接對應到 Python 程式碼。
Tool:讓模型採取行動
Tool 適合需要執行的能力,例如查詢訂單、計算報表或呼叫一個外部服務。FastMCP 會依照函式名稱、docstring 與型別註記建立工具描述和輸入 schema,並在收到呼叫時進行參數處理。
@mcp.tool
def add(a: int, b: int) -> int:
"""Add two integers."""
return a + b我會把 tool 視為一個需要被授權的動作,而不是「任何函式都可以直接公開」。涉及刪除、付款、寄信或修改資料的 tool,應該另外加入明確的權限檢查、冪等設計與人工確認。框架能幫你描述與註冊能力,但不會替你判斷某個使用者是否有權使用它。
Resource:讓模型讀取上下文
Resource 比較接近只讀資料入口,可以回傳文字、JSON、檔案或由 URI template 產生的動態內容。例子如下:
import json
@mcp.resource("data://config")
def get_config() -> str:
return json.dumps({
"theme": "dark",
"features": ["tools", "resources"],
})當需求是「讓模型讀取目前設定」或「取得某個可定位的資料來源」,我會優先考慮 resource,而不是新增一個看起來像查詢動作的 tool。這樣 client 和人類讀者都更容易理解這個入口是否有副作用。
Prompt:讓互動流程可重用
Prompt 適合把領域團隊反覆使用的訊息模板集中管理。例如,依照主題產生一個請求說明:
from fastmcp.prompts import Message
@mcp.prompt
def ask_about_topic(topic: str) -> str:
return f"Can you explain the concept of '{topic}'?"
@mcp.prompt
def code_request(language: str, task: str) -> list[Message]:
return [
Message(f"Write a {language} function for: {task}"),
Message("I will help you write it.", role="assistant"),
]Prompt 不是權限系統,也不是把所有商業規則藏起來的地方。它的價值是讓 client 能發現一個可重用的互動入口。若一個流程需要真正取得資料或改變狀態,仍要把動作放在適合治理的 tool,並在 server 端做驗證。
我會怎麼安排實際導入
第一步:先定義一個小而清楚的能力
不要從「把整個資料庫交給 agent」開始。先挑一個輸入和輸出都能明確描述的工作,例如查詢某個專案的部署狀態、依 ID 取得一筆文件,或計算一個不會改變資料的結果。第一版越小,越容易觀察模型到底如何選擇工具,以及錯誤訊息是否足夠。
第二步:用型別與 docstring 固定契約
Python 的型別註記不是裝飾品。它會影響 schema 和 client 對工具的理解。我會明確寫出可接受的值域、單位、時區、分頁行為與錯誤條件;對複雜輸入則建立清楚的資料模型,而不是接受一個沒有結構的字串。這能降低模型傳錯參數的機率,也讓人類開發者更快看懂。
第三步:在本機用 stdio 驗證發現和呼叫
官方文件的 quickstart 不是只提供 hello world,它完整走過 server、tool、client 和視覺化結果的概念。我的驗證順序會是:先確認 server 能啟動,再確認 client 能列出工具,最後用固定輸入呼叫一次並檢查結果。若這三步都過不了,先不要急著接模型,因為問題多半在協定描述、啟動命令或輸入 schema。
我也實際用 FastMCP 的公開 API 做了最小 smoke test:註冊一個 add tool 和一個 data://status resource,列出兩者名稱,再呼叫 add(2, 3)。實際結果是 tool 清單包含 add、resource 清單包含 data://status,計算結果為 5。這個測試很小,卻能驗證 decorator 註冊和公開列舉 API 都能正常工作。
第四步:只有在需求成立時才切換 HTTP
本機桌面 client 或開發環境適合 stdio,因為它不必先暴露網路服務。當多個使用者或服務需要共用同一個 MCP Server,才考慮 HTTP。此時要把認證方式、租戶隔離、請求逾時、重試、日誌脫敏與流量上限列入設計,而不是把傳輸參數當成純技術細節。
第五步:把工具治理放在 server 邊界
模型輸入永遠是不可信的。即使 FastMCP 會依照型別處理參數,業務規則仍需要自己驗證,例如使用者只能讀取所屬專案、查詢條件必須限制範圍、外部 URL 不可任意存取。對會改變狀態的操作,我會記錄呼叫者、輸入摘要、結果狀態與 trace id,並為重試設計冪等鍵。
FastMCP 的限制與容易誤判的地方
第一,MCP 是能力交換協定,不是完整的 agent framework。它可以讓模型發現和呼叫 tools、讀取 resources、取得 prompts,但不會替你決定何時呼叫、如何規劃長流程、如何評估答案品質。若團隊要做多步驟 agent,還需要另一層 orchestration 或 application logic。
第二,Python 的低摩擦不等於低風險。把既有函式加上 decorator 很方便,也可能把原本只在內部呼叫的高權限函式快速暴露出去。導入前應該建立公開能力清單,逐一標記讀取、寫入、外部網路與敏感資料風險。
第三,HTTP 部署的複雜度會顯著高於本機 stdio。你仍要處理網路可靠性、認證、授權和可觀測性;如果只是想讓本機 coding assistant 呼叫幾個工具,直接採用遠端部署反而可能增加不必要的攻擊面。
第四,工具描述品質會直接影響模型選擇。FastMCP 能從簽名與 docstring 產生結構,但它不能替你寫出精準的名稱、邊界和錯誤說明。兩個功能相近的 tool 若描述模糊,模型可能選錯;所以 schema review 應該和一般 API review 一樣正式。
哪些團隊適合先試?
我會推薦以下幾類團隊先建立小型 PoC:
- 已經以 Python 維護內部 API、資料處理函式或自動化腳本,希望用一致協定接到 AI client。
- 想把搜尋、查詢、檔案讀取等能力提供給多個 MCP client,而不想為每個 client 重做一套 adapter。
- 需要在本機先驗證工具契約,再視需求演進到 HTTP 服務的開發團隊。
- 正在建立 AI agent 平台,希望把「工具實作」與「agent 的規劃和對話邏輯」拆成不同層次。
相反地,如果團隊目前還沒有明確的工具使用場景,只是因為 MCP 很熱門就想把所有內部系統接上去,我會建議先做能力盤點和風險分級。框架再好,也不能替沒有邊界的整合需求收斂範圍。
我的判斷:先把能力邊界做小,FastMCP 才能放大價值
FastMCP 的優勢不是把 MCP 複雜度假裝不存在,而是把第一個正確實作的距離縮短。Python 函式、型別、docstring、tool/resource/prompt 分層和 stdio quickstart,讓團隊可以很快得到一個可列舉、可呼叫、可測試的能力入口。接下來要不要改用 HTTP、要不要接多個 client、要不要加入授權與觀測性,則可以依照真實需求逐步增加。
我會把它放在 AI application 的「能力層」,而不是把它當成完整產品平台。最實用的導入策略,是先挑一個低風險、可重複驗證的 read-only 工作,確認 client 能發現並正確呼叫,再把工具契約、權限與日誌納入正式工程流程。這樣做,FastMCP 才不是另一個需要維護的 wrapper,而是把既有 Python 能力轉成可重用 AI 介面的清楚邊界。
參考資料