商业产业 Hacker News Show HN AI 2026-08-05T12:39 正文 ok 1569 words

Show HN:Labgrid-MCP——让 AI Agent 驱动真实嵌入式硬件实验室

英文标题:🔶 Show HN: Labgrid-MCP – let AI agents drive real embedded hardware labs

Labgrid-MCP 是一个 Model Context Protocol(MCP)服务器,可将基于 labgrid 的嵌入式硬件实验室接入 Claude、AI 编辑器及其他 MCP 客户端。它提供 47 项工具和 5 个可浏览的 `labgrid://` 资源,覆盖开发板发现、预约、供电、串口、SSH、文件传输和可选烧录等完整流程。项目通过只读模式、按类别白名单及默认关闭烧录和设备删除等机制控制高风险操作。对嵌入式开发团队而言,这意味着 Agent 可以在保留 labgrid 资源预约与所有权仲裁能力的前提下,直接自动化真实硬件测试和调试工作流。
打开原文相关 6 · 机会 2
media1.2 KB media3.8 KB media7.0 MB media121.0 KB

中文

PyPI labgrid-mcp MCP 服务器

通过 Claude、AI 编辑器和任意 MCP 客户端驱动真实嵌入式硬件。

labgrid 是嵌入式团队用于共享实验室硬件的开源框架:开发板(“places”)配备可远程切换的电源、串口控制台、USB 多路复用器和烧录工具。labgrid-mcp 是一个 Model Context Protocol 服务器,可将任意 labgrid 实验室接入 MCP 生态系统,使 Agent 和开发工具能够直接操作实验室:

“获取 rk3399 开发板,烧录昨晚的镜像,对它执行断电重启,并告诉我它是否进入登录提示符。如果没有,请粘贴控制台日志。”

它不仅适用于聊天:任何脚本驱动或人工操作的 MCP 客户端,都能通过 labgrid 成熟的驱动生态系统获得受策略控制的远程操控界面,并拥有临时设备服务器所不具备的预约和所有权仲裁能力。

Claude 获取开发板、开机、读取串口控制台,然后关机并释放开发板——全部针对内置演示实验室执行

Claude 驱动内置演示实验室——无需硬件,一条命令:uvx labgrid-mcp demo

  • 完整设备生命周期:发现、预约、获取、释放;由 keepalive 支持,因此占用不会在任务中途过期
  • 硬件控制:开机、关机、重启,数字 I/O,SD/USB 多路复用切换
  • 交互式串口控制台:打开、读取、发送、关闭;采用环形缓冲区
  • 通过 SSH 连接设备:运行命令、传输文件、双向隧道
  • 烧录 (选择启用):DFU、fastboot、bootstrap 加载器、镜像写入;均以后台任务形式执行,并支持状态和日志轮询
  • 实验室维护:标签、别名、注释、place 管理、变更监控
  • 安全门控:只读模式和按类别设置的白名单;不可逆类别(烧录、删除 place)默认关闭

共 47 项工具、5 个可浏览的 labgrid:// 资源,每项工具均提供如实的 readOnly/destructive 标注。

5 分钟试用(无需硬件)

需要 uv(其内置的 uvx 会处理其余工作,包括配置 Python):

这会在你的机器上启动一个完整的虚拟实验室:真实的 labgrid coordinator 和 exporter、一个配有虚拟电源开关和虚拟串口控制台的演示开发板。它会打印一段可直接粘贴的 .mcp.json 片段。随后向你的 Agent 提问:

  • “列出 places,然后获取 demo-place”
  • “打开 demo-place 电源并读取它的电源状态”
  • “打开 demo-place 的控制台并读取其输出”

按 Ctrl-C 即可销毁全部内容。

无需单独安装——uvx 首次运行时会从 PyPI 获取 labgrid-mcp。(更喜欢 pip?执行 pip install labgrid-mcp,随后使用不带下方 args 的 "command": "labgrid-mcp"。)

你需要运行中的、gRPC 时代的 labgrid coordinator(labgrid ≥ 24;已针对 26.x 测试),且该 coordinator 必须可从此机器访问。

1. 在 MCP 客户端中注册服务器。 各处的服务器定义相同——命令为 uvx,参数为 ["labgrid-mcp"],并附加你的 LG_* 环境变量——只有配置文件位置和顶层键名不同。请选择你的客户端:

Claude Code

在项目根目录保存为 .mcp.json:

{
  "mcpServers": {
    "labgrid": {
      "command": "uvx",
      "args": ["labgrid-mcp"],
      "env": { "LG_COORDINATOR": "your-coordinator-host:20408" }
    }
  }
}

或使用一条命令:claude mcp add labgrid --env LG_COORDINATOR=your-coordinator-host:20408 -- uvx labgrid-mcp

Claude Desktop

依次打开“设置 → 开发者 → 编辑配置”,然后在 claude_desktop_config.json 的 mcpServers 下添加:

{
  "mcpServers": {
    "labgrid": {
      "command": "uvx",
      "args": ["labgrid-mcp"],
      "env": { "LG_COORDINATOR": "your-coordinator-host:20408" }
    }
  }
}

Cursor

保存为 .cursor/mcp.json(项目级)或 ~/.cursor/mcp.json(全局):

{
  "mcpServers": {
    "labgrid": {
      "command": "uvx",
      "args": ["labgrid-mcp"],
      "env": { "LG_COORDINATOR": "your-coordinator-host:20408" }
    }
  }
}

VS Code(Copilot)

保存为 .vscode/mcp.json——注意 VS Code 使用 servers 键:

{
  "servers": {
    "labgrid": {
      "command": "uvx",
      "args": ["labgrid-mcp"],
      "env": { "LG_COORDINATOR": "your-coordinator-host:20408" }
    }
  }
}

Windsurf

在 ~/.codeium/windsurf/mcp_config.json 的 mcpServers 下添加:

{
  "mcpServers": {
    "labgrid": {
      "command": "uvx",
      "args": ["labgrid-mcp"],
      "env": { "LG_COORDINATOR": "your-coordinator-host:20408" }
    }
  }
}

任何其他 MCP 客户端 / SDK

labgrid-mcp 是标准的 stdio MCP 服务器:在环境中设置 LG_COORDINATOR 后,启动 uvx labgrid-mcp(或在执行 pip install labgrid-mcp 后启动 labgrid-mcp),并通过 stdin/stdout 使用 MCP 协议通信。它适用于支持 stdio 服务器的任何客户端或 Agent SDK。

2. 重启客户端,使其加载新服务器。

3. 确认已连接——向 Agent 提问 “列出 labgrid places”;你应该会得到实验室中的开发板列表。至此即可开始使用。

身份标识的工作方式与 labgrid-client 完全相同:设置 LG_HOSTNAME / LG_USERNAME,或者省略它们以使用真实的主机名/用户名。安全性委托给网络(VPN / SSH 隧道),与 labgrid-client 相同。

(从克隆的代码仓库而非 PyPI 运行?请使用 "command": "uv"、"args": ["run", "--directory", "/path/to/labgrid-mcp", "labgrid-mcp"]。)

将服务器构建并运行在容器中(适用于受限主机,或在实验室网络内部托管)

从仓库的 Dockerfile 构建镜像:

git clone https://github.com/onurcelep/labgrid-mcp && cd labgrid-mcp
docker build -t labgrid-mcp .

然后让 MCP 客户端指向它:

{
  "mcpServers": {
    "labgrid": {
      "command": "docker",
      "args": ["run", "-i", "--rm",
               "-e", "LG_COORDINATOR=your-coordinator-host:20408",
               "labgrid-mcp"]
    }
  }
}

对于实验室,一个实用模式是:在实验室网络内的一台主机上构建并运行容器,而 MCP 客户端可在任意位置运行;每名用户使用一个容器,从而使身份和所有权保持按人区分:

{
  "mcpServers": {
    "labgrid": {
      "command": "ssh",
      "args": ["labhost", "docker", "run", "-i", "--rm",
               "-e", "LG_COORDINATOR=127.0.0.1:20408",
               "-e", "LG_USERNAME=your-name",
               "labgrid-mcp"]
    }
  }
}

不要让多名用户共享一个正在运行的服务器:每个实例只持有一个 labgrid 身份,因此共享实例会使所有人的获取操作无法区分。每个用户/Agent 使用一个容器,能够保持实验室的所有权模型完整。(注意:你构建的镜像会捆绑 labgrid,其许可证为 LGPL-2.1-or-later——可在任何地方使用;如果你再分发该镜像,则 LGPL 条款适用于该副本,镜像中已包含 labgrid 的许可证文本。)

只需用自然语言提出请求——Agent 会将其映射至正确工具。典型的首次工作流如下:

  • “现在有哪些空闲的 places?”
  • “帮我获取 board-7。”
  • “打开电源,然后打开串口控制台并展示启动输出。”
  • “通过 SSH 登录并运行 uname -a。”
  • “关闭电源并释放开发板。”

只读请求(“列出 places”“谁在占用 board-7?”)可立即执行。任何会改变硬件状态的操作都受到门控(见下文);两个不可逆类别——烧录和删除 place——会保持关闭状态,直到你显式启用。

环境变量 默认值 作用
LG_COORDINATOR 127.0.0.1:20408 Coordinator 地址
LG_HOSTNAME / LG_USERNAME 真实主机/用户 身份标识,与 labgrid-client 相同
LABGRID_MCP_READONLY 关闭 1 = 仅注册只读工具:Read 组,以及 wait_for_change 和 forward_list
LABGRID_MCP_ALLOW 未设置 要注册的类别逗号分隔列表;必须显式列出 flash 和 place_delete;它们即使在默认情况下也处于关闭状态
LABGRID_MCP_SSH_KEYFILE 未设置 SSH 工具的私钥;未设置时,会在调用时明确报错
LABGRID_MCP_ACQUIRE_TIMEOUT 120 acquire_place 等待分配的最长秒数

安全性一段话说明:烧录和删除 place 可能造成不可逆损害,因此每项操作都需要在 LABGRID_MCP_ALLOW 中单独显式列出。SSH 工具可在已获取的开发板上执行任意命令,其信任级别与控制台会话相同;LABGRID_MCP_READONLY=1 会移除它们及其他所有受门控工具(forward_list 除外,因为它仅列出内存中的隧道状态)。还有一项值得了解的 labgrid 注意事项:coordinator 不会对 place 元数据实施所有权保护——本服务器拒绝编辑已被获取的 place,除非使用 force=True;但任何机制都无法保护无人持有的 place(且 set_place_tags 中的空标签值会删除该键,这是 labgrid 自身的语义)。详见:docs/DESIGN.md §4 和 §11.12。

按分组列出的全部 47 项工具 组别 工具
读取 coordinator_info, list_places, show_place, who, list_resources, list_reservations
获取 / 预约 acquire_place, release_place, allow_place, release_from, reserve, cancel_reservation, reservation_wait
驱动 get_power_state, set_power, get_io, set_io, get_sd_mux, set_sd_mux, set_usb_mux
控制台 console_open, console_read, console_send, console_close
SSH / 转发 ssh_run, put_file, get_file, forward_open, forward_remote_open, forward_close, forward_list
烧录 (选择启用) flash_dfu, flash_fastboot, flash_script, bootstrap, write_image, flash_status, flash_logs
Place 元数据 add_place, add_place_alias, delete_place_alias, set_place_tags, set_place_comment, add_place_match
删除 place (选择启用) delete_place, delete_place_match
变更监控 wait_for_change

资源:labgrid://places、labgrid://places/{name}、labgrid://resources、labgrid://reservations、labgrid://sessions。

每项工具的参数和行为均记录在该工具自身的描述中(可在你的 MCP 客户端内查看),也记录在 docs/DESIGN.md §5/§11 中。

  • 不支持视频/音频/屏幕采集或 USB 仪器(需要 gstreamer 和物理 USB;没有合理的 MCP 操作界面)
  • 不提供实时事件流;改用 wait_for_change 长轮询
  • 旧版 crossbar coordinator(labgrid < 24)无法连接
  • 身份验证处于网络层(VPN/隧道),完全遵循 labgrid 自身的模型
  • 真实的烧录/多路复用驱动步骤需要真实开发板:任务机制已针对虚拟设备完成完整 CI 测试,但实际触及芯片的步骤尚未测试

开发 labgrid-mcp 本身

集成测试套件会运行完整技术栈,包括演示环境;它在每个 PR 的 CI 中针对真实 coordinator/exporter 进程和虚拟硬件执行,并且每周针对 labgrid master 运行一次金丝雀测试:

git clone <this-repo> labgrid-mcp && cd labgrid-mcp
uv sync
uv run pytest              # unit
uv run pytest -m integration

架构、决策日志以及经验证的 labgrid 内部机制参考资料:docs/DESIGN.md。

Apache-2.0。版权所有 2026 Onur Celep。

labgrid 本身采用 LGPL-2.1-or-later 许可证,并作为常规、未经修改的依赖项使用。

English / 原文

PyPI labgrid-mcp MCP server

Drive real embedded hardware from Claude, AI editors, and any MCP client.

labgrid is the open-source framework embedded teams use to share lab hardware: boards ("places") with remotely switchable power, serial consoles, USB muxes, and flashing tools. labgrid-mcp is a Model Context Protocol server that plugs any labgrid lab into the MCP ecosystem, so agents and dev tools can work with the lab directly:

"Acquire the rk3399 board, flash last night's image, power-cycle it, and tell me whether it reaches a login prompt. Paste the console log if it doesn't."

Not only for chat: any MCP client, scripted or human-driven, gets a policy-gated remote-control surface over labgrid's mature driver ecosystem, with the reservations and ownership arbitration ad-hoc device servers don't have.

Claude acquiring a board, powering it on, reading its serial console, then powering off and releasing it — all against the built-in demo lab

Claude driving the built-in demo lab — no hardware, one command:uvx labgrid-mcp demo

  • Full device lifecycle : discover, reserve, acquire, release; keepalive-backed so holds never expire mid-task
  • Hardware control : power on/off/cycle, digital I/O, SD/USB mux switching
  • Interactive serial console : open, read, send, close; ring-buffered
  • SSH to the device : run commands, transfer files, tunnels in both directions
  • Flashing (opt-in) : DFU, fastboot, bootstrap loaders, image writing, all as background jobs with status/log polling
  • Lab housekeeping : tags, aliases, comments, place management, change monitoring
  • Safety gating : read-only mode and per-category allowlists; the irreversible families (flash, place deletion) are off by default

47 tools, 5 browseable labgrid:// resources, honest readOnly/destructive annotations on every tool.

Try it in 5 minutes (no hardware needed)

Requires uv (its bundled uvx does the rest, including provisioning Python):

This boots a complete fake lab on your machine: a real labgrid coordinator and exporter, one demo board with a fake power switch and a fake serial console. It prints a paste-ready .mcp.json snippet. Then ask your agent:

  • "List places, then acquire demo-place"
  • "Power demo-place on and read its power state"
  • "Open the console on demo-place and read its output"

Ctrl-C tears everything down.

No separate install step — uvx fetches labgrid-mcp from PyPI the first time it runs. (Prefer pip? pip install labgrid-mcp, then use "command": "labgrid-mcp" with no args below.)

You need a running, gRPC-era labgrid coordinator (labgrid ≥ 24; tested against 26.x) reachable from this machine.

1. Register the server with your MCP client. The server definition is the same everywhere — command uvx, args ["labgrid-mcp"], plus your LG_* env vars — only the config file location and top-level key differ. Pick your client:

Claude Code

Save as .mcp.json in your project root:

{
  "mcpServers": {
    "labgrid": {
      "command": "uvx",
      "args": ["labgrid-mcp"],
      "env": { "LG_COORDINATOR": "your-coordinator-host:20408" }
    }
  }
}

or one command: claude mcp add labgrid --env LG_COORDINATOR=your-coordinator-host:20408 -- uvx labgrid-mcp

Claude Desktop

Settings → Developer → Edit Config, then add under mcpServers in claude_desktop_config.json:

{
  "mcpServers": {
    "labgrid": {
      "command": "uvx",
      "args": ["labgrid-mcp"],
      "env": { "LG_COORDINATOR": "your-coordinator-host:20408" }
    }
  }
}

Cursor

Save as .cursor/mcp.json (project) or ~/.cursor/mcp.json (global):

{
  "mcpServers": {
    "labgrid": {
      "command": "uvx",
      "args": ["labgrid-mcp"],
      "env": { "LG_COORDINATOR": "your-coordinator-host:20408" }
    }
  }
}

VS Code (Copilot)

Save as .vscode/mcp.json — note VS Code uses a servers key:

{
  "servers": {
    "labgrid": {
      "command": "uvx",
      "args": ["labgrid-mcp"],
      "env": { "LG_COORDINATOR": "your-coordinator-host:20408" }
    }
  }
}

Windsurf

Add under mcpServers in ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "labgrid": {
      "command": "uvx",
      "args": ["labgrid-mcp"],
      "env": { "LG_COORDINATOR": "your-coordinator-host:20408" }
    }
  }
}

Any other MCP client / SDK

labgrid-mcp is a standard stdio MCP server: spawn uvx labgrid-mcp (or labgrid-mcp after pip install labgrid-mcp) with LG_COORDINATOR set in its environment, and speak MCP over stdin/stdout. Works with any client or agent SDK that supports stdio servers.

2. Restart the client so it picks up the new server.

3. Confirm it's connected — ask your agent "List the labgrid places" ; you should get your lab's boards back. You're ready.

Identity works exactly like labgrid-client: set LG_HOSTNAME / LG_USERNAME, or omit them to use your real hostname/user. Security is delegated to the network (VPN / SSH tunnel), same as labgrid-client.

(Running from a clone instead of PyPI? Use"command": "uv", "args": ["run", "--directory", "/path/to/labgrid-mcp", "labgrid-mcp"].)

Build and run the server as a container (locked-down hosts, or hosting it inside the lab network)

Build the image from the repo's Dockerfile:

git clone https://github.com/onurcelep/labgrid-mcp && cd labgrid-mcp
docker build -t labgrid-mcp .

Then point your MCP client at it:

{
  "mcpServers": {
    "labgrid": {
      "command": "docker",
      "args": ["run", "-i", "--rm",
               "-e", "LG_COORDINATOR=your-coordinator-host:20408",
               "labgrid-mcp"]
    }
  }
}

A useful pattern for labs: build and run the container on a host inside the lab network while your MCP client runs anywhere, one container per user so identity and ownership stay per-person:

{
  "mcpServers": {
    "labgrid": {
      "command": "ssh",
      "args": ["labhost", "docker", "run", "-i", "--rm",
               "-e", "LG_COORDINATOR=127.0.0.1:20408",
               "-e", "LG_USERNAME=your-name",
               "labgrid-mcp"]
    }
  }
}

Don't share one running server between users: each instance holds a single labgrid identity, so a shared instance would make everyone's acquisitions indistinguishable. One container per user/agent keeps the lab's ownership model intact. (Note: an image you build bundles labgrid, LGPL-2.1-or-later — fine to use anywhere; if you redistribute the image, the LGPL's terms apply to that copy, with labgrid's license texts already inside it.)

Just ask in plain language — the agent maps it to the right tools. A typical first workflow:

  • "Which places are free right now?"
  • "Acquire board-7 for me."
  • "Power it on, then open the serial console and show me the boot output."
  • "SSH in and run uname -a."
  • "Power it off and release the board."

Read-only asks ("list places", "who's holding board-7?") work immediately. Anything that changes hardware state is gated (see below), and the two irreversible families — flashing and place deletion — stay off until you explicitly enable them.

Env var Default Effect
LG_COORDINATOR 127.0.0.1:20408 Coordinator address
LG_HOSTNAME / LG_USERNAME real host/user Identity, as in labgrid-client
LABGRID_MCP_READONLY off 1 = only read-only tools are registered: the Read group plus wait_for_change and forward_list
LABGRID_MCP_ALLOW unset Comma list of categories to register; flash and place_delete must be listed explicitly ; they're off even by default
LABGRID_MCP_SSH_KEYFILE unset Private key for the SSH tools; unset, they error clearly at call time
LABGRID_MCP_ACQUIRE_TIMEOUT 120 Max seconds acquire_place waits for allocation

Safety in one paragraph: flashing and place deletion can do irreversible damage, so each needs its own explicit LABGRID_MCP_ALLOW entry. SSH tools are arbitrary command execution on the acquired board, the same trust class as a console session; LABGRID_MCP_READONLY=1 drops them along with every other gated tool (forward_list stays, since it only lists in-memory tunnel state). And a labgrid caveat worth knowing: the coordinator enforces no ownership guard on place metadata: this server refuses to edit an acquired place without force=True, but nothing can protect a place nobody holds (and an empty tag value in set_place_tags deletes that key, which is labgrid's own semantics). Details: docs/DESIGN.md §4 and §11.12.

All 47 tools by group Group Tools
Read coordinator_info, list_places, show_place, who, list_resources, list_reservations
Acquisition / reservation acquire_place, release_place, allow_place, release_from, reserve, cancel_reservation, reservation_wait
Drivers get_power_state, set_power, get_io, set_io, get_sd_mux, set_sd_mux, set_usb_mux
Console console_open, console_read, console_send, console_close
SSH / forward ssh_run, put_file, get_file, forward_open, forward_remote_open, forward_close, forward_list
Flash (opt-in) flash_dfu, flash_fastboot, flash_script, bootstrap, write_image, flash_status, flash_logs
Place metadata add_place, add_place_alias, delete_place_alias, set_place_tags, set_place_comment, add_place_match
Place deletion (opt-in) delete_place, delete_place_match
Change monitoring wait_for_change

Resources: labgrid://places, labgrid://places/{name}, labgrid://resources, labgrid://reservations, labgrid://sessions.

Per-tool arguments and behaviors are documented in each tool's own description (visible in your MCP client) and in docs/DESIGN.md §5/§11.

  • No video/audio/screen capture or USB instruments (need gstreamer + physical USB; no sane MCP surface)
  • No live event stream; wait_for_change long-polling instead
  • Old crossbar coordinators (labgrid < 24) can't connect
  • Authentication is network-level (VPN/tunnel), exactly labgrid's own model
  • The real flash/mux driver step needs a real board: the job machinery is fully CI-tested against fakes, the silicon-touching step is not

Working on labgrid-mcp itself

The integration suite runs the whole stack, including the demo, against real coordinator/exporter processes with fake hardware, in CI on every PR, plus a weekly canary against labgrid master:

git clone <this-repo> labgrid-mcp && cd labgrid-mcp
uv sync
uv run pytest              # unit
uv run pytest -m integration

Architecture, decision log, and a verified reference of labgrid's internals: docs/DESIGN.md.

Apache-2.0. Copyright 2026 Onur Celep.

labgrid itself is LGPL-2.1-or-later and is used as a regular, unmodified dependency.