9.5 MCP协议:AI与物联网的桥梁
9.5.1 MCP协议诞生背景与核心设计
MQTT、CoAP、LwM2M 和 OPC UA 的通信模型本质上是静态的:规则由平台定义,数据按 Topic 或资源路径流动,状态变更由设备或平台端触发。AI 应用在操作这些设备时,面临的不再是数据不可达问题,而是三个更深层的鸿沟。
语义鸿沟。MQTT 发布一条 topic/dev/001/temp,载荷是 26.8。AI 能收到这个值,但不清楚它是摄氏度还是华氏度、是瞬时值还是五分钟平均值、是正常范围还是异常告警。CoAP 的路径结构更规范一些,但字段含义仍依赖平台侧的物模型映射。AI 系统需要的不仅是数据流,还需要设备功能的元描述:哪些参数可读、哪些可写、写操作的约束条件是什么、返回值如何解读。
安全边界与上下文缺失。AI 应用直接通过 MQTT Client 订阅设备 Topic,要么获得过多权限(能读到其他租户的设备),要么缺乏控制操作的上下文(不知道目标设备是否处于可操作状态)。MQTT Broker 不会为一次 AI 对话维护会话状态、鉴权上下文和调用链。AI 处理一个问题通常需要多步推理,涉及多个设备或数据源,每个调用都必须携带已建立的安全上下文。
状态管理不对称。设备通信协议多为事件驱动或轮询模型:设备上报,平台消费。但 AI Agent 的任务通常跨越多步:它需要先理解当前状态,再决定下一步操作,操作后还需确认结果。MQTT 的发布—订阅模型对查询—响应模式并不友好;CoAP 的请求—响应模型虽然接近,但没有统一的工具发现和参数描述机制。AI 需要一套可发现能力边界的交互协议;任务状态、对话记忆和审批进度则由 Host、Agent Runtime 或业务系统维护,不能假定基础协议替应用保存这些状态。
MCP(Model Context Protocol,模型上下文协议)正是在这一背景下产生的。它不是设备协议,而是一套面向 AI 应用与外部工具、资源和知识库交互的上下文交换协议。
在下文展开之前,先划清两类陈述的边界:关于 IoT DC3 的实现事实,以 2026-08-29 的 987c96d50 源码快照为准;关于该类协议在物联网中的应用方式与价值边界,则是作者的工程判断,并非正式标准的最终定义,部分细节以示例方式呈现。版本升级后,应重新核对端点、协议修订号、能力声明与授权链路。
MCP的上下文模型与通信模型
MCP 将 AI 与外部系统的交互抽象为可发现的能力和结构化请求。规范定义的核心能力包括资源(Resources)、工具(Tools)和提示(Prompts),但具体服务器可以只实现其中一部分:
- Resources:由服务端暴露的可读上下文,供 Host 或 Client 按需纳入模型上下文。它们通过 URI 标识,可带 MIME 类型;规范还提供资源模板、列表分页和可选订阅,不等同于 HTTP 内容协商或任意字节范围读取。
- Tools:可由模型请求触发的可执行动作。每个 Tool 声明输入 Schema,描述参数名称、类型、约束和是否必填。AI 模型提出调用请求,MCP Server 仍需执行鉴权、参数校验、风险控制和审计。IoT DC3 在该源码快照中只声明 Tools 能力:它把
dc3_api、dc3_resource中的平台目录与版本化的静态openapi-*.json快照聚合为工具定义,再按 OAuth scope、租户、权限和风险策略裁剪。这里既不是运行时无边界抓取所有中心 OpenAPI,也不能据此推断 Resources 或 Prompts 已经实现。 - Prompts:可复用的、参数化的提示模板,允许服务端指导模型“如何理解这个领域的资源”。
IoT DC3 的 MCP 端点使用 JSON-RPC 2.0 交换消息。该源码快照实现的是 2025-06-18 修订版的初始化握手,处理 initialize、notifications/initialized、ping、tools/list 和 tools/call;Gateway 对外提供 POST /mcp,并在每次请求中内省 Bearer Token。当前代码没有声明 Resources、Prompts 或 Tasks。JSON-RPC request ID 只负责关联请求与响应,初始化状态也不等于服务器保存了对话 session;跨调用的任务状态、超时补偿和审批记录仍须落在 Agent Runtime 或业务存储中。认证方式还取决于传输和部署方式;OAuth 2.1 在这里是授权方案基础,且截至 2026-08 仍处于 IETF 草案阶段,不能写成已经发布的 RFC。
图 9-9 展示了 MCP 协议在 IoT 场景中一次典型的交互序列,涵盖初始化、工具目录发现、工具调用和状态反馈。
这一设计与 MQTT 的 Topic 发布订阅模型不同:在 IoT DC3 实现所采用的 2025-06-18 生命周期中,MCP 完成初始化与能力协商后,以结构化请求发现和调用能力;服务端根据每次请求重新验证的身份、租户和策略上下文裁剪工具目录。这种协议握手状态不等于业务对话或任务状态,跨调用状态仍属于 Host、Agent Runtime 或业务存储。2026-07-28 发布候选版提出了无需 initialize、在请求中携带协议元数据的无状态生命周期,不能倒推为该源码快照已经实现的行为。
MCP与IoT平台的分工边界
在 IoT DC3 项目中,MCP 入口位于 Gateway,工具目录与策略由 Auth Center 相关能力管理,实际调用再路由到所选平台中心 API;它是平台适配入口,而不是设备协议的替代品。该源码快照中的调用链是:
- AI Agent(如 Claude Desktop 或自定义 Agent)完成初始化,通过
tools/list获取当前 Bearer Token、租户和权限上下文可见的工具目录。 - MCP Gateway 根据 API/资源目录与版本化 OpenAPI 快照形成候选工具,返回前再做 scope、租户、权限和风险过滤;
tools/call时还会重新校验可见性与授权,而不是只信任先前拿到的目录。 - 当 Agent 调用一个“读取设备位号”工具时,Gateway 经受控的平台中心 API 读取数据或触发既有命令链路,不直接向设备发送 CoAP 请求或向设备 Topic 发布消息。
这一设计确保 MCP 不绕过已有的 IoT 安全治理。设备侧协议依然是 MQTT、CoAP、OPC UA 或 Modbus。MCP 增加的是 AI 与平台之间的互操作层,而不是对设备通信协议的重新发明。
工程实践中应避免的误区
实践中,团队容易把 MCP 当作“让 AI 直连设备”的捷径。最典型的设计失误是:MCP Server 直接维护 MQTT 连接池,Agent 调用工具时直接 publish 到设备 Topic。这种架构绕过了平台层的策略引擎、服务降级、租户隔离和联动逻辑,将双因子确认、写入频率限制和操作审计的义务交给了 AI Prompt。AI 模型不是确定的实时控制系统,任何绕过平台治理的调用链都应视作安全违规。
更稳妥的判断是:MCP 在物联网中的正确位置是 AI 应用与 IoT 平台之间的互操作层。它解决的是“AI 如何以统一协议发现和调用平台能力”,而不是“AI 如何替代 MQTT/CoAP 接管设备通信”。平台依然用 MQTT 收遥测,用 CoAP 管设备,用 OPC UA 做工业语义;MCP 只增加一层面向 AI 的工具抽象,让模型能在安全上下文中操作经过策略裁剪的平台能力。这两个栈之间不应直接短接,除非架构师愿意承担开环控制风险。
延伸阅读:第 7 章 7.3 节介绍 IoT DC3 Agentic Center 的工具目录、平台对话状态与安全策略;MCP 的协议握手状态不等于平台对话状态,也不替应用保存业务任务。第 8 章 8.5.4 节讨论 AI Agent 操作设备时的安全边界与审计方案。
9.5.2 MCP协议消息格式与能力描述
MCP 的消息载体采用 JSON‑RPC 2.0。这一选择并非追求最小 payload,而是为了降低 AI 应用侧的接入门槛:支持 JSON 序列化的语言即可处理消息。已发布的 2025-11-25 规范定义 stdio 与 Streamable HTTP;早期 HTTP+SSE 传输已由 Streamable HTTP 取代。IoT DC3 源码快照只有一个处理 JSON-RPC 的 POST /mcp 入口,因此可确认的是“HTTP POST MCP 端点”,不能仅凭路径就声称它实现了 Streamable HTTP 的全部 GET、SSE 与会话语义。实验性 Tasks 已在 2025-11-25 规范中出现,但该快照没有实现;2026-07-28 是提出无状态生命周期等变化的发布候选版,不应写成已经稳定落地的实现基线。第 7 章 7.1.5 节从 IoT DC3 的实现边界讨论这些机制,本节关注协议层次与版本边界。MCP 不定义设备侧的信封、帧头或 payload 格式;它解决的是 AI 应用如何发现并调用外部能力,以及这些能力如何描述自己。
标准消息模型与能力协商
本节先按 IoT DC3 所实现的 2025-06-18 生命周期说明消息模型;2025-11-25 已发布规范也保留这一握手。Client 先发送 initialize 请求,声明协议版本和 capabilities,Server 返回选定版本、capabilities 及实现信息;Client 再发送 notifications/initialized。后续操作必须符合协商结果。初始化状态只约束协议交互,不等于 Server 保存了业务对话、审批或长任务状态。采用 2026-07-28 发布候选版时则应按其无状态生命周期重新设计,不能混用两套流程。
一个典型的 initialize 请求如下:
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {
"name": "iot-supervisor-agent",
"version": "1.0.0"
}
}
}这里使用 IoT DC3 源码快照声明的 2025-06-18。Client 应发送自己支持的修订版并处理 Server 选定的版本,不能使用含义不明的 v1。能力协商不是授权凭证;建立新的连接或交互上下文时,应重新校验认证、授权与能力。Server 可能更新可用的 Tools 或资源路径,Client 不应跨上下文长期复用过期清单。
规范允许 Server 在响应中声明它实际支持的能力;常见类别包括:
- tools:可由模型调用的动作,需声明名称、描述和 JSON Schema 输入参数。
- resources:由 client 读取的上下文资源(设备说明、历史摘要、文档),支持 URI 模式匹配。
- prompts:可发现、可参数化的提示模板,用于引导模型行为。
服务器不必同时支持三类能力。IoT DC3 该快照只声明 tools,因此客户端不能据通用规范假定 resources/list 或 prompts/list 可用。
JSON Schema 明确用于 Tool 的输入参数;Resources 以 URI、内容与模板等字段描述,Prompts 也有自己的参数和消息结构,不能说三类能力都采用同一种 JSON Schema 描述。MCP 不替平台定义设备领域语义。一个读取设备位号的 Tool 描述如下:
{
"name": "iot_read_point",
"description": "读取当前用户有权限访问的设备位号",
"inputSchema": {
"type": "object",
"properties": {
"deviceId": {"type": "string", "description": "设备标识"},
"pointId": {"type": "string", "description": "位号标识"}
},
"required": ["deviceId", "pointId"]
}
}这里的 inputSchema 定义的是 MCP tool 的调用参数,不是设备寄存器映射或 CoAP 资源的统一格式。MCP server 内部如何将参数路由到 IoT 平台的实际协议驱动,对 AI 应用完全透明。调用方只关心 name 和 arguments,不关心目标设备是通过 MQTT 还是 Modbus 访问。
AI Agent 通过 tools/call 方法发送实际操作请求:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "iot_read_point",
"arguments": {
"deviceId": "pump-001",
"pointId": "motor_temp"
}
}
}Server 返回结果:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [{"type": "text", "text": "motor_temp = 68.5°C"}],
"isError": false
}
}整条调用链中,server 负责校验用户权限、租户边界和数据脱敏,模型不直接接触原始位号值。MCP 的“能力描述”本质上是安全代理的接口合约,不是设备自身的功能清单。这一点对架构师尤为重要:如果希望模型直接操作设备寄存器,那是绕过平台治理的危险设计,不应通过 MCP 来实现。
能力描述的责任边界:与 WoT TD 的区别
物联网设备的属性、事件、命令、数据类型、单位、协议绑定,应该由物模型、LwM2M 对象、OPC UA 信息模型或 W3C Web of Things Thing Description 负责。MCP server 可以适配这些模型生成 tools 或 resources,但适配不是 MCP 标准的一部分——MCP 只规定 tools 的描述格式,不规定“温度属性”的测量单位、枚举范围或生命周期。
以 WoT TD 为例,一个照明设备的 TD 描述了 brightness 属性、setBrightness 动作及其参数约束。MCP server 可以基于该 TD 生成一个 set_brightness tool,但必须额外补充三件事:
- 用户权限——当前主体是否被授权调用该动作。
- 动作风险等级——写参数操作是否需要二次确认。
- 幂等策略——重复调用是否安全。
适配链如下:
设备模型 / WoT TD / OPC UA 信息模型
↓ 适配与权限裁剪
MCP tools / resources
↓
AI 应用发现、解释和调用不能把 WoT TD 的 JSON 字段直接当作 MCP 的“能力描述”字段。MCP 只关心调用接口的语义,不定义设备属性的单位、枚举或生命周期。这与本章 9.6.2 节讨论的层次化语义模型一致:最底层是设备标准模型,中间层是平台内部适配,顶层是 AI 侧发现的接口。
A2A 与 MCP 的互补关系
MCP 解决的是 AI 应用与工具/资源之间的连接。A2A 解决的是 Agent 与 Agent 之间发现、任务委派和结果交换。两者分工明确:一个编排 Agent 可以通过 A2A 将“诊断泵异常”任务委派给诊断 Agent,后者再通过 MCP 查询设备状态和历史记录。
身份认证、授权和用户同意不应由 MCP 或 A2A 绕过。每次 tool 调用仍须校验主体、租户、动作和参数。工具描述本身属于不可信输入——client 应限制 server 来源,审核 tool 名称和 schema 变化,防止恶意描述诱导模型泄露上下文或调用未经授权的能力。这与本章 9.7.2 节的安全检查项一致:协议本身不负责信任,信任由平台层的鉴权与治理实现。
协议设计的分界判断
如果项目需要一种设备注册、能力目录同步或动作执行协议,可以把它设计为平台内部的“设备语义适配协议”,独立于 MCP 定义。这种协议可以基于 MQTT、CoAP 或消息队列传输,但必须明确以下几点:
- 消息字段、注册流程、错误码是自定义内容。
- 与 MCP 的关系是适配或桥接,不是 MCP 规范的一部分。
- 所有假设字段和示例参数都应标注为示例,避免读者误认为是标准化定义。
实时遥测、设备影子同步、安全控制优先使用物联网平台已有的数据面与控制面。MCP 只作为 AI 应用侧的能力发现和调用入口,不替代设备面的协议栈。这一边界判断,是物联网架构师在引入 AI 交互层时必须守住的工程底线。
9.5.3 MCP协议工程原型:AI控制灯光
9.5.1 与 9.5.2 交代了 MCP 的设计动机与消息格式,本节用一个完整场景把它们串起来,看 MCP(Model Context Protocol)如何将 AI 应用与物联网设备的控制链路衔接。
场景:用户通过AI语音助手说出“把卧室灯调成暖黄色,亮度百分之六十”。AI Agent完成自然语言解析、工具发现、参数映射、远程调用和状态同步后,实现对智能灯的控制。整个交互中,AI Agent不直接与设备或MQTT代理通信——它只与MCP Server交互;MCP Server将工具调用翻译为IoT平台的REST接口,平台再通过MQTT下发指令。
设备注册与能力暴露
在这个教学原型中,智能灯在 IoT 平台注册时声明 set_light(设置亮度和颜色)、get_status(查询当前状态),适配层再把受控平台 API 映射为 MCP Tools。这是说明分层关系的示例,不是 IoT DC3 当前工具聚合器的逐行复刻。完成 initialize 与 notifications/initialized 后,Client 单独发送 tools/list,Server 才返回可见工具。以下是简化的响应片段:
{
"tools": [
{
"name": "iot_get_device_status",
"description": "查询设备当前状态,包括亮度和颜色",
"inputSchema": {
"type": "object",
"properties": {
"deviceId": {"type": "string", "description": "设备ID"}
},
"required": ["deviceId"]
}
},
{
"name": "iot_set_light",
"description": "设置灯具亮度(0-100)和颜色(支持'冷白','自然白','暖黄','暖白')",
"inputSchema": {
"type": "object",
"properties": {
"deviceId": {"type": "string"},
"brightness": {"type": "integer", "minimum": 0, "maximum": 100},
"color": {"type": "string", "enum": ["冷白", "自然白", "暖黄", "暖白"]}
},
"required": ["deviceId", "brightness"]
}
}
]
}AI解析与工具调用
AI Agent将用户语音解析为工具调用意图。这一过程通常包含:命名实体识别(“卧室灯”→设备ID light-bedroom-01)、参数提取(“六十”→60,“暖黄色”→"暖黄")和工具匹配(选定iot_set_light)。Agent随后构造tools/call请求:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "iot_set_light",
"arguments": {
"deviceId": "light-bedroom-01",
"brightness": 60,
"color": "暖黄"
}
}
}MCP Server 收到请求后,通过内部处理器调用 IoT 平台 API,平台再沿既有命令链路执行真实操作。下面的 Python 代码模拟从 Agent 到 Server 再到平台和设备的消息流;HTTP 传输封装、MCP 初始化握手、请求认证和外部任务状态从略,只聚焦核心消息处理与状态变化。代码中的 request_context 是示例业务鉴权上下文,不代表 MCP Server 保存对话 session:
import json
import time
from dataclasses import dataclass, field
# ---------- 模拟IoT平台中的设备抽象 ----------
@dataclass
class LightDevice:
device_id: str
brightness: int = 0
color: str = "冷白"
online: bool = True
def set_light(self, brightness: int, color: str) -> bool:
if not self.online:
raise RuntimeError("设备离线")
if not (0 <= brightness <= 100):
raise ValueError("亮度超出范围")
if color not in ["冷白", "自然白", "暖黄", "暖白"]:
raise ValueError("不支持的颜色")
self.brightness = brightness
self.color = color
return True
# ---------- 模拟MCP Server ----------
class MCPToolServer:
def __init__(self, platform):
self.platform = platform
self.tools = {
"iot_get_device_status": {"handler": self.handle_get_status},
"iot_set_light": {"handler": self.handle_set_light}
}
def handle_get_status(self, request_context, args):
device = self.platform.get_device(args["deviceId"])
if device is None:
return {"error": "设备不存在"}
return {
"brightness": device.brightness,
"color": device.color,
"online": device.online
}
def handle_set_light(self, request_context, args):
device = self.platform.get_device(args["deviceId"])
if device is None:
return {"error": "设备不存在"}
try:
device.set_light(args.get("brightness"), args.get("color", "冷白"))
# 平台通过MQTT下发真实指令
mqtt_publish(device.device_id, device.brightness, device.color)
return {
"success": True,
"state": {
"brightness": device.brightness,
"color": device.color
}
}
except (ValueError, RuntimeError) as e:
return {"error": str(e)}
# ---------- 模拟MQTT发布 ----------
def mqtt_publish(device_id, brightness, color):
print(f"[MQTT] 下发命令: {device_id} 亮度={brightness} 颜色={color}")
# ---------- 模拟IoT平台 ----------
class IoTPlatform:
def __init__(self):
self.devices = {}
def register_device(self, device: LightDevice):
self.devices[device.device_id] = device
def get_device(self, device_id):
return self.devices.get(device_id)
# ---------- 模拟AI Agent(MCP Client) ----------
class AIAgent:
def __init__(self, mcp_server: MCPToolServer):
self.server = mcp_server
self.request_context = {"user": "admin"}
def parse_intent(self, text: str):
"""简化的意图解析,仅为演示"""
if "卧室灯" in text and "亮度" in text:
brightness = 60 if ("六十" in text or "60" in text) else 50
color = "暖黄" if "暖黄" in text else "冷白"
return "iot_set_light", {
"deviceId": "light-bedroom-01",
"brightness": brightness,
"color": color
}
return None, None
def execute_intent(self, tool_name, args):
if tool_name not in self.server.tools:
print("工具不存在")
return
result = self.server.tools[tool_name]["handler"](self.request_context, args)
print(f"[AI Agent] 执行结果: {result}")
return result
# ---------- 主流程 ----------
def main():
platform = IoTPlatform()
device = LightDevice(
device_id="light-bedroom-01",
brightness=50,
color="冷白",
online=True
)
platform.register_device(device)
mcp_server = MCPToolServer(platform)
agent = AIAgent(mcp_server)
user_voice = "把卧室灯调成暖黄色,亮度百分之六十"
tool_name, args = agent.parse_intent(user_voice)
if not tool_name:
print("无法解析意图")
return
print(f"[解析结果] 工具: {tool_name}, 参数: {args}")
result = agent.execute_intent(tool_name, args)
time.sleep(0.1)
print(f"[最终状态] 亮度={device.brightness}, 颜色={device.color}")
if __name__ == "__main__":
main()运行输出
[解析结果] 工具: iot_set_light, 参数: {'deviceId': 'light-bedroom-01', 'brightness': 60, 'color': '暖黄'}
[MQTT] 下发命令: light-bedroom-01 亮度=60 颜色=暖黄
[AI Agent] 执行结果: {'success': True, 'state': {'brightness': 60, 'color': '暖黄'}}
[最终状态] 亮度=60, 颜色=暖黄异常处理与工程边界
实际部署中,MCP Server必须处理以下异常场景,返回结构化的错误信息而非直接崩溃:
- 设备离线:平台检测到设备不可达,返回
{"error": "device offline"}。 - 参数越界:Server端校验后返回
{"error": "brightness out of range"}。 - 权限不足:当前请求上下文中的用户无权控制该设备,Server 应拒绝调用并记录审计日志。
- 超时与重试:平台下发指令后若超时未收到设备确认,应按动作语义决定查询状态、补偿或有限重试;业务封装可以增加
idempotencyKey,但它不是 MCP 核心tools/call的标准字段,双方必须在工具输入契约中显式约定。
这一工程模式的核心分层逻辑在于:AI Agent 不直接触及设备链路。设备注册、能力描述、命令执行和状态同步仍由IoT平台和已有协议(如MQTT)完成,MCP Server仅在AI与平台之间履行转换和管控职责。这种分层为安全审计、权限控制和工具版本管理提供了明确的执行点,也大幅降低了AI应用接入时对设备侧协议的感知成本。