MCP资源模型
4831 字约 16 分钟
AIAgentMCPResource
2026-07-24
Resource 是 MCP Server 暴露的可读取数据和上下文。Resource 更适合表达可以被读取、引用和注入上下文的数据;需要执行动作或动态计算时,通常应考虑 Tool。
一、基本定义
Resource 是 MCP Server 通过协议暴露给 Client 的数据源。每个 Resource 代表一段可被模型读取和引用的信息,例如文件内容、数据库记录、配置快照、文档片段等。
与 Tool 不同,Resource 的核心特征:
- 被动读取:模型或 Client 主动请求读取,Resource 本身不执行动作
- 无副作用:读取操作不改变系统状态
- URI 寻址:每个 Resource 通过唯一 URI 标识
- 可发现:Client 可以动态列出可用 Resource
- 可订阅:Client 可以监听 Resource 的变更通知
二、为什么需要 Resource
在 AI 应用中,模型需要访问两类信息:
| 类型 | 特征 | 对应 MCP 能力 |
|---|---|---|
| 已有数据 | 静态或半静态、可寻址、无副作用 | Resource |
| 动态操作 | 需要执行、有副作用、参数化 | Tool |
没有 Resource 模型时,每个 AI 应用都需要自己实现数据源适配:一个应用为文件系统写一套集成,另一个应用为数据库写另一套集成,数据源越多重复工作越多。Resource 模型的价值在于提供统一的协议层,让数据源提供方只需实现一次 MCP Server,所有兼容 MCP 的 Client 都能自动发现和使用这些数据。
Resource 解决的核心问题:
- 上下文注入:为模型提供它无法自带的外部知识,如项目配置、业务规则、实时数据
- 数据标准化:不同数据源用统一接口暴露,Client 无需适配每种 API 的差异
- 动态发现:Client 无需硬编码数据源地址,运行时自动发现可用 Resource 并理解其用途
- 实时性:支持订阅和通知,模型可以感知数据变化而不需要反复轮询
- 解耦:数据源的变化不影响模型逻辑,模型只需要理解 Resource 的语义描述
三、在 MCP 体系中的位置
MCP 定义三种核心能力原语:
| 原语 | 用途 | 方向 |
|---|---|---|
| Resource | 暴露可读取的数据 | Server → Client(数据流出) |
| Tool | 暴露可执行的操作 | Client → Server(动作触发) |
| Prompt | 暴露可复用的提示模板 | Server → Client(模板提供) |
Resource 是 MCP 中「数据侧」的基础设施。模型通过 Client 读取 Resource 来获取上下文,通过调用 Tool 来执行动作。两者经常配合使用:模型先通过 Resource 读取状态,再通过 Tool 做出操作。
四、Resource 数据结构
一个 Resource 定义包含以下字段:
Resource {
uri: string // 资源唯一标识符(URI)
name: string // 人类可读名称
description: string // 资源描述(可选)
mimeType: string // 资源 MIME 类型(可选)
}字段说明
| 字段 | 必填 | 说明 |
|---|---|---|
| uri | 是 | 全局唯一的资源标识符,用于定位和读取 |
| name | 是 | 人类可读的名称,帮助理解和选择 |
| description | 否 | 更详细的描述,说明资源的内容和用途 |
| mimeType | 否 | 标识资源的数据格式,帮助 Client 正确解析 |
五、Resource URI 设计
URI 是 Resource 的核心标识符,需要遵循良好的设计原则:
URI 格式
<server-prefix>://<path>常见模式
# 文件系统
file:///projects/app/config.json
# 数据库
db://users/12345
db://orders?status=pending
# API 数据
api://weather/shanghai
api://metrics/cpu-usage
# 知识文档
docs://architecture/overview
docs://api-reference/auth设计原则
- 语义清晰:URI 本身应该暗示资源内容,模型看到 URI 就能大致理解资源含义
- 层级结构:用路径分隔表示分类关系,便于模型按类别推理
- 唯一稳定:同一资源 URI 不应变化,避免破坏已建立的引用和订阅
- 避免歧义:不同资源使用不同 URI,相同内容的不同视图用不同 URI 区分
- 避免过长:URI 应保持简洁,必要的参数通过路径而非查询字符串表达
URI 设计示例
✅ 好的设计:
docs://onboarding/getting-started
db://projects/active
config://app/logging-level
❌ 差的设计:
resource://001 → 无语义
data://fetch?type=3&id=abc → 过度依赖参数
doc → 缺少层级,无法分类六、Resource 模板(URI Templates)
对于参数化的 Resource 集合,Server 可以使用 URI 模板来描述动态资源:
ResourceTemplate {
uriTemplate: string // URI 模板,如 db://users/{userId}
name: string // 模板名称
description: string // 模板描述
mimeType: string // 资源 MIME 类型(可选)
}URI 模板允许 Client 通过填充参数来构造具体的 Resource URI:
模板:db://users/{userId}
实例:db://users/12345 → 读取用户 12345 的信息模板的意义在于:Server 不需要枚举所有可能的资源,而是描述资源的生成规则,Client 按需构造 URI 并读取。
七、静态 Resource vs 动态 Resource
| 维度 | 静态 Resource | 动态 Resource |
|---|---|---|
| 定义方式 | 直接列出 | 通过 URI 模板描述 |
| 内容变化 | 不经常变化 | 可能频繁变化 |
| 发现方式 | resources/list 直接返回 | 需要通过模板构造 URI |
| 典型例子 | 配置文件、README、文档 | 数据库记录、实时指标 |
| 缓存友好度 | 高 | 低,需考虑刷新策略 |
实际设计中,两者通常并存。一个 Server 既暴露固定的文档资源,也暴露通过模板访问的动态数据资源。
八、文本资源 vs 二进制资源 vs 结构化资源
文本资源
MIME 类型为 text/*,内容直接以字符串形式返回:
text/plain → 纯文本
text/markdown → Markdown 文档
text/html → HTML 内容
text/csv → CSV 数据
application/json → JSON 数据文本资源是最常见的类型,模型可以直接理解和处理。
二进制资源
MIME 类型为图片、音频、视频等二进制格式:
image/png → PNG 图片
image/jpeg → JPEG 图片
application/pdf → PDF 文档二进制资源通常需要 Client 做额外处理(如 base64 编码传输),模型能否理解取决于其多模态能力。
结构化资源
使用 JSON 等结构化格式,内容具有明确的字段和层级:
{
"user": {
"id": 12345,
"name": "张三",
"role": "admin"
}
}结构化资源的优势在于模型可以精确提取特定字段,而不需要从非结构化文本中解析信息。
九、MIME 类型
MIME 类型帮助 Client 和模型理解资源的格式和处理方式:
| MIME 类型 | 说明 | 模型处理方式 |
|---|---|---|
| text/plain | 纯文本 | 直接注入上下文 |
| text/markdown | Markdown | 直接注入上下文 |
| application/json | JSON | 解析后注入或提取字段 |
| image/png | PNG 图片 | 需要多模态能力 |
| application/octet-stream | 通用二进制 | 需要 Client 特殊处理 |
建议:始终为 Resource 指定 MIME 类型。如果不确定,文本资源使用 text/plain,结构化数据使用 application/json。
十、资源列表(resources/list)
Client 通过 resources/list 请求获取 Server 暴露的所有可用资源:
Client → Server: resources/list
Server → Client: { resources: [Resource], nextCursor?: string }返回结果包含:
- resources:资源列表数组
- nextCursor:分页游标(如果有更多资源)
资源列表是 Client 发现可用数据源的入口。Client 通常在连接建立后调用此方法,获取当前 Server 可以提供的所有资源信息。
十一、资源读取(resources/read)
Client 通过 resources/read 请求读取指定资源的内容:
Client → Server: resources/read { uri: "file:///config.json" }
Server → Client: { contents: [ResourceContents] }返回结果包含:
ResourceContents {
uri: string // 资源 URI
mimeType: string // MIME 类型
text?: string // 文本内容(文本资源)
blob?: string // Base64 编码内容(二进制资源)
}一个 resources/read 请求可能返回多个内容块,例如一个资源由多个文件组成。
十二、资源订阅/更新通知(resources/listChanged)
当 Server 的资源列表发生变化时,Client 可以通过订阅机制收到通知:
Client → Server: resources/subscribe { uri: "db://orders?status=pending" }
Server → Client: notifications/resources/updated { uri: "..." }两种通知类型:
| 通知 | 触发条件 | 用途 |
|---|---|---|
resources/listChanged | 可用资源列表发生变化 | Client 重新获取资源列表 |
resources/updated | 特定资源内容发生变化 | Client 决定是否重新读取 |
订阅机制让模型可以感知外部数据的变化,而不需要轮询。
十三、分页
当资源数量较多时,resources/list 支持基于游标的分页:
第一页请求:resources/list
第一页响应:{ resources: [...], nextCursor: "abc123" }
第二页请求:resources/list { cursor: "abc123" }
第二页响应:{ resources: [...], nextCursor: "def456" }
最后一页响应:{ resources: [...], nextCursor: null }分页设计要点:
- 游标由 Server 生成和管理,Client 不解析游标含义
nextCursor为 null 或不存在时表示已到最后一页- 分页不影响资源 URI 的稳定性
十四、元数据
Resource 的元数据帮助模型和 Client 做出更好的决策:
- name:帮助模型在多个资源中选择
- description:帮助模型理解资源的内容和适用场景
- mimeType:帮助 Client 选择正确的解析方式
- uri:隐含资源的分类和层级关系
元数据的质量直接影响模型能否正确选择和使用资源。好的描述应该说明资源包含什么、何时需要读取。
十五、缓存策略
Resource 的缓存需要在实时性和效率之间权衡:
| 策略 | 适用场景 | 优缺点 |
|---|---|---|
| 不缓存 | 实时性要求高的数据 | 实时但效率低 |
| 读取时缓存 | 读取频率高的静态资源 | 效率高但可能过期 |
| 订阅驱动刷新 | 支持订阅的资源 | 平衡实时性和效率 |
| TTL 过期 | 有一定时效性的数据 | 简单但不够精确 |
建议:静态文档类资源可以使用缓存加 TTL;动态数据类资源优先使用订阅通知驱动刷新。
十六、版本和一致性
Resource 本身不内建版本控制,但可以通过以下方式管理一致性:
- URI 区分版本:
docs://api/v1/authvsdocs://api/v2/auth - ETag / Last-Modified:Server 返回缓存验证头,Client 按需验证
- 时间戳标记:在资源内容中包含生成时间
- 订阅通知:内容变更时通知 Client 重新读取
对于需要强一致性的场景(如配置变更),建议使用订阅通知而非轮询。
十七、权限控制
Resource 的权限控制通常在 Server 层面实现,采用分层防御模型:
权限模型:
├── 公开资源:任何 Client 都可读取(如公共文档)
├── 认证资源:需要有效的 Client 身份(如用户个人数据)
├── 授权资源:需要特定权限级别(如管理员配置)
└── 敏感资源:需要用户明确授权(如财务数据、密钥)Host 在将资源注入模型上下文前,应执行多层检查:
- Client 是否有权访问该资源(认证和授权)
- 资源内容是否包含用户未授权的信息(内容过滤)
- 是否需要用户确认后才能读取(敏感操作确认)
- 注入模型后是否可能导致信息泄露(上下文安全检查)
Server 端的权限过滤应该在资源列表阶段就生效:Client 调用 resources/list 时,只应返回该 Client 有权访问的资源,而不是返回所有资源然后在读取时报错。这种方式更安全,也减少了不必要的网络请求。
十八、敏感数据处理
Resource 中可能包含敏感数据,需要在 Server 和 Host 两个层面处理:
Server 端(数据源头):
- 凭证和密钥:绝对不应作为 Resource 暴露,即使 Client 有访问权限
- 个人信息:需要脱敏处理或确认授权后才能读取
- 内部基础设施信息:IP 地址、内部域名等可能不应暴露给外部模型
Host 端(模型上下文注入前):
- 对资源内容进行最终检查,过滤可能泄露隐私的字段
- 对模型可见的资源摘要不应该包含敏感原文
- 记录敏感资源的访问日志,便于审计
脱敏策略示例:
- 邮箱地址:
zhang@example.com→z***@example.com - 手机号:
13800138000→138****8000 - 身份证:完整号码 → 仅保留前后各两位
核心原则:Resource 暴露给模型的内容应该是模型完成任务所需的最小信息集,而不是数据源的全部内容。
十九、大文件和增量读取
对于超过单次传输限制的大资源:
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 分片读取 | 通过 URI 参数指定范围 | 日志文件、大数据集 |
| 摘要 + 详情 | 先返回摘要,按需读取详情 | 长文档 |
| 流式传输 | 分块传输内容 | 超大文件 |
| 外部引用 | 返回文件路径而非内容 | 本地文件系统 |
设计建议:大资源应提供结构化的分片方式,让模型可以选择只读取相关部分,而不是加载全部内容。
二十、Resource vs Tool 判断表
| 问题 | 更适合 Resource | 更适合 Tool |
|---|---|---|
| 获取已有文档 | ✅ 是 | 否 |
| 执行搜索 | 视情况 | ✅ 通常是 |
| 修改记录 | 否 | ✅ 是 |
| 获取配置快照 | ✅ 是 | 视情况 |
| 运行计算 | 否 | ✅ 是 |
| 读取固定知识 | ✅ 是 | 否 |
核心判断逻辑:
- 数据已存在且只需要读取 → Resource
- 需要执行动作或动态计算 → Tool
- 数据已存在但需要复杂查询逻辑 → Tool(或带搜索能力的 Resource)
- 既是数据又需要修改 → 用 Resource 读取 + Tool 修改
二十一、Resource vs RAG 区别
| 维度 | MCP Resource | RAG |
|---|---|---|
| 数据获取 | 精确读取指定 URI | 通过向量检索匹配 |
| 数据源 | Server 显式暴露 | 向量数据库中的文档块 |
| 选择方式 | Client/模型主动选择 | 系统自动匹配 |
| 实时性 | 实时读取原始数据 | 依赖索引时效 |
| 粒度 | 整个资源或资源分片 | 文档块(chunk) |
| 适用场景 | 精确定位、配置、文档 | 大规模知识检索 |
Resource 和 RAG 不是替代关系,而是互补。RAG 适合大规模、模糊的知识检索;Resource 适合精确定位、实时性要求高的数据访问。一个完整的 AI 系统可以同时使用两者。
实际选择时的判断依据:
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 已知文档标题或路径 | Resource | 精确定位,无需检索 |
| 大规模知识库问答 | RAG | 模糊匹配,语义检索 |
| 实时配置和状态 | Resource | 直接读取,保证最新 |
| 历史文档和经验 | RAG | 已有向量索引,检索高效 |
| 小量确定性数据 | Resource | 无需向量化的开销 |
| 跨领域知识融合 | RAG | 语义空间统一检索 |
二十二、Resource vs 文件系统
| 维度 | MCP Resource | 文件系统 |
|---|---|---|
| 抽象层级 | 语义化资源(文档、配置、记录) | 物理文件路径 |
| 访问方式 | 通过 URI 和标准协议 | 通过文件路径和系统调用 |
| 数据源 | 不限于文件(数据库、API 等) | 仅限文件系统 |
| 权限模型 | Server 控制 | 操作系统控制 |
| 发现机制 | 动态列出可用资源 | 需要知道目录结构 |
| 跨平台 | 统一协议,跨平台 | 路径格式因 OS 而异 |
Resource 是对数据源的更高层抽象。文件系统可以作为 Resource 的一种实现后端,但 Resource 不限于文件。
二十三、MCP 资源模型架构
二十四、设计原则
- URI 语义清晰:URI 应自解释资源内容,避免随意编码
- Resource 无副作用:读取操作不应改变系统状态
- 描述优先:投入精力写好 name 和 description,帮助模型正确选择
- MIME 类型必填:始终指定 MIME 类型,帮助 Client 正确解析
- 粒度适中:一个 Resource 应该是一个有意义的信息单元,不过大也不过小
- 静态与动态分离:固定文档用静态 Resource,变化数据用模板 + 订阅
- 权限前置:在 Server 端实现权限过滤,不暴露无权资源
- 分页支持:资源列表和大资源都应支持分页
二十五、常见误区
- 把 Tool 做成 Resource:需要执行计算或产生副作用的操作应该用 Tool,不应该包装成 Resource
- 把 Resource 做成 Tool:简单的数据读取不需要 Tool,直接暴露为 Resource 更自然
- URI 设计随意:
resource://1、data://abc这类无语义 URI 让模型无法理解资源含义 - 忽略 MIME 类型:不指定 MIME 类型,Client 无法正确解析和展示资源
- 描述过于简略:name 为 "data"、description 为空,模型无法区分多个资源
- 大资源不分片:一次返回几 MB 的内容,消耗大量 Token 且影响性能
- 不处理权限:所有资源对所有 Client 开放,存在安全风险
- Resource 和 Tool 职责混淆:同一个能力既有 Resource 又有 Tool 版本,造成选择困难
二十六、实践检查清单
二十七、关联笔记
- MCP基础:Resource 在 MCP 协议中的基本定位
- MCP架构总览:Resource 在整体架构中的位置
- MCP Tool能力:与 Resource 对应的操作能力,两者的区别和配合
- MCP Prompt能力:第三种能力原语
- MCP Server设计:Resource 如何注册和管理
- MCP Client设计:Client 如何发现、读取和订阅资源
- MCP能力设计指南:如何选择使用 Resource、Tool 还是 Prompt
- MCP能力发现:资源发现和模板机制
- MCP安全边界:Resource 的权限和安全考量
- MCP与本地知识库:Resource 在知识库场景的实际应用
- MCP与数据库:数据库作为 Resource 后端的设计
- MCP与Obsidian:Obsidian 笔记作为 Resource 暴露