Skip to content

资源

将服务器中的数据和内容公开给 LLM

资源是模型上下文协议 (MCP) 中的核心基元概念,它允许服务器公开可由客户端读取并用作 LLM 交互上下文的数据和内容。

image-20250306202838264

一、概述

资源表示 MCP 服务器希望提供给客户端的任何业务类型的数据。这可能包括:

  • 文件内容
  • 数据库记录
  • API 响应
  • 实时系统数据
  • 屏幕截图和图像
  • 日志文件
  • 以及更多

每个资源都由唯一的 URI 标识,并且可以包含文本或二进制数据。

《模型上下文协议中文网》附注:资源在业务上的本质,就是你对外所提供的核心增强价值点之一(业务数据),最终以数据形式返回。

二、资源 URI

使用遵循以下格式的 URI 标识资源:

plaintext
[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

typescript
{
  uri: string;           // 资源的唯一标识符
  name: string;          // 可读名称
  description?: string;  // 可选描述
  mimeType?: string;     // 可选 MIME 类型
}

2、资源模板

对于动态资源,服务器可以公开 URI 模板,客户端可以使用这些模板来构造有效的资源 URI:

typescript
{
  uriTemplate: string;   // URI 模板遵循 RFC 6570
  name: string;          // 该类型的可读名称
  description?: string;  // 可选说明
  mimeType?: string;     // 所有匹配资源的可选 MIME 类型
}

五、阅读资源

要读取资源,客户端使用资源 URI 发出请求。resources/read

服务器使用资源内容列表进行响应:

typescript
{
  contents: [
    {
      uri: string;        // 资源的唯一标识符
      mimeType?: string;  // 可选 MIME 类型

      // 二选一的类型
      text?: string;      // 文本资源
      blob?: string;      // 二进制资源(base64 编码)
    }
  ]
}

image-20250306204805499

六、资源更新

MCP 通过两种机制支持实时更新资源:

1、列表更改

当 Client 端的可用资源列表发生更改时,Server 可以通过通知接口,通知 Client 端。notifications/resources/list_changed

2、内容更改

客户端可以订阅特定资源的更新:

  1. 带有资源 URI 的客户端发送resources/subscribe
  2. 服务器在资源更改时发送notifications/resources/updated
  3. 客户端可以使用resources/read
  4. 客户可以使用resources/unsubscribe

七、示例实现

以下是在 MCP 服务器中实现资源支持的简单示例:

TypeScript范例
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、最佳实践

实施资源支持时:

  1. 使用清晰、描述性强的资源名称和 URI
  2. 包括有用的描述以指导理解 LLM
  3. 在已知时设置适当的 MIME 类型
  4. 为动态内容实施资源模板
  5. 对频繁更改的资源使用订阅
  6. 使用清晰的错误消息优雅地处理错误
  7. 考虑对大型资源列表进行分页
  8. 在适当时缓存资源内容
  9. 在处理之前验证 URI
  10. 记录您的自定义 URI 方案

2、安全注意事项

公开资源时:

  • 验证所有资源 URI
  • 实施适当的访问控制
  • 清理文件路径以防止目录遍历
  • 谨慎处理二进制数据
  • 考虑对资源读取进行速率限制
  • 审计资源访问
  • 加密传输中的敏感数据
  • 验证 MIME 类型
  • 为长时间运行的读取实施超时
  • 适当地处理资源清理