MCP server for ESP32 / MicroPython devices: streaming flash, REPL and filesystem over the wire
Solid foundation with clear naming (verb_noun pattern) and comprehensive parameter descriptions. All 8 tools have input schemas with types and descriptions. However, tool descriptions vary in depth, some lack context on when to use them or what they return. Output schemas are not formally documented. Error handling returns structured dicts but lacks recovery guidance. No tool annotations (readOnlyHint/destructiveHint) despite clear risk profiles. Missing idempotency and confirmation patterns for irreversible operations like flash_firmware.
Chip family, flash size, MAC address, and MicroPython version (if any) for `port`.
Write `firmware_path` to `port`. Reports progress at least every 5% via MCP progress notifications and can be cancelled mid-flash. `erase=True` wipes the whole flash first and requires `confirm_erase=True` as a separate explicit argument.
Read a file from the board. Content comes back base64-encoded; refuses files over max_bytes.
List a directory on the board's filesystem.
Write a base64-encoded payload to a file on the board, chunked over several raw-REPL exchanges.
List serial ports, including the simulator, with a best-guess chip identification.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) despite clear risk profiles. flash_firmware is IRREVERSIBLE but unmarked; fs_ls, fs_get, board_info, list_ports are READ_ONLY but unmarked.
Output schemas not formally documented. Callers must infer structure from code (e.g., flash_firmware returns {port, ok, bytes_written, error?}). LLMs cannot plan downstream calls without explicit schema.
flash_firmware (IRREVERSIBLE) lacks dry-run or explicit confirmation beyond confirm_erase. Agents can trigger destructive flash without a final confirmation step. Pattern: confirmation-request.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 59 | 2026-07-28+ | v2 |
Run `code` on `port` over MicroPython's raw REPL; stdout/stderr/exception come back separately.
Capture raw serial output for up to 30 seconds without going through the REPL protocol.
Error responses return structured dicts but lack recovery guidance. E.g., BoardError.to_dict() returns {kind, message} with no hint on what to try next (retry? different port? check connection?).
Tool descriptions lack context on when to use them vs. similar tools. E.g., tail_serial vs repl_exec both read from board, when should an LLM pick one over the other? No guidance.