Skip to main content

platformio.mcp

Give your AI coding agent hands on real hardware.
An MCP server for PlatformIO: build, flash (serial or OTA), watch serial, run tests, decode crashes and core dumps, check partition tables, watch heap and power, debug over GDB, shrink firmware.

CI PyPI Python 3.12+ Tools MIT

Python native · no Node · one line to install · works with Claude Code, Claude Desktop, Cursor, Codex, Windsurf, Cline


⚡ 60-second install

You need uv (curl -LsSf https://astral.sh/uv/install.sh | sh). Then:

uvx platformio.mcp install --claude-code      # or --cursor  --claude-desktop  --codex  --windsurf

No PlatformIO on this machine? Add --with-platformio and the server brings PlatformIO Core along. Optional extras: platformio.mcp[coredump] adds the ESP32 core-dump analyzer, platformio.mcp[power] adds the Nordic PPK2 driver.

Any other MCP client (Cline, Zed, Continue, ...)
uvx platformio.mcp install --print
{ "mcpServers": { "platformio": { "command": "uvx", "args": ["platformio.mcp"] } } }

Use "args": ["platformio.mcp[platformio]"] to bundle PlatformIO Core.

As a plugin (Claude Code, Cursor: server + a skill that teaches the loop)

The repo follows the Open Plugins layout: .mcp.json, skills/platformio/SKILL.md, rules/platformio.mdc, plugin.json.

claude plugin marketplace add powerdragonfire/platformio.mcp   # Claude Code
claude plugin install platformio@platformio.mcp
Already have PlatformIO?

The server finds platformio / pio on your PATH or in ~/.platformio/penv. Override with PLATFORMIO_MCP_PIO=/path/to/pio. Run uvx platformio.mcp doctor to see what the agent will see.

🎬 What it looks like

You: flash the view env and make sure it boots.

Agent → pio_flash_and_verify(env="view", expect="setup done")

FAIL: firmware flashed but the boot log matched the failure pattern:
'Guru Meditation Error: Core 1 panic'ed (LoadProhibited)'.
Cause: LoadProhibited. 3/3 addresses resolved:
  DisplayTask::run() (display_task.cpp:22) <- DisplayTask::run() (display_task.cpp:23) <- vPortTaskWrapper (port.c:143)

Agent: null pointer on line 22 of display_task.cpp, tft_ is used before begin(). Fixing, rebuilding, flashing again.

PASS: flashed env view in 14.2s and saw 'setup done' on /dev/cu.usbserial-0001 after 2.1s of boot output.

No 40 KB build logs in the context window. No human reading the serial monitor. The agent gets a verdict, a file and a line.

🔁 The loop the agent runs

flowchart LR
    A[pio_project_envs] --> B[edit code]
    B --> C[pio_build]
    C -- errors with file:line --> B
    C -- ok --> D[pio_flash_and_verify]
    D -- PASS --> E([done])
    D -- FAIL: decoded backtrace --> B
    D -- TIMEOUT --> F[pio_monitor_capture]
    F --> B

🧰 The 40 tools

GroupToolsWhat the agent gets back
🔍 Discover pio_system_info · pio_list_boards · pio_board_info · pio_list_devices PlatformIO version and policy; ~1,700 boards with MCU, clock, RAM and flash sizes; serial ports with the likely dev boards flagged
📁 Project pio_project_init · pio_project_envs · pio_project_metadata A real pio project init (never a hand-written ini); every env with board, framework, monitor and upload settings; defines and include paths
🔨 Build & flash pio_build · pio_upload · pio_upload_ota · pio_clean · pio_list_targets · pio_run_target Status, parsed errors and warnings (file, line, column), RAM/Flash %, last 40 lines, full log path. Extra targets like buildfs, erase. OTA over Wi-Fi to ArduinoOTA boards. Port failures come back classified (busy, permission, missing, no response) with the fix
📟 Serial pio_monitor_start / read / write / stop / list · pio_monitor_capture · pio_port_diagnose Background sessions with a ring buffer, cursor reads, and wait_for regex; or a one-shot capture with nothing to manage. Port diagnosis: who holds it (our session, another process), permissions, the fix
✅ Verify pio_test · pio_check Unity tests with per-case pass/fail and messages; cppcheck / clang-tidy defects by severity with CWE ids
📦 Packages pio_pkg_search / install / uninstall / list / outdated / update · pio_deps_check Registry search and dependency changes that keep platformio.ini in sync; an audit for name collisions, unpinned specs, leftovers, and circular dependencies
🧠 Analyse pio_flash_and_verify · pio_decode_backtrace · pio_size_report Hardware-in-the-loop pass/fail; crash dumps resolved to file:line; where every byte of flash and RAM goes
💾 Flash layout pio_partition_table · pio_coredump ESP32 partition CSV checks (alignment, overlap, fit, OTA slots) and a diff against the table actually on the chip; core dump pulled from flash and decoded
📈 Runtime pio_memory_watch · pio_power_profile Heap and stack telemetry parsed from serial with a leak verdict and per-task headroom; current draw from a serial meter or a Nordic PPK2 with sleep/active split and battery estimate
🐞 Debug pio_debug_start / cmd / stop / list A live GDB session over pio debug: breakpoints, step, backtrace, variables, with MI records parsed into structured results

Every tool returns ok, a one-paragraph summary written for the model, structured fields, and a log_path to the full output. Long output stays on disk under ~/.platformio-mcp/logs (newest 200 files kept).

The tools that go beyond the CLI

What it does Under the hood
🚀 pio_flash_and_verify Flash, open the port, read until expect matches (pass), a crash signature matches (fail, auto-decoded), or the timeout passes (timeout) pio run -t upload + pyserial; fail_on defaults to Guru Meditation, HardFault, abort(), assert failed, watchdog, brownout, heap corruption
🩺 pio_decode_backtrace Turn an ESP32 Backtrace: 0x400d... dump or a Cortex-M pc/lr dump into function, file, line, inlined frames, cause, reset reason Toolchain located from pio project metadata, then <target>-addr2line -pfiaC on firmware.elf; fixes Xtensa A0 window bits
📊 pio_size_report Why is the firmware this big? Flash/RAM %, loaded sections, biggest symbols with file:line, per-file totals, regex filter pio run -t checkprogsize (partition-aware) + GNU size -A + nm -S -C -l --size-sort
💾 pio_partition_table Catch the silent ESP32 corruption where an app-only flash leaves an old partition table on the chip; alignment, overlap, OTA slot, and app-fit checks Parses the env's partition CSV; read_device=true reads 0x8000 with esptool read_flash and diffs
🧯 pio_coredump Pull the core dump from the coredump partition after a crash and decode task, registers, and backtrace esptool read_flash + optional esp-coredump info_corefile (platformio.mcp[coredump])
📈 pio_memory_watch Leak, fragmentation, and stack-headroom verdicts from what the firmware already prints Parses Free heap:, heap_caps_print_heap_info, vTaskList, uxTaskGetStackHighWaterMark lines; least-squares slope
🔋 pio_power_profile Average/min/max/p95 current, sleep vs active split, energy, battery-life estimate A serial meter (INA219 sketch, USB meter log) or a Nordic PPK2 (platformio.mcp[power])
🐞 pio_debug_* Breakpoints, step, backtrace, and variable inspection through the debug probe pio debug --interface=gdb driven over GDB/MI with parsed *stopped events
🌐 pio_upload_ota Flash over Wi-Fi with failures mapped to the fix (wrong password, no ArduinoOTA.handle(), firewall, no OTA slot) pio run -t upload --upload-port <ip> (espota auto-switch) or espota.py directly
🔌 pio_port_diagnose Why the upload cannot open the port: our session, another process, permissions, or a board not in bootloader mode lsof/fuser + pio device list; never kills anything
📚 pio_deps_check Library name collisions where lib_deps order silently picks the winner, unpinned specs, leftovers, cycles Manifests in .pio/libdeps and lib/, plus the LDF dependency graph with build=true

🔒 Safety policy

Set PLATFORMIO_MCP_POLICY in the server's env, or pass --policy to install:

Policy Can build Can flash / erase / write serial Use it for
full (default) ✅ ✅ Your own bench
build_only ✅ ❌ Shared labs, CI, "look but don't touch"
read_only ❌ ❌ Code review, onboarding, untrusted prompts

MCP clients also prompt before each tool call. Policies are the second layer, not the only one.

⚙️ Settings

Variable Purpose Default
PLATFORMIO_MCP_POLICY full, build_only, read_only full
PLATFORMIO_MCP_PROJECT_DIR Project used when a tool is called without project_dir server's cwd
PLATFORMIO_MCP_PIO Explicit path to the pio executable auto-detect
PLATFORMIO_MCP_LOG_DIR Where full command logs go ~/.platformio-mcp/logs
PLATFORMIO_MCP_MAX_LOGS How many log files to keep 200

📝 Serial monitor notes

Sessions talk to the port with pyserial directly, because PlatformIO's own monitor needs an interactive terminal. PlatformIO monitor filters such as esp32_exception_decoder therefore do not apply; pio_decode_backtrace does that job. Baud and port default from monitor_speed / monitor_port in platformio.ini when project_dir is passed, otherwise the single detected dev board at 115200. Opening the port resets most dev boards, which is why pio_flash_and_verify sees the boot log from the top.

🛠️ Development

git clone https://github.com/powerdragonfire/platformio.mcp && cd platformio.mcp
uv sync
uv run pytest                    # unit tests, no hardware or network
uv run pytest -m integration     # builds the bundled native fixture with your PlatformIO
uv run platformio-mcp doctor     # what the agent's pio_system_info sees
npx @modelcontextprotocol/inspector uv run platformio-mcp   # poke tools interactively

To use your checkout in Claude Code instead of the PyPI release:

claude mcp add platformio -- uv run --directory /path/to/platformio.mcp platformio-mcp

Changes are tracked in CHANGELOG.md.

🤝 Contributing

Bug reports from real boards are the most useful thing you can send. Use the issue forms, ask questions in Discussions, and read CONTRIBUTING.md before opening a PR. Issues tagged good first issue are scoped for newcomers.

🔭 Prior art

jl-codes/platformio-mcp is a TypeScript server with the same goal, a web dashboard, and a GPIO pin audit. This project exists for people who want a Python-only install through uvx, one that can bundle PlatformIO itself, and crash decoding, size budgeting, partition checks, core dumps, OTA, live GDB, and memory/power profiling built in.

License

MIT

Metadata

Release files for platformio.mcp 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for platformio.mcp 0.2.0
File Size Uploaded
platformio_mcp-0.2.0.tar.gz 78.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for platformio.mcp 0.2.0
File Interpreter ABI Platform
platformio_mcp-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 172.4 kB

Release files / platformio_mcp-0.2.0.tar.gz

Download URL platformio_mcp-0.2.0.tar.gz
Size 78.6 kB
Tags Source
SHA-256 checksum
How to use checksums
b905d4d68ea56887a0f149547e97c64fc54073d0698236447a7dc7d4be33d4f2
BLAKE2b-256 checksum
How to use checksums
0ffd1d15bb0c43e78677b37259c2062e41cb9583c1e6883d3524a7b2039230c7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.

Transparency log

Release files / platformio_mcp-0.2.0-py3-none-any.whl

Download URL platformio_mcp-0.2.0-py3-none-any.whl
Size 93.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0639f9ef4822d927f82bc341aeab6e554c7a6d7b4d2d77e35ea88c662bb64b61
BLAKE2b-256 checksum
How to use checksums
865d8a1a6111735454f5975862114241e0e722ef6bfa861356e2cb0930008770
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page