smolmux
This MCP server provides read-only visibility into a smolmux-managed serial/UART device connection and host serial ports.
Drain buffered session output since the last read (
serial_read) and read shared output history losslessly with a cursor (serial_output_history).Inspect port/link state: baud, connection and suspension, pins, identity strength, connected clients, and write-control holder (
serial_port_status).Track cold-boot stages, furthest progress, and stalls using device-profile boot stages (
serial_boot_status).Wait for a regex in serial output with a timeout, without sending anything (
serial_wait_for).Retrieve detected anomalies such as panics, faults, asserts, watchdog, brownout, and resets (
serial_get_incidents).Monitor output for a fixed duration and return captured text plus anomalies (
serial_monitor).Generate a Markdown snapshot covering profile, port status, and incidents (
serial_generate_report).List host serial ports with by-id/by-path paths and USB VID/PID, even without a running broker (
serial_list_ports).No device-writing, sending, flashing, or control tools are exposed in this schema; all listed tools are marked read-only.
smolmux
A portable C11 device multiplexer. Holds a device connection open (serial UART, GDB stub) and multiplexes access to multiple clients over Unix sockets using newline-delimited JSON.
Single static binary, low latency, small footprint - built for daily serial and GDB bring-up on Linux.
New here? docs/START-HERE.md is a one-screen router - find your intent (run it, bring up a new board with an AI agent, understand the architecture, hack on the code) and it points you to the right doc.
One port, three clients

One broker holds an ESP32-S3's UART. The monitor (top) watches it live. In the
bottom pane a script sends temp and gets the reply on the same wire, resets
the board and waits for its prompt, then esptool reads the flash ID through
with-port: the broker suspends, esptool runs, the broker resumes, and the
monitor never loses the port.
Related MCP server: Board Terminal Skill
Example: probe an unknown board
One broker holds SWD; smolmux-gdb-mcp runs probe_unknown_board. On a
SAM C21 Xplained Pro that path decoded Cortex-M0+ from CPUID, named the
part via SAM DSU DID, rejected a false STM32 match, and wrote a starter
*.gdb-profile.json. Tools, register values, and profile shape:
docs/demo-samc21-probe-transcript.md.
Day-to-day serial (multi-client, U-Boot break-in, flasher handoff): docs/daily-driver.md.
Features
Serial UART, GDB MI, and serial-over-TCP (telnet + RFC2217) device links via vtable polymorphism
Multiple concurrent clients over Unix sockets with role-based access (observer/controller/takeover)
Expect engine - concurrent regex matching on the device byte stream with timeouts
Anomaly detection - pattern-based crash/error detection with cooldown and incident tracking
Output history - timestamped ring buffer for replay by late-joining clients
Structured logging - JSONL I/O log + human-readable text log with rotation (the I/O log records everything sent to and from the device, including anything typed at a login prompt — it is created
0600under your private state directory, and smolmux refuses to write it through a symlink or to a file owned by another user)Network sinks - TCP and WebSocket for remote access (loopback by default). The wire protocol is cleartext, and any client that completes the handshake gets full control of the device — console writes, pins, BREAK, SysRq, GDB. On loopback without
--auth-token, the broker generates a token into a0600file in$XDG_RUNTIME_DIR(or/tmp), so other local users and processes cannot connect; your ownsmolmux-monitor/smolmux-mcpread it automatically, andsmolmux-cli tokenprints it. For remote use, keep the bind on loopback and reach it over an SSH tunnel or WireGuard rather than exposing the port; smolmux refuses to serve a non-loopback TCP bind with no--auth-token.--insecure-no-authturns both protections off.MCP servers - standalone
smolmux-mcp/smolmux-gdb-mcpattach to a running broker; optional in-process--mcpsink for single-process stdioBoot tracking & autoresponder - ordered boot stages, stall events, standing expect->send rules
Autoboot interrupt - broker-side key flood (and optional DTR/RTS reset) for
bootdelay=0U-BootDevice profiles / board manifests - JSON configs for prompts, anomalies, multi-wire boards
Auto-reconnect - exponential backoff recovery on USB-serial disconnect
Build-time feature selection - Kconfig-based; UART-only builds carry no GDB/TCP/WebSocket code
Quick start
Prerequisites: Linux, a C11 compiler, CMake 3.21+, Python 3 with
kconfiglib (the configure step
generates the feature header with it). libpcre2-8 is optional; without it
regex matching falls back to POSIX.
# Debian/Ubuntu
sudo apt install build-essential cmake python3 python3-pip libpcre2-dev
pip install kconfiglib # or in a venv; Debian's system Python may need
# --break-system-packagescmake -B build && cmake --build build -j$(nproc)
./build/smolmux /dev/ttyUSB0Connect a client:
# Needs a running broker (above). Auto-discovers the socket from the port name.
./build/smolmux-monitor /dev/ttyUSB0Day-to-day workflows (profiles, logs, U-Boot break-in, multi-wire boards): docs/daily-driver.md. Intent router: docs/START-HERE.md.
Build
cmake -B build && cmake --build build -j$(nproc) # Default (all features)
ctest --test-dir build # Run testsFeature profiles
cp configs/defconfig.minimal .config && cmake -B build # UART only, no sinks/watcher
cp configs/defconfig.uart .config && cmake -B build # UART + MCP sink + watcher
cp configs/defconfig.embedded .config && cmake -B build # Embedded target profile
cp configs/defconfig.full .config && cmake -B build # Everything (GDB, TCP, WS, MCP, watcher)Or toggle features directly:
cmake -B build -DSM_ENABLE_GDB=OFF -DSM_ENABLE_SINK_WS=OFFDeveloper benchmarks (e.g. the output coalescer harness) are off by default:
cmake -B build -DSM_BUILD_BENCH=ON && cmake --build build --target bench_coalesceInteractive configuration:
cmake --build build --target menuconfigStatic builds
cmake -B build -DSM_MUSL_STATIC=ON # Fully static musl binary (zero runtime deps)
cmake -B build -DSM_STATIC=ON # Static linking (except glibc)Usage
smolmux <port> [options]
Options:
-b, --baud <rate> Baud rate (default: 115200)
-s, --socket <path> Unix socket path
-l, --log-dir <dir> I/O log directory
(default: $XDG_STATE_HOME/smolmux or
~/.local/state/smolmux)
-t, --text-log-dir <dir> Text log directory
-p, --profile <path> Device profile JSON file
--board <name> Group this wire under a board (for discovery)
--role <label> This wire's role on the board (console, swd, ...)
--gdb Use GDB MI link instead of UART
--gdb-path <path> Path to gdb binary (default: gdb)
--gdb-target <spec> GDB target (e.g., localhost:3333)
--serial-tcp <host:port> Connect to a serial-over-TCP device server
(ser2net, socat, terminal server; telnet +
RFC2217 baud/DTR/RTS/break control)
--mcp Enable in-process MCP stdio sink (prefer standalone
smolmux-mcp against a daemon broker for daily use)
--tcp-port <port> Enable TCP sink (default: 5555)
--tcp-bind <addr> TCP bind address (default: 127.0.0.1)
--auth-token <token> Require token in hello from TCP clients
(prefer env SMOLMUX_AUTH_TOKEN - hidden from ps)
--auth-token-file <path> Read the token from a file
--insecure-no-auth Serve TCP/WS with no token. Without it, a
loopback listener gets a generated token
(0600 file; smolmux-cli token prints it) and
a non-loopback --tcp-bind is refused.
--ws-port <port> Enable WebSocket sink (default: 5556)
--no-text-log Disable text log
--no-io-log Disable JSONL I/O log
--no-reconnect Don't auto-reconnect on disconnect
--wait-device <seconds> Wait for the device path before open
--gdb-allow-shell Permit GDB shell/python/eval (off by default)
--list-ports List available serial ports and exit
--list-profiles List available device profiles and exit
--help-protocol Show wire protocol documentation
-v, --verbose Enable debug logging
-V, --version Show version
-h, --help Show this helpWire protocol
Newline-delimited JSON over Unix sockets (also TCP/WS sinks). Binary data is base64-encoded. Message set covers session control, expect, history, anomaly, boot stages, autoboot flood, and autoresponder.
Full reference: ./build/smolmux --help-protocol (always matches this binary).
Client -> Broker: hello, send, send_expect, takeover, release, status, pin_control, set_baud, suspend, resume, history_request, incidents_request, configure_anomaly, interrupt_autoboot, configure_autoresponder, autoresponders_request
Broker -> Client: welcome, output, input_echo, expect_result, status_response, error, history_response, incidents_response, anomaly, autoboot_result, boot_stage, boot_stall, autoresponders_response, autoresponder_fired, suspended, resumed, link_down, link_up
Example session:
-> {"type":"hello","name":"my-tool","role":"controller","protocol_version":1}
<- {"type":"welcome","broker_version":"x.y.z","protocol_version":1,"port":"/dev/ttyUSB0","baud":115200,"your_role":"controller"}
-> {"type":"send","id":"1","data":"dW5hbWUgLWEK"}
<- {"type":"output","data":"TGludXggNC4xOS4w...","timestamp":1709654321.123}Architecture
┌───────────┐ ┌───────────┐
│ uart link │ │ gdb link │ <- device-facing, compiled in/out via Kconfig
└─────┬─────┘ └─────┬─────┘
│ │
▼ ▼
┌──────────────────────────────┐
│ smolmux core │ <- epoll event loop, message bus,
│ history · logging · anomaly │ role enforcement, expect engine
└──┬───────┬───────┬───────┬───┘
│ │ │ │
▼ ▼ ▼ ▼
┌──────┐┌─────┐┌─────┐┌──────┐
│ unix ││ tcp ││ ws ││ mcp │ <- sinks, also compiled in/out
│socket││sink ││sink ││ sink │
└──────┘└─────┘└─────┘└──────┘See DESIGN.md for full architecture documentation.
Dependencies
Required: cJSON (vendored, single file)
Auto-detected: PCRE2 (libpcre2-8). Used as the regex engine when
present, because it bounds backtracking internally; the build falls back to
POSIX ERE automatically when it is absent, so it is never required. Force
either way with -DSM_ENABLE_PCRE2=ON (error if missing) or
-DSM_ENABLE_PCRE2=OFF.
Core has zero required external dependencies beyond POSIX + cJSON.
Companion tools
smolmux-cli - command-line client (send commands, read output;
with-port <cmd>suspends the port, runs an external tool like a flasher, then always resumes)smolmux-monitor - interactive terminal client with escape sequences (prefix key then a command; prefix defaults to Ctrl-], change with
-e, e.g.-e escor-e ^A)smolmux-mcp - standalone MCP server: connects to a running broker and exposes serial tools (
serial_send_command,serial_read,serial_boot_status,serial_add_autoresponder, ...). Alternative: broker--mcpsink embeds MCP in-process.smolmux-gdb-mcp - standalone MCP server for GDB debugging: 21 tools over a broker holding a
--gdblink - breakpoints, stepping, backtrace, name-labeled registers, memory, expression eval, fault-register decode (where the core has them), peripheral reads,gdb_interrupt, and unknown-board probing on ARM Cortex-M today (gdb_identify_target/gdb_generate_profile; other architectures are planned). Resources and prompts includesmolmux-gdb://board-probingandprobe_unknown_board. Built whenSM_ENABLE_GDBis on; chip-ID validated on a SAM C21 Xplained Pro.smolmux-watcher - daemon that monitors for anomalies and saves incident reports to disk
Related Documentation
Start here - One-screen intent router (daily use, new board, architecture, hacking).
MCP setup - Register
smolmux-mcp/smolmux-gdb-mcpwith Claude Code, Claude Desktop, or Cursor.Daily driver - Recommended build, runtime flags, U-Boot break-in, boot stages, boards, coexistence with flashers.
Board Exploration Workflow - Runbook for a fresh board (manually or with an AI agent): wires, SWD identify, console, peripherals.
Board Bring-up Template - Copy-per-board fact-capture template.
Persistent Serial Device Names - Stable names for UART dongles (
/dev/serial/rpi-consoleetc.).Hardware validation matrix - What is validated on real hardware vs not yet proven.
Free vs Pro
Everything in this repository is MIT-licensed - full source, wire protocol, generic device profiles, build system. Build it yourself and you have the complete product.
smolmux Pro is convenience, not a feature gate: prebuilt static binaries
(x86_64 + aarch64, musl, zero runtime dependencies), the curated profile pack
with per-profile notes, and 6 months of email support. One-time purchase
($79). MCP setup for zip paths is docs/MCP-SETUP-FULL.md (also in
this public tree).
Buy smolmux Pro - $79 one-time - download includes current static binaries and the profile pack.
License
MIT. cJSON is vendored under its own MIT license
(deps/cJSON/LICENSE).
Available Tools
9 toolsserial_boot_statusARead-only
Report cold-boot progress: which boot stages the device has reached, the furthest stage, and whether the boot has stalled. Requires the device profile to declare boot_stages; otherwise reports none. Use after a reset or power cycle; if stalled, check serial_get_incidents.
Inputs: no named parameters. Returns: state, total, stages, reached, +2 more
serial_generate_reportARead-only
Markdown summary of device profile, port status and incidents. Use to open a debugging session or hand a human a snapshot; for one fact, call the single-purpose tool.
Inputs: no named parameters.
serial_get_incidentsARead-only
List anomalies the broker detected in output (kernel panic, oops, hard fault, assert, watchdog, brownout, ESP resets, plus profile patterns) with the match and pre-context. Use when a boot stalls, a wait aborts, or output looks like a crash; pair with serial_output_history for the surrounding log.
Inputs: seconds. Returns: count, incidents
serial_list_portsARead-only
List serial ports on this host with by-id paths and USB VID/PID (works without a broker). Use to pick a port before starting a broker, or when output is garbage (wrong port). Bridge chips name the adapter, not the MCU.
Inputs: no named parameters. Returns: ports
serial_monitorARead-only
Listen for a fixed time (default 30 s, max 300 s) and return what the device printed plus anomalies in that window. Use when you do not know what to expect; when you do, serial_wait_for returns as soon as it matches.
Inputs: duration_seconds.
serial_output_historyARead-only
Read past output from the broker's shared history without consuming it. For anything you must not miss, page with since_seq (start at 0; pass the returned cursor back; check dropped and has_more). Without since_seq: text by seconds or last_bytes. serial_read is drain-only.
Inputs: seconds, max_bytes, since_seq, last_bytes. Returns: mode, text, chunks, cursor, +2 more
serial_port_statusARead-only
Check the link before sending, or when output looks wrong: port, baud, connected/suspended, by-id identity strength, pins, who holds write control, and connected clients. Boot progress: serial_boot_status. Crashes: serial_get_incidents.
Inputs: no named parameters. Returns: baud, port, role, board, +14 more
serial_readARead-only
Drain the output this MCP session buffered since the last read, without sending. Quick look after your own command; lossy across turns. Lossless capture: serial_output_history with since_seq. Waiting for known text: serial_wait_for.
Inputs: no named parameters.
serial_wait_forARead-only
Wait for a regex in serial output without sending. Use when you know the text to expect (a prompt, login:, a log line). Works for observers. Ends early on a critical anomaly ([ABORTED anomaly:...]). Open-ended listening: serial_monitor. Output that already arrived: serial_output_history.
Inputs: pattern (required), timeout_ms.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 9 tools
The four output-reading tools (serial_read, serial_output_history, serial_wait_for, serial_monitor) occupy adjacent territory, but their descriptions explicitly cross-reference each other and draw sharp boundaries (drain vs. lossless capture, known text vs. open-ended listen). The remaining tools target distinct concerns (ports, status, boot, incidents, report), so an agent can reliably pick apart.
All nine tools share the serial_ prefix, giving a strong predictable namespace. Most are verb_noun (serial_read, serial_wait_for, serial_list_ports, serial_get_incidents), though a few are noun_status forms (serial_port_status, serial_boot_status) — a minor deviation, not a genuine inconsistency.
Nine tools is well-scoped for a serial-debugging broker: each covers a distinct facet (port discovery, status, read/history, waiting/listening, boot, incidents, report). No tool appears redundant or padded.
Observational coverage is thorough — discovery, liveness, historical and live capture, waiting, anomaly detection, boot tracking, and reporting. The notable gap is that the surface is entirely read-only (no send/write tool), though the descriptions frame the server as an observer/broker, so this may be scoped intent rather than a true gap.
Maintenance
Related MCP Connectors
Find MCP servers for ESP32, Arduino, 3D printers, Home Assistant, cameras and other hardware.
2,000+ MCP servers read at source level. Know what one does before you connect. Free, no key.
An MCP server that measures MCP client behaviour and converts EBCDIC to ASCII, which nobody needs.
MCP gateway and cloud hosting for MCP servers, agents and apps like RAG, managed from your agent.
Related MCP Servers
- AlicenseAqualityDmaintenanceStateful MCP server for driving debug probes (J-Link) to flash, debug, and inspect embedded targets. Enables AI agents to perform flash, memory, breakpoint, and ELF/SVD-aware operations conversationally.4149 PyPI10MIT
- FlicenseBqualityDmaintenanceMCP server for running shell commands on a Linux development board via UART serial.1-
- AlicenseAqualityBmaintenanceAgentic Hardware-in-the-Loop (Agentic HIL) lets coding agents develop firmware on real embedded boards: flash, reset, read UART and exchange CAN traffic, diagnose and fix. Local, policy-gated MCP tools support OpenOCD, pyOCD and STM32CubeProgrammer, with pytest for CI.441,737 PyPI25Apache 2.0
- AlicenseBqualityCmaintenanceMCP server for embedded board debugging, providing structured serial capture, crash decoding, and flash-safe port arbitration via bounded CLI and MCP tools.102MIT