AgentStack
MCP verified MIT Self-run

Mcpd

mcp-quantumnic-mcpd · by quantumnic

MCP Server SDK for Microcontrollers — Expose ESP32/RP2040 hardware as AI-accessible tools via Model Context Protocol

No reviews yet
0 installs
1 views
0.0% view→install

Install

$ agentstack add mcp-quantumnic-mcpd

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Mcpd? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

                              ___
   _ __ ___   ___ _ __   __| |
  | '_ ` _ \ / __| '_ \ / _` |
  | | | | | | (__| |_) | (_| |
  |_| |_| |_|\___| .__/ \__,_|
                  |_|
  ⚡ MCP Server SDK for Microcontrollers

Expose ESP32/RP2040 hardware as AI-accessible tools via Model Context Protocol

[](https://github.com/quantumnic/mcpd/actions/workflows/test.yml) [](LICENSE) [](https://platformio.org) [](https://www.arduino.cc) [](https://modelcontextprotocol.io) [](https://claude.ai/download)


mcpd turns your microcontroller into a standards-compliant MCP server. Claude Desktop, Cursor, or any MCP client can discover and interact with your hardware — read sensors, toggle GPIOs, control servos — using the same protocol they use for any other tool.

> 💡 30-second pitch: Flash an ESP32, connect to WiFi, and Claude can read your temperature sensor. No cloud. No custom API. Just MCP.

Why mcpd?

| Feature | mcpd | ESP32MCPServer | esp-mcp | |---|:---:|:---:|:---:| | Runs on the MCU | ✅ | ✅ | ❌ CLI tool | | MCP spec compliant | ✅ 2025-11-25 | ❌ custom WS | ❌ | | Actually compiles | ✅ 1827 tests | ❌ self-described | N/A | | Streamable HTTP + SSE | ✅ | ❌ | ❌ | | WebSocket transport | ✅ | ✅ | ❌ | | Claude Desktop bridge | ✅ | ❌ | ❌ | | mDNS discovery | ✅ | ❌ | ❌ | | Resource Templates (RFC 6570) | ✅ | ❌ | ❌ | | Built-in tools (GPIO, I2C, SPI, ADC, UART, CAN, Modbus, FS, Power, Timer, LCD, IR, RTC, Camera, ESP-NOW…) | ✅ 106 tools | ❌ | ❌ | | Sampling (server requests LLM from client) | ✅ | ❌ | ❌ | | Elicitation (server requests user input) | ✅ | ❌ | ❌ | | Audio content type | ✅ | ❌ | ❌ | | Tool Annotations (readOnly, destructive hints) | ✅ | ❌ | ❌ | | Server Instructions (LLM guidance) | ✅ | ❌ | ❌ | | Runtime Tool Enable/Disable | ✅ | ❌ | ❌ | | Structured Content (text, image, resource) | ✅ | ❌ | ❌ | | Icons (server, tools, resources, prompts) | ✅ | ❌ | ❌ | | ResourceLink content type | ✅ | ❌ | ❌ | | Progress Notifications | ✅ | ❌ | ❌ | | Request Cancellation | ✅ | ❌ | ❌ | | Prompts support | ✅ | ❌ | ❌ | | Authentication | ✅ | ❌ | ❌ | | Role-Based Access Control (RBAC) | ✅ | ❌ | ❌ | | OTA Updates | ✅ | ❌ | ❌ | | Prometheus Metrics | ✅ | ❌ | ❌ | | Health Checks (component-level) | ✅ | ❌ | ❌ | | Circuit Breaker (fault tolerance) | ✅ | ❌ | ❌ | | Retry Policies (exponential backoff) | ✅ | ❌ | ❌ | | Captive Portal + Setup CLI | ✅ | ❌ | ❌ | | Hardware Abstraction Layer | ✅ | ❌ | ❌ | | Resource Subscriptions | ✅ | ❌ | ❌ | | Completion/Autocomplete | ✅ | ❌ | ❌ | | Roots | ✅ | ❌ | ❌ | | Multi-platform (ESP32, RP2040, STM32) | ✅ | ESP32 only | ESP32 only |

Architecture

┌──────────────────────┐         ┌─────────────────────────────┐
│   Claude Desktop /   │  stdio  │      mcpd-bridge            │
│   Cursor / any MCP   │◄───────►│   (Python, runs on host)    │
│   Client             │         │   Auto-discovers via mDNS   │
└──────────────────────┘         └──────────┬──────────────────┘
                                            │
                              ┌─────────────┼─────────────┐
                              │ HTTP POST   │ SSE GET     │ WebSocket
                              │ (Streamable HTTP)         │
                              ▼             ▼             ▼
                   ┌──────────────────────────────────────────┐
                   │            ESP32 / RP2040                 │
                   │  ┌──────────────────────────────────────┐│
                   │  │           mcpd::Server                ││
                   │  │  ┌────────────┐  ┌────────────────┐  ││
                   │  │  │ Transport  │  │   Dispatch      │  ││
                   │  │  │ HTTP/SSE/WS│  │ JSON-RPC 2.0   │  ││
                   │  │  └────────────┘  └───────┬────────┘  ││
                   │  │          ┌───────────────┬┼──────┐   ││
                   │  │          ▼               ▼▼      ▼   ││
                   │  │  ┌─────────────┐ ┌──────────┐ ┌───┐ ││
                   │  │  │Tools (22)   │ │Resources │ │Tpl│ ││
                   │  │  │GPIO PWM I2C │ │Readings  │ │URI│ ││
                   │  │  │SPI ADC UART │ │Status    │ │   │ ││
                   │  │  │Servo DHT NP │ │Custom    │ │   │ ││
                   │  │  │WiFi Sys MQTT│ │          │ │   │ ││
                   │  │  │Power Timer  │ │          │ │   │ ││
                   │  │  └─────────────┘ └──────────┘ └───┘ ││
                   │  └──────────────────────────────────────┘│
                   │  ┌──────────────────────────────────────┐│
                   │  │ Platform HAL │ Auth │ OTA │ Metrics  ││
                   │  └──────────────────────────────────────┘│
                   │  mDNS: _mcp._tcp    /metrics (Prometheus)│
                   └──────────────────────────────────────────┘

Quick Start

1. Install

PlatformIO (recommended):

; platformio.ini
[env:esp32]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
    mcpd
    bblanchon/ArduinoJson@^7

Arduino IDE: Download as ZIP → Sketch → Include Library → Add .ZIP Library

2. Minimal Firmware (5 minutes)

#include 

mcpd::Server mcp("my-device");

void setup() {
    Serial.begin(115200);
    WiFi.begin("MySSID", "MyPassword");
    while (WiFi.status() != WL_CONNECTED) delay(500);

    mcp.addTool("read_temperature", "Read the temperature sensor", R"({
        "type": "object",
        "properties": {}
    })", [](const JsonObject& params) -> String {
        float temp = analogRead(34) * 0.1; // your sensor logic
        return String("{\"temperature_c\":") + temp + "}";
    });

    mcp.begin();
    Serial.printf("MCP server at http://%s/mcp\n", WiFi.localIP().toString().c_str());
}

void loop() {
    mcp.loop();
}

3. Connect Claude Desktop

Add to your claude_desktop_config.json:

{
  "mcpServers": {
    "my-device": {
      "command": "python3",
      "args": ["/path/to/mcpd/host/mcpd_bridge.py", "--host", "my-device.local"]
    }
  }
}

The bridge discovers your MCU via mDNS and translates stdio ↔ Streamable HTTP.

4. Talk to your hardware!

> You: "What's the temperature?" > > Claude: calls read_temperature → "The sensor reads 23.5°C"

Features

🔐 Authentication

Protect your MCP server with API key authentication:

#include 
#include 

mcpd::Server mcp("my-device");
mcpd::Auth auth;

void setup() {
    // ...WiFi setup...
    auth.setApiKey("your-secret-key-here");
    // Auth integrates with the server — see examples for full setup
    mcp.begin();
}

Supports Bearer tokens, X-API-Key header, and ?key= query parameter.

📡 SSE Transport

Server-Sent Events for streaming responses (MCP Streamable HTTP spec):

#include 

mcpd::SSEManager sse;
// Clients connect via GET /mcp with Accept: text/event-stream
// Server pushes events in real-time

📶 Captive Portal Setup

No hardcoded WiFi credentials — configure via captive portal:

#include 

mcpd::Config config;

void setup() {
    if (!config.load()) {
        // First boot: start WiFi setup portal
        config.startCaptivePortal("mcpd-setup");
    }
    config.connectWiFi();
}

Connect to the mcpd-setup WiFi network and a setup page opens automatically.

🔄 OTA Updates

Update firmware over WiFi — no USB cable needed:

#include 

mcpd::OTA ota;

void setup() {
    // ...WiFi setup...
    ota.begin("my-device");
}

void loop() {
    ota.loop();  // handles OTA in background
    mcp.loop();
}

Then: pio run -t upload --upload-port my-device.local

💬 Prompts

Expose reusable prompt templates that MCP clients can discover and use:

#include 

mcp.addPrompt("diagnose_sensor",
    "Diagnose a sensor issue",
    {
        mcpd::MCPPromptArgument("sensor_id", "Sensor to diagnose", true),
        mcpd::MCPPromptArgument("symptom", "Observed symptom", false)
    },
    [](const std::map& args) -> std::vector {
        String sensor = args.at("sensor_id");
        return {
            mcpd::MCPPromptMessage("user",
                (String("Please diagnose sensor '") + sensor +
                 "'. Read its current value, check the last 5 readings, "
                 "and tell me if anything looks wrong.").c_str())
        };
    });

Clients call prompts/list to discover available prompts and prompts/get to retrieve them with arguments filled in.

📝 Logging

MCP-native logging — clients control the log level, server sends structured log notifications:

#include 

mcpd::Server mcp("my-device");

void setup() {
    // ... WiFi + tools setup ...
    mcp.begin();

    // Log at various levels — only messages >= client's level are sent
    mcp.logging().info("sensors", "Temperature sensor initialized");
    mcp.logging().warning("battery", "Battery below 20%");
    mcp.logging().error("network", "MQTT connection failed");
}

Clients call logging/setLevel to control verbosity (debug → emergency). Log messages arrive as notifications/message.

📄 Pagination

For devices with many tools/resources, enable cursor-based pagination:

mcp.setPageSize(5);  // 5 items per page
// Clients receive nextCursor in response to fetch more

🔄 Dynamic Tools

Add or remove tools at runtime (e.g., when peripherals are connected/disconnected):

mcp.addTool("new_sensor", "Read new sensor", schema, handler);
mcp.notifyToolsChanged();  // Notify connected clients

mcp.removeTool("old_sensor");
mcp.notifyToolsChanged();

// Enable/disable tools without removing them
mcp.disableTool("maintenance_tool");   // Hidden from clients
mcp.enableTool("maintenance_tool");    // Visible again

📋 Server Instructions

Guide the LLM's behavior with your device using server instructions (MCP 2025-11-25):

mcp.setInstructions(
    "This device controls a greenhouse. Always read temperature "
    "before adjusting fans. Never set irrigation above 80%."
);

Instructions are sent in the initialize response and help the model understand the context and constraints of your hardware.

🏷️ Custom Version

Override the version string in server info (useful for firmware versioning):

mcp.setVersion("2.1.0-greenhouse");

📊 Prometheus Metrics

Monitor your device with /metrics endpoint:

#include 

mcpd::Metrics metrics;
// After server starts:
// metrics.begin(httpServer);

Exposes: mcpd_uptime_seconds, mcpd_free_heap_bytes, mcpd_requests_total, mcpd_request_latency_ms_avg, mcpd_wifi_rssi_dbm, and more.

curl http://my-device.local/metrics
# mcpd_uptime_seconds 3421
# mcpd_free_heap_bytes 142680
# mcpd_requests_total 847
# mcpd_wifi_rssi_dbm -42

Built-in Tools

mcpd ships with optional built-in tools:

| Tool | Functions | Library Required | |------|-----------|-----------------| | GPIO | digital_read, digital_write, analog_read, pin_mode | — | | PWM | pwm_write, pwm_stop | — | | Servo | servo_write, servo_detach | ESP32Servo | | NeoPixel | neopixel_set, neopixel_fill, neopixel_clear | Adafruit NeoPixel | | DHT | dht_read (temperature & humidity) | DHT | | WiFi | wifi_status, wifi_scan | — | | I2C | i2c_scan, i2c_read, i2c_write | — | | MQTT | mqtt_connect, mqtt_publish, mqtt_subscribe, mqtt_messages, mqtt_status | PubSubClient | | System | system_info (heap, uptime, chip) | — | | OTA | ota_info, ota_partitions, ota_rollback, ota_mark_valid | — |

#include 
#include 
#include 

mcpd::tools::GPIOTool::attach(mcp);
mcpd::tools::SystemTool::attach(mcp);

mcpd::tools::MQTTTool mqtt;
mqtt.attach(mcp);
// In loop(): mqtt.loop();

For full API documentation, see [docs/API.md](docs/API.md). For a technical overview of the codebase, see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).

Examples

| Example | Description | Hardware | |---------|-------------|----------| | [basic_server](examples/basicserver/) | Minimal MCP server with one custom tool | ESP32 only | | [sensor_hub](examples/sensorhub/) | Multi-sensor setup with resources | ESP32 + sensors | | [home_automation](examples/homeautomation/) | GPIO + MQTT home automation | ESP32 + relays | | [weather_station](examples/weatherstation/) | Temperature, humidity, pressure as MCP resources | ESP32 + DHT22 + BMP280 | | [mqtt_bridge](examples/mqttbridge/) | MQTT pub/sub bridge — AI talks to IoT | ESP32 + MQTT broker | | [robot_arm](examples/robotarm/) | Claude controls a 4-DOF servo robot arm | ESP32 + 4× servos | | [smart_greenhouse](examples/smartgreenhouse/) | Greenhouse automation with logging & dynamic tools | ESP32 + DHT22 + relays | | [async_tasks](examples/asynctasks/) | Async tool execution with progress tracking & input flow | ESP32 only |

Supported Platforms

| Platform | Status | WiFi | Flash | RAM | Notes | |----------|--------|------|-------|-----|-------| | ESP32 | ✅ Stable | Built-in | 4 MB | 520 KB | Recommended for beginners | | ESP32-S2 | ✅ Stable | Built-in | 4 MB | 320 KB | Single-core, USB native | | ESP32-S3 | ✅ Stable | Built-in | 8 MB | 512 KB | Dual-core, AI acceleration | | ESP32-C3 | ✅ Stable | Built-in | 4 MB | 400 KB | RISC-V, low power | | RP2040 (Pico W) | 🧪 HAL ready | CYW43 | 2 MB | 264 KB | Platform HAL implemented | | STM32 + Ethernet | 🔜 Planned | External | Varies | Varies | Requires Ethernet shield |

MCP Compliance

Implements MCP specification 2025-11-25:

  • ✅ JSON-RPC 2.0 message format
  • initialize / initialized lifecycle
  • tools/list and tools/call
  • resources/list and resources/read
  • ✅ Capability negotiation
  • ✅ Streamable HTTP transport (POST + SSE)
  • ✅ Session management (Mcp-Session-Id)
  • ✅ mDNS service advertisement (_mcp._tcp)
  • prompts/list and prompts/get
  • ✅ Batch request support
  • ✅ CORS headers for browser clients
  • logging/setLevel and notifications/message (logging capability)
  • ✅ Cursor-based pagination for list methods
  • notifications/*/list_changed (dynamic tool/resource/prompt changes)
  • notifications/cancelled handling

Native Testing

Test on macOS/Linux without any hardware:

make test
  • 1827 tests across 29 test suites — JSON-RPC, tools, HTTP, infrastructure, modules, auth, sessions, transports, tasks, validation, caching, scheduling, pipelines, tool groups, event store, state store, RBAC, audit log, alerts, watchdog, health checks, rate limiting, circuit breaker, retry policies

Roadmap

  • [x] Core MCP server with Streamable HTTP
  • [x] Built-in GPIO, PWM, Servo, NeoPixel, DHT, I2C, System tools
  • [x] Host bridge (Python stdio ↔ HTTP)
  • [x] mDNS discovery
  • [x] SSE transport
  • [x] Authentication (API key / Bearer token)
  • [x] Configuration persistence (NVS + Captive Portal)
  • [x] OTA updates
  • [x] Prometheus metrics
  • [x] WebSocket transport
  • [x] Hardware Abstraction Layer (ESP32 + RP2040)
  • [x] Interactive serial setup CLI
  • [x] Resource Templates (RFC 6570 Level 1)
  • [ ] RP2040 (Pico W) full platform testing
  • [x] Built-in MQTT tool
  • [x] Prompts support
  • [x] BLE transport (ESP32)
  • [x] Rate limiting
  • [x] Connection lifecycle hooks
  • [x] Watchdog tool
  • [x] Circuit breaker pattern
  • [x] Retry policies with exponential backoff
  • [x] Health check monitoring
  • [x] Event store (ring-buffer)
  • [x] State store with transactions
  • [x] Audit logging
  • [x] Alert engine with hysteresis
  • [x] Tool pipelines (atomic sequences)
  • [x] Tool groups (bulk enable/disable)
  • [x] Tool caching with TTL
  • [x] Input/output validation
  • [x] Async tasks (MCP 2025-11-25)
  • [x] Role-based access control (RBAC)
  • [ ] mTLS authentication

Testing

For host-side testing without hardware, see esp32emu — a lightweight ESP32/Arduino emulator with real network sockets.

L

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.