MCP(Model Context Protocol)模型上下文协议 理论篇5 - 资源(Resources)

资源(Resources)将服务器中的数据和内容暴露给大语言模型(LLMs)

在模型上下文协议(MCP)中,资源是一个核心基本元素,允许服务器将数据和内容暴露给客户端,并作为LLM交互的上下文使用。资源的设计是应用程序控制的,这意味着客户端应用程序可以决定何时以及如何使用这些资源。不同的MCP客户端可能会以不同的方式处理资源,例如:

  • Claude Desktop 目前要求用户显式选择资源后才能使用。
  • 其他客户端可能会根据启发式方法自动选择资源。
  • 某些实现甚至可能允许AI模型本身决定使用哪些资源。

服务器作者在实现资源支持时应准备好处理这些交互模式。为了自动向模型暴露数据,服务器作者应使用模型控制的工具(如Tools)。

概述

资源代表MCP服务器希望向客户端提供的任何类型的数据。这可以包括:

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

资源URI

资源使用以下格式的URI进行标识:

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

例如:

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

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

资源类型

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

文本资源

文本资源包含UTF-8编码的文本数据,适用于:

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

二进制资源

二进制资源包含以base64编码的原始二进制数据,适用于:

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

资源发现

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

直接资源

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

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

资源模板

对于动态资源,服务器可以暴露URI模板,客户端可以使用这些模板构建有效的资源URI:

{
  "uriTemplate": "string",   // 遵循RFC 6570的URI模板
  "name": "string",          // 此类型的名称
  "description": "string",   // 可选的描述
  "mimeType": "string"       // 所有匹配资源的可选MIME类型
}

读取资源

客户端通过发送resources/read请求并附带资源URI来读取资源。服务器响应包含资源内容列表:

{
  "contents": [
    {
      "uri": "string",        // 资源的URI
      "mimeType": "string",   // 可选的MIME类型
      "text": "string",       // 文本资源的内容
      "blob": "string"        // 二进制资源的内容(base64编码)
    }
  ]
}

服务器可能会在一次resources/read请求中返回多个资源,例如读取目录时返回目录中的所有文件。

资源更新

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

列表变化

服务器可以通过notifications/resources/list_changed通知客户端可用资源列表的变化。

内容变化

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

  1. 客户端发送resources/subscribe请求并附带资源URI。
  2. 服务器在资源更新时发送notifications/resources/updated通知。
  3. 客户端可以通过resources/read获取最新内容。
  4. 客户端可以通过resources/unsubscribe取消订阅。

示例实现

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

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: "Application Logs",
        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("Resource not found");
});

总结

资源是MCP中的核心概念,允许服务器将数据和内容暴露给客户端,并作为LLM交互的上下文。资源的设计灵活,支持多种数据类型和交互模式。通过URI标识资源,客户端可以发现、读取和订阅资源的变化。服务器作者应根据不同的客户端需求实现资源支持,并考虑使用模型控制的工具来自动暴露数据。

### Python MCP Server 中 Cursor 的用法 在 Python MCP (Message Communication Protocol) 服务器中,`cursor` 是用于管理数据库查询结果的一个重要对象。它允许开发者通过编程方式执行 SQL 查询并处理返回的数据集[^1]。 以下是 `cursor` 在 Python MCP Server 连接中的典型用法: #### 建立连接与创建游标 首先需要建立到数据库的连接,并从中获取一个 `cursor` 对象。这通常涉及以下几个步骤: - 使用合适的库(如 psycopg2 或 pymysql)来初始化数据库连接。 - 调用连接对象上的 `.cursor()` 方法以获得一个新的游标实例。 ```python import mcp.db as db_module # 假设这是自定义模块或者标准库的一部分 connection = db_module.connect( host="localhost", user="your_username", password="your_password", database="mcp_database" ) cursor = connection.cursor() ``` 上述代码展示了如何设置基本的数据库连接以及创建游标的过程[^3]。 #### 执行查询操作 一旦获得了游标对象,就可以调用其方法来执行各种类型的 SQL 操作,比如 SELECT、INSERT 和 UPDATE 等语句。 对于简单的读取数据场景可以这样实现: ```python query = "SELECT id, name FROM users WHERE active = %s" try: cursor.execute(query, ("true",)) # 参数化查询防止SQL注入攻击 except Exception as e: print(f"An error occurred while executing the query: {e}") else: results = cursor.fetchall() # 获取所有匹配记录 for row in results: print(row) finally: cursor.close() # 关闭游标释放资源 ``` 这里需要注意的是,在实际应用过程中应当始终考虑异常情况的发生,并采取适当措施加以应对[^2]。 #### 更新或删除数据 除了检索之外,还可以利用游标的 execute 函数来进行修改型的操作,例如更新某条特定用户的邮箱地址如下所示: ```python update_query = """UPDATE users SET email=%(email)s WHERE username=%(username)s""" data_to_update = { 'email': 'new.email@example.com', 'username': 'johndoe' } affected_rows_count = None try: affected_rows_count = cursor.execute(update_query, data_to_update) connection.commit() # 提交更改至永久存储介质上 except Exception as err_msg: connection.rollback() # 如果失败则回滚事务状态回到之前的状态 raise RuntimeError('Database update failed') from err_msg print(f"{affected_rows_count} rows were updated.") ``` 此片段说明了当尝试改变表内字段值时应遵循的最佳实践之一——即先测试再确认提交;如果出现问题,则立即撤销所做的任何潜在破坏性的变动。 最后别忘了断开已不再使用的链接以免浪费系统资源---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值