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 Path
mcp = 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 获取,就能把大量上下文从提示词里“移出来”,按需加载、可缓存、更稳更省。