Skip to main content

meshtastic-mcp

CI PyPI Python License: GPL-3.0 Ruff

A home for AI tooling to discover, drive, observe, and test Meshtastic devices and the apps that talk to them. An MCP server plus a bundled agent skill set for closed-loop device ↔ app end-to-end testing.

Extracted and decoupled from the Meshtastic firmware repo's mcp-server/ so it can be installed and distributed on its own. The firmware-build tools become an optional capability that lights up only when a firmware checkout is present.

Quick start (60 seconds)

Plug in a Meshtastic device, then:

uvx meshtastic-mcp doctor          # check what's available

Inside Claude Code (or any MCP client registered with meshtastic):

list_devices()                          → find your device port
device_info(port="/dev/cu.usbmodem101") → firmware, region, node count
list_nodes(port="/dev/cu.usbmodem101")  → mesh peers
send_text(port="/dev/cu.usbmodem101", text="hello mesh")
packets_window(port="/dev/cu.usbmodem101", start="-30s")  → confirm TX packet

No firmware checkout required. Core tools work against any serial or TCP device.

Install

# Install the CLI + MCP server (uv recommended; also works with pipx)
uv tool install 'meshtastic-mcp[ui]'       # includes camera/OCR support
# or without UI extras:
uv tool install meshtastic-mcp
# other extras: [web] FleetSuite bench UI · [sdr] RF-compliance oracle · [test] pytest harness

# Install from a local checkout (dev):
uv tool install --editable '/path/to/meshtastic-mcp[ui]'

# One step: register the server in your MCP client + install the bundled skills
meshtastic-mcp install                 # claude-code user scope; --client cursor|windsurf|claude-desktop
meshtastic-mcp install --local         # register the current interpreter (editable/dev install)
meshtastic-mcp install --print         # just emit the JSON snippet (edit nothing)
meshtastic-mcp uninstall               # remove the registration  (--purge-skills to drop skills too)

# Or do the pieces manually:
claude mcp add meshtastic -s user -- meshtastic-mcp     # register with Claude Code
meshtastic-mcp skills install           # → ~/.agents/skills/ (device-ops, e2e, org-knowledge)
meshtastic-mcp skills uninstall         # remove them

install edits the client's mcpServers JSON in place (preserving other entries) — it picks the right config path per --client (claude-code / claude-desktop / cursor / windsurf) and --scope (user / project), or pass --config PATH. Add capability env vars with --env KEY=VALUE. Restart the MCP client to pick up the change.

Source repos (optional capabilities)

Set env vars pointing at local checkouts to activate firmware-build, Android, and Apple capabilities. The provision subcommand clones everything automatically:

meshtastic-mcp provision              # clones firmware + android + apple, prints export commands
source ~/.local/share/meshtastic-mcp/repos/.env

# Then add to your shell profile:
export MESHTASTIC_FIRMWARE_ROOT=~/meshtastic/firmware
export MESHTASTIC_ANDROID_ROOT=~/meshtastic/android
export MESHTASTIC_APPLE_ROOT=~/meshtastic/apple

# Add to your MCP client config so the server process picks them up:
# { "env": { "MESHTASTIC_FIRMWARE_ROOT": "/path/to/firmware", ... } }

esptool — if PlatformIO is installed, esptool is auto-discovered from the PlatformIO penv and wrapped automatically. No manual setup required.

meshtastic-mcp doctor          # verify what's active after setup

Capabilities

A portable core always works against any connected device (serial or tcp://host:port) with no firmware checkout. Optional capabilities activate when their prerequisite is present:

Capability Prerequisite Adds
core discovery, serial+TCP transport, device_info/list_nodes/admin/send_text/reboot, recorder + log/telemetry/packet/event queries, replay (simulated TCP device + synthetic mesh + fuzzer), input-events, uhubctl, esptool/nrfutil/picotool
firmware MESHTASTIC_FIRMWARE_ROOT + PlatformIO pio build / clean / flash / OTA / board enum / userPrefs
android android CLI + adb Android-emulator + native-node orchestration for hardware-free e2e
apple xcrun (+ idb for UI) iOS Simulator / macOS-app orchestration for hardware-free e2e
local-model a reachable Ollama or OpenAI-compatible llama-server (or a llama binary to start one) offload tools that push token-heavy work onto a local GPU — summarize/triage recorder windows, e2e-failure first pass, and an offline vision oracle; see docs/local-models.md
sdr [sdr] extra + librtlsdr + an RTL-SDR dongle RF-compliance oracle: rf_scan occupancy checks and rf_confirm_tx on-air verification, no second radio needed
sdk-cli (experimental) Kotlin SDK headless CLI alternate device-IO backend over the JVM CLI; see docs/sdk-cli-bridge.md

The active set is logged at startup (meshtastic-mcp capabilities active: …).

Beyond tools, the server exposes MCP resources (meshtastic://doctor, meshtastic://capabilities, and the templated meshtastic://e2e/{loop} for bundled e2e recipes) and prompts (triage_e2e_failure, bringup_device, inbound_loop). The android_docs_search/ android_docs_fetch tools answer Android/Compose questions grounded in the official Knowledge Base.

Source repos — two modes

Build tools (build_meshtasticd.sh, build_android_apk.sh, build_apple.sh) work in two modes:

Dev with existing checkouts — point env vars at your local trees:

export MESHTASTIC_FIRMWARE_ROOT=~/firmware
export MESHTASTIC_ANDROID_ROOT=~/Meshtastic-Android
export MESHTASTIC_APPLE_ROOT=~/Meshtastic-Apple

Portable / fresh environment — clone everything in one shot:

meshtastic-mcp provision              # clones all three repos, writes a .env file
source ~/.local/share/meshtastic-mcp/repos/.env

provision respects any env vars already set (skips those repos) and writes a sourceable .env for the ones it clones. Run doctor afterwards to confirm all binary deps are present too.

doctor — probe the environment

Run before starting e2e work (also exposed as the doctor MCP tool, so an agent can self-provision):

meshtastic-mcp doctor          # per-dependency status + exact, platform-aware install commands
meshtastic-mcp doctor --json   # machine-readable; `fix_commands[]` is ready to run

Probes binaries (pio, adb, xcrun, idb_companion, fb-idb, ffmpeg, uhubctl, OCR) and source repo roots (MESHTASTIC_FIRMWARE_ROOT, MESHTASTIC_ANDROID_ROOT, MESHTASTIC_APPLE_ROOT), reporting ok/missing/degraded with the exact command to fix each — including non-obvious ones (e.g. idb_companion lives in the facebook/fb tap, fb-idb requires Python ≤ 3.12).

Build scripts

Script Builds Key flags
scripts/build_meshtasticd.sh Native meshtasticd daemon --env native|native-macos, --ref, --firmware-dir / MESHTASTIC_FIRMWARE_ROOT
scripts/build_android_apk.sh Meshtastic-Android APK --ref, --variant, --source-dir / MESHTASTIC_ANDROID_ROOT
scripts/build_apple.sh Meshtastic iOS-Simulator .app --ref, --sim, --source-dir / MESHTASTIC_APPLE_ROOT

All scripts clone fresh if no source dir is provided, accept --ref to pin a git sha/tag/branch, and print a machine-readable <component>-sha=<sha> line for CI provenance.

Hardware-free e2e (emulator + TCP)

Portduino meshtasticd native nodes run as TCP daemons (:4403) and mesh over UDP multicast (224.0.0.69:4403) with no LoRa hardware. The Android emulator connects over TCP to 10.0.2.2:<port> as its DUT radio; the MCP server connects to other native nodes as testers. Every e2e loop — inbound/outbound message, node-sync, config-writeback, resilience — runs in software, CI-able on Linux runners. See src/meshtastic_mcp/emulator/native_node.py and the bundled meshtastic-e2e skill.

Replay — a simulated Meshtastic device (the inverse of the recorder)

Where the recorder subscribes to a live mesh and writes packets out, replay serves a capture as a fake radio over TCP. An app (or AVD at 10.0.2.2:<port>) connects to the listen port, does the want-config handshake, and receives a paced packet stream restamped to "now" — behaving like a radio sitting in the mesh. Useful for app/UI development and testing with zero hardware and a fully controllable, reproducible mesh.

replay_start(source="meshcon")                       # generated synthetic mesh (no file)
replay_start(source="capture.db", speed=30)          # SQLite capture (full-fidelity payloads)
replay_start(source="event.db", channels=[             # split by OTA hash + decrypt
    {"name": "Primary", "psk": "AQ==", "primary": True},
    {"name": "Secret", "psk": "<base64-key>"},
    {"name": "Unknown", "catch_all": True}])
replay_start(source="meshcon", fuzz="adversary")     # lace it with bad actors
replay_start(source="capture.db", announce_interval=30)  # in-app "Replay Clock" progress
replay_inject(sid, "waypoint", {"lat":37,"lon":-122,"geofence_radius":500,"notify_on_enter":True})
replay_status(); replay_stop()
  • Sources (replay/capture.py): SQLite captures (*.db/.gz, the Burning Man / DEF CON / MeshCon schema), the recorder's own packets.jsonl, or an in-memory synthetic mesh.
  • Multi-channel captures: pass a channels list (name + PSK, optional explicit OTA hashes, optional catch_all bucket) to route packets into the real channels by their OTA channel hash and advertise the keys so a connecting app shows the true channels and live-decrypts the encrypted half. The channel set is caller-supplied data — e.g. for an event capture you provide that event's channel names + PSKs; nothing event-specific is baked in.
  • Synthetic mesh (replay/sim.py): seeded, PII-free MeshCon generator — tunable node count (default 800, scales to thousands) / channels / duration, a diurnal activity envelope, and every portnum/flavor (incl. RANGE_TEST). Its default distributions (hardware/role mix, telemetry value ranges, position precision, hop-limit spread, text rate, node presence/churn — a persistent core plus transient attendees, which reproduces the real heavy activity skew — short-message lengths, and a share of encrypted/foreign traffic) are informed by the aggregate statistics of real ~1,800-node captures (Burning Man + DEF CON 33) — proportions only; every identity, position, and message is generated. sim.fit_profile(capture) derives such a profile from any capture.
  • Live injection (replay_inject): push exact packets into a running session to drive app features on demand — a waypoint with a geofence, a node position crossing it, a text, a NodeInfo, or raw. Builders (replay/build.py) set proto fields the bundled lib predates (e.g. geofence) via raw-wire append; fuzz=True injects a deliberately malformed packet (shares the fuzzer's emit path). capture.from_events([…]) turns a scripted scenario into a replayable capture. (Validated end-to-end against the Android waypoint-geofence PR.)
  • App-facing polish: the connected node is placed at the capture's median position (sane map
    • distances); announce_interval adds a "Replay Clock" node posting kickoff + live ETA/progress to the busiest channel; modem_preset / firmware_edition set the advertised LoRa preset and the app's event banner (e.g. DEFCON, HAMVENTION); replay_status returns connect host:port hints; a send timeout keeps a stalled app from hanging a session.
  • Fuzzer (replay/fuzz.py, replay_start(fuzz=…), replay_fuzz_presets): turn the stream hostile to test decoder + UI robustness. Protocol faults (corrupt/garbage/truncated payloads, portnum↔body mismatch, invalid-UTF-8 text, impossible telemetry, teleporting positions, hop anomalies, drop/duplicate) and bad-actor campaigns (evil-twin impersonation, flooding, GPS spoofing, forged ACKs, rogue ADMIN reboot/factory-reset, malicious waypoints). Seeded so a crash reproduces; activity surfaces under fuzz in replay_status. Presets: light, parser, adversary, chaos.

Bundled skills

Three skills ship in the wheel (meshtastic-mcp skills install copies them to your skills dir):

  • meshtastic-device-ops — discover/connect/configure/observe/recover/flash via the MCP tool surface (the non-e2e workflows).
  • meshtastic-e2e — cross-plane (device + app) testing: per-loop references, a verified device-plane helper (mesh_e2e.py), journey-driven UI (references/journeys/), triage, and the vision-oracle fallback.
  • meshtastic-org-knowledge — answer questions that span the Meshtastic GitHub org: which project does X, status of Y, where Z is documented, what changed recently.

FleetSuite — web control plane for a device bench

A local web UI for running a multi-board hardware bench: live device registry (discovery + auto-enrichment with firmware/hw/region), build queue + flash, an escalating recovery ladder (reboot → USB power-cycle → bootloader → reflash), per-device camera streams for screen assertions, the tiered test runner, serial monitors, and optional Datadog log/metric shipping.

uv tool install 'meshtastic-mcp[web]'
meshtastic-mcp-web              # desktop window at http://127.0.0.1:8765
meshtastic-mcp-web --browser    # serve only (headless / open it yourself)

Binds to 127.0.0.1 by default. Destructive actions (reflash / factory-reset) require an explicit confirmation. While FleetSuite runs it owns the bench's serial ports (monitors + enrichment) — pause it or use its own controls rather than pointing a second tool at the same ports; its test runner already suspends the monitors for the duration of a run. From a source checkout, ./scripts/fleetsuite.sh bootstraps everything (venv + npm + SPA build) in one command; ./scripts/web-dev.sh runs the backend + Vite dev server with HMR. Point MESHTASTIC_FIRMWARE_ROOT at a firmware checkout to enable builds, reflash recovery, and exact per-board PlatformIO env resolution — without it FleetSuite still discovers, enriches, and drives devices.

Hardware test suite

tests/ is a tiered pytest suite (unit, mesh, telemetry, monitor, recovery, ui, fleet, admin, provisioning). unit runs with no hardware; the hardware tiers target a USB-hub bench with per-board roles keyed by hub slot (reference bench: T-Echo, Heltec T114, RAK4631, ESP32-S3 — see tests/_bench.py and tests/README.md). Drive it via run-tests.sh, the meshtastic-mcp-test-tui terminal UI, or FleetSuite's test runner. Setting up your own bench (any boards, any hub): docs/bench-setup.md.

License

GPL-3.0-only.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

meshtastic_mcp-0.1.0.tar.gz (854.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

meshtastic_mcp-0.1.0-py3-none-any.whl (452.3 kB view details)

Uploaded Python 3

File details

Details for the file meshtastic_mcp-0.1.0.tar.gz.

File metadata

  • Download URL: meshtastic_mcp-0.1.0.tar.gz
  • Upload date:
  • Size: 854.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for meshtastic_mcp-0.1.0.tar.gz
Algorithm Hash digest
SHA256 dc72654d6b3a80c8c4b1bc033f5bdfb077689a91ac200e36b9d634e9ad5cfb03
MD5 ad771375a672dc2a50dbd63f73d3556e
BLAKE2b-256 4791042bb3e5ee3fd0f28eef87f78186cfef6ef3fd4f6f567d8e9458e2fd2de1

See more details on using hashes here.

Provenance

The following attestation bundles were made for meshtastic_mcp-0.1.0.tar.gz:

Publisher: release.yml on meshtastic/meshtastic-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file meshtastic_mcp-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: meshtastic_mcp-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 452.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for meshtastic_mcp-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 17ef8cc8f94cbd7a90865a001abbebfd283d639c9d9f024983ad3e94b67ba265
MD5 ebe82bd412c685256aa0fce231ad06c4
BLAKE2b-256 70ab627e7291a2be59723c853134563b7fc2d8b1a1042d88f50911ad541bbc59

See more details on using hashes here.

Provenance

The following attestation bundles were made for meshtastic_mcp-0.1.0-py3-none-any.whl:

Publisher: release.yml on meshtastic/meshtastic-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page