Skip to content

MCP 工具参考 ​

本页的工具名 / 描述 / 入参逐字取自 src-tauri/src/mcp/protocol.rs 的 tool_defs(); 「返回」列是对着真实运行的服务实调一遍抓下来的 structuredContent 结构,不是照记忆写的。 上手步骤见 MCP.md,设计与取舍见 MCP_DESIGN.md。

字段命名:参数与返回一律 camelCase(portName / sinceSeq / maxLinesPerChannel)。 有四个参数历史上写成了蛇形,旧拼写仍然认(since_seq / case_sensitive / max_lines_per_channel / ok_only)—— 直接改名会让按旧写法调用的人静默失效,那比报错更危险。

⚠️ 返回结构里没有的字段就是真的没有(例如串口项只有 portName / friendlyName / productName,没有 VID/PID)。 ⚠️ 很多客户端只把 content[].text 给模型看,所以摘要必须把数据说出来(serial_list_ports 的文本里就带着端口名)。

💡 读日志优先用 format:"text"(log_tail / serial_get_output):一行一条纯文本,同样内容比默认 json 省一半以上 token。实测(200 条短行):json 101 字节/行 → text 29 字节/行,省 3.5 倍;行越长省得越少(长行只剩 ~30%)。text 编码的正文放在 content[].text(只有一份),structuredContent 只给元信息,所以"省 token"不会变成"看不到日志"。

💡 要"有没有 / 几次"就别拉命中行:log_search{mode:"count"} 只回计数(几十 token),mode:"matches" 只回片段,mode:"lines"(默认)才回整行。三档的数据是同一份,差的只是回多少。

1. 怎么连 ​

传输两种并存(默认):① Streamable HTTP(POST /mcp,2025-03-26+ 规范,新版客户端默认走它);② 遗留 SSE(GET /sse + POST /messages,只支持 SSE 的老客户端)。也可以在弹窗里选「仅 /mcp」或「仅 SSE」—— 那时另一条端点返回 404
端点(推荐,新客户端)POST /mcp?token=… 发 JSON-RPC,结果直接从这次 HTTP 响应回来(Content-Type: application/json);initialize 的响应头带 Mcp-Session-Id,后续请求用同名请求头带回来;GET /mcp 可另挂一条 SSE 流收服务端通知;DELETE /mcp 主动结束会话
端点(老客户端)GET /sse(建立会话,首帧下发 event: endpoint)→ POST /messages?sessionId=…(发 JSON-RPC,结果从 SSE 流回)
鉴权每个请求都要带 token:?token=… 或 Authorization: Bearer …;GET /healthz 是唯一免鉴权端点,只回 {"ok":true}
监听只监听回环(127.0.0.1 / ::1 / localhost),不对外网/局域网开放
握手顺序(Streamable HTTP)POST /mcp initialize(不带会话头)→ 从响应头拿 Mcp-Session-Id → 后续请求都带上它 → notifications/initialized(回 202)→ tools/list
握手顺序(遗留 SSE)客户端必须先 GET /sse 拿到 endpoint,再 POST initialize → notifications/initialized → tools/list
地址从哪来程序弹窗里的「Streamable HTTP / 遗留 SSE」两块地址,或 %APPDATA%\seahi-serial\mcp-endpoint.json(url 与 urlStreamable 两个字段)
传输档位弹窗里的「传输」三档:两种都提供(默认,兼容性最好)/ 仅 /mcp / 仅 SSE。配置键是 server.transport(老的 server.streamableHttp 布尔写法仍然认)。选单档时另一条端点立刻返回 404(切换立即生效,不用重启服务器)

2. 怎么拿工具列表 ​

  • 运行时:tools/list(分页,每页 50,用 nextCursor 翻页)——这是权威来源,本页只是它的可读版本。
  • mcp_limits / mcp_status 里的 toolCount / builtinToolCount 能看到数量。
  • 内置工具 54 个;另有可选的 ctl_*(见 §4)。

3. 一页速查 ​

工具读/写作用
serial_get_state读操作串口前先调它:读该分栏的完整状态(端口/波特率/帧格式/行尾/DTR-RTS/显示开关/是否在监控/行数与字节数/全部分栏名 panes),外加 portOptions —— 这个分栏当前能选的端口(Windows 是 COM 名,WSL 是 /dev/...;inUse = 被别的分栏占着)。
serial_select_port写选该分栏要用的端口。值必须来自该分栏的 portOptions(见 serial_get_state);给错会回列可选值。⚠️ 别拿 serial_list_ports 当依据:它只有 Windows 的 COM 口,WSL 分栏要的是 /dev/ttyUSB0 这类 WSL 内部路径。
serial_set_baud写设置波特率(110..4000000)。等价于在「波特率」输入框里填值。
serial_set_frame写设置帧格式(dataBits / stopBits / parity,至少给一个)。只在未连接时有意义,连接中请先 serial_close。
serial_set_lines写设置 DTR / RTS 电平(布尔)。常用于让目标板复位(DTR 拉低)或进入下载模式。
serial_set_display写设置显示与行为开关(viewMode / lineEnding / echo / lineNum / timestamp / autoScroll / autoReconnect / terminalMode / advOpen,至少给一个)。serial_get_state 报出来的每个开关这里都能设。⚠️ 终端模式下「行号 / 时间戳 / 回显」是置灰的:设它们不算失败,返回里带 skipped:true(当前状态本来就不生效),别重试。
serial_open写开始监控(=点「开始监控」按钮)。可同时给 port/baud,省两次调用。返回前确认真的连上(最多 6 秒),失败会说明可能原因(端口被占用 / 设备拔出 / 驱动异常)。
serial_close写停止监控(等价于点「停止监控」),返回前确认已断开。
serial_send写往该分栏发数据(需已在监控中)。mode=hex 时 data 按十六进制解析(如 "01 03 00 00 00 02"),否则按文本;lineEnding 会覆盖该分栏的行尾并留在界面上。单次最多 64K 字符,大块数据请分批。
serial_clear写清空该分栏的输出区(=点「清除内容」)。连带清掉磁盘上的会话日志缓存 —— %APPDATA%\seahi-serial\log-cache 下属于该分栏的 session 文件会被截断;界面上不要了的内容,磁盘上也别留着。
serial_get_history读读该分栏的发送历史(最近的在前)。用来回看刚才发过什么,或复用上一条指令。
serial_get_output读读串口分栏实际收发的内容 —— 设备回了什么就用它(不用 log_tail,也不用猜通道名)。默认收+发按时间归并,dir 区分收发、src 区分 ai/ui/none(追溯谁发的)。优先 format:"text":一行一条,比 json 省一半以上 token;要逐行字段时才用 json。还没数据时回空列表,不报错。
serial_quick_cmd读面板「快速指令」列表(按循环组分段)。不带参数=列出(含 index/组/值/发送参数/groups/loop);给 index=执行那一条(index 从 0 起,用户口语的「第 N 条」= index N-1);action=loop=开/关整条循环链;**action=add
serial_workflow读串口/WSL 面板的自动化工作流规则(收到匹配数据就自动执行动作:发数据 / 切 DTR-RTS / 存日志)。省略 action=列出;add/update/remove=改规则(新规则一律 running=false,改动立刻写进配置)。⚠️ 规则一旦 running 就会自动往设备发数据 —— 要启动必须用 serial_workflow_run(带 confirm),别用 ui_click 绕开确认。
serial_workflow_run写 ⚠️开始/停止一条工作流规则的运行(running)。⚠️ 危险动作:开始之后,这条规则一收到匹配的数据就会自动往设备发数据(动作里可能还有存日志文件),必须带 confirm:true;不带时不会执行并返回 -32006 说明后果。停止(on=false)同样需要 confirm —— 它属于同一条工具。
ble_get_state读蓝牙分栏的当前状态:是否在扫描、扫到几台设备、选中/已连的是哪台、GATT 服务树有几个服务、订阅了几路通知、内嵌监视器是否打开。只读,无副作用。
ble_list_devices读读蓝牙扫描结果(不触发扫描):MAC / 名称 / RSSI / 是否配对 / 是否选中。支持分页(limit + offset,返回 hasMore/nextOffset;扫描未完时翻页可能重复或漏,要稳定名单就等 scanning=false)。列表为空多半是设备不广播(被 Windows 配对过 / 被别的主机连走)—— 这时用 ble_connect 按 MAC 直连。只读。
ble_start_scan写开始扫描蓝牙设备。时长由面板上的设置决定,本工具不收时长参数;扫完用 ble_list_devices 取结果。⚠️ 连上设备会自动停扫描,所以连接后 scanning=false 属正常;要再找别的设备就重新调它。写操作(占用射频)。
ble_stop_scan写停止蓝牙扫描(复用同一颗按钮的路径)。写操作。
ble_connect写连接一台 BLE 设备。给 addr 时:列表里有它就点卡片连,列表里没有就按 MAC 直连(不依赖广播 —— 不广播的设备只有这条路)。不给 addr 用面板当前选中的那台。等连接真的成功才返回(带服务数)。⚠️ 连上会自动停扫描,返回后 scanning=false 属正常。写操作。
ble_disconnect写断开当前已连接的设备(面板那颗「断开设备」按钮的同一条路)。断开后服务树、订阅状态、本次会话的数据日志一并清空。写操作。
ble_get_services读当前已连接设备的 GATT 服务树(服务 UUID / 名称,每个服务下的特征 UUID、属性 props、描述符个数)。只读,取的是面板已经拉到的那份,不会重新去问设备。
ble_read读读一个特征的值(按 UUID)—— 走面板那颗读按钮,结果随后出现在 ble_get_output 里。需要设备已连接、该特征有 read 属性(见 ble_get_services)。
ble_write写往一个特征写数据(按 UUID)—— 打开面板那个写入窗并点「发送」,HEX/文本解析、行尾、写响应全用面板那套。需要设备已连接、该特征有 write 属性(见 ble_get_services)。写操作。
ble_subscribe写开/关某个特征的通知订阅(notify / indicate)——点的是面板上那颗订阅按钮,数据随后出现在 ble_get_output 里。状态已经在目标值时不会重复点(不会把用户刚打开的订阅关掉)。
ble_get_output读读蓝牙面板本次会话的数据日志(收到的通知/读值 + 写出去的内容;切设备或断开会清空)。跨会话历史用返回的 channels.rx/tx 去 log_tail。只想知道出现几次就别拉条目:给 pattern + mode(count / matches / lines)。⚠️ CTS 时间条目已自动附 decoded/decodedSummary,不用再喂 ble_cts_time。只读。
ble_refresh_rssi读读已连接设备的信号强度(负数,越接近 0 越强)。只问一次射频、不改状态。⚠️ 没连设备会直接失败(先 ble_connect)。
ble_cts_time读把 CTS 时间特征的原始值翻译成人话(0x2A2B / 0x2A0F / 0x2A14,按长度认字段:10 / 2 / 4 字节)。回 utc / skewSecs / 星期 / adjustReasons / notes,并主动指出可疑处(年份像 RTC 没初始化、星期与日期对不上、偏了多少分钟)。data 必须来自实际读取(ble_read,或 ble_get_output 里的条目),别凭空构造。设备没给出的字段回 null,不猜。纯后端:不碰设备也不碰界面。
adb_list_devices读列出 adb devices -l 看到的设备(序列号 / 状态 / 型号)。只读,不会开 shell。只有 state=device 的那台才可用;unauthorized 表示还没在设备上点「允许 USB 调试」。
adb_open_shell写 ⚠️在设备上开一个交互式 shell(=点面板上那台设备的卡片:建 xterm + PTY),等 PTY 真的建出来才返回(最长 10 秒);先确认设备 state=device。⚠️ 危险动作,必须带 confirm:true,否则不执行并回 -32006。开完用 adb_shell_write 发命令、adb_shell_read 读输出。
adb_shell_write写 ⚠️往已打开的 ADB shell 写入内容(与在面板终端敲键盘同一条路)。命令要自己带上 \n,不带就只填在命令行上、不会执行。⚠️ 危险动作(内容会被设备真的执行),必须带 confirm:true。单次最多 4096 字符。
adb_shell_read读读 ADB shell 已经产生的输出(日志中心 adb:rx 的旁路副本,不抢界面终端要显示的队列)。items 是 PTY 输出块、不是按行切的文本;增量跟进给 sinceSeq。logcat 刷屏时先给 pattern + mode(count 只回计数、matches 只回片段)。只读,没有界面也能用。
adb_shell_resize写调整已打开 ADB shell 会话的 PTY 尺寸(与面板跟着容器尺寸自动推的是同一个后端命令)。cols/rows 都是 2~1000(mcp_limits.maxAdbCols / maxAdbRows)。注意:面板自己的尺寸同步(窗口/容器变化时)可能随后把它改回真实容器尺寸。写操作。
adb_close_shell写关掉当前 ADB shell 会话(等价于点面板上会话的关闭:杀掉 adb shell 子进程 + 移除终端)。本来就没开会话时是幂等的(closed:false + note),不是错误。写操作。
mcp_danger读列出需要二次确认的危险工具(会对外产生不可撤销影响的那些)与各自的后果。调用它们时必须带 confirm:true,否则不会执行。只读。
app_info读本机 SeaHi Serial 应用的基本信息(版本、平台、进程、运行时长)。只读,无副作用。
mcp_status读不确定从我这儿怎么下手就先调它:MCP 服务器自身状态(是否运行、监听端点、会话数、请求数与限流/丢弃计数),外加一份 nextSteps —— 按「有没有界面 / 用户是不是开了只读模式」给出下一步该调什么。只读。
mcp_limits读MCP 服务器的硬性上限(会话数、队列深度、心跳、限流、超时等)。只读,用于判断会不会被限流。⚠️ toolsPage 只对控件工具(名字以 ctl 开头的那批)生效 —— 内置工具一律在 tools/list 第一页给全,不会把你分页切走。
serial_list_ports读枚举本机串口(端口名 / 友好名称 / 产品名)。只读,不打开端口。⚠️ 只有 Windows 的 COM 口 —— WSL 分栏要的是 WSL 内部的 /dev/...,看 serial_get_state 的 portOptions。
ui_list读列出界面上的可操控控件(按钮/输入框/下拉/开关)。每条给出 path、类型、面板、当前值、是否可用与不可用的原因。建议先用它枚举,再决定操作哪个。
ui_describe读看某个控件的完整信息与它的输入格式(inputSchema):可选值有哪些、要传数字还是布尔。
ui_get读读某个控件的当前值(实时从界面读,不是缓存的配置)。
ui_set写设置控件值(与用户点击同一条路径,界面会同步变)。返回的是写后的真实值;可用 items 批量。⚠️ 少数动作是「点了才开始跑」(典型是 WSL 端口映射复选框,可能要用户点授权框):结果带 mapRequest.settled=false + note,别重试,稍后用 ui_get_state{section:"wslDevices"} 看 status 是否变成 mapped。
ui_click写点一个按钮/开关(等价于 ui_set 传 true,但语义更清楚)。⚠️ 同 ui_set:WSL 端口映射那种「点了才开始跑」的控件会在结果里带 mapRequest.settled=false,别重试,去 ui_get_state{section:"wslDevices"} 复查。
ui_get_state读读界面状态快照(随用户配置持久化的那份:各监视器的端口/波特率/行尾/显示模式/开关、主题、蓝牙选中项)。用 section 只取子树;两张运行时设备表(bleDevices / wslDevices)只有这里能读到。
log_channels读不确定日志在哪时先调它:列出所有日志通道(条数 / 字节 / seq 区间 / 被丢弃条数 / 最后一条时间)。
log_tail读读某个日志通道的尾部。优先 format:"text"(一行一条,比 json 省一半以上 token);要逐行结构化字段(含来源 src:ai/ui/none)时才用 json。增量拉给 sinceSeq,下次用返回的 nextSinceSeq(别直接跳 seqTo,会跳过 missed 的行);mayBeIncomplete=true = 该通道丢过最旧的行,别把它当完整证据。通道名见 log_channels。
log_search读在日志里检索(子串或正则;不给 channel 就搜全部)。按需要的信息量选 mode:count 只回计数(「出现几次」用它)、matches 只回匹配片段、lines(默认)回命中行并可带前后 context 行。命中都带 channel/seq,便于接着 log_tail。⚠️ 要成段读某个通道别用它,用 log_tail{format:"text"}。
log_stats读各通道的概览:条数、字节、被丢弃条数、告警/错误数、时间跨度与平均行/秒。用来判断"是不是在刷屏"。
log_clear写清空某个通道,或省略 channel 清空全部。⚠️ 这是销毁证据的动作:清掉的行回不来了(用户想复盘设备行为就只能让他复现)—— 只在确认这份记录不再需要时用,别为「看起来干净」随手清。
mcp_calls读查最近的工具调用记录(谁在什么时候调了什么、成没成、耗时多久、改动了哪些控件)。记录写在独立的 ai-calls.jsonl,不碰用户配置。
mcp_stats读调用统计:总次数、按工具分布、时间范围、记录文件大小与丢弃数。
mcp_config_get读读 MCP 自己的配置(服务器开关/端口/记录设置等)。token 只回打码值。
mcp_config_set写改 MCP 自己的配置。只支持 server 与 callLog 两类键(未知键会报错)。改 server.* 只保存、不立刻重启(需在界面里关闭再启用才生效);不接受改 token。

「写」= 会改变程序状态(界面 / 日志缓存 / AI 配置)。AI 调用这些工具时请先确认意图。 只读(沙箱)模式:用户在弹窗里打开后,上表所有「写」工具一律被拒(错误码 -32007,且没有执行 —— 界面与配置文件一个字都不变)。 注意这个不对称是故意的:mcp_config_set 自己也是写工具,所以 AI 只能打开只读模式、关不掉它,要关必须由用户在弹窗里点。

4. 逐个工具 ​

串口语义工具(优先用这些,比 ui_* 通用桥更准) ​

serial_get_state ​

  • 作用:操作串口前先调它:读该分栏的完整状态(端口/波特率/帧格式/行尾/DTR-RTS/显示开关/是否在监控/行数与字节数/全部分栏名 panes),外加 portOptions —— 这个分栏当前能选的端口(Windows 是 COM 名,WSL 是 /dev/...;inUse = 被别的分栏占着)。
  • 读/写:只读,无副作用
  • 返回:{pane, isConnected, portName, port, baud, viewMode, lineEnding, sendAs, dataBits, stopBits, parity, dtr, rts, autoScroll, autoReconnect, lineNum, timestamp, echo, terminalMode, lineBuf, advOpen, outputLines, outputBytes, historyCount, panes, portOptions:[{value,label,inUse}], logChannels:{rx,tx}}
  • 注意:操作串口前先调它;省略 pane 默认 main;logChannels 是"收发内容去哪读"的通道名;portOptions 是这个分栏当前能选的端口(Windows 分栏是 COM 名,WSL 分栏是 /dev/... 路径)——选端口前先看它

入参

参数类型必填说明
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来

serial_select_port ​

  • 作用:选该分栏要用的端口。值必须来自该分栏的 portOptions(见 serial_get_state);给错会回列可选值。⚠️ 别拿 serial_list_ports 当依据:它只有 Windows 的 COM 口,WSL 分栏要的是 /dev/ttyUSB0 这类 WSL 内部路径。
  • 读/写:写(会改状态)
  • 返回:{pane, applied:[{name,ok,from,to}]}
  • 注意:值必须是该分栏端口下拉里的一个(就是 serial_get_state 的 portOptions[].value);给错 → 协议级 -32602 并回列真实可选值,照着改就行。⚠️ 别拿 serial_list_ports 当依据:它只有 Windows 的 COM 口,WSL 分栏要的是 /dev/ttyUSB0 这类 WSL 内部路径

入参

参数类型必填说明
portstring是端口名:Windows 分栏如 COM3;WSL 分栏如 /dev/ttyUSB0
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来

serial_set_baud ​

  • 作用:设置波特率(110..4000000)。等价于在「波特率」输入框里填值。
  • 读/写:写(会改状态)
  • 返回:同上
  • 注意:110..4000000;越界报 -32602

入参

参数类型必填说明
baudnumber是波特率,如 115200
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来

serial_set_frame ​

  • 作用:设置帧格式(dataBits / stopBits / parity,至少给一个)。只在未连接时有意义,连接中请先 serial_close。
  • 读/写:写(会改状态)
  • 返回:同上
  • 注意:dataBits/stopBits/parity 至少给一个;连接中改帧格式无效,先 serial_close

入参

参数类型必填说明
dataBitsstring否枚举:5 / 6 / 7 / 8
stopBitsstring否枚举:1 / 2
paritystring否枚举:none / odd / even
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来

serial_set_lines ​

  • 作用:设置 DTR / RTS 电平(布尔)。常用于让目标板复位(DTR 拉低)或进入下载模式。
  • 读/写:写(会改状态)
  • 返回:同上
  • 注意:dtr/rts 布尔;常用于让目标板复位或进下载模式

入参

参数类型必填说明
dtrboolean否
rtsboolean否
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来

serial_set_display ​

  • 作用:设置显示与行为开关(viewMode / lineEnding / echo / lineNum / timestamp / autoScroll / autoReconnect / terminalMode / lineBuf / advOpen,至少给一个)。serial_get_state 报出来的每个开关这里都能设。⚠️ 终端模式下「行号 / 时间戳 / 回显」是置灰的:设它们不算失败,返回里带 skipped:true(当前状态本来就不生效),别重试。⚠️ lineBuf(命令行缓冲:整行发送 + 本地回显,AT 指令用)只对终端模式生效,终端模式关着时同样回 skipped:true。
  • 读/写:写(会改状态)
  • 返回:同上
  • 注意:viewMode/lineEnding/echo/lineNum/timestamp/autoScroll(自动滚动)/autoReconnect/terminalMode/lineBuf(命令行缓冲)/advOpen;serial_get_state 报出来的每个开关这里都能设(断言集里有一条守着这条对称性)

入参

参数类型必填说明
viewModestring否枚举:text / hex
lineEndingstring否枚举:crlf / lf / cr / none
echoboolean否
lineNumboolean否
timestampboolean否
autoScrollboolean否
autoReconnectboolean否
terminalModeboolean否
lineBufboolean否命令行缓冲:整行发送 + 本地回显(AT 指令用);只对终端模式生效,终端模式关着时设它会回 skipped
advOpenboolean否「更多设置」栏是否展开(真串口面板才有)
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来

serial_open ​

  • 作用:开始监控(=点「开始监控」按钮)。可同时给 port/baud,省两次调用。返回前确认真的连上(最多 6 秒),失败会说明可能原因(端口被占用 / 设备拔出 / 驱动异常)。
  • 读/写:写(会改状态)
  • 返回:{pane, connected:true, state:{…}}
  • 注意:会等最多 6 秒确认真连上;失败 → isError:true(-32006)并给出可能原因,不是乐观返回

入参

参数类型必填说明
portstring否可选:先选端口再打开
baudnumber否可选:先设波特率再打开
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来

serial_close ​

  • 作用:停止监控(等价于点「停止监控」),返回前确认已断开。
  • 读/写:写(会改状态)
  • 返回:{pane, connected:false, state:{…}}
  • 注意:会等最多 3 秒确认已断开

入参

参数类型必填说明
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来

serial_send ​

  • 作用:往该分栏发数据(需已在监控中)。mode=hex 时 data 按十六进制解析(如 "01 03 00 00 00 02"),否则按文本;lineEnding 会覆盖该分栏的行尾并留在界面上。单次最多 64K 字符,大块数据请分批。
  • 读/写:写(会改状态)
  • 返回:
  • 注意:需要该分栏已在监控中;mode=hex 时 data 按十六进制解析;lineEnding 会留在界面上(不是临时覆盖)

入参

参数类型必填说明
datastring是要发送的内容(文本或 HEX 串);单次最多 64K 字符,大块数据请分批
modestring否枚举:text / hex 发送模式,默认沿用界面当前设置
lineEndingstring否枚举:crlf / lf / cr / none 临时改行尾(改完会留在界面上)
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来

serial_clear ​

  • 作用:清空该分栏的输出区(=点「清除内容」)。连带清掉磁盘上的会话日志缓存 —— %APPDATA%\seahi-serial\log-cache 下属于该分栏的 session 文件会被截断;界面上不要了的内容,磁盘上也别留着。
  • 读/写:写(会改状态)
  • 返回:
  • 注意:连带清掉磁盘会话日志缓存:该分栏在 log-cache 里的 session 文件会被截断(不是只清界面)

入参

参数类型必填说明
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来

serial_get_history ​

  • 作用:读该分栏的发送历史(最近的在前)。用来回看刚才发过什么,或复用上一条指令。
  • 读/写:只读,无副作用
  • 返回:
  • 注意:最近的在前

入参

参数类型必填说明
limitnumber否最多返回多少条,默认 20,上限 200
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来

serial_get_output ​

  • 作用:读串口分栏实际收发的内容 —— 设备回了什么就用它(不用 log_tail,也不用猜通道名)。默认收+发按时间归并,dir 区分收发、src 区分 ai/ui/none(追溯谁发的)。优先 format:"text":一行一条,比 json 省一半以上 token;要逐行字段时才用 json。还没数据时回空列表,不报错。
  • 读/写:只读,无副作用
  • 返回:{pane, direction, format, isConnected, channels:{rx,tx}, count, items:[{seq,ts,dir,text,bytes}], truncated, note?}(format:"text" 时改为 {…, text},没有再给 items)
  • 注意:串口监视器的核心:读设备回了什么。默认收+发按时间归并;数据与 log_tail 同一份存储,但不需要你知道通道名,且"还没收到数据"返回空列表 + note 而不是报错。优先用 format:"text"(一行一条 [时刻] [rx|tx] 正文,比 json 省一半以上 token;头部那行带着两通道各自的 dropped/mayBeIncomplete,正文在 content 文本里)

入参

参数类型必填说明
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来
directionstring否枚举:rx / tx / both 只要收(rx)/只要发(tx)/都要(both,默认)
linesnumber否最多返回多少行,默认 50,上限 2000
formatstring否枚举:json / text 输出编码:text=一行一条纯文本(推荐,省 token);json=逐行结构化对象(默认)

serial_quick_cmd ​

  • 作用:面板「快速指令」列表(按循环组分段)。不带参数=列出(含 index/组/值/发送参数/groups/loop);给 index=执行那一条(index 从 0 起,用户口语的「第 N 条」= index N-1);action=loop=开/关整条循环链;action=add|update|remove|group=改列表(会写回它挂载的外部文件)。⚠️ 循环里只有同时配了 expect 且 timeoutMs>0 的条目才等回应;没写成功词的条目不等回应,此时 timeoutMs 就是发下一条的间隔。
  • 读/写:只读,无副作用
  • 返回:{pane, items:[{index,label,value,seq,timeoutMs,expect,retry,okGoto,errGoto,hex}], usable, file, source}
  • 注意:不带 index 只列;带 index 才执行(→ {pane, ran, label, value, hex})。seq/timeoutMs/expect/retry/okGoto/errGoto/hex 是每条自己的等待参数(顺序号 > 0 才进面板上的「循环发送」列表;⚠️ 等回应 ⇔ expect 非空 且 timeoutMs > 0:expect 留空 = 这条不等回应,此时 timeoutMs 就是"隔多久发下一条"的间隔(要等内置的 OK 也得显式写 OK,它是追加的成功词);timeoutMs 缺省 3000、上限 600000、填 0 = 按 20ms 最小间隔连发,配了 expect 时它是等回应的上限(等满就按失败跳转,默认终止整链);retry = 收到 ERROR 后重发几次、缺省 3;okGoto/errGoto = 跳转:收到 OK 走前者、ERROR 用尽或超时走后者,取值 留空/下一条(缺省)/ 数字=顺序号 / 结束 —— 这就是"分支与循环",它们同样只在等回应的条目上生效);除 timeoutMs 外这几项面板上都没有入口,写在指令文件的同名列里;add/update 也收 delayMs(旧拼写,与 timeoutMs 同值);source=file 表示这个列表来自外部文件(面板里增删改会写回该文件),file 是它的路径;source=config 才是纯配置里的列表

入参

参数类型必填说明
indexnumber否要执行(不带 action 时)或要改(update/remove 时)的条目下标,从 0 开始,见 quickList 的 items[].index(按组→组内摊平)
actionstring否枚举:loop / add / update / remove / group 要做的动作:loop=开关循环发送;add=加一条;update=改一条;remove=删一条;group=组操作。省略=按 index 执行/只列举
onboolean否action=loop 时:true 开、false 关(省略=取反);action=group 且 op=on/fold 时:该组是否参与循环 / 是否折叠
groupany否action=add/group 时指定哪一组:组序号(0 起,见 quickList 的 groups[].index)、组名或组 id。add 省略时加到最后那组(这里用 anyOf 而不是 type 数组:数组型 type 的客户端兼容性差,官方 Inspector 会报)
namestring否action=group 且 op=rename 时的新组名
toIndexnumber否action=group 且 op=move 时的目标组序号(0 起;组的上下顺序就是循环顺序)
valuestring否action=add/update 时的指令内容(原样发送,不按逗号切分)
seqnumber否action=add/update 时的顺序号:0 = 不参与循环,>0 在组内按数字升序发
timeoutMsnumber否action=add/update 时的超时(毫秒):有 expect 时是等回应的上限(等满按失败跳转);没写 expect 时它就是发下一条的间隔。缺省 3000,上限 600000,填 0 = 20ms 最小间隔
delayMsnumber否⚠️ 旧拼写:与 timeoutMs 同一个值(这一项的语义是「超时」,不是「发送间隔」)。新调用请用 timeoutMs —— 两个都给时以 timeoutMs 为准
expectstring否action=add/update 时的成功词,多个用 `
retrynumber否action=add/update 时:收到 ERROR 后最多重发几次(缺省 3,上限 10;0 = 不重发,直接终止)
hexboolean否action=add/update 时:这一条是否按 HEX 解析后发送(默认 false)
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来

serial_workflow ​

  • 作用:串口/WSL 面板的自动化工作流规则(收到匹配数据就自动执行动作:发数据 / 切 DTR-RTS / 存日志)。省略 action=列出;add/update/remove=改规则(新规则一律 running=false,改动立刻写进配置)。⚠️ 规则一旦 running 就会自动往设备发数据 —— 要启动必须用 serial_workflow_run(带 confirm),别用 ui_click 绕开确认。
  • 读/写:只读,无副作用
  • 返回:{pane, count, runningCount, rules:[{id,name,enabled,running,conditions,actions,domIds}], limits}
  • 注意:串口/WSL 分栏的自动化工作流规则(面板「更多设置 → 工作流」):收到匹配数据就自动执行动作。省略 action = 列出;action=add|update|remove 改规则(走的就是面板改的同一条路,立刻写进配置)。⚠️ 新规则一律 running=false;running:true 这里会被拒(-32602)—— 让规则跑起来必须用 serial_workflow_run(带确认门)。规则一旦 running,收到匹配数据就会自动往设备发数据

入参

参数类型必填说明
actionstring否枚举:list / add / update / remove 要做的动作:list=列出(省略即 list);add=加一条;update=改一条;remove=删一条
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来
rulestring否update/remove 时的规则 id(见 list 里 rules[].id)
namestring否add/update 时的规则名(最长 64 字符)
enabledboolean否add/update 时这条规则是否启用(关掉的规则不参与匹配;注意它与 running 是两回事)
runningboolean否⚠️ 这里只接受 false(用来停一条正在跑的规则);想启动请用 serial_workflow_run。add 时给 true 会被强制成 false
conditionsarray<object>否匹配条件,全部满足才触发:[{"type":"string_contains
actionsarray<object>否命中后按顺序执行:[{"type":"send_data

serial_workflow_run ​

  • 作用:开始/停止一条工作流规则的运行(running)。⚠️ 危险动作:开始之后,这条规则一收到匹配的数据就会自动往设备发数据(动作里可能还有存日志文件),必须带 confirm:true;不带时不会执行并返回 -32006 说明后果。停止(on=false)同样需要 confirm —— 它属于同一条工具。
  • 读/写:只读,无副作用
  • 返回:
  • 注意:开始/停止一条工作流规则的运行(running)。危险动作(开始之后规则会自动往设备发数据、动作里可能还有存日志文件),必须带 confirm:true,否则不执行并回 -32006。rule 是规则 id(见 serial_workflow 的 rules[].id),on 省略 = true

入参

参数类型必填说明
rulestring是规则 id(见 serial_workflow 的 rules[].id)
onboolean否true = 开始跑,false = 停止(省略 = true)
panestring否分栏:main / extra-N(Windows)、wsl / wsl-xN(WSL),省略=main。写操作会把该面板切到前台;WSL 分栏是懒创建的,写操作会顺带建出来
confirmboolean否危险动作确认:必须为 true 才会执行(想清楚再传)

蓝牙语义工具(BLE,主机方向) ​

ble_get_state ​

  • 作用:蓝牙分栏的当前状态:是否在扫描、扫到几台设备、选中/已连的是哪台、GATT 服务树有几个服务、订阅了几路通知、内嵌监视器是否打开。只读,无副作用。
  • 读/写:只读,无副作用
  • 返回:
  • 注意:操作蓝牙前先调它;只反映面板内存里的状态,不会去碰适配器

入参

无(不需要参数)

ble_list_devices ​

  • 作用:读蓝牙扫描结果(不触发扫描):MAC / 名称 / RSSI / 是否配对 / 是否选中。支持分页(limit + offset,返回 hasMore/nextOffset;扫描未完时翻页可能重复或漏,要稳定名单就等 scanning=false)。列表为空多半是设备不广播(被 Windows 配对过 / 被别的主机连走)—— 这时用 ble_connect 按 MAC 直连。只读。
  • 读/写:只读,无副作用
  • 返回:{scanning, total, offset, limit, returned, hasMore, nextOffset, devices:[{mac,name,rssi,paired,selected}], selected, note?}
  • 注意:每调一次都会现问一次后端(不是只读面板缓存)—— 刚 ble_start_scan 完立刻问也拿得到。支持分页:limit 每页几台(省略=全量)、offset 从第几台开始,返回里给 hasMore/nextOffset 接着翻。空列表时 note 会说下一步(含"设备不广播就只能按 MAC 直连");RSSI 是负数,越接近 0 越强

入参

参数类型必填说明
limitnumber否每页最多几台(省略/0=不限,一次全给)
offsetnumber否从第几台开始(0 起,默认 0);翻页时用返回的 nextOffset

ble_start_scan ​

  • 作用:开始扫描蓝牙设备。时长由面板上的设置决定,本工具不收时长参数;扫完用 ble_list_devices 取结果。⚠️ 连上设备会自动停扫描,所以连接后 scanning=false 属正常;要再找别的设备就重新调它。写操作(占用射频)。
  • 读/写:写(会改状态)
  • 返回:
  • 注意:走面板那颗「开始/停止扫描」按钮的同一路径;按面板上设的时长自动停止,扫完用 ble_list_devices 取结果

入参

无(不需要参数)

ble_stop_scan ​

  • 作用:停止蓝牙扫描(复用同一颗按钮的路径)。写操作。
  • 读/写:写(会改状态)
  • 返回:
  • 注意:同上:复用同一颗按钮的路径

入参

无(不需要参数)

ble_connect ​

  • 作用:连接一台 BLE 设备。给 addr 时:列表里有它就点卡片连,列表里没有就按 MAC 直连(不依赖广播 —— 不广播的设备只有这条路)。不给 addr 用面板当前选中的那台。等连接真的成功才返回(带服务数)。⚠️ 连上会自动停扫描,返回后 scanning=false 属正常。写操作。
  • 读/写:写(会改状态)
  • 返回:
  • 注意:via=list(扫描列表里点卡片连)/ direct(列表里没有 → 按 MAC 直连,不依赖广播)/ selected(用面板已选中的那台)。等连接真的成功才返回;需要配对时会弹出配对窗等用户确认

入参

参数类型必填说明
addrstring否设备 MAC,如 A4:C1:38:11:14:2B(省略=用面板已选中的设备)

ble_disconnect ​

  • 作用:断开当前已连接的设备(面板那颗「断开设备」按钮的同一条路)。断开后服务树、订阅状态、本次会话的数据日志一并清空。写操作。
  • 读/写:写(会改状态)
  • 返回:
  • 注意:断开后面板的服务树、订阅状态、本次会话数据日志一并清空(与点那颗「断开设备」按钮完全一样)

入参

无(不需要参数)

ble_get_services ​

  • 作用:当前已连接设备的 GATT 服务树(服务 UUID / 名称,每个服务下的特征 UUID、属性 props、描述符个数)。只读,取的是面板已经拉到的那份,不会重新去问设备。
  • 读/写:只读,无副作用
  • 返回:{connected, addr, serviceCount, services:[{uuid,name,chars:[{uuid,props,descs}]}]}
  • 注意:取的是面板已经拉到的那份服务树(不会重新去问设备);还没连设备时 note 会说明

入参

无(不需要参数)

ble_read ​

  • 作用:读一个特征的值(按 UUID)—— 走面板那颗读按钮,结果随后出现在 ble_get_output 里。需要设备已连接、该特征有 read 属性(见 ble_get_services)。
  • 读/写:只读,无副作用
  • 返回:
  • 注意:按特征 UUID 寻址,点的是面板上那颗读按钮;结果随后出现在 ble_get_output 里。特征没有 read 属性时直接说清

入参

参数类型必填说明
charstring是特征 UUID(见 ble_get_services 的 services[].chars[].uuid)

ble_write ​

  • 作用:往一个特征写数据(按 UUID)—— 打开面板那个写入窗并点「发送」,HEX/文本解析、行尾、写响应全用面板那套。需要设备已连接、该特征有 write 属性(见 ble_get_services)。写操作。
  • 读/写:写(会改状态)
  • 返回:
  • 注意:打开面板那个写入窗并点「发送」:HEX/文本解析、行尾、写响应/无响应全用面板那套(写入窗会留在界面上)。单次最多 maxBleWriteChars 个字符;特征的写入方式不支持时要的错误里会把可选值列出来

入参

参数类型必填说明
charstring是特征 UUID(见 ble_get_services 的 services[].chars[].uuid)
datastring是要写入的内容;format=hex 时是十六进制串(如 01A0FF 或 01 A0 FF)
formatstring否枚举:text / hex 内容格式(省略=text)
lineEndingstring否枚举:none / cr / lf / crlf 文本模式追加的行尾(省略=none,即原样写入 —— 协议帧最不容易被写坏)
writeTypestring否枚举:write / write_without_response 写响应 / 无响应(省略=用该特征的第一种;给了但该特征不支持会报错并把可选值列出来)

ble_subscribe ​

  • 作用:开/关某个特征的通知订阅(notify / indicate)——点的是面板上那颗订阅按钮,数据随后出现在 ble_get_output 里。状态已经在目标值时不会重复点(不会把用户刚打开的订阅关掉)。
  • 读/写:写(会改状态)
  • 返回:
  • 注意:开/关通知订阅(notify/indicate)。状态已经是目标值时不会重复点(changed:false)—— 否则会把用户刚打开的订阅关掉

入参

参数类型必填说明
charstring是特征 UUID(见 ble_get_services 的 services[].chars[].uuid)
onboolean否true=订阅、false=退订(省略=true)

ble_get_output ​

  • 作用:读蓝牙面板本次会话的数据日志(收到的通知/读值 + 写出去的内容;切设备或断开会清空)。跨会话历史用返回的 channels.rx/tx 去 log_tail。只想知道出现几次就别拉条目:给 pattern + mode(count / matches / lines)。⚠️ CTS 时间条目已自动附 decoded/decodedSummary,不用再喂 ble_cts_time。只读。
  • 读/写:只读,无副作用
  • 返回:{pane, count, scanned, mode, total, channels:{rx}, items:[{seq,ts,kind,hex,charUuid,descUuid,text,dim}]}(CTS 条目另有 decoded / decodedSummary);mode:"matches" 时是 hits:[{seq,ts,kind,match}],mode:"count" 时是 total/totalMatches(都没有 items),后两档另外带 pattern/regex
  • 注意:本次会话的蓝牙数据日志(切设备/断开就清空)。要跨会话用 channels.rx 去 log_tail;sinceSeq 增量跟进。要"这条 ERROR 出现几次"别拉条目:给 pattern + mode(count 只回计数、matches 只回片段);匹配的文本取 text,text 为空时取 hex(HEX 通知也搜得到)。⚠️ CTS 的时间条目会自动带上解读(items[].decoded + items[].decodedSummary),不用再把这些 HEX 喂给 ble_cts_time;判据是特征短号 2a2b/2a0f 且长度正好对得上 —— 描述符的值不解读(CCCD 也是 2 字节,解出来会说一个错的时区)

入参

参数类型必填说明
limitnumber否只要最后 N 条(省略=全部)
sinceSeqnumber否增量:只要 seq 大于它的(与返回的 items[].seq 对齐)
patternstring否要检索的内容(字符串按字面量处理,regex=true 才是正则)。上限 512 字符
modestring否枚举:lines / matches / count count=只回计数(最省)/ matches=只回匹配片段 / lines=条目本身(默认)。后两档必须给 pattern
regexboolean否true 时 pattern 按正则解释,默认 false
caseSensitiveboolean否默认 false 区分大小写;也接受旧拼写 case_sensitive

ble_refresh_rssi ​

  • 作用:读已连接设备的信号强度(负数,越接近 0 越强)。只问一次射频、不改状态。⚠️ 没连设备会直接失败(先 ble_connect)。
  • 读/写:只读,无副作用
  • 返回:
  • 注意:只问一次射频、不改状态;没连设备时直接报"先连上"

入参

无(不需要参数)

ble_cts_time ​

  • 作用:把 CTS 时间特征的原始值翻译成人话(0x2A2B / 0x2A0F / 0x2A14,按长度认字段:10 / 2 / 4 字节)。回 utc / skewSecs / 星期 / adjustReasons / notes,并主动指出可疑处(年份像 RTC 没初始化、星期与日期对不上、偏了多少分钟)。data 必须来自实际读取(ble_read,或 ble_get_output 里的条目),别凭空构造。设备没给出的字段回 null,不猜。纯后端:不碰设备也不碰界面。
  • 读/写:只读,无副作用
  • 返回:{field, charUuid, bytes, hex, utc, skewSecs, year, month, day, hour, minute, second, dayOfWeek, dayOfWeekName, fractions256, fractionMillis, adjustReason, adjustReasons, notes};field:"localTimeInfo"(2 字节)时是 {timeZoneQuarterHours, utcOffset, utcOffsetMinutes, dstOffset, dstName, dstOffsetMinutes, notes};field:"referenceTimeInfo"(4 字节)时是 {timeSource, timeSourceName, timeAccuracy, accuracyMillis, accuracyName, daysSinceUpdate, hoursSinceUpdate, sinceUpdateHours, sinceUpdateText, notes}
  • 注意:把 CTS(Current Time Service 0x1805)的原始值翻译成人话 —— 纯后端工具:不碰设备也不碰界面(读值仍走 ble_read → ble_get_output)。按长度认字段:2A2B 的 10 字节 / 2A0F 的 2 字节 / 2A14 的 4 字节都认;返回里 utc/skewSecs 是结论,notes 会主动指出可疑处(年份像 RTC 没初始化、星期与日期对不上、时钟偏了多少分钟、设备自报"未同步")。⚠️ 设备没给出的字段回 null,不许猜一个具体值(0 也是结论):时区 -128 → utcOffset:null、DST 0xFF → dstOffsetMinutes:null、时间精度 254/255 → accuracyMillis:null(timeZoneQuarterHours/dstOffset/timeAccuracy 保留原始字节)。单位都按规范:DST 值是 15 分钟单位(2=+0.5h / 4=+1h / 8=+2h)、时间精度是 1/8 秒(125ms)步长;越界与保留值都会写进 notes。

入参

参数类型必填说明
dataany是要解码的整条特征值(别截断)

ADB 语义工具(ADB shell) ​

adb_list_devices ​

  • 作用:列出 adb devices -l 看到的设备(序列号 / 状态 / 型号)。只读,不会开 shell。只有 state=device 的那台才可用;unauthorized 表示还没在设备上点「允许 USB 调试」。
  • 读/写:只读,无副作用
  • 返回:{total, ready, devices:[{serial,state,model,product}], note?}
  • 注意:只有 state=device 的那台可用(unauthorized 表示设备上还没点「允许 USB 调试」)。读的是 adb devices -l 的实时结果(与面板那颗「刷新」同一个命令),不吃面板 5 秒轮询的空窗

入参

无(不需要参数)

adb_open_shell ​

  • 作用:在设备上开一个交互式 shell(=点面板上那台设备的卡片:建 xterm + PTY),等 PTY 真的建出来才返回(最长 10 秒);先确认设备 state=device。⚠️ 危险动作,必须带 confirm:true,否则不执行并回 -32006。开完用 adb_shell_write 发命令、adb_shell_read 读输出。
  • 读/写:只读,无副作用
  • 返回:
  • 注意:危险动作(开出来之后就能在设备上执行任意命令),必须带 confirm:true,否则不执行并回 -32006。开之前先确认设备 state=device(serial 省略=用第一台可用的);等 PTY 真的建出来才返回(最长 10 秒),失败会如实说清是"这台机器没有可用设备"还是"serial 不存在"

入参

参数类型必填说明
serialstring否设备序列号(见 adb_list_devices;省略=用第一台 state=device 的设备)
confirmboolean否危险动作确认:必须为 true 才会执行

adb_shell_write ​

  • 作用:往已打开的 ADB shell 写入内容(与在面板终端敲键盘同一条路)。命令要自己带上 \n,不带就只填在命令行上、不会执行。⚠️ 危险动作(内容会被设备真的执行),必须带 confirm:true。单次最多 4096 字符。
  • 读/写:只读,无副作用
  • 返回:
  • 注意:危险动作(写进去的内容会被设备真的执行),必须带 confirm:true。命令要自己带 \n,不带只是填在命令行上;单次最多 maxAdbWriteChars 个字符(超了 -32602)。走的就是面板终端敲键盘那条命令

入参

参数类型必填说明
datastring是要写入 shell 的内容,如 "ls -l\n"
confirmboolean否危险动作确认:必须为 true 才会执行

adb_shell_read ​

  • 作用:读 ADB shell 已经产生的输出(日志中心 adb:rx 的旁路副本,不抢界面终端要显示的队列)。items 是 PTY 输出块、不是按行切的文本;增量跟进给 sinceSeq。logcat 刷屏时先给 pattern + mode(count 只回计数、matches 只回片段)。只读,没有界面也能用。
  • 读/写:只读,无副作用
  • 返回:{serial, channel, count, scanned, mode, items:[{seq,ts,level,dir,bytes,text}], truncated, dropped, mayBeIncomplete, note?};mode:"matches" 时是 hits:[{seq,ts,level,dir,match}],mode:"count" 时是 total/totalMatches(都没有 items),后两档另外带 pattern/regex
  • 注意:读日志中心 adb:rx —— PTY 读线程在生产端旁路的一份副本(不会抢走界面终端要显示的队列)。items 是 PTY 的输出块、不是按行切好的文本;truncated=true 表示凑满了一页(还有更多,用 sinceSeq 接着拉);mayBeIncomplete=true 表示通道丢过最旧的行。logcat 刷屏时先给 pattern + mode:count 只回"命中多少块/多少处"(几十 token),matches 只回片段。纯后端工具,没有界面也能用

入参

参数类型必填说明
sinceSeqnumber否只要 seq 大于它的行(增量跟进;省略=取尾部 limit 行)
limitnumber否最多回多少行,默认 200,上限 2000(mcp_limits.maxAdbReadLines)
patternstring否要检索的内容(字符串按字面量处理,regex=true 才是正则)。上限 512 字符
modestring否枚举:lines / matches / count count=只回计数(最省)/ matches=只回匹配片段 / lines=条目本身(默认)。后两档必须给 pattern
regexboolean否true 时 pattern 按正则解释,默认 false
caseSensitiveboolean否默认 false 区分大小写;也接受旧拼写 case_sensitive

adb_shell_resize ​

  • 作用:调整已打开 ADB shell 会话的 PTY 尺寸(与面板跟着容器尺寸自动推的是同一个后端命令)。cols/rows 都是 2~1000(mcp_limits.maxAdbCols / maxAdbRows)。注意:面板自己的尺寸同步(窗口/容器变化时)可能随后把它改回真实容器尺寸。写操作。
  • 读/写:写(会改状态)
  • 返回:
  • 注意:cols / rows 都是 2~1000(maxAdbCols / maxAdbRows),越界或 0/1 → -32602。注意面板自己的尺寸同步(窗口/容器变化时)可能随后把 PTY 改回真实容器尺寸

入参

参数类型必填说明
colsnumber是列数(2~1000)
rowsnumber是行数(2~1000)

adb_close_shell ​

  • 作用:关掉当前 ADB shell 会话(等价于点面板上会话的关闭:杀掉 adb shell 子进程 + 移除终端)。本来就没开会话时是幂等的(closed:false + note),不是错误。写操作。
  • 读/写:写(会改状态)
  • 返回:
  • 注意:关掉当前会话(kill adb shell 子进程 + 移除终端);本来就没开会话时是幂等的(closed:false + note),不是错误

入参

无(不需要参数)

安全与策略 ​

mcp_danger ​

  • 作用:列出需要二次确认的危险工具(会对外产生不可撤销影响的那些)与各自的后果。调用它们时必须带 confirm:true,否则不会执行。只读。
  • 读/写:只读,无副作用
  • 返回:{tools:[{name, consequence, confirm}], total, note}
  • 注意:危险工具清单(会对外产生不可撤销影响的那些)。先问后果再确认:不带 confirm 调用它们不会执行

入参

无(不需要参数)

应用与服务器 ​

app_info ​

  • 作用:本机 SeaHi Serial 应用的基本信息(版本、平台、进程、运行时长)。只读,无副作用。
  • 读/写:只读,无副作用
  • 返回:{name, version, profile, os, arch, pid, uptimeSecs}

入参

无(不需要参数)

mcp_status ​

  • 作用:不确定从我这儿怎么下手就先调它:MCP 服务器自身状态(是否运行、监听端点、会话数、请求数与限流/丢弃计数),外加一份 nextSteps —— 按「有没有界面 / 用户是不是开了只读模式」给出下一步该调什么。只读。
  • 读/写:只读,无副作用
  • 返回:打码后的服务器状态:running/enabled/host/port/streamableHttp/tokenMasked/sessions/statusEmits/readOnly/requests/dropped/toolCalls/registry/logHub/errorReports/callLog/limits/version/uptimeSecs
  • 注意:不含 token 与完整 URL(urlMasked 与 streamableUrlMasked 只在服务器通过界面启动、确实绑定了端口时出现;两条 URL 都打码);streamableHttp 为 false 时 /mcp 返回 404、只剩遗留 SSE;statusEmits 是"往前端推过多少次状态",用来判断界面上的会话数是不是在更新;readOnly 必须先看 —— 为 true 时所有写操作会被拒(-32007)

入参

无(不需要参数)

mcp_limits ​

  • 作用:MCP 服务器的硬性上限(会话数、队列深度、心跳、限流、超时等)。只读,用于判断会不会被限流。⚠️ toolsPage 只对控件工具(名字以 ctl 开头的那批)生效 —— 内置工具一律在 tools/list 第一页给全,不会把你分页切走。
  • 读/写:只读,无副作用
  • 返回:{maxSessions, sessionQueue, heartbeatSecs, maxBodyBytes, maxUiSetItems, maxSendChars, toolsPage, idleTimeoutSecs, rateLimitPerMin, protocolVersion, protocolFallback, logMaxLineBytes, logTotalCapBytes, logMaxChannels, maxQuickCmdItems, maxQuickCmdLabelChars, maxQuickCmdValueChars, maxQuickCmdFileBytes, maxQuickCmdTimeoutMs, maxQuickCmdRetry, maxQuickCmdExpectChars, maxBleWriteChars, maxAdbWriteChars, maxAdbCols, maxAdbRows, maxAdbReadLines}
  • 注意:用来判断会不会被限流/丢弃;加新工具时这里也该有对应的一条上限。注意"报出来"≠"被执行":这几个数各自都有代码里真的拦一道(快速指令的 maxQuickCmdTimeoutMs/maxQuickCmdRetry/maxQuickCmdExpectChars 就是在碰界面之前校验的)

入参

无(不需要参数)

serial_list_ports ​

  • 作用:枚举本机串口(端口名 / 友好名称 / 产品名)。只读,不打开端口。⚠️ 只有 Windows 的 COM 口 —— WSL 分栏要的是 WSL 内部的 /dev/...,看 serial_get_state 的 portOptions。
  • 读/写:只读,无副作用
  • 返回:{count, ports:[{portName, friendlyName, productName}]}
  • 注意:不会打开端口;端口名在 portName(字段一律驼峰,别去猜 port_name)。⚠️ 只列 Windows 侧的 COM 口 —— WSL 分栏的端口是 WSL 内部的 /dev/...,不在这里(用 serial_get_state 的 portOptions)

入参

无(不需要参数)

界面操作(走合成 DOM 事件,和用户点击同一条路径) ​

ui_list ​

  • 作用:列出界面上的可操控控件(按钮/输入框/下拉/开关)。每条给出 path、类型、面板、当前值、是否可用与不可用的原因。建议先用它枚举,再决定操作哪个。
  • 读/写:只读,无副作用
  • 返回:{total, controls:[{path, kind, panel, group, label, enabled, disabledReason, value?, options?}], nextCursor?}
  • 注意:enabled=false 时 disabledReason 会说明原因(如"串口未连接");建议先枚举再操作

入参

参数类型必填说明
panelstring否只看某个面板:serial / wsl / adb / ble / global / mcp / dialog
kindstring否只看某种类型:button / toggle / select / text / number / checkbox / range
querystring否按 path 或标签做子串匹配
cursorstring否分页游标(上一次返回的 nextCursor)
limitnumber否每页条数,默认 100,最大 500

ui_describe ​

  • 作用:看某个控件的完整信息与它的输入格式(inputSchema):可选值有哪些、要传数字还是布尔。
  • 读/写:只读,无副作用
  • 返回:{…控件公开字段…, description, inputSchema}
  • 注意:等于"这个控件怎么用"的说明书

入参

参数类型必填说明
pathstring是控件路径,如 serial.conn.portSelect

ui_get ​

  • 作用:读某个控件的当前值(实时从界面读,不是缓存的配置)。
  • 读/写:只读,无副作用
  • 返回:{path, value, enabled, disabledReason}

入参

参数类型必填说明
pathstring是

ui_set ​

  • 作用:设置控件值(与用户点击同一条路径,界面会同步变)。返回的是写后的真实值;可用 items 批量。⚠️ 少数动作是「点了才开始跑」(典型是 WSL 端口映射复选框,可能要用户点授权框):结果带 mapRequest.settled=false + note,别重试,稍后用 ui_get_state{section:"wslDevices"} 看 status 是否变成 mapped。
  • 读/写:写(会改状态)
  • 返回:{results:[{path, ok, notFound?, error?, from?, to?, mapRequest?}], effects:[{path, from, to}]}(单目标失败时不会有这个结构:整个调用直接失败)
  • 注意:会真的改界面;支持批量 items:[{path,value}](整批一次回执);只给一个 path/value 时按单目标语义——失败即整次调用失败(路径不存在 → -32602;控件被禁用 → isError+-32006)。⚠️ 少数动作点了才开始跑(典型:WSL 端口映射那个复选框要过 usbipd、还可能弹授权框等用户点)—— 那时结果里会带 mapRequest.settled=false + note:别重试,稍后用 ui_get_state{section:"wslDevices"} 看 status 是否变成 mapped

入参

参数类型必填说明
pathstring否
valueany否新值:文本/数字/布尔;下拉传选项的 data-val
itemsarray<object>否批量设置:[{path, value}, …](一次最多 200 个,这是硬上限:这条链路跑在界面主线程上,超了会报 -32602,请分批)

ui_click ​

  • 作用:点一个按钮/开关(等价于 ui_set 传 true,但语义更清楚)。⚠️ 同 ui_set:WSL 端口映射那种「点了才开始跑」的控件会在结果里带 mapRequest.settled=false,别重试,去 ui_get_state{section:"wslDevices"} 复查。
  • 读/写:写(会改状态)
  • 返回:{results:[{path, ok, notFound?, error?, mapRequest?}], effects:[…]}(单目标失败时不会有这个结构:整个调用直接失败)
  • 注意:会真的点下去(例如"开始监控");用于 setter 够不到的动作;点击不存在/不可用的控件 → -32602 / isError+-32006,不会假装成功。⚠️ 同 ui_set:WSL 端口映射那种"点了才开始跑"的动作会带 mapRequest.settled=false,别重试

入参

参数类型必填说明
pathstring是

ui_get_state ​

  • 作用:读界面状态快照(随用户配置持久化的那份:各监视器的端口/波特率/行尾/显示模式/开关、主题、蓝牙选中项)。用 section 只取子树;两张运行时设备表(bleDevices / wslDevices)只有这里能读到。
  • 读/写:只读,无副作用
  • 返回:当前会话配置快照(与界面「保存配置」同一份真源);两张"运行时设备表"都要从它读:section:"bleDevices" = 蓝牙扫描结果全量、section:"wslDevices" = WSL 端口映射的 USB 设备表({wslRunning, targetDistro, panelOpened, count, mapped, devices:[{busid, port, name, vidpid, hasCom, status, wslPath, wslSerial, busy, mapControlPath, autoMapControlPath}], note, mapUnavailableReason})—— 两处的行都是动态 div、不在控件注册表里,只有通用桥的客户端只能从这里读;ble 段里另带一份前 10 台的 scanResult

入参

参数类型必填说明
sectionstring否枚举:serial / wsl / ble / bleDevices / wslDevices / theme / window / monitors serial / wsl / ble / bleDevices / wslDevices / theme / window / monitors;省略=全部。运行时设备表(不是配置):蓝牙扫描结果读 bleDevices(全量)或 ble.scanResult(前 10 台);WSL 端口映射的 USB 设备表读 wslDevices —— 两处的行都是动态 div、不在控件注册表里,所以只有通用桥的客户端必须从这里读。wslDevices 每条还带 mapControlPath(可直接交给 ui_set 的控件路径),要映射某台设备就先用它把 COM 名对上 busid。

日志中心 ​

log_channels ​

  • 作用:不确定日志在哪时先调它:列出所有日志通道(条数 / 字节 / seq 区间 / 被丢弃条数 / 最后一条时间)。
  • 读/写:只读,无副作用
  • 返回:{enabled, channelCount, channels:[{channel, lines, bytes, capBytes, seqFrom, seqTo, dropped, lastTs}], totalBytes, totalCapBytes, maxChannels, lockSkips, channelSkips, reclaims, reclaimedBytes}
  • 注意:不确定去哪找日志时先调它

入参

无(不需要参数)

log_tail ​

  • 作用:读某个日志通道的尾部。优先 format:"text"(一行一条,比 json 省一半以上 token);要逐行结构化字段(含来源 src:ai/ui/none)时才用 json。增量拉给 sinceSeq,下次用返回的 nextSinceSeq(别直接跳 seqTo,会跳过 missed 的行);mayBeIncomplete=true = 该通道丢过最旧的行,别把它当完整证据。通道名见 log_channels。
  • 读/写:只读,无副作用
  • 返回:{channel, format, lines:[{seq, ts, level, dir, text, rawBytes}], returned, dropped, seqFrom, seqTo, missed, nextSinceSeq, mayBeIncomplete, truncated}(format:"text" 时是 {…, text},没有再给 lines)
  • 注意:读日志优先用 format:"text":一行一条纯文本(头部一行元信息 + [时刻] [级别] 正文),同样数据比 json 省一半以上 token —— 实测 200 条短行 101 字节/行 → 29 字节/行(3.5 倍),行越长省得越少。增量跟进用 sinceSeq,并把返回里的 nextSinceSeq 当下次的入参(别直接跳到 seqTo,那会跳过 missed 那些行);missed>0 = 这一段还有行没给你(含已被裁掉的),mayBeIncomplete=true = 该通道丢过最旧的行。text 格式的正文在 content 文本里,structuredContent 只给元信息(要逐行字段就用默认 json)。渠道名见 log_channels

入参

参数类型必填说明
channelstring是通道名,如 app / error / mcp / serial:main:rx / ble:rx / ui:sys
linesnumber否最多返回多少行,默认 100,上限 2000
sinceSeqnumber否只取 seq 大于它的行(用于增量跟进);也接受旧拼写 since_seq
formatstring否枚举:json / text 输出编码:text=一行一条纯文本(推荐,省 token);json=逐行结构化对象(默认)
  • 作用:在日志里检索(子串或正则;不给 channel 就搜全部)。按需要的信息量选 mode:count 只回计数(「出现几次」用它)、matches 只回匹配片段、lines(默认)回命中行并可带前后 context 行。命中都带 channel/seq,便于接着 log_tail。⚠️ 要成段读某个通道别用它,用 log_tail{format:"text"}。
  • 读/写:只读,无副作用
  • 返回:{pattern, regex, mode, hits:[{channel, seq, ts, level, dir, text, before?, after?}], scanned, truncated};mode:"matches" 时 hits[] 里是 {channel, seq, ts, level, dir, match}(没有整行 text);mode:"count" 时是 {pattern, regex, mode, total, channels:[{channel, count, scanned}], scanned, scannedChannels, truncated:false}(没有 hits)
  • 注意:三档按需要的信息量选:count 只回计数(几十 token —— "ERROR 出现过几次""到底有没有超时"就用它);matches 只回匹配片段(一行多处算多条,长行日志用它比回整行省得多);lines(默认)回命中行,可配 context 0~5 带前后几行。不给 channel 就搜所有通道;matches/count 的图案同样按字面量处理(+/( 不用转义)

入参

参数类型必填说明
patternstring是要找的内容(不能为空串;regex=true 时按正则解释)
channelstring否限定通道;省略=全部
regexboolean否true 时 pattern 按正则解释,默认 false
caseSensitiveboolean否默认 false 区分大小写;也接受旧拼写 case_sensitive
limitnumber否最多回多少条(matches 模式是匹配处数,一行多处算多条),默认 100,上限 500
modestring否枚举:lines / matches / count 返回什么:count=只回计数(最省)/ matches=只回匹配片段(rg -o 那种)/ lines=命中行(默认)
contextnumber否命中行前后各带几行(0~5,默认 0;只对 mode:"lines" 有意义)

log_stats ​

  • 作用:各通道的概览:条数、字节、被丢弃条数、告警/错误数、时间跨度与平均行/秒。用来判断"是不是在刷屏"。
  • 读/写:只读,无副作用
  • 返回:{enabled, channels:[{channel, lines, bytes, dropped, warnOrError, spanSecs, linesPerSec}], totalBytes, totalCapBytes, maxChannels, lockSkips, channelSkips, reclaims, reclaimedBytes}
  • 注意:用来判断"是不是在刷屏"

入参

无(不需要参数)

log_clear ​

  • 作用:清空某个通道,或省略 channel 清空全部。⚠️ 这是销毁证据的动作:清掉的行回不来了(用户想复盘设备行为就只能让他复现)—— 只在确认这份记录不再需要时用,别为「看起来干净」随手清。
  • 读/写:写(会改状态)
  • 返回:{clearedChannels, channel}
  • 注意:省略 channel 清全部;通道名不存在会报 -32602(不静默成功);清空后通道仍在,log_tail 返回 0 行而不是报错

入参

参数类型必填说明
channelstring否

调用记录与配置 ​

mcp_calls ​

  • 作用:查最近的工具调用记录(谁在什么时候调了什么、成没成、耗时多久、改动了哪些控件)。记录写在独立的 ai-calls.jsonl,不碰用户配置。
  • 读/写:只读,无副作用
  • 返回:{calls:[{seq, ts, session, tool, args, ok, error, durationMs, effects}], returned, scanned, tailOnly, file, enabled, note}
  • 注意:返回值默认不记(includeResults 打开才记);只读文件尾部窗口 —— tailOnly=true 表示更早的记录没被扫到,returned 小于 limit 时别当成"历史上就这么多"(用 export 或直接读文件)

入参

参数类型必填说明
limitnumber否最多返回多少条,默认 50,上限 2000
toolstring否只看某个工具
okOnlyboolean否true 只看成功,false 只看失败;也接受旧拼写 ok_only
formatstring否枚举:jsonl / md jsonl(默认)或 md 表格

mcp_stats ​

  • 作用:调用统计:总次数、按工具分布、时间范围、记录文件大小与丢弃数。
  • 读/写:只读,无副作用
  • 返回:{callLog:{totalCalls, seq, dropped, byTool, firstAt, lastAt, settings, enabled, file, fileBytes}, sessionToolCalls:{工具名: 次数}}

入参

无(不需要参数)

mcp_config_get ​

  • 作用:读 MCP 自己的配置(服务器开关/端口/记录设置等)。token 只回打码值。
  • 读/写:只读,无副作用
  • 返回:{server:{host, port, tokenMasked, …}, callLog:{…}, expose:{autoControlTools, namespaces, readOnly}, version}
  • 注意:token 打码;expose.readOnly 是只读(沙箱)模式的开关状态

入参

无(不需要参数)

mcp_config_set ​

  • 作用:改 MCP 自己的配置。只支持 server 与 callLog 两类键(未知键会报错)。改 server.* 只保存、不立刻重启(需在界面里关闭再启用才生效);不接受改 token。
  • 读/写:写(会改状态)
  • 返回:{applied:[生效的键路径], needRestart:bool}
  • 注意:只接受 server / callLog 两类键;不接受改 token;host 只允许回环;改 server.* 只保存,需在界面关闭再启用才生效

入参

参数类型必填说明
patchobject是例:{"callLog":{"includeResults":true}} 或 {"server":{"port":7778}}

5. ctl_*:把每个界面控件都变成一个工具(可选) ​

默认关闭。打开 expose.autoControlTools 后,程序启动时会扫描界面上所有按钮 / 输入框 / 下拉框, 为每个控件生成一个 ctl_* 工具:

命名ctl_ + 控件路径清洗(非字母数字转 _),总长 ≤ 64 字符,撞名加序号
路径<面板>.<分组>.<控件名>,如 serial.conn.portSelect;面板 ∈ serial / wsl / adb / ble / global
入参按控件类型派生:开关→boolean、数字输入→number、下拉→enum(选项就是下拉里的真实选项)
不可用控件当前不可用时,原因写进工具描述(如"串口未连接"),AI 不用盲试
上限单次最多 400 个 ctl_*;namespaces 可只暴露某些面板
工具列表变化控件增减时会推 notifications/tools/list_changed,客户端不必重连

为什么默认关闭:几百个工具会明显拖累模型选工具的准确率(见 MCP_DESIGN.md §5.6 D2)。 想按需使用:平时用 ui_list / ui_get / ui_set(按路径操作,只有 6 个工具),需要"每个控件一个工具"时再打开。

6. 错误语义 ​

情况表现
参数错误(缺必填 / 类型错 / 不存在的控件路径 / 取值不在可选集里(如端口名给错)/ 不存在的日志通道 / 非法正则 / 未知工具名)JSON-RPC error.code = -32602(E_INVALID_PARAMS)
工具执行失败(控件被禁用、前置状态没满足(如没开监控就发数据)、写盘失败…)正常 result + isError: true,原因在文本内容里(不是 JSON-RPC error)
没有界面上下文(服务器脱离 GUI 跑,只有开发/测试会遇到)isError: true,文本为 错误 -32006: MCP 服务器没有界面上下文
前端桥超时(界面动作 5 秒没回执)-32004(E_UI_TIMEOUT)
前端桥在途请求过多-32005(E_UI_BUSY)
超过 60 次/分-32000(E_RATE_LIMITED)
工具内部 panic-32603,消息里写明"已上报";连接不会被打死,且会上报错误库
POST /mcp 带的 Mcp-Session-Id 不认识(过期/被表满淘汰/伪造)HTTP 404 + session not found(不是 JSON-RPC 错误);规范里客户端拿到 404 应当重新 initialize
POST /mcp 的 MCP-Protocol-Version 不认识HTTP 400,响应体里列出我们支持的版本(缺失该头按 2025-03-26 放行)
POST /mcp 带了非回环的 Origin(http://evil.com / https://… / null)HTTP 403(防 DNS rebinding;不带 Origin 的 SDK/curl 不受影响)
token 不对 / 缺失HTTP 401(不是 JSON-RPC 层)

7. 上限与安全边界 ​

项值
同时会话数4,两种传输共用一张表:SSE 会话在流断开时立刻回收;HTTP 会话没有断连信号可依赖,靠 30 分钟空闲回收 + 客户端 DELETE /mcp
表满时(HTTP 新建会话)淘汰最久未活动的 HTTP 会话(客户端下次请求得 404 并重新 initialize,可恢复);只有剩下的全是 SSE 会话时才回 429 —— 淘汰 SSE 会话会把它那条长连接变成收不到东西的僵尸
每会话出站队列 / 心跳 / 空闲回收 / 限流256 条丢最旧 · 15s · 30 分钟 · 60 次/分
请求体上限1 MiB
ui_set 单次 items200(超了 -32602;这条链路跑在界面主线程上)
ui_set 单条 value8192 字符(超了 -32602;只挡条数挡不住"一条巨型字符串")
快速指令 value / 组名 / 条目数4096 / 64 字符 · 500 条(超长 -32602;条目满了是 -32006,先删几条)
serial_send 单次字符数64K(超了 -32602;串口写是排队的)
ble_write 单次字符数4096(超了 -32602;BLE 单次写受 MTU 限制)
adb_shell_write 单次字符数4096(超了 -32602;这一头是设备的 shell)
adb_shell_resize 的 cols / rows2~1000(越界 / 0 / 1 都是 -32602)
adb_shell_read 一次行数默认 200,上限 2000
工具列表每页50
ctl_* 上限400
日志单条 / 每通道 / 总量 / 通道数8 KiB 截断 · 128 KiB~1 MiB · 16 MiB(超了裁最大通道)· 64 个
读日志的编码(log_tail / serial_get_output)默认 json(逐行 seq/ts/t/level/dir/bytes/text);format:"text" 一行一条纯文本(头部一行元信息 + [时刻] [级别/方向] 正文)。两种编码的数据与丢弃账完全一致:returned / seqFrom / seqTo / missed / dropped / mayBeIncomplete / truncated / nextSinceSeq
一次日志读取的行数log_tail 默认 100 · serial_get_output 默认 50 · adb_shell_read 默认 200,三者上限都是 2000(text 编码只改写法,不改这个上限)
log_search 的 limit / contextlimit 默认 100、上限 500(matches 档算的是匹配处数,一行多处算多条);context 0~5,超了或配在非 lines 档上都是 -32602
检索图案 pattern 的长度512 字符(maxSearchPatternChars;log_search / adb_shell_read / ble_get_output 共用)—— 图案要被编译成正则,1 MiB 的请求体塞得进一条巨型正则,所以在碰主程序之前就拦
桥回执超时 / 在途上限界面动作 5 秒、设备动作 30 秒、ble_connect 130 秒 · 32
ble_list_devices / ui_get_state(bleDevices) 每页200 台(limit 只能是 1~200,0 与超限都是 -32602;要全量就不给 limit,或用 offset 翻页)

安全边界:

  1. 只监听回环,server.host 只接受 127.0.0.1/::1/localhost;
  2. 必须带 token;/healthz 是唯一免鉴权端点且只回 {"ok":true};/status 需 token 且两条 URL 都打码(urlMasked / streamableUrlMasked),绝不回显 token 与完整 URL;/mcp 另外校验 Origin(只放行回环);
  3. 工具不能改 token(必须在界面点「重置令牌」);
  4. AI 记录写独立的 ai-calls.jsonl,用户配置 config.json 里不会出现任何 AI 痕迹;
  5. 运行期错误走程序既有的错误上报(LogHub → 本地日志 → Sentry/自建服务),上报前 token 打码,同类错误 5 分钟只报一次;
  6. MCP 的运行不得拖慢主程序:串口收发热路径上只有一次非阻塞的日志旁路(try_lock,拿不到锁就丢并计数),上报走独立线程的 channel,SSE 出站是「有界队列 + try_send」(生产者绝不阻塞,慢客户端直接断开),界面命令有在途上限(32)与分档超时(界面动作 5s、设备动作 30s、连接 130s —— 连接要等用户点配对弹窗,按 5s 算必然假失败),所有外部输入都有上限(见上表)。

8. 手测示例(curl) ​

Streamable HTTP(推荐,新版客户端走这条)

bash
# 1) initialize:不带会话头,从**响应头**里拿 Mcp-Session-Id(-i 才会打印响应头)
curl.exe -i -X POST "http://127.0.0.1:7777/mcp?token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2025-06-18" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","clientInfo":{"name":"curl"}}}'
#   期望 HTTP 200 + content-type: application/json + 响应头 mcp-session-id: <SID>
#   ⚠️ 结果**就在这个响应体里**(不必像 SSE 那样另开一条流等)

# 2) 后续请求带上会话头(结果同样直接从响应回来)
curl.exe -i -X POST "http://127.0.0.1:7777/mcp?token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -H "Mcp-Session-Id: <SID>" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"app_info"}}'

# 3) 通知:回 202 + 空体(规范要求,不是 200 加空 JSON)
curl.exe -i -X POST "http://127.0.0.1:7777/mcp?token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -H "Mcp-Session-Id: <SID>" \
  -d '{"jsonrpc":"2.0","method":"notifications/initialized"}'

# 4) 用完主动结束会话(立刻释放一个会话名额)
curl.exe -i -X DELETE "http://127.0.0.1:7777/mcp?token=<TOKEN>" -H "Mcp-Session-Id: <SID>"
#   期望 HTTP 204

遗留 SSE(只支持 SSE 的老客户端走这条)

bash
# 0) 探活(不需要 token)
curl.exe -i http://127.0.0.1:7777/healthz

# 1) 建 SSE 会话,看首帧 endpoint(-N 关缓冲;这个连接要一直挂着)
curl.exe -N "http://127.0.0.1:7777/sse?token=<TOKEN>"
#   event: endpoint
#   data: /messages?sessionId=<SID>&token=<TOKEN>

# 2) 另开一个窗口,往上面那个 SID 发 JSON-RPC
curl.exe -i -X POST "http://127.0.0.1:7777/messages?sessionId=<SID>&token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","clientInfo":{"name":"curl"}}}'
#   期望 HTTP 202;结果从第 1 步的 SSE 流里出来

# 3) 列工具(同样 202,结果从 SSE 流回)
curl.exe -i -X POST "http://127.0.0.1:7777/messages?sessionId=<SID>&token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

# 4) 调一个只读工具
curl.exe -i -X POST "http://127.0.0.1:7777/messages?sessionId=<SID>&token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"app_info"}}'

9. 本页怎么校对 ​

页面里的工具清单可以直接和运行中的服务器对账:

bash
# 起一个自带 3 个假控件、固定 token=testtoken 的联调服务器(127.0.0.1:7799)
cargo test --manifest-path src-tauri/Cargo.toml mcp_serve_for_manual_check -- --ignored --nocapture

# 另开窗口,用任意 MCP 客户端(SDK / curl)列一下 tools/list,与本页 §4 逐个核对

本文档由 node .walkthrough/gen_mcp_tools_doc.js 生成(工具名/描述/入参直接读 protocol.rs, 所以改了工具定义后重跑一次就不会漂)。断言集里有一条守着"本页必须列出全部内置工具名"。

基于 MIT 许可证发布 · 安装包未做代码签名