Let Claude Code flash and monitor your ESP32

Claude Code can already write ESP32 firmware. What it usually cannot do is see the board. This MCP server gives it three things for that: find the ESP32 on USB, flash it with esptool, and read the serial console, so you stop pasting boot logs back into the chat.

Last checked against the source code on 2026-09-20.

What you need

How the agent finds your ESP32

list_boards reads the operating system's serial port list and matches each port's USB vendor ID and product ID against a fixed table. For the ESP32 family that table holds Espressif's native USB-CDC ID (303a:1001), its USB-JTAG/serial debug unit (303a:0002), the Silicon Labs CP2102 bridge (10c4:ea60), and the WCH CH340 (1a86:7523) and CH9102 (1a86:55d4) bridges. Each match comes back with its port path, for example /dev/cu.usbserial-0001 on macOS or COM5 on Windows.

A CH340 or CP2102 is a generic chip, so a non-ESP32 board built on the same bridge will also be listed as esp32. Tell the agent which board is which if you have more than one plugged in.

Flashing

Ask for it in plain words. The tool call Claude Code makes looks like this:

flash_firmware {
  "family": "esp32",
  "path": "/dev/cu.usbserial-0001",
  "firmwarePath": "/Users/you/blink/build/blink-merged.bin"
}

On the server side that becomes esptool --port /dev/cu.usbserial-0001 write-flash 0x0 <file>. The image is written at offset 0x0, so give it a merged image. With ESP-IDF, build as usual and run esptool merge-bin over the bootloader, partition table and app. With the Arduino ESP32 core, use the merged binary produced by Export Compiled Binary. The result is returned whether it worked or not, including esptool's own error text, so the agent can see a wrong port or a board that is not in download mode.

Watching it run

serial_open  { "family": "esp32", "path": "/dev/cu.usbserial-0001", "baudRate": 115200 }
serial_read  { "family": "esp32", "handle": { ... }, "timeoutMs": 2000 }
serial_write { "family": "esp32", "handle": { ... }, "dataBase64": "aGVsbG8K" }
serial_close { "family": "esp32", "handle": { ... } }

Bytes travel base64-encoded in both directions so binary protocols survive intact. A practical loop is to ask Claude Code to flash, open the port, read for a few seconds and then explain the boot log or panic backtrace it sees, before touching the code again.

Driving pins on an ESP32 running MicroPython

If the board runs MicroPython, the agent also gets gpio_mode, gpio_read, gpio_write, adc_read, pwm_write, i2c_scan, i2c_read, i2c_write, spi_transfer and mpy_exec, with no firmware of ours on the board: the server drives MicroPython's raw REPL over the same USB port, the way mpremote does, and board_info tells the agent which runtime it found. As of 2026-09-20 these tools are proven against the real MicroPython interpreter (its WebAssembly build) in a simulator and have not been run on a physical ESP32 by the studio; the quickstart keeps that status current.

What it does not do yet

Frequently asked questions

Can Claude Code flash my ESP32 by itself?
Yes, once this MCP server is registered and esptool is installed. The agent calls list_boards to find the port, then flash_firmware with family esp32, that port and the path to a firmware image. The server runs esptool write-flash at offset 0x0 and returns esptool's own output.
Which ESP32 boards are detected?
Boards that show up over Espressif's native USB (ESP32-S2, S3 and C3 dev kits) and boards that use a Silicon Labs CP2102 or a WCH CH340 or CH9102 USB-to-serial chip, which covers most ESP32 DevKitC boards and their clones.
What kind of firmware file does flash_firmware expect for an ESP32?
A single image that is meant to be written at offset 0x0, which means a merged binary containing bootloader, partition table and app. esptool merge-bin produces one. Handing it an app-only .bin, which belongs at 0x10000, will not boot.
Can the agent read what my ESP32 prints?
Yes. serial_open opens the port at the baud rate you give it (115200 by default), serial_read returns the buffered bytes base64-encoded, and serial_write sends bytes back. The agent decodes the output and can react to a boot log, a panic backtrace or your own debug prints.
Does this replace ESP-IDF or the Arduino core?
No. The server does not run idf.py. Its compile_sketch tool runs arduino-cli and its build_project tool runs PlatformIO, both proven so far against recorded tool output rather than a real install; for ESP-IDF, Claude Code still runs idf.py in your terminal, and this server gives it a reliable way to put the result on the board and watch it run.