跳转到主要内容

资源与提示词

6.1 Resources(资源)详解

Resources让Server向AI应用暴露数据。和Tools的区别:
ToolsResources
性质执行操作提供数据
控制方AI模型决定调用应用(Host)主动读取
副作用可能有(写数据库、调API)无(只读)
场景”帮我查库存""这是商品分类结构”

资源URI

每个资源有唯一的URI标识:
commerce://catalog/categories     # 商品分类
commerce://store/info             # 店铺信息
file:///path/to/config.json       # 本地文件
https://api.example.com/data      # 远程数据

URI模板(RFC 6570)

MCP支持RFC 6570 URI模板语法,用于定义动态资源。Server在 resources/list 返回中可以包含URI模板,Client通过模板变量填充来请求具体资源:
{
  "uriTemplate": "commerce://products/{sku}",
  "name": "商品详情",
  "description": "按SKU获取指定商品的详细信息",
  "mimeType": "application/json"
}
常用URI模板模式:
commerce://products/{sku}              # 单个商品
commerce://orders/{orderId}/items      # 订单明细
commerce://categories/{categoryId}     # 分类详情
commerce://inventory/{sku}/{warehouse} # 指定仓库的库存
Client使用时填充变量:
{
  "method": "resources/read",
  "params": {
    "uri": "commerce://products/SHOE-001"
  }
}

Annotations(资源注解)

每个资源可以携带Annotations元数据,帮助Host决定如何使用资源:
{
  "uri": "commerce://catalog/categories",
  "name": "商品分类",
  "description": "完整的商品分类层级结构",
  "mimeType": "application/json",
  "annotations": {
    "audience": ["user", "assistant"],
    "priority": 0.8,
    "lastModified": "2026-04-10T08:00:00Z"
  }
}
Annotations字段说明:
字段类型说明
audience字符串数组目标受众。"user" 表示适合展示给用户,"assistant" 表示适合提供给AI模型
priority数字(0-1)优先级。1为最高。Host可据此决定在上下文窗口有限时优先加载哪些资源
lastModifiedISO 8601字符串最后修改时间。帮助Client决定是否需要重新读取

资源订阅

如果Server在初始化时声明 resources: { subscribe: true },Client可以订阅资源变化:
// Client → Server: 订阅资源
{
  "method": "resources/subscribe",
  "params": { "uri": "commerce://inventory/SHOE-001" }
}

// Server → Client: 资源内容变化通知
{
  "method": "notifications/resources/updated",
  "params": { "uri": "commerce://inventory/SHOE-001" }
}
收到通知后,Client重新调用 resources/read 获取最新数据。这种模式适合实时性要求高的场景,如库存监控。 取消订阅:
{
  "method": "resources/unsubscribe",
  "params": { "uri": "commerce://inventory/SHOE-001" }
}

资源列表变更通知

当Server的资源集合发生变化(新增或移除资源),可通知Client:
{ "method": "notifications/resources/list_changed" }
Client收到后重新调用 resources/list 获取最新的资源列表。

实现示例

// 静态资源
server.resource(
  "commerce://catalog/categories",
  "商品分类",
  "application/json",
  async () => {
    const categories = await db.categories.getAll();
    return JSON.stringify(categories, null, 2);
  }
);

// 动态资源(URI模板)
server.resource(
  "commerce://products/{sku}",
  "商品详情",
  "application/json",
  async (uri) => {
    const sku = uri.pathname.split("/").pop();
    const product = await db.products.findBySku(sku);
    if (!product) throw new Error(`商品 ${sku} 不存在`);
    return JSON.stringify(product, null, 2);
  }
);

6.2 Prompts(提示词模板)详解

Prompts是Server预定义的交互模板。与Tools和Resources不同,Prompts是用户控制的 — 用户在Host应用中主动选择使用哪个模板。

提示词结构

{
  "name": "product_comparison",
  "description": "对比两个商品的优劣",
  "arguments": [
    { "name": "product1", "description": "第一个商品SKU", "required": true },
    { "name": "product2", "description": "第二个商品SKU", "required": true },
    { "name": "focus", "description": "关注维度(价格/性能/评价)", "required": false }
  ]
}

获取提示词(带参数)

// Client → Server
{
  "method": "prompts/get",
  "params": {
    "name": "product_comparison",
    "arguments": {
      "product1": "SHOE-001",
      "product2": "SHOE-002",
      "focus": "性价比"
    }
  }
}

// Server → Client
{
  "result": {
    "messages": [
      {
        "role": "user",
        "content": {
          "type": "text",
          "text": "请从性价比角度对比以下商品:\n\n商品1: Nike Air Max (SHOE-001) - 899元\n商品2: Adidas Ultra Boost (SHOE-002) - 1299元\n\n分析各自优劣并给出购买建议。"
        }
      }
    ]
  }
}

商务场景的提示词示例

// 商品对比
server.prompt(
  "product_comparison",
  "对比两个商品的优劣",
  [
    { name: "product1", description: "第一个商品SKU", required: true },
    { name: "product2", description: "第二个商品SKU", required: true }
  ],
  async ({ product1, product2 }) => {
    const p1 = await db.products.findBySku(product1);
    const p2 = await db.products.findBySku(product2);
    return {
      messages: [{
        role: "user",
        content: {
          type: "text",
          text: `请对比以下两个商品:\n\n商品1: ${JSON.stringify(p1)}\n\n商品2: ${JSON.stringify(p2)}\n\n从价格、功能、评价三个维度分析各自优劣。`
        }
      }]
    };
  }
);

// 订单摘要
server.prompt(
  "order_summary",
  "生成用户订单的摘要报告",
  [
    { name: "userId", description: "用户ID", required: true },
    { name: "period", description: "时间范围(如 last_month)", required: false }
  ],
  async ({ userId, period = "last_month" }) => {
    const orders = await db.orders.getByUser(userId, period);
    return {
      messages: [{
        role: "user",
        content: {
          type: "text",
          text: `以下是用户最近的订单数据:\n\n${JSON.stringify(orders, null, 2)}\n\n请生成一份简洁的消费摘要,包括总消费、常购品类、消费趋势。`
        }
      }]
    };
  }
);

多消息提示词

Prompts可以返回多条消息,包括system角色:
server.prompt(
  "customer_service",
  "启动客服助手模式",
  [],
  async () => {
    const policies = await db.policies.getAll();
    return {
      messages: [
        {
          role: "assistant",
          content: {
            type: "text",
            text: `你是一个专业的客服助手。以下是店铺政策:\n\n${JSON.stringify(policies)}\n\n请始终基于政策回答用户问题。`
          }
        }
      ]
    };
  }
);

嵌入资源的提示词

Prompts中的消息可以使用 embedded_resource 类型嵌入资源数据:
server.prompt(
  "analyze_catalog",
  "分析商品目录结构",
  [],
  async () => {
    return {
      messages: [{
        role: "user",
        content: {
          type: "resource",
          resource: {
            uri: "commerce://catalog/categories",
            mimeType: "application/json",
            text: await db.categories.getJsonString()
          }
        }
      }]
    };
  }
);

何时用Prompt vs Tool vs Resource

场景推荐原因
固定的交互模式Prompt模板化,用户可选
动态的操作ToolAI模型自主决策
需要特定提问格式Prompt控制输入质量
需要执行动作ToolPrompt只提供模板
静态上下文数据Resource无副作用,Host控制读取时机
高优先级背景信息Resource + Annotationspriority字段控制加载优先级

下一章: 安全与认证 — OAuth 2.1集成和权限管理