将服务器中的数据和内容公开到LLMs
资源是模型上下文协议 (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方案。
资源类型
资源可以包含两种类型的内容:
文本资源
文本资源包含UTF-8编码的文本数据。这些适用于:
源代码
配置文件
日志文件
JSON/XML数据
纯文本
二进制资源
二进制资源包含以base64编码的原始二进制数据。这些适用于:
图像
PDFs
音频文件
视频文件
其他非文本格式
资源发现
客户端可以通过两种主要方法发现可用资源:
直接资源
服务器通过resources/list
端点。每个资源包括:
{
uri: string; // Unique identifier for the resource
name: string; // Human-readable name
description?: string; // Optional description
mimeType?: string; // Optional MIME type
size?: number; // Optional size in bytes
}
资源模板
对于动态资源,服务器可以公开URI模板客户端可以使用它来构造有效的资源uri:
复制
{
uriTemplate: string; // URI template following RFC 6570
name: string; // Human-readable name for this type
description?: string; // Optional description
mimeType?: string; // Optional MIME type for all matching resources
}
阅读资源
要读取资源,客户端会创建一个resources/read
具有资源URI的请求。
服务器以资源内容列表进行响应:
复制
{
contents: [
{
uri: string; // The URI of the resource
mimeType?: string; // Optional MIME type
// One of:
text?: string; // For text resources
blob?: string; // For binary resources (base64 encoded)
}
]
}
服务器可能会返回多个资源以响应一个resources/read
请求。例如,这可以用于在读取目录时返回目录内的文件列表。
资源更新
MCP通过两种机制支持资源的实时更新:
列表更改
当可用资源列表发生更改时,服务器可以通过notifications/resources/list_changed
通知。
内容更改
客户端可以订阅特定资源的更新:
客户端发送
resources/subscribe
使用资源URI服务器发送
notifications/resources/updated
当资源发生变化时客户端可以使用获取最新内容
resources/read
客户端可以取消订阅
resources/unsubscribe
示例实现
下面是在MCP服务器中实现资源支持的简单示例:
app = Server("example-server")
@app.list_resources()
async def list_resources() -> list[types.Resource]:
return [
types.Resource(
uri="file:///logs/app.log",
name="Application Logs",
mimeType="text/plain"
)
]
@app.read_resource()
async def read_resource(uri: AnyUrl) -> str:
if str(uri) == "file:///logs/app.log":
log_contents = await read_log_file()
return log_contents
raise ValueError("Resource not found")
# Start server
async with stdio_server() as streams:
await app.run(
streams[0],
streams[1],
app.create_initialization_options()
)
最佳实践
实施资源支持时:
使用清晰的描述性资源名称和uri
包括有用的描述以指导LLM理解
已知时设置适当的MIME类型
为动态内容实施资源模板
将订阅用于频繁更改的资源
使用清晰的错误消息优雅地处理错误
考虑大型资源列表的分页
适当时缓存资源内容
在处理之前验证uri
记录您的自定义URI方案
安全注意事项
公开资源时:
验证所有资源uri
实施适当的访问控制
清理文件路径以防止目录遍历
谨慎处理二进制数据
考虑资源读取的速率限制
审计资源访问
加密传输中的敏感数据
验证MIME类型
为长时间运行的读取实现超时
适当地处理资源清理
评论区