简体中文 | English
UART 串口 MCP 服务器:把本地串口设备封装成标准的 MCP (Model Context Protocol) 工具,让 AI 助手(Claude Desktop、Cursor 及任何 MCP 客户端)直接读写串口。
flowchart LR
client["MCP 客户端<br>(AI 助手)"]
server["ser2mcp<br>(事件驱动读线程+环形缓冲)"]
uart["UART 设备<br>(TX-RX)"]
client <==>|"JSON-RPC over stdio"| server
server <==>|"串口"| uart
- 14 个 MCP 工具:枚举端口、打开、运行时重配置、写、读、写+读、等待匹配输出、匹配后立即发送、状态、清缓冲、关闭、文件发送(估算/发送/取消)
- 文件流式发送:
uart_send_file一次调用把本地文件分片限速发送到串口(text 原样 / base64 自动换行),替代模型逐块调uart_write;配套uart_send_estimate耗时估算与uart_send_cancel/uart_close/ 客户端取消通知三级中止,发送中可查进度 - 完整串口参数配置:波特率 / 数据位(5-8) / 校验位(none/even/odd) / 停止位(1,2) / 流控(none/software/hardware) / 读超时,均可在
uart_open/uart_configure中指定 - 内部参数可配置:环形缓冲大小
buffer_size(默认 1 MiB)、空闲判定idle_ms、单次拉取上限max_bytes、总超时timeout_ms、读线程超时read_timeout_ms(默认 500ms,仅作读安全上限,不影响延迟) - 事件驱动/非阻塞读线程(平台适配层):Unix(Linux/macOS)用
poll(2)+ 自建管道事件驱动;Windows 用 1ms 轮询 +bytes_to_read()门控 +timeBeginPeriod(1),仅在数据就绪时read(),读写延迟不再受读超时参数影响 - 上行数据持续缓冲:事件驱动/非阻塞读线程持续把串口数据囤积进环形缓冲;写满后覆盖最旧数据并累计溢出计数,返回值带
overflow_delta / overflow_total,数据缺口可检测 - 二进制安全:数据以 hex 字符串传递(如
"41 54 0D 0A"),mode="text"可切换 UTF-8 文本;read_mode="text-escaped"文本为主、非文本字节\xNN转义(终端/日志场景不降级) - 单二进制交付:
cargo build --release产出单个可执行文件,Windows / Linux / macOS 均无需额外运行时
也可以直接从 Releases 下载对应平台的预编译二进制(Windows / Linux / macOS)。
# 1. 拉取仓库
git clone https://github.com/woooooooooolf/ser2mcp.git
cd ser2mcp
# 2. Linux 系统依赖(仅 Debian/Ubuntu 需要;macOS/Windows 跳过)
sudo apt-get install -y libudev-dev
# 3. 构建 release 二进制
cargo build --release
# 产物:target/release/ser2mcp(Windows 下为 ser2mcp.exe)
# 4. 自检(可选):枚举本机串口
target/release/ser2mcp --list-ports
# 5. 注册为 MCP server(见下方「接入 MCP 客户端」)验证安装成功:注册后调用 uart_list_ports 应返回本机串口列表(可能为空数组);若有 TX-RX 回环硬件,调用 uart_exchange 发送的数据应原样返回。
Linux 用户注意:
serialport枚举 USB 端口信息依赖libudev,编译前需先安装 Debian/Ubuntu:sudo apt-get install -y libudev-dev
cargo build --release # 构建
cargo test # 单元 + 端到端 MCP 协议测试(无需串口硬件)
cargo doc --no-deps # 生成 Rust 文档下载预编译二进制或构建完成后,可直接运行:
ser2mcp --list-ports # 枚举本机串口
ser2mcp --version # 显示版本号
ser2mcp --help # 显示帮助不带参数运行即进入 MCP stdio 服务模式(供 AI 助手调用)。
MCP 客户端以 stdio 方式启动 server 子进程。通用配置(.mcp.json / Claude Desktop 等):
{
"mcpServers": {
"ser2mcp": {
"command": "/absolute/path/to/ser2mcp",
"args": []
}
}
}Windows 示例:"command": "C:\\tools\\ser2mcp.exe"。
在 Reasonix 中执行:
Install the ser2mcp plugin package from https://github.com/woooooooooolf/ser2mcp. Use install_source with kind="auto" (or "plugin").
仓库根目录的 reasonix-plugin.json 将 ser2mcp 声明为标准 MCP 服务器(bin/ 内含 Windows / Linux / macOS 三平台预编译二进制与跨平台启动脚本):
- 在 Reasonix 中执行
install_source:源填仓库 URLhttps://github.com/woooooooooolf/ser2mcp,kind 用auto(自动识别为插件包)或显式plugin,scope 默认global - Reasonix 把整个仓库复制到自己的全局插件目录(Windows 为
%APPDATA%\reasonix\plugins\ser2mcp),manifest 里的command(相对路径bin/ser2mcp.cmd)按插件包根目录解析——无需手动改任何路径 - 安装后自动注册名为
ser2mcp的 MCP 服务器,工具以mcp__ser2mcp__uart_*暴露 - 验证:调用
uart_list_ports,应返回本机串口列表(可能为空数组)
bin/ser2mcp.cmd是跨平台启动脚本(Unix 按uname选ser2mcp/ser2mcp-macos,Windows 直接调用ser2mcp.exe;注意保持纯 ASCII,cmd.exe 在非 UTF-8 代码页下解析非 ASCII 字节会出错)。离线安装:也可用
install_source的本地路径作为源(本地仓库目录或解压后的 release 包目录),同样按插件包方式安装。
环境变量(可选):
| 变量 | 默认 | 说明 |
|---|---|---|
RUST_LOG |
info |
日志级别(日志输出到 stderr,不污染 stdio 协议通道) |
| 工具 | 说明 |
|---|---|
uart_list_ports |
枚举本机可用串口(名称/类型/USB 描述) |
uart_open |
打开串口并启动读线程(port 必填;含全部串口参数 + buffer_size 等内部参数) |
uart_configure |
运行时重配置(port 必填,仅更新传入项) |
uart_write |
发送数据,立即返回(port 必填,不等回复) |
uart_read |
拉取上行缓冲(port 必填) |
uart_exchange |
发送 + 读取一步完成(port 必填;短命令,idle 收尾) |
uart_expect |
等待匹配输出:阻塞直到串口输出中出现指定 pattern 或超时(port、pattern 必填;可选 data 实现"发送+等待") |
uart_expect_send |
匹配后立即发送:等待 pattern 出现后在同一临界区内发送 reply(port、pattern、reply 必填) |
uart_available |
状态快照:配置、缓冲未读字节数、累计溢出、读线程错误、文件发送进度(port 必填) |
uart_clear |
清空未读缓冲(port 必填) |
uart_close |
关闭串口并释放句柄(port 必填;进行中的文件发送会被中断) |
uart_send_estimate |
估算文件发送字节数与耗时(path 必填;无需打开串口,baudrate 默认 115200) |
uart_send_file |
文件流式发送:分片限速发送本地文件到串口,一次调用(port、path 必填) |
uart_send_cancel |
中止进行中的文件发送(port 必填;无传输时为 no-op) |
多端口与透传:支持同时打开多个串口,端口名(如
COM3、/dev/ttyUSB0)就是句柄,除uart_list_ports外每个工具都要指定port。串口字节流原样透传:ser2mcp 不做内容解析或过滤(uart_expect/uart_expect_send仅在缓冲中做条件查找、不修改数据),非预期数据也会原样返回,由 AI 与上层自行判断。
完整使用指南以插件自带 SKILL 形式提供,AI Agent 会话中按需加载(详见"AI Agent 兼容"):
ser2mcp-usage:工具速查、数据表示与编码选择、读取/expect 语义、命令完成判定、故障排查ser2mcp-file-transfer:文件流式发送完整流程(估算/发送/EOF/对账、对端 tty 注意事项)
快速要点(完整语义以 SKILL 为准):
- 编码:
hex(默认,二进制安全)/text(UTF-8)/text-escaped(仅返回侧,控制字节转义为\xNN);终端命令务必newline="crlf"带行尾,否则命令不执行且残留行缓冲会与下一条命令拼合 - 读取:
uart_read/uart_exchange在空闲判定(idle_ms默认 300ms,应大于设备响应间隙)/ 达到上限(max_bytes默认 64 KiB)/ 总超时(timeout_ms默认 5000ms)之一满足时返回;overflow_delta > 0表示缓冲溢出、数据有缺口 - 完成判定:用
uart_expect等输出锚点(如"# "、"Zynq>"),命中即返回(毫秒级),不要 sleep 盲等或加大 timeout 干等;提示符因设备而异,不可用(echo 关闭/无提示符设备)时改用命令特有结束标记。长命令(wget/tar 解包等)的uart_expect与 idle 无关,其timeout_ms只是兜底上限(上限 5 分钟、命中即提前返回),可放大到覆盖整个命令时长 - 大文件:
uart_send_estimate→uart_send_file一次调用(勿逐块uart_write),完成后与对端wc -c/md5sum对账
常用示例:
uart_exchange {port: "COM3", data: "ls /", mode: "text", newline: "crlf", read_mode: "text-escaped"} # 终端命令
uart_exchange {port: "COM3", data: "AT\r\n", mode: "text"} # AT 指令
uart_exchange {port: "COM3", data: "AA 55 01 00 0D 0A", mode: "hex"} # 二进制帧
uart_expect {port: "COM3", data: "ls /", mode: "text", newline: "crlf", pattern: "# ", pattern_mode: "text", read_mode: "text-escaped"} # 发送+等提示符收尾一步完成
uart_expect {port: "COM3", pattern: "Zynq>", pattern_mode: "text"} # 等待提示符
uart_expect_send {port: "COM3", pattern: "Hit any key", reply: "\n", reply_mode: "text", pattern_mode: "text"} # 命中即按键
SKILL 使用通用 Agent Skills 格式(SKILL.md,frontmatter 含 name / description),可跨工具使用:
- Reasonix:插件安装即获得,以
/ser2mcp:ser2mcp-usage、/ser2mcp:ser2mcp-file-transfer命名空间调用,或由 Agent 按description自动选择 - Claude Code / Codex:将仓库
skills/目录挂载为.claude/skills/(或.codex/skills/)即可直接使用
1. uart_list_ports → 定位 "COM3"
2. uart_open {port: "COM3", baudrate: 115200}
3. uart_exchange {port: "COM3", data: "41 54 0D 0A"} → AT 指令(hex)
4. uart_exchange {port: "COM3", data: "ls /", mode: "text", newline: "crlf", read_mode: "text-escaped"} → 终端命令
5. uart_expect {port: "COM3", pattern: "Zynq>", pattern_mode: "text"} → 等待提示符(时序编排)
6. uart_expect_send {port: "COM3", pattern: "Hit any key", reply: "\n", reply_mode: "text", pattern_mode: "text"} → 抢 bootdelay 窗口
7. uart_configure {port: "COM3", baudrate: 9600} → 设备切换波特率后重配置
8. uart_close {port: "COM3"}
文件传输场景(大文件用 uart_send_file,勿逐块 uart_write;完整流程见 SKILL ser2mcp-file-transfer):
uart_send_estimate {path: "C:/tmp/fw.bin", mode: "base64"} → 先估算耗时
uart_exchange {port: "COM3", data: "stty -echo; cat > /tmp/f.b64", mode: "text", newline: "lf"} → 对端开始接收
uart_send_file {port: "COM3", path: "C:/tmp/fw.bin", mode: "base64"} → 一次发送
uart_write {port: "COM3", data: "04"} → 补 \x04 结束对端 cat(EOF)
uart_exchange {port: "COM3", data: "wc -c /tmp/f.b64; md5sum /tmp/f.b64", mode: "text", newline: "lf"} → 对账
内置一键自测工具:枚举串口 + 对指定端口做完整回环验证(发送 0x00-0xFF 全字节序列并校验原样返回):
cargo run --release --example loopback -- --list # 枚举本机串口
cargo run --release --example loopback -- COM3 115200 # 回环测试src/
├── main.rs # 入口:stdio 传输启动
├── lib.rs # crate 文档与模块声明
├── hex.rs # hex 编解码(hex/text/text-escaped 三模式)
├── ring.rs # 有界环形缓冲(覆盖最旧 + 溢出计数 + Notify 唤醒 + pattern 查找)
├── sendfile.rs # 文件流式发送(分块 + base64 编码 + 耗时估算)
├── manager.rs # 串口管理器(打开/重配置/读线程/写/拉取/期待匹配/文件发送)
├── reader.rs # 事件驱动/非阻塞读线程(平台适配层)
└── server.rs # MCP 工具层(14 个工具 + ServerHandler)
tests/
├── e2e.rs # 端到端 MCP 协议测试(子进程真实握手,无硬件)
└── loopback.rs # 真实硬件回环测试(#[ignore],SER2MCP_LOOPBACK_PORT 指定端口)
scripts/
└── mcp_cli.py # 轻量 MCP stdio 命令行客户端(动作序列批量调用)
skills/
├── ser2mcp-usage/ # AI 使用指南 SKILL:工具速查/编码/读取语义/故障排查
└── ser2mcp-file-transfer/ # 文件流式发送 SKILL:估算/发送/EOF/对账/对端 tty 注意事项
examples/
├── loopback.rs # 回环自测工具
└── latency_probe.rs # 延迟探针(bench/benchw,真实硬件压测)
- rmcp(官方 Rust MCP SDK)
- serialport
- tokio / serde / schemars
ser2mcp 会把串口的读写能力直接交给 AI 助手:已授权的 MCP 客户端(以及背后的模型)可以向串口设备发送任意字节。请只连接你信任的设备,并确保 MCP 客户端与模型来源可信;不要把该工具用于可能因错误指令而损坏的设备。
- Linux 下提示权限不足 / 无法打开
/dev/ttyUSB0:当前用户不在dialout(或uucp)组。以 root 运行scripts/linux-serial-permissions.sh,注销并重新登录后生效。 - 端口打开失败 / 提示已被占用:确认没有其他串口终端或 MCP 实例占用该端口。
- Windows 下枚举不到串口:检查 CH340 / CP210x 等 USB 转串口驱动是否已安装。
- 工具调用延迟偏高:单次读写往返的固定等待主要来自
idle_ms(默认 300ms);可按设备响应节奏调小(例如 50ms)。read_timeout_ms(默认 500ms)只是读安全上限,不影响延迟。 - 数据不完整或缺失:返回值
overflow_delta > 0表示缓冲溢出丢数据,应调大buffer_size或减小拉取间隔。
MIT OR Apache-2.0(见 LICENSE-MIT 与 LICENSE-APACHE)