> ## Documentation Index
> Fetch the complete documentation index at: https://model-context-protocol.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 资源

> 将数据和内容从您的服务器暴露给 LLM

资源是模型上下文协议（MCP）中的核心原语，允许服务器暴露数据和内容，客户端可以读取这些数据并将其用作 LLM 交互的上下文。

<Note>
  资源设计为**应用程序控制**，这意味着客户端应用程序可以决定如何以及何时使用它们。
  不同的 MCP 客户端可能会以不同的方式处理资源。例如：

  * Claude 桌面版目前要求用户明确选择资源后才能使用
  * 其他客户端可能会根据启发式自动选择资源
  * 一些实现甚至可能允许 AI 模型本身决定使用哪些资源

  服务器作者在实现资源支持时应准备好处理任何这些交互模式。为了自动向模型暴露数据，服务器作者应使用**模型控制**的原语，例如[工具](./tools)。
</Note>

## 概述

资源表示 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 编码的原始二进制数据。适用于：

* 图像
* PDF
* 音频文件
* 视频文件
* 其他非文本格式

## 资源发现

客户端可以通过两种主要方法发现可用资源：

### 直接资源

服务器通过 `resources/list` 端点暴露具体资源列表。每个资源包括：

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

### 资源模板

对于动态资源，服务器可以暴露[URI 模板](https://datatracker.ietf.org/doc/html/rfc6570)，客户端可以使用这些模板构建有效的资源 URI：

```typescript theme={null}
{
  uriTemplate: string;   // 遵循 RFC 6570 的 URI 模板
  name: string;          // 此类型的人类可读名称
  description?: string;  // 可选描述
  mimeType?: string;     // 所有匹配资源的可选 MIME 类型
}
```

## 读取资源

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

服务器响应资源内容列表：

```typescript theme={null}
{
  contents: [
    {
      uri: string;        // 资源的 URI
      mimeType?: string;  // 可选 MIME 类型

      // 其中之一：
      text?: string;      // 对于文本资源
      blob?: string;      // 对于二进制资源（base64 编码）
    }
  ]
}
```

<Tip>
  服务器可以在一个 `resources/read` 请求中返回多个资源。这可以用于例如在读取目录时返回目录中的文件列表。
</Tip>

## 资源更新

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

### 列表更改

服务器可以通过 `notifications/resources/list_changed` 通知通知客户端其可用资源列表发生更改。

### 内容更改

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

1. 客户端发送 `resources/subscribe`，附带资源 URI
2. 资源更改时，服务器发送 `notifications/resources/updated`
3. 客户端可以使用 `resources/read` 获取最新内容
4. 客户端可以使用 `resources/unsubscribe` 取消订阅

## 实现示例

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

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    const server = new Server({
      name: "example-server",
      version: "1.0.0"
    }, {
      capabilities: {
        resources: {}
      }
    });

    // 列出可用资源
    server.setRequestHandler(ListResourcesRequestSchema, async () => {
      return {
        resources: [
          {
            uri: "file:///logs/app.log",
            name: "应用程序日志",
            mimeType: "text/plain"
          }
        ]
      };
    });

    // 读取资源内容
    server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
      const uri = request.params.uri;

      if (uri === "file:///logs/app.log") {
        const logContents = await readLogFile();
        return {
          contents: [
            {
              uri,
              mimeType: "text/plain",
              text: logContents
            }
          ]
        };
      }

      throw new Error("资源未找到");
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    app = Server("example-server")

    @app.list_resources()
    async def list_resources() -> list[types.Resource]:
        return [
            types.Resource(
                uri="file:///logs/app.log",
                name="应用程序日志",
                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("资源未找到")

    # 启动服务器
    async with stdio_server() as streams:
        await app.run(
            streams[0],
            streams[1],
            app.create_initialization_options()
        )
    ```
  </Tab>
</Tabs>

## 最佳实践

实现资源支持时：

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

## 安全考虑

暴露资源时：

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