能力发现与协商机制
概述
UCP 的核心创新之一是动态能力发现和协商机制。这个机制使得平台可以自主发现商家支持的能力,并通过协商确定双方共同支持的能力集合,从而实现无许可集成(Permissionless Onboarding)。
能力发现流程
1. 商家 Profile 发布
商家在 /.well-known/ucp 端点发布自己的 Profile,声明支持的能力、服务和支付处理器。
Profile 结构:
{
"ucp": {
"version": "2026-01-23",
"services": {
"dev.ucp.shopping": [
{
"version": "2026-01-23",
"spec": "https://ucp.dev/.../specification/overview",
"transport": "rest",
"endpoint": "https://business.example.com/api/v2",
"schema": "https://ucp.dev/.../rest.openapi.json"
}
]
},
"capabilities": {
"dev.ucp.shopping.checkout": [
{
"version": "2026-01-23",
"spec": "https://ucp.dev/.../specification/checkout",
"schema": "https://ucp.dev/.../schemas/shopping/checkout.json"
}
],
"dev.ucp.shopping.fulfillment": [
{
"version": "2026-01-23",
"spec": "https://ucp.dev/.../specification/fulfillment",
"schema": "https://ucp.dev/.../schemas/shopping/fulfillment.json",
"extends": "dev.ucp.shopping.checkout"
}
]
},
"payment_handlers": { ... }
},
"signing_keys": [ ... ]
}关键字段:
version:协议版本(日期格式 YYYY-MM-DD)services:支持的服务和传输绑定capabilities:支持的能力和扩展payment_handlers:支付处理器配置signing_keys:用于验证签名的公钥
2. 平台 Profile 声明
平台在每次请求中通过 UCP-Agent header 声明自己的 Profile URI。
REST 传输:
POST /checkout-sessions HTTP/1.1
UCP-Agent: profile="https://platform.example/profiles/shopping-agent.json"
Content-Type: application/jsonMCP 传输:
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "create_checkout",
"arguments": {
"meta": {
"ucp-agent": {
"profile": "https://platform.example/profiles/shopping-agent.json"
}
},
"checkout": { ... }
}
}
}3. Profile 获取和验证
商家收到请求后:
获取 Platform Profile:
- 从
UCP-Agentheader 提取 Profile URI - 如果未缓存,则获取 Platform Profile
- 验证 Profile 格式和签名
- 从
验证要求:
- Profile URL 必须使用 HTTPS
- 不允许重定向(3xx)
- 必须包含有效的 JSON Schema
- 签名密钥必须有效
缓存策略:
- 最小 TTL 60 秒
- 支持 stale-while-revalidate
- 固定大小的 LRU 缓存
能力协商算法
协商流程
能力协商遵循 server-selects 架构,即商家(服务器)决定激活的能力集合。
┌─────────────┐ ┌─────────────┐
│ Platform │ │ Business │
└──────┬──────┘ └──────┬──────┘
│ │
│ 1. 请求 + Platform Profile URI │
├──────────────────────────────────>│
│ │
│ 2. 获取 Platform Profile
│ │
│ 3. 计算能力交集
│ │
│ 4. 版本选择
│ │
│ 5. 修剪孤立扩展
│ │
│ 6. 响应 + 激活的能力列表 │
│<──────────────────────────────────┤交集算法详解
能力交集算法确定哪些能力在会话中激活:
步骤 1:计算交集
对于商家的每个能力,如果平台也声明了同名能力,则包含在结果中。
def compute_intersection(business_capabilities, platform_capabilities):
intersection = {}
for name, business_versions in business_capabilities.items():
if name in platform_capabilities:
intersection[name] = {
'business': business_versions,
'platform': platform_capabilities[name]
}
return intersection示例:
- 商家支持:
checkout,fulfillment,discount - 平台支持:
checkout,cart,discount - 交集:
checkout,discount
步骤 2:版本选择
对于交集中的每个能力,计算双方都支持的版本集合,选择最高版本。
def select_version(business_versions, platform_versions):
# 计算共同版本
common_versions = set(business_versions) & set(platform_versions)
if not common_versions:
return None # 无共同版本,排除该能力
# 选择最高版本(日期格式,最新日期)
return max(common_versions)版本格式:YYYY-MM-DD(日期格式)
示例:
- 商家支持:
["2026-01-11", "2026-01-23"] - 平台支持:
["2026-01-11", "2026-01-23", "2026-02-01"] - 共同版本:
["2026-01-11", "2026-01-23"] - 选择版本:
2026-01-23
步骤 3:修剪孤立扩展
移除任何 extends 字段存在但父能力不在交集中的扩展。
def prune_orphaned_extensions(intersection):
active_capabilities = set(intersection.keys())
pruned = {}
for name, data in intersection.items():
capability = data['business'][0] # 假设选择第一个版本
# 检查扩展依赖
if 'extends' in capability:
parents = capability['extends']
if isinstance(parents, str):
parents = [parents]
# 检查是否至少有一个父能力在交集中
if any(parent in active_capabilities for parent in parents):
pruned[name] = data
else:
# 根能力,直接包含
pruned[name] = data
return pruned扩展依赖规则:
- 单父扩展:
extends: "dev.ucp.shopping.checkout"→ 父能力必须在交集中 - 多父扩展:
extends: ["checkout", "cart"]→ 至少一个父能力必须在交集中
步骤 4:重复修剪
重复步骤 3,直到没有更多能力被移除(处理传递性扩展链)。
传递性示例:
extension_a扩展checkoutextension_b扩展extension_a- 如果
checkout不在交集中,则extension_a和extension_b都需要移除
完整算法实现
def negotiate_capabilities(business_profile, platform_profile):
"""
能力协商算法
Args:
business_profile: 商家 Profile
platform_profile: 平台 Profile
Returns:
激活的能力集合
"""
business_caps = business_profile['ucp']['capabilities']
platform_caps = platform_profile['ucp']['capabilities']
# 步骤 1:计算交集
intersection = {}
for name, business_versions in business_caps.items():
if name in platform_caps:
intersection[name] = {
'business': business_versions,
'platform': platform_caps[name]
}
# 步骤 2:版本选择
active_capabilities = {}
for name, data in intersection.items():
business_versions = [v['version'] for v in data['business']]
platform_versions = [v['version'] for v in data['platform']]
common_versions = set(business_versions) & set(platform_versions)
if common_versions:
selected_version = max(common_versions)
# 选择对应的能力定义
business_def = next(v for v in data['business']
if v['version'] == selected_version)
active_capabilities[name] = business_def
# 步骤 3-4:修剪孤立扩展(重复直到稳定)
changed = True
while changed:
changed = False
active_names = set(active_capabilities.keys())
to_remove = []
for name, capability in active_capabilities.items():
if 'extends' in capability:
parents = capability['extends']
if isinstance(parents, str):
parents = [parents]
if not any(p in active_names for p in parents):
to_remove.append(name)
changed = True
for name in to_remove:
del active_capabilities[name]
return active_capabilities命名空间治理
反向域名命名
UCP 使用反向域名命名将治理权限直接编码到能力标识符中,无需中央注册表。
命名格式:
{reverse-domain}.{service}.{capability}组件:
{reverse-domain}:从域名所有权派生的权限标识符{service}:服务/垂直类别(如shopping、common){capability}:具体能力名称
示例:
dev.ucp.shopping.checkout:UCP 官方结账能力dev.ucp.shopping.fulfillment:UCP 官方履约能力com.example.payments.installments:供应商自定义分期付款能力
Spec URL 绑定
能力的 spec 和 schema 字段的 URL 源必须匹配命名空间权限。
规则:
dev.ucp.*→https://ucp.dev/...com.example.*→https://example.com/...
验证:
- 平台必须验证此绑定
- 如果源不匹配,应拒绝该能力
治理模型
| 命名空间模式 | 权限 | 治理 |
|---|---|---|
dev.ucp.* | ucp.dev | UCP 治理机构 |
com.{vendor}.* | {vendor}.com | 供应商组织 |
org.{org}.* | {org}.org | 组织 |
dev.ucp.* 命名空间保留给 UCP 治理机构批准的能力。供应商必须使用自己的反向域名命名空间定义自定义能力。
Schema 解析流程
解析步骤
平台必须按照以下顺序解析 Schema:
- 发现:从
/.well-known/ucp获取商家 Profile - 协商:计算能力交集
- 获取 Schema:获取基础 Schema 和所有激活的扩展 Schema
- 版本兼容性:验证扩展 Schema 的
requires约束 - 组合:通过
allOf链合并 Schema - 验证:根据组合后的 Schema 验证请求和响应
Schema 组合规则
扩展 Schema 模式
扩展 Schema 使用 allOf 定义组合类型,$defs 键必须使用完整的父能力名称:
{
"$defs": {
"discounts_object": { ... },
"dev.ucp.shopping.checkout": {
"title": "Checkout with Discount",
"allOf": [
{"$ref": "checkout.json"},
{
"type": "object",
"properties": {
"discounts": {
"$ref": "#/$defs/discounts_object"
}
}
}
]
}
}
}要求:
- 扩展 Schema 必须为
extends中声明的每个父能力提供$defs条目 $defs键必须与父能力的完整名称完全匹配
解析约定
要验证 payload,实现按以下方式解析扩展 Schema:
- 从操作确定根能力(如结账操作使用
dev.ucp.shopping.checkout) - 对于每个激活的扩展,解析并应用其
$defs[{root_capability}]
示例:结账响应包含折扣扩展
- 根能力:
dev.ucp.shopping.checkout - 扩展 Schema:
discount.json - 解析:
discount.json#/$defs/dev.ucp.shopping.checkout
版本依赖
扩展 Schema 可以声明 requires 对象来指示所需的协议和能力版本:
{
"name": "com.acme.shopping.loyalty",
"requires": {
"protocol": { "min": "2026-01-23" },
"capabilities": {
"dev.ucp.shopping.checkout": { "min": "2026-06-01" }
}
}
}约束格式:
min:最小版本(必需,包含)max:最大版本(可选,包含)
验证:
- 如果
requires存在,平台和商家必须验证协商的协议版本和能力版本满足声明的约束 - 不兼容的扩展从激活能力集中排除
响应中的能力声明
能力选择规则
商家必须在响应的 ucp.capabilities 中仅包含:
- 在此会话的协商交集中的能力,且
- 与此响应的操作类型相关的能力
根能力相关性
根能力如果匹配操作类型,则相关:
create_checkout/update_checkout/complete_checkout→dev.ucp.shopping.checkoutcreate_cart/update_cart→dev.ucp.shopping.cart- Order webhooks →
dev.ucp.shopping.order
扩展相关性
如果扩展的 extends 值中任何一个匹配相关根能力,则扩展相关。
选择示例
| 响应类型 | 包含 | 不包含 |
|---|---|---|
| Checkout | checkout, discount, fulfillment | cart, order |
| Cart | cart, discount | checkout, fulfillment, order |
| Order | order | checkout, cart, discount |
错误处理
协商错误类型
1. 发现失败
商家无法获取或解析平台的 Profile。
错误代码:
invalid_profile_url:Profile URL 格式错误、缺失或无法解析profile_unreachable:URL 可解析但获取失败(超时、非 2xx)profile_malformed:获取的内容不是有效的 JSON 或违反 Schema
HTTP 状态码:
- REST:400, 424, 422
- MCP:-32001
2. 协商失败
提供的 Profile 有效但能力交集为空或版本不兼容。
错误代码:
version_unsupported:平台的协议版本不受支持capabilities_incompatible:交集中没有兼容的能力
HTTP 状态码:
- REST:422(版本不支持)或 200(能力不兼容)
- MCP:-32001(版本不支持)或 result(能力不兼容)
continue_url 字段
当 UCP 协商失败时,continue_url 提供回退 Web 体验。
使用场景:
- 结账操作:链接到购物车或结账页面
- 目录操作:链接到产品或搜索结果
- 回退:链接到店面首页
这实现了优雅降级——代理可以将买家重定向到标准 Web 界面完成任务。
性能优化
Profile 缓存
商家端:
- 维护预批准平台的注册表
- 使用固定大小的 LRU 缓存
- 最小 TTL 60 秒
- 支持 stale-while-revalidate
平台端:
- 缓存商家 Profile
- 遵循 HTTP Cache-Control 指令
- 最小 TTL 60 秒
异步发现
商家可以实现异步 Profile 发现:
- 收到未知平台的请求
- 返回
503状态码和Retry-Afterheader - 在后台解析 Profile
- 平台重试时,已验证的 Profile 已缓存
这限制了资源消耗,同时保持响应性。
总结
能力发现与协商机制是 UCP 的核心创新,它实现了:
- 无许可集成:无需预先注册即可集成
- 动态适配:通过协商自动确定共同支持的能力
- 版本管理:支持独立的能力版本控制
- 扩展支持:通过依赖修剪确保扩展正确激活
- 性能优化:通过缓存和异步发现提高效率
这种设计使得 UCP 能够支持快速集成和灵活的功能组合,同时保持安全性和可扩展性。