Resources = 給 MCP 客戶端/LLM 讀取的數據端點(只讀、按 URI 索引、像“虛擬文件系統”或“HTTP GET”);
Templates = 可帶參數的資源路由(URI 里占位符 → 運行函數動態生成內容)。
快速要點
? 用途:把文件、配置、數據庫查詢結果、運行時狀態、動態生成的文本/JSON/二進制等,按需提供給 LLM(通過 resources/read 而不是塞進提示詞里),減少 token 壓力。
? 只讀:資源的定位是“讀取數據”。涉及改變狀態/執行動作的,應該用 Tool(RPC)而不是 Resource。
? URI 是鑰匙:@mcp.resource(“scheme://path”) 把函數注冊為一個資源;客戶端用這個 URI 來取數據。
? 動態/靜態都行:
? 動態:用 @mcp.resource 裝飾函數,讀取時才執行(Lazy)。
? 靜態:用 mcp.add_resource(TextResource/FileResource/DirectoryResource/HttpResource …) 直接掛現成內容或文件夾索引。
? 模板(Templates):URI 里寫占位符(如 user://{name}、path://{filepath*}),請求時把路徑參數傳給函數,動態生成資源。
? 返回類型:str→text/plain,dict/list/model→自動 JSON,bytes→Blob(要給合適 mime_type),None→空內容。
? 元數據與提示:mime_type / tags / meta / annotations(readOnlyHint,idempotentHint) 用于客戶端展示、緩存與安全提示(不強制,僅提示)。
? 啟用/禁用:可在裝飾器或運行時 enable()/disable();變更時會向客戶端發 resources/list_changed 通知。
? 上下文:簽名里加 ctx: Context 可拿到 request_id 等(做審計、多租戶、鑒權等)。
? 錯誤處理:拋標準異常會被轉為 MCP 錯誤;想隱藏細節可開 mask_error_details=True 或拋 ResourceError 精準控制對外消息。
? 重復注冊策略:on_duplicate_resources 控制重復 URI 的處理(warn/error/replace/ignore)。
和 Tool/Prompt 的區別(記這個表就行)
能力 Resource Tool
語義 讀取數據(GET) 執行動作/有副作用(POST/PUT/DELETE)
觸發 resources/read tools/call
適合 文件/配置/查詢結果/日志/監控視圖 寫庫、發送消息、下單、觸發流程
可參數化 通過 URI 模板 {param}/{param*} 通過函數參數(JSON-RPC)
緩存/冪等 天然適合緩存(idempotentHint) 需謹慎,可能有副作用
設計建議(結合你的場景)
? RAG/知識庫:
? kb://doc/{id} 返回單文檔;kb://search/{query} 返回檢索結果(只讀→Resource,若要寫入索引→Tool)。
? 大結果可分頁:kb://search/{query}?page=1&page_size=20(FastMCP 側解析查詢串或用 {page} 模板)。
? 短期記憶/Redis(只讀視圖):
? memory://session/{sid} 返回當前會話摘要;寫入或清空記憶則走 Tool(如 memory.clear)。
? 監控/狀態面板:
? status://app/current、metrics://{name},給 mime_type=“application/json”,加 annotations={“readOnlyHint”: true} 方便客戶端緩存與展示。
? 文件系統/日志:
? file://…/DirectoryResource 暴露目錄清單;敏感路徑用 mask_error_details 或做白名單。
? 命名與穩定性:URI 要穩定可書簽化(避免把會頻繁變動的細節放進路徑),必要時用 meta 攜帶版本等信息。
? 性能:昂貴的動態資源(例如深度檢索)要么緩存、要么限制參數范圍,并在 description 里寫清語義,便于 LLM 正確選擇。
小例子(動態模板 + 靜態文件)
from fastmcp import FastMCP, Context
from fastmcp.resources import FileResource
from pathlib import Pathmcp = FastMCP(name="KB")
動態模板:會話記憶只讀視圖
@mcp.resource("memory://session/{sid}")
def session_view(sid: str, ctx: Context) -> dict:"""Return chat memory snapshot for a session (read-only)."""return {"sid": sid, "summary": "...", "messages": []}
暴露 README.md 作為靜態資源
readme = Path("./README.md").resolve()
if readme.exists():mcp.add_resource(FileResource(uri=f"file://{readme.as_posix()}",path=readme,name="Project README",mime_type="text/markdown",tags={"docs"}))
記住:讀 = Resource,寫/動作 = Tool;固定 = 資源,帶參數 = 模板。把需要“讓 LLM 隨取隨用”的上下文做成資源 URI,客戶端用 resources/list 發現、用 resources/read 獲取,就能把大量上下文從提示詞里“移出來”,按需加載、可緩存、更穩更省。