HivePaaS
Docker Swarm 기반 오픈소스 자체 호스팅 PaaS, SSL·백업·자동 확장 지원
labgrid 하드웨어 제어를 LLM 에이전트에 제공하는 MCP 서버 47개 도구와 gRPC·드라이버 스택 지원 독립 실행
MCP server exposing labgrid hardware-in-the-loop device operations to LLM agents — 47 tools over coordinator gRPC + labgrid's client-side driver stack (power/console/io/flash/mux/SSH). Standalone, coo
개발 도구Python · DockerfileGitHub @onurcelep직접 설치운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
설치형 프로젝트는 배포 도메인 없이도 확인할 수 있습니다. 개인 저장소는 GitHub 로그인으로, 조직 저장소는 위의 저장소 확인 파일로 직접 확인해 주세요.
MCP server exposing labgrid hardware-in-the-loop device operations to LLM agents — 47 tools over coordinator gRPC + labgrid's client-side driver stack (power/console/io/flash/mux/SSH). Standalone, coordinator-agnostic.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗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.
47 tools, 5 browseable labgrid:// resources, honest
readOnly/destructive annotations on every tool.
Requires uv (its bundled uvx does the rest,
including provisioning Python):
uvx labgrid-mcp demo
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:
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
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" }
}
}
}
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" }
}
}
}
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" }
}
}
}
Add under mcpServers in ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"labgrid": {
"command": "uvx",
"args": ["labgrid-mcp"],
"env": { "LG_COORDINATOR": "your-coordinator-host:20408" }
}
}
}
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 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.
| 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.
wait_for_change long-polling insteadThe 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.
Contributions are welcome; see CONTRIBUTING.md for the
workflow, the full check list, and the DCO sign-off requirement.
Apache-2.0. Copyright 2026 Onur Celep.
labgrid itself is LGPL-2.1-or-later and is used as a regular, unmodified dependency.