资源
将服务器中的数据和内容公开给 LLM
资源是模型上下文协议 (MCP) 中的核心基元概念,它允许服务器公开可由客户端读取并用作 LLM 交互上下文的数据和内容。
一、概述
资源表示 MCP 服务器希望提供给客户端的任何业务类型的数据。这可能包括:
- 文件内容
- 数据库记录
- API 响应
- 实时系统数据
- 屏幕截图和图像
- 日志文件
- 以及更多
每个资源都由唯一的 URI 标识,并且可以包含文本或二进制数据。
《模型上下文协议中文网》附注:资源在业务上的本质,就是你对外所提供的核心增强价值点之一(业务数据),最终以数据形式返回。
二、资源 URI
使用遵循以下格式的 URI 标识资源:
[protocol]://[host]/[path]
例如:
file:///home/user/documents/report.pdf
postgres://database/customers/schema
screen://localhost/display1
协议和路径结构由 MCP 服务器实现定义。服务器可以定义自己的自定义 URI 方案。
《模型上下文协议中文网》附注:
自定义URI方案是一个什么概念?
假设我们开发一个天气查询的 MCP 服务器,它提供实时天气数据作为资源。一个典型的资源描述可能如下:
URI:
weather://data/12345
内容:
{ "temperature": 22, "humidity": 60, "condition": "Clear" }
客户端可以通过 weather://data/12345
这个 URI 来请求天气数据,服务器返回的是当前的天气信息。
三、资源类型
资源可以包含两种类型的内容:
1、文本资源
文本资源包含 UTF-8 编码的文本数据。这些适用于:
- 源代码
- 配置文件
- 日志文件
- JSON/XML 数据
- 纯文本
2、二进制资源
二进制资源包含以 base64 编码的原始二进制数据。这些适用于:
- 图像
- PDF文件
- 音频文件
- 视频文件
- 其他非文本格式
四、资源发现
客户端可以通过两种主要方法发现可用资源:
1、直接资源
服务器通过端点公开具体资源的列表。每个资源包括:resources/list
{
uri: string; // 资源的唯一标识符
name: string; // 可读名称
description?: string; // 可选描述
mimeType?: string; // 可选 MIME 类型
}
2、资源模板
对于动态资源,服务器可以公开 URI 模板,客户端可以使用这些模板来构造有效的资源 URI:
{
uriTemplate: string; // URI 模板遵循 RFC 6570
name: string; // 该类型的可读名称
description?: string; // 可选说明
mimeType?: string; // 所有匹配资源的可选 MIME 类型
}
五、阅读资源
要读取资源,客户端使用资源 URI 发出请求。resources/read
服务器使用资源内容列表进行响应:
{
contents: [
{
uri: string; // 资源的唯一标识符
mimeType?: string; // 可选 MIME 类型
// 二选一的类型
text?: string; // 文本资源
blob?: string; // 二进制资源(base64 编码)
}
]
}
六、资源更新
MCP 通过两种机制支持实时更新资源:
1、列表更改
当 Client 端的可用资源列表发生更改时,Server 可以通过通知接口,通知 Client 端。notifications/resources/list_changed
2、内容更改
客户端可以订阅特定资源的更新:
- 带有资源 URI 的客户端发送
resources/subscribe
- 服务器在资源更改时发送
notifications/resources/updated
- 客户端可以使用
resources/read
- 客户可以使用
resources/unsubscribe
七、示例实现
以下是在 MCP 服务器中实现资源支持的简单示例:
TypeScript范例
// 创建一个 MCP 服务器实例
const server = new Server(
{
// 配置服务器的名称和版本
name: "example-server", // 服务器的名称
version: "1.0.0" // 服务器的版本
},
{
capabilities: {
// 服务器的功能声明,此处声明了资源功能
resources: {} // 目前没有资源的具体功能细节,表示资源是可用的,但没有更多细节
}
}
);
// 设置请求处理器,用于处理列出资源的请求
// 该请求处理器响应 ListResourcesRequestSchema 类型的请求
server.setRequestHandler(ListResourcesRequestSchema, async () => {
// 返回一个包含可用资源的响应
return {
resources: [
{
// 资源的 URI,表示资源的位置
uri: "file:///logs/app.log", // 该资源是服务器日志文件的 URI
name: "Application Logs", // 资源的名称,表示该资源是应用程序日志
mimeType: "text/plain" // 资源的 MIME 类型,表示资源是文本文件
}
]
};
});
// 设置请求处理器,用于处理读取资源内容的请求
// 该请求处理器响应 ReadResourceRequestSchema 类型的请求
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
// 获取请求中的 URI 参数
const uri = request.params.uri;
// 检查 URI 是否匹配我们预定义的日志文件资源
if (uri === "file:///logs/app.log") {
// 如果请求的 URI 是日志文件 URI,则读取日志文件的内容
const logContents = await readLogFile();
// 返回资源的内容,包含 URI、MIME 类型和文件的文本内容
return {
contents: [
{
uri, // 返回资源的 URI
mimeType: "text/plain", // 返回资源的 MIME 类型
text: logContents // 返回读取到的文本内容
}
]
};
}
// 如果 URI 不匹配预定义的资源,抛出错误
throw new Error("Resource not found");
});
其他
《模型上下文协议中文网》附注:下面部分新手可先不关注
1、最佳实践
实施资源支持时:
- 使用清晰、描述性强的资源名称和 URI
- 包括有用的描述以指导理解 LLM
- 在已知时设置适当的 MIME 类型
- 为动态内容实施资源模板
- 对频繁更改的资源使用订阅
- 使用清晰的错误消息优雅地处理错误
- 考虑对大型资源列表进行分页
- 在适当时缓存资源内容
- 在处理之前验证 URI
- 记录您的自定义 URI 方案
2、安全注意事项
公开资源时:
- 验证所有资源 URI
- 实施适当的访问控制
- 清理文件路径以防止目录遍历
- 谨慎处理二进制数据
- 考虑对资源读取进行速率限制
- 审计资源访问
- 加密传输中的敏感数据
- 验证 MIME 类型
- 为长时间运行的读取实施超时
- 适当地处理资源清理