协议规范 
本文档定义了 MCP 协议在 MQTT 传输层下的特殊要求,包括 MQTT 主题、客户端 ID 格式等,并描述了 MQTT 传输层的生命周期,包括服务发现、初始化、能力列表变更、资源更新和关闭流程。
请结合 MCP 规范一起阅读。
术语 
- server-name:MCP 服务器的标识符,将包含在 MQTT 消息主题中。 - 多个使用相同 - server-name的连接视为同一个 MCP 服务器的多个实例,提供完全相同的服务。MCP 客户端发送初始化消息时,应根据客户端侧策略选择其中一个。- 不同 - server-name的 MCP 服务器可能提供类似功能,此时客户端可根据权限、LLM 推荐或用户选择,决定初始化连接的服务器。- 连接 MQTT Broker 后,Broker 可通过 MQTT CONNECT 消息中的 - MCP-SERVER-NAME用户属性建议 MCP 服务器使用的- server-name。如有建议,MCP 服务器必须采用该名称;否则应根据自身功能使用默认名称。- server-name必须采用以- /分隔的层级主题风格,便于客户端通过 MQTT 通配符订阅特定类型的 MCP 服务器,例如:- server-type/sub-type/name。- server-name不应包含- +和- #字符,且应在所有 MCP 服务器中唯一。
- server-name-filter:用于匹配 - server-name的 MQTT 主题过滤器,可包含- /、- +、- #。详见 server-name 说明。- 连接 MQTT Broker 后,Broker 可通过 MQTT CONNACK 消息中的 - MCP-SERVER-NAME-FILTERS用户属性建议 MCP 客户端使用的过滤器。该属性值为字符串数组,每个字符串为 MQTT 主题过滤器。若无建议,客户端应根据自身功能使用默认过滤器。
- server-id:MCP 服务器实例的 MQTT Client ID,除 - /、- +、- #外任意字符串。必须全局唯一,并包含在主题中。
- mcp-client-id:客户端的 MQTT Client ID,除 - /、- +、- #外任意字符串。必须全局唯一,并包含在主题中。每次初始化请求需使用不同的 client-id。
消息主题 
MCP 通过 MQTT 主题传递消息,协议包含如下主题:
| 主题名称 | 主题格式 | 说明 | 
|---|---|---|
| 服务器控制主题 | $mcp-server/{server-id}/{server-name} | 初始化及其他控制消息。 | 
| 服务器能力变更主题 | $mcp-server/capability/{server-id}/{server-name} | 能力列表变更或资源更新通知。 | 
| 服务器在线状态主题 | $mcp-server/presence/{server-id}/{server-name} | 服务器在线/离线状态消息。 | 
| 客户端在线状态主题 | $mcp-client/presence/{mcp-client-id} | 客户端在线/离线状态消息。 | 
| 客户端能力变更主题 | $mcp-client/capability/{mcp-client-id} | 客户端能力列表变更通知。 | 
| RPC 主题 | $mcp-rpc/{mcp-client-id}/{server-id}/{server-name} | RPC 请求/响应及通知消息。 | 
MQTT 协议版本 
MCP 服务器和客户端必须使用 MQTT 5.0 协议。
用户属性 
CONNECT 消息必须设置如下用户属性:
- MCP-COMPONENT-TYPE:- mcp-client或- mcp-server
- MCP-META:包含 MCP 组件元数据的 JSON 对象,如版本、实现信息、位置等。Broker 可据此建议 server-name 或 server-name-filter。
CONNACK 消息(Broker 发送)可选用户属性:
- MCP-SERVER-NAME:Broker 建议的 MCP 服务器名称,仅服务器连接时存在。
- MCP-RBAC:JSON 数组,包含服务器名称及对应角色名,客户端可据此判断权限。每个元素为包含- server_name和- role_name的对象,仅客户端连接时存在。
- MCP-SERVER-NAME-FILTERS:Broker 建议的服务器名称过滤器,字符串数组,每个为 MQTT 主题过滤器,仅客户端连接时存在。
PUBLISH 消息必须设置如下用户属性:
- MCP-COMPONENT-TYPE:- mcp-client或- mcp-server
- MCP-MQTT-CLIENT-ID:发送方的 MQTT Client ID
会话过期时间 
会话过期时间必须设为 0,客户端断开时会话立即清理。
MQTT Client ID 
MCP 服务器 
MCP 服务器的 Client ID(server-id)为除 /、+、# 外的任意字符串。
MCP 客户端 
MCP 客户端的 Client ID(mcp-client-id)为除 /、+、# 外的任意字符串,每次初始化请求需使用不同的 client-id。
MQTT 主题与过滤器 
MCP 服务器订阅 
| 主题过滤器 | 说明 | 
|---|---|
| $mcp-server/{server-id}/{server-name} | 服务器控制主题,接收控制消息。 | 
| $mcp-client/capability/{mcp-client-id} | 客户端能力变更主题,接收客户端能力列表变更通知。 | 
| $mcp-client/presence/{mcp-client-id} | 客户端在线状态主题,接收客户端断开通知。 | 
| $mcp-rpc/{mcp-client-id}/{server-id}/{server-name} | RPC 主题,接收来自客户端的 RPC 请求、响应和通知。 | 
注意
服务器订阅 RPC 主题时必须设置 No Local 选项,避免收到自身消息。
MCP 服务器发布 
| 主题名称 | 消息内容 | 
|---|---|
| $mcp-server/capability/{server-id}/{server-name} | 能力列表变更或资源更新通知。 | 
| $mcp-server/presence/{server-id}/{server-name} | 服务器在线状态消息,详见服务发现。 | 
| $mcp-rpc/{mcp-client-id}/{server-id}/{server-name} | RPC 请求、响应和通知。 | 
注意
- 服务器发布在线状态消息时,必须将 $mcp-server/presence/{server-id}/{server-name}的 RETAIN 标志设为 True。
- 连接 MQTT Broker 时,服务器必须将 $mcp-server/presence/{server-id}/{server-name}设为遗嘱主题,负载为空,用于异常断开时清除保留消息。
MCP 客户端订阅 
| 主题过滤器 | 说明 | 
|---|---|
| $mcp-server/capability/{server-id}/{server-name-filter} | 能力变更主题,接收服务器能力列表变更或资源更新通知。 | 
| $mcp-server/presence/+/{server-name-filter} | 服务器在线状态主题,接收服务器在线状态消息。 | 
| $mcp-rpc/{mcp-client-id}/{server-id}/{server-name-filter} | RPC 主题,接收服务器发送的 RPC 请求、响应和通知。 | 
注意
客户端订阅 RPC 主题时必须设置 No Local 选项,避免收到自身消息。
MCP 客户端发布 
| 主题名称 | 消息内容 | 
|---|---|
| $mcp-server/{server-id}/{server-name} | 发送控制消息,如初始化请求。 | 
| $mcp-client/capability/{mcp-client-id} | 发送客户端能力列表变更通知。 | 
| $mcp-client/presence/{mcp-client-id} | 发送客户端断开通知。 | 
| $mcp-rpc/{mcp-client-id}/{server-id}/{server-name} | 向指定服务器发送 RPC 请求/响应。 | 
注意
连接 MQTT Broker 时,客户端必须将 $mcp-client/presence/{mcp-client-id} 设为遗嘱主题,负载为 "disconnected" 通知,用于异常断开时通知服务器。
服务发现 
服务注册 
MCP 服务器启动后,向 MQTT Broker 注册服务。服务发现与注册主题为:$mcp-server/presence/{server-id}/{server-name}。
服务器必须在启动时向服务在线状态主题发布 "server/online" 通知,并设置 RETAIN 标志为 True。
"server/online" 通知应只包含简要信息,避免消息过大。客户端可在初始化后请求详细信息。
- MCP 服务器功能简述,便于客户端选择初始化对象。
- 元数据,如角色与权限,帮助客户端理解访问控制策略。rbac字段可包含角色列表,每个角色含名称、描述、允许的方法、工具和资源,Broker 可据此实现基于角色的访问控制(RBAC)。
{
    "jsonrpc": "2.0",
    "method": "notifications/server/online",
    "params": {
        "server_name": "example/server",
        "description": "简要描述 MCP 服务器功能,便于客户端按需选择。若提供工具,仅说明工具类型,不含参数,减少消息体积。",
        "meta": {
            "rbac": {
                "roles": [
                    {
                        "name": "admin",
                        "description": "管理员角色,拥有全部权限",
                        "allowed_methods": [
                            "notifications/initialized",
                            "ping", "tools/list", "tools/call", "resources/list", "resources/read",
                            "resources/subscribe", "resources/unsubscribe"
                        ],
                        "allowed_tools": "all",
                        "allowed_resources": "all"
                    },
                    {
                        "name": "user",
                        "description": "普通用户角色,权限有限",
                        "allowed_methods": [
                            "notifications/initialized",
                            "ping", "tools/list", "tools/call", "resources/list", "resources/read"
                        ],
                        "allowed_tools": [
                            "get_vehicle_status", "get_vehicle_location"
                        ],
                        "allowed_resources": [
                            "file:///vehicle/telemetry.data"
                        ]
                    }
                ]
            }
        }
    }
}详细信息如工具参数,应由客户端按需通过 **/list 请求获取。
客户端可随时订阅 $mcp-server/presence/+/{server-name-filter},其中 {server-name-filter} 为服务器名称过滤器。
例如,若服务器名称为 {server-type}/{sub-type}/{name},客户端仅有权限访问 {server-type}/{sub-type} 类型服务器,则可订阅 $mcp-server/presence/+/{server-type}/{sub-type}/#,一次性获取所有 {sub-type} 类型服务器的在线状态。
虽然客户端可订阅 $mcp-server/presence/+/# 获取所有类型服务器,但管理员可通过 MQTT Broker 的 ACL 限制其只能在如 $mcp-rpc/{mcp-client-id}/{server-id}/{server-type}/{sub-type}/# 等主题收发消息。因此,过宽的订阅无实际意义。合理设计 {server-name-filter} 可减少无关信息干扰。
服务注销 
连接 MQTT Broker 时,服务器必须将 $mcp-server/presence/{server-id}/{server-name} 设为遗嘱主题,负载为空,用于异常断开时清除注册信息。
主动断开前,服务器必须向 $mcp-server/presence/{server-id}/{server-name} 发送空消息,清除注册信息。
在 $mcp-server/presence/{server-id}/{server-name} 主题上:
- 客户端收到 server/online通知时,应记录{server-id}为该{server-name}的一个实例。
- 客户端收到空消息时,应清除缓存的 {server-id}。只要有任一实例在线,客户端应认为 MCP 服务器在线。
服务注册与注销消息流程如下:
初始化 
本节仅描述 MQTT 传输相关的初始化流程,详细内容见生命周期。
初始化阶段必须是客户端与服务器的首次交互。
客户端必须在发送初始化请求前,订阅 RPC 主题($mcp-rpc/{mcp-client-id}/{server-id}/{server-name}),并设置 No Local 选项。
服务器必须在响应初始化前,订阅 RPC 主题($mcp-rpc/{mcp-client-id}/{server-id}/{server-name}),并设置 No Local 选项。
客户端必须通过 $mcp-server/{server-id}/{server-name} 主题发送 initialize 请求,内容包括:
- 支持的协议版本
- 客户端能力
- 客户端实现信息
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
        "protocolVersion": "2024-11-05",
        "capabilities": {
            "roots": {
                "listChanged": true
            },
            "sampling": {}
        },
        "clientInfo": {
            "name": "ExampleClient",
            "version": "1.0.0"
        }
    }
}服务器必须通过 $mcp-rpc/{mcp-client-id}/{server-id}/{server-name} 主题响应自身能力及信息:
{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "protocolVersion": "2024-11-05",
        "capabilities": {
            "logging": {},
            "prompts": {
                "listChanged": true
            },
            "resources": {
                "subscribe": true,
                "listChanged": true
            },
            "tools": {
                "listChanged": true
            }
        },
        "serverInfo": {
            "name": "ExampleServer",
            "version": "1.0.0"
        }
    }
}初始化成功后,客户端必须通过 $mcp-rpc/{mcp-client-id}/{server-id}/{server-name} 发送已初始化通知:
{
    "jsonrpc": "2.0",
    "method": "notifications/initialized"
}能力列表变更 
客户端在发送初始化请求前,必须订阅服务器能力列表变更主题:$mcp-server/capability/{server-id}/{server-name-filter}。
服务器在响应初始化请求前,必须订阅客户端能力列表变更主题:$mcp-client/capability/{mcp-client-id}。
后续能力列表更新时:
- 服务器向 $mcp-server/capability/{server-id}/{server-name}发送通知
- 客户端向 $mcp-client/capability/{mcp-client-id}发送通知
能力列表变更通知负载依赖具体能力,如工具变更为 "notifications/tools/list_changed"。收到通知后,需通过 RPC 获取最新能力列表,详见相关能力文档。
资源更新 
MCP 协议允许客户端订阅特定资源的变更。
若服务器支持资源订阅能力,客户端可在发送已初始化通知前订阅资源变更主题。
客户端订阅资源变更主题为:$mcp-server/capability/{server-id}/{server-name}。
资源变更时,服务器应向 $mcp-server/capability/{server-id}/{server-name} 发送通知。
关闭流程 
服务器断开 
服务器必须连接时设置遗嘱消息,通知客户端异常断开,遗嘱主题为 $mcp-server/presence/{server-id}/{server-name},负载为空。
主动断开前,服务器必须向该主题发送空消息。
服务器如需与客户端“去初始化”但保持与 Broker 的连接,必须向 RPC 主题 $mcp-rpc/{mcp-client-id}/{server-id}/{server-name} 发送 "disconnected" 通知,并取消订阅如下主题:
- $mcp-client/capability/{mcp-client-id}
- $mcp-client/presence/{mcp-client-id}
- $mcp-rpc/{mcp-client-id}/{server-id}/{server-name}
"disconnected" 通知格式:
{
    "jsonrpc": "2.0",
    "method": "notifications/disconnected"
}客户端收到服务器在线状态主题的空消息或 RPC 主题的 "disconnected" 通知时,必须视服务器为离线,清除缓存的 {server-id},并取消订阅如下主题:
- $mcp-server/capability/{server-id}/{server-name-filter}
- $mcp-rpc/{mcp-client-id}/{server-id}/{server-name-filter}
客户端断开 
服务器必须在响应初始化前订阅客户端在线状态主题($mcp-client/presence/{mcp-client-id})。
客户端必须连接时设置遗嘱消息,通知服务器异常断开,遗嘱主题为 $mcp-client/presence/{mcp-client-id},负载为 "disconnected" 通知。
主动断开前,客户端必须向该主题发送 "disconnected" 通知。
客户端如需与服务器“去初始化”但保持与 Broker 的连接,必须向 RPC 主题 $mcp-rpc/{mcp-client-id}/{server-id}/{server-name} 发送 "disconnected" 通知,并取消订阅如下主题:
- $mcp-server/capability/{server-id}/{server-name-filter}
- $mcp-rpc/{mcp-client-id}/{server-id}/{server-name-filter}
服务器收到 "disconnected" 通知后,必须取消订阅如下主题:
- $mcp-client/capability/{mcp-client-id}
- $mcp-client/presence/{mcp-client-id}
- $mcp-rpc/{mcp-client-id}/{server-id}/{server-name}
"disconnected" 通知格式:
{
    "jsonrpc": "2.0",
    "method": "notifications/disconnected"
}健康检查 
客户端或服务器可随时发送 ping 请求检查对方健康状态。
- 客户端若未在合理时间收到服务器 ping响应,必须向$mcp-client/presence/{mcp-client-id}发送 "disconnected" 通知并断开自身连接。
- 服务器若未及时收到客户端 ping响应,必须向客户端发送其他 RPC 请求。
详见 Ping。
超时设置 
所有 RPC 请求均通过 MQTT 异步发送,需考虑超时。不同请求超时时间可配置,推荐默认值如下:
- "initialize":30 秒
- "ping":10 秒
- "roots/list":30 秒
- "resources/list":30 秒
- "tools/list":30 秒
- "prompts/list":30 秒
- "prompts/get":30 秒
- "sampling/createMessage":60 秒
- "resources/read":30 秒
- "resources/templates/list":30 秒
- "resources/subscribe":30 秒
- "tools/call":60 秒
- "completion/complete":60 秒
- "logging/setLevel":30 秒
错误处理 
实现应准备处理如下错误场景:
- 协议版本不匹配
- 必需能力协商失败
- 初始化请求超时
- 关闭超时
实现应为所有请求设置合理超时,防止连接挂起和资源耗尽。
初始化错误示例:
{
    "jsonrpc": "2.0",
    "id": 1,
    "error": {
        "code": -32602,
        "message": "不支持的协议版本",
        "data": {
            "supported": ["2025-03-26"],
            "requested": "1.0.0"
        }
    }
}