Junki
Junki
Published on 2025-03-21 / 68 Visits
0
0

MCP 优雅加载服务器中的数据和内容:Resources 详解

资源是模型上下文协议(MCP)中的一种核心基本元素,它使服务器能够公开数据和内容,这些数据和内容可供客户端读取,并用作大语言模型(LLM)交互时的上下文信息。

官方文档:https://modelcontextprotocol.io/docs/concepts/resources

一、资源简介

(一)概述

资源代表着模型上下文协议(MCP)服务器希望向客户端提供的任何类型的数据。这可以包括:

  • 文件内容
  • 数据库记录
  • 应用程序编程接口(API)响应数据
  • 实时系统数据
  • 屏幕截图和图像
  • 日志文件
  • 以及更多其他数据

每个资源都由一个唯一的统一资源标识符(URI)来标识,并且可以包含文本数据二进制数据

(二)资源统一资源标识符(URI)

资源通过遵循以下格式的 URI 来进行标识:

[协议]://[主机]/[路径]

例如:

  • file:///home/user/documents/report.pdf
  • postgres://database/customers/schema
  • screen://localhost/display1

协议和路径结构由 MCP 服务器的实现来定义。服务器可以定义它们自己的自定义 URI 方案。

(三)资源类型

资源可以包含两种类型的内容:

文本资源

文本资源包含以 UTF-8 编码的文本数据。它们适用于以下场景:

  • 源代码
  • 配置文件
  • 日志文件
  • JSON/XML 数据
  • 纯文本

二进制资源

二进制资源包含以 Base64 编码的原始二进制数据。它们适用于以下场景:

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

二、开发实践

源码仓库:https://gitee.com/fangjunjie/mcp-resources-demo

(一)MCP Server 关键代码解析

直接资源注册

// 直接资源
let appConfig = "一些配置内容"
mcpServer.resource(
    "config",
    "config://app",
    async (uri) => ({
        contents: [{
            uri: uri.href,
            text: appConfig
        }]
    })
);

注册资源的名称、地址、内容返回。

模板资源注册

// 模板资源
const userProfileResources = [{
    uri: 'users://1001/profile',
    name: 'user-1001-profile'
}]
// 注册模板资源
mcpServer.resource(
    "user-profile",
    new ResourceTemplate("users://{userId}/profile", {
        list: async () => ({
            resources: userProfileResources
        })
    }),
    async (uri, {userId}) => ({
        contents: [{
            uri: uri.href,
            text: `用户 ${userId} 的个性化配置`
        }]
    })
);

注册资源的名称、地址模板、内容返回。

ResourceTemplate 对象定义类资源模板。这里的 userId 就是一个动态参数。这里的 list 函数定义了可能的所有模板资源,如果不需要被客户端查询到所有资源列表,可以直接设置为 null

内容返回函数中的 contents 是一个内容对象数组。内容对象可以是文本内容也可以是二进制内容,对应 textblob 字段。

资源更新时通知客户端

// 模拟资源动态更新
setInterval(async () => {
    // 修改配置内容
    appConfig = `一些配置内容${new Date().getTime()}`

    // 随机增加一个用户配置
    const userId = new Date().getTime()
    userProfileResources.push({
        uri: `users://${userId}/profile`,
        name: `user-${userId}-profile`
    })

    if (transport) {
        // 通知客户端资源列表更新
        await mcpServer.server.notification({method: "notifications/resources/list_changed"});
        // 通知客户端资源内容更新
        await mcpServer.server.notification({method: "notifications/resources/updated", params: {uri: "config://app"}});
    }
}, 5000)

notifications/resources/list_changed 为资源列表更新通知。

notifications/resources/updated 为资源内容更新通知,可以通过 params 参数传递具体资源信息。

(二)MCP Client 关键代码解析

获取资源列表

const resources = await client.listResources();
console.log("列出所有资源:")
console.log(resources)

读取资源内容

const resource = await client.readResource({uri: uri});
console.log("读取指定资源:")
console.log(resource)

订阅服务器通知

// 订阅资源更新
client.fallbackNotificationHandler = async (notification) => {
    console.log("接收到通知:")
    console.log(notification)

    if (notification.method === "notifications/resources/list_changed") {
        console.log("收到资源列表更新通知,读取资源列表。")
        await listResources()
    }

    if (notification.method === "notifications/resources/updated") {
        console.log("收到资源内容更新通知,读取资源内容。")
        await readResource(notification.params!.uri as string)
    }
};

Comment