MCP 服务器
概述
Model Context Protocol (MCP)是一种开放标准,用于将 AI 应用连接到外部数据源和工具。它定义了 MCP 客户端(AI 代理)与 MCP 服务器(能力提供方)之间基于 JSON-RPC 的通信协议。
Zephyr MCP 服务器库实现 MCP 规范(版本 2025-11-25)中的服务器角色。它使联网的 Zephyr 设备能够公开工具,供 AI 代理通过 HTTP 发现和调用。该库基于现有的 Zephyr 子系统构建:用于传输的 HTTP 服务器库和用于序列化的 JSON 库。
备注
该库被标记为 实验性。目前仅实现带文本响应的工具服务。更多内容类型、会话管理、SSE 流式传输、授权以及其他服务等附加功能计划在后续版本中提供。
架构
- 应用
注册工具并实现其回调。工具执行结果通过
mcp_server_submit_tool_message()提交回核心。- MCP 服务器核心
实现 MCP 协议状态机。管理客户端连接、工具注册表、执行跟踪以及可配置的工作线程池。健康监视线程负责执行超时并触发取消操作。
- JSON 处理
使用 Zephyr JSON 库序列化传出的响应,并反序列化传入的 JSON-RPC 请求。
- 传输层
对网络协议进行抽象。随附的 HTTP 传输使用 Zephyr HTTP 服务器库。另提供用于单元测试的模拟传输。
HTTP 传输与异步响应
Zephyr 的 HTTP 服务器在单线程中运行,并且一次只能处理所有连接中的一个请求。资源回调必须返回后,服务器才能处理来自任何客户端的下一个请求。由于工具执行耗时可能超过阻塞整个服务器所能接受的程度,MCP HTTP 传输实现了轮询到 SSE 的回退机制:
对于 POST 请求,传输层会在内部轮询工具响应,最长持续
CONFIG_MCP_HTTP_TIMEOUT_MS(每隔CONFIG_MCP_HTTP_POLL_INTERVAL_MS检查一次)。如果响应在此时间窗口内就绪,则直接以
application/json返回。如果超时到期,传输层会切换到 SSE 模式:返回一个仅包含事件 ID(不含数据)的
text/event-stream响应。这会通知客户端响应仍在等待中,客户端应开始通过周期性 GET 请求进行轮询(间隔由CONFIG_MCP_HTTP_SSE_RETRY_MS控制)。客户端随后使用
Last-Event-Id标头发起周期性 GET 请求。如果结果已就绪,服务器会发送响应并结束 SSE 流。如果结果尚未就绪,服务器会再次发送重试响应。
备注
这并不是完整的 SSE 流式传输。该机制仅为无法在初始 HTTP 超时内完成的请求提供延迟响应。本阶段不支持服务器发起的通知和流式工具输出。
配置
使用 CONFIG_MCP_SERVER 启用该库。传输方式通过 CONFIG_MCP_TRANSPORT_HTTP (默认)或 CONFIG_MCP_TRANSPORT_MOCK (仅用于测试)选择。
最小 prj.conf:
CONFIG_NETWORKING=y
CONFIG_NET_TCP=y
CONFIG_HTTP_SERVER=y
CONFIG_MCP_SERVER=y
CONFIG_MCP_TRANSPORT_HTTP=y
关键配置组:
- 可扩展性
CONFIG_MCP_MAX_CLIENTS,CONFIG_MCP_MAX_CLIENT_REQUESTS,CONFIG_MCP_MAX_TOOLS,CONFIG_MCP_REQUEST_WORKERS- 超时
CONFIG_MCP_TOOL_EXEC_TIMEOUT_MS,CONFIG_MCP_TOOL_IDLE_TIMEOUT_MS,CONFIG_MCP_TOOL_CANCEL_TIMEOUT_MS,CONFIG_MCP_CLIENT_TIMEOUT_MSCONFIG_MCP_HTTP_TIMEOUT_MS- 内存分配
CONFIG_MCP_ALLOC_SLAB(默认)使用预分配的 slab 提供确定且无碎片的分配。CONFIG_MCP_ALLOC_HEAP使用k_malloc/k_free进行按需分配,但可能产生碎片。
用法
服务器设置
#include <zephyr/net/mcp/mcp_server.h>
#include <zephyr/net/mcp/mcp_server_http.h>
static mcp_server_ctx_t server;
int main(void)
{
server = mcp_server_init();
mcp_server_http_init(server);
/* Register tools here */
mcp_server_start(server);
mcp_server_http_start(server);
return 0;
}
工具注册
static int my_tool_cb(enum mcp_tool_event_type event,
const char *arguments,
const char *execution_token)
{
if (event == MCP_TOOL_CANCEL_REQUEST) {
struct mcp_tool_message ack = {
.type = MCP_USR_TOOL_CANCEL_ACK,
};
mcp_server_submit_tool_message(server, &ack, execution_token);
/* Handle cancellation here */
}
struct mcp_tool_message resp = {
.type = MCP_USR_TOOL_RESPONSE,
.data = "Tool execution result",
.length = strlen("Tool execution result"),
.is_error = false,
};
return mcp_server_submit_tool_message(server, &resp, execution_token);
}
static const struct mcp_tool_record my_tool = {
.metadata = {
.name = "my_tool",
.input_schema = "{\"type\":\"object\",\"properties\":{}}",
},
.callback = my_tool_cb,
};
mcp_server_add_tool(server, &my_tool);
.data 字段接受纯文本字符串。服务器会自动将其包装为符合 MCP 的 "text" 内容项。最大长度为 CONFIG_MCP_TOOL_RESULT_MAX_LEN。
工具回调模式
- 阻塞
短时运行的工具直接在工作线程中执行,并在返回前调用
mcp_server_submit_tool_message()。工作线程栈大小为CONFIG_MCP_REQUEST_WORKER_STACK_SIZE。- 异步
长时间运行的工具应派生专用线程,从回调中立即返回,并在稍后使用提供的执行令牌提交响应。周期性 ping(
MCP_USR_TOOL_PING)可防止健康监视器取消空闲执行。- 取消
当健康监视器或客户端请求取消时,会使用
MCP_TOOL_CANCEL_REQUEST调用回调。工具应停止工作并提交MCP_USR_TOOL_CANCEL_ACK。
工具移除
可以在运行时使用 mcp_server_remove_tool() 移除工具。如果工具当前正在执行,该调用会返回 -EBUSY;请稍后重试。
限制
以下 MCP 功能尚未实现:
资源、提示、采样、根和会话管理
服务器发起的通知和流式工具输出
图像和嵌入式资源内容类型(仅支持
"text")完整 SSE 传输(仅支持延迟响应交付)
测试
单元测试位于 tests/net/lib/mcp/。它们使用模拟传输(CONFIG_MCP_TRANSPORT_MOCK)在没有网络协议栈的情况下测试协议逻辑。
示例
有关注册多个工具(包括基于 GPIO 的 LED 控制)的可运行示例,请参见 MCP Server Hello World。