{"slug": "device-context-protocol-bridge-llm-agents-to-physical-devices", "title": "Device Context Protocol – Bridge LLM Agents to Physical Devices", "summary": "A new open protocol, Device Context Protocol (DCP), enables large language model agents to safely control physical devices including low-cost microcontrollers. DCP uses a compact wire format and a Bridge process for safety enforcement, with reference firmware validated on ESP32 hardware. The protocol is designed to complement the Model Context Protocol (MCP) by translating DCP to MCP for zero-configuration use with existing LLM hosts.", "body_md": "**Status:** Draft v0.3 — May 2026 · Hardware-validated on ESP32-WROOM-32\n\nA protocol that lets LLM agents safely control physical devices, down to dollar-class microcontrollers.\n\nIntent-level, transport-agnostic, capability-scoped. Compact wire format (sub-50-byte frames). Self-contained firmware: under 1 KB of RAM, ~28 KB of flash.\n\nComplementary to\n\n[MCP]— a reference Bridge translates DCP ↔ MCP so any MCP host (Claude Desktop, Claude Code, IDE assistants) works zero-config.\n\n[Why DCP?](#why-dcp)[Design principles](#design-principles)[Architecture](#architecture)[Quickstart](#quickstart)[Add a feature in 5 steps](/device-context-protocol/dcp/blob/main/docs/ADDING_FEATURES.md)[Recipes — five ready-to-flash device skeletons](/device-context-protocol/dcp/blob/main/docs/RECIPES.md)[Wire format](#wire-format)· full[SPEC.md](/device-context-protocol/dcp/blob/main/SPEC.md)[Manifest](#manifest)[Roadmap](#roadmap)**Design rationale:**[docs/RATIONALE.md](/device-context-protocol/dcp/blob/main/docs/RATIONALE.md)— why not MCP-on-MCU, why not WoT, why not Matter.\n\nMCP is excellent for SaaS tools, but assumes JSON-RPC over WebSocket and runtime tool discovery. On an MCU with 32 KB of RAM, that's a non-starter.\n\nDCP keeps MCP's mental model (manifest + tool calls) but:\n\n- compiles to a compact CBOR wire format\n- uses a static intent table (no runtime negotiation)\n- moves safety enforcement to a Bridge process\n\nA reference Bridge translates **DCP ↔ MCP**, so any MCP-compatible LLM works\nout of the box. DCP is the last mile to physical hardware.\n\n*Why this matters in one chart: the protocol's schema decides how many\nhallucinated or adversarial calls are stopped before any byte reaches a\ndevice. DCP catches all six categories at the wire layer; the others\ncatch what their existing schema happens to cover.*\n\n**Intent, not register.**`set_brightness(50%)`\n\n, not`write_pwm(pin=5, duty=128)`\n\n.**Units in the protocol.** Every number declares a unit. No ambiguity.**Static intent table.** Manifest known at compile time; runtime is pure binary.**Safety lives in the Bridge.** Devices trust the Bridge; LLMs never see raw GPIO.**Idempotent by default.** Non-idempotent intents must declare themselves.**Transport-agnostic.** UART, BLE, MQTT, USB-CDC, WebSocket — one frame.\n\nThe Bridge is the sole trust boundary. On every call it issues and verifies capability tokens, enforces range/type/unit checks from the manifest, and supports dry-run as a wire-format primitive. Devices remain simple enough to fit on commodity microcontrollers; everything the LLM is allowed to do is enforced before any byte traverses the device boundary.\n\nAs of v0.3 the reference firmware is **measured-validated on two\nphysical boards** — an ESP32-WROOM-32 dev board over CH340 USB-Serial,\nand an ESP32-S3 (LILYGO T-Panel S3) over the S3's native USB-Serial/JTAG\n— both at 115 200 baud:\n\n- 13/13 round-trip tests pass on each board (\n`tools/test_uart_roundtrip.py`\n\n) - 88/88 Python unit & conformance tests pass\n- Full lamp firmware: 295 KB flash, 22.7 KB globals on WROOM-32 — most of which is the Arduino-ESP32 runtime + FreeRTOS, not DCP\n**The DCP layer itself measures 27.6 KB of flash and 0.6 KB of RAM** over a baseline empty sketch — reproduce with`docs/paper/figures/measure_footprint.py`\n\n. The flash figure is over the original`<16 KB`\n\ndesign target (set before on-device HMAC was added); the RAM figure is well under it.- The S3 run also exercises DCP over a native-USB CDC link rather than a USB-UART bridge chip — same firmware, no transport-specific code\n\n*Static RAM is the scarce resource on an MCU. The DCP layer's measured\n0.6 KB of RAM sits two orders of magnitude under IoT-MCP's reported\n74 KB peak memory. DCP's flash cost (27.6 KB, measured) is not plotted\n— IoT-MCP does not report a comparable flash figure.*\n\nSee [docs/RATIONALE.md §7](/device-context-protocol/dcp/blob/main/docs/RATIONALE.md) for what the hardware\nvalidation does and does not prove.\n\nThe reference firmware is portable by design (Arduino `Stream`\n\n+ a\nsoftware SHA-256, no SoC-specific code paths in `DCP.{h,cpp}`\n\n). It\ncross-compiles for every current ESP32 variant *and* for ESP8266;\ntwo of those targets are also runtime-validated on real boards, the\nrest are build-validated pending hardware on the bench:\n\n| Target | ISA | Flash (lamp+blink) | Globals | Status |\n|---|---|---|---|---|\n| ESP32-WROOM-32 | Xtensa LX6 (baseline) | 294 KB | 22.7 KB | runtime ✓ |\n| ESP32-S3 (T-Panel) | Xtensa LX7 | 322 KB | 22.7 KB | runtime ✓ (native USB) |\n| ESP32-C3 | RV32IMC | 289 KB | 13.4 KB | builds ✓ |\n| ESP32-C6 | RV32IMAC + HW-crypto | 266 KB | 14.0 KB | builds ✓ |\n| ESP32-H2 | RV32IMAC + 802.15.4 | 292 KB | 14.0 KB | builds ✓ |\n| ESP32-P4 | RV32IMAFC dual-core | 326 KB | 22.0 KB | builds ✓ |\n| ESP8266 NodeMCU | Xtensa LX106 (legacy) | 242 KB | 28.9 KB | builds ✓ |\n\nAll builds use Arduino-ESP32 core 3.3.8 / Arduino-ESP8266 core 3.x\n\n- the same\n`firmware/esp32/`\n\nlibrary. The sketch picks PWM API at compile time (`ledcAttach`\n\n/`ledcWrite`\n\non ESP32,`analogWrite`\n\non ESP8266); the protocol layer itself has no`#ifdef`\n\n. Reproduce with:\n\n```\narduino-cli compile --clean --fqbn esp32:esp32:esp32c3 \\\n    --library firmware/esp32 firmware/esp32/examples/lamp\narduino-cli compile --clean --fqbn esp8266:esp8266:nodemcuv2 \\\n    --library firmware/esp32 firmware/esp32/examples/lamp\ndcp: 0.3\ndevice:\n  id:     lamp-kitchen-01\n  model:  smart_lamp_v1\n  vendor: example.dev\n\nintents:\n  - name: set_brightness\n    params:\n      level: { type: float, unit: percent, range: [0, 100] }\n      fade:  { type: duration, unit: ms, default: 0 }\n    capability: lamp.write\n    idempotent: true\n    dry_run: true\n\n  - name: read_brightness\n    returns: { type: float, unit: percent }\n    capability: lamp.read\n\nevents:\n  - name: motion_detected\n    payload:\n      confidence: { type: float, unit: ratio, range: [0, 1] }\n    capability: lamp.read\n```\n\n`intent_id = crc16(name)`\n\n— manifests and firmware stay in sync without\ncoordination.\n\nA frame is a 6-byte fixed header + CBOR payload + an optional 16-byte truncated HMAC-SHA256. Header fields:\n\n| field | meaning |\n|---|---|\n`ver` |\n1 in v0.3 |\n`kind` |\n0x01 call · 0x02 reply · 0x03 event · 0x04 error · 0x81 dry-run |\n`seq` |\nclient-chosen, echoed in reply |\n`intent_id` |\nCRC-16/CCITT of intent name |\n`cbor` |\nCBOR map: params / return / event payload / error |\n\nReply status codes: `ok`\n\n, `denied`\n\n, `range`\n\n, `busy`\n\n, `unknown_intent`\n\n, `capability_required`\n\n.\n\nA typical `set_brightness(50)`\n\ncall is 19 bytes on the wire; the MCP\nJSON-RPC equivalent is approximately 180 bytes. The full normative spec\nlives at [SPEC.md](/device-context-protocol/dcp/blob/main/SPEC.md).\n\nSee [docs/ADDING_FEATURES.md](/device-context-protocol/dcp/blob/main/docs/ADDING_FEATURES.md) for the full\n5-step loop with a worked `blink(times, period)`\n\nexample. The short\nversion: edit the manifest, add a C++ handler + binding, recompile,\nflash, restart the MCP server — the LLM picks up the new tool\nautomatically. The Bridge needs no code change.\n\n```\n# As a user — install from PyPI:\npip install \"pydcp[mcp,serial]\"            # or [mcp,serial,mqtt,ble] for all transports\ndcp inspect examples/lamp_manifest.yaml    # parsed manifest summary\ndcp serve   examples/lamp_manifest.yaml --simulator\n# As a contributor — editable install from source:\ngit clone https://github.com/device-context-protocol/dcp.git\ncd dcp\npip install -e \".[mcp,serial,mqtt,ble,dev]\"\npytest                                     # all 88 tests\npython examples/lamp_demo.py               # in-process bridge ↔ fake lamp\n```\n\nThe PyPI package is named `pydcp`\n\n(the bare `dcp`\n\nis squatted by an\nunrelated package). The import name is `dcp`\n\n. The protocol name is DCP.\n\nThe reference Bridge ships an MCP server that exposes each DCP intent as an\nMCP tool. With `--simulator`\n\nit spins up an in-process fake device, so you\ncan demo with no hardware.\n\n```\ndcp serve examples/lamp_manifest.yaml --simulator               # no hardware\ndcp serve examples/lamp_manifest.yaml --serial COM3             # real ESP32 over UART\ndcp serve examples/lamp_manifest.yaml --mqtt broker.lan:1883 \\  # MQTT\n            --mqtt-prefix dcp/lamp-kitchen\ndcp serve examples/lamp_manifest.yaml --ble AA:BB:CC:DD:EE:FF \\ # BLE\n            --ble-service 12345678-1234-5678-1234-567812345678\n```\n\nFor multi-tenant or scoped access, mint short-lived HMAC tokens and pass them to the Bridge:\n\n```\nexport DCP_SECRET=$(dcp token keygen)\ndcp token mint --caps lamp.write,lamp.read --ttl 3600\n# eyJjYXBzIjpb...sig\n```\n\nTokens are verified by the Bridge on every call. The device sees only\nalready-authorized frames. Devices themselves do **not** verify signatures\nin v0.2 — that requires on-device HMAC, which is on the roadmap.\n\nTo wire it into **Claude Desktop**, add this to your\n`claude_desktop_config.json`\n\n:\n\n```\n{\n  \"mcpServers\": {\n    \"smart-lamp\": {\n      \"command\": \"dcp\",\n      \"args\": [\n        \"serve\",\n        \"C:/path/to/protocol/examples/lamp_manifest.yaml\",\n        \"--simulator\"\n      ]\n    }\n  }\n}\n```\n\nThen ask Claude *\"set the lamp to 60% brightness\"*. The call flow:\n\n```\nClaude ─MCP─▶ dcp serve ─Bridge─▶ Loopback ─DCP wire─▶ GenericSimulator\n```\n\nFor production use, replace `GenericSimulator`\n\nwith a real transport\n(UART / MQTT / BLE — coming next).\n\n- Multi-device atomic transactions\n- Firmware OTA\n- Mesh routing (use Thread / Zigbee underneath if you need it)\n- LLM-side authentication (delegated to the MCP host's session model)\n- Native CAN FD frames (ESP32-S3 TWAI is classic CAN; v0.4 ESP32-P4 port enables true CAN FD)\n\nIf you use DCP in academic work, please cite the arXiv preprint:\n\n```\n@misc{yang2026dcp,\n  title        = {Device Context Protocol: A Compact, Safety-First Architecture\n                  for LLM-Driven Control of Constrained Devices},\n  author       = {Yang, Dongxu},\n  year         = {2026},\n  eprint       = {2605.26159},\n  archivePrefix= {arXiv},\n  primaryClass = {cs.NI},\n  url          = {https://arxiv.org/abs/2605.26159},\n}\n```\n\nA machine-readable [ CITATION.cff](/device-context-protocol/dcp/blob/main/CITATION.cff) is also provided — GitHub\nrenders a \"Cite this repository\" button in the sidebar.\n\nMIT.\n\n- Wire format + manifest parser\n- Reference Python Bridge with loopback transport\n- Lamp example\n- MCP server wrapper + CLI (\n`dcp serve`\n\n) - Generic in-process device simulator\n- UART transport (COBS framing + CRC-16)\n- ESP32 reference firmware (Arduino-compatible C++)\n- Design rationale (\n[docs/RATIONALE.md](/device-context-protocol/dcp/blob/main/docs/RATIONALE.md)) - CI (GitHub Actions, Linux + Windows, py 3.11–3.13)\n- MQTT transport\n- HMAC-SHA256 capability tokens (Bridge-side enforcement)\n- Manifest compiler:\n`dcp codegen`\n\n(YAML → C header) - Compile-time\n`DCP_ID(name)`\n\nmacro in firmware - BLE GATT transport (bleak)\n- Release prep: CONTRIBUTING / CHANGELOG / CoC / SECURITY / issue templates\n- On-device HMAC verification (per-frame signatures, ESP32 firmware)\n- ESP32 BLE peripheral example (NimBLE-Arduino)\n- Conformance test suite (golden frames, language-neutral YAML)\n- Codegen\n`--stubs`\n\n: emits handler signatures + binding table - Quickstart video script (\n[docs/QUICKSTART_VIDEO.md](/device-context-protocol/dcp/blob/main/docs/QUICKSTART_VIDEO.md)) - Real-hardware validation on two boards (ESP32-WROOM-32 over CH340, ESP32-S3 / T-Panel over native USB), 13/13 round-trips each\n- Cross-compile clean on ESP32 RISC-V family (C3, C6, H2, P4) and ESP8266\n- Public repo at\n`device-context-protocol/dcp`\n\n(v0.3.0 released) - PyPI release (\n`pip install pydcp`\n\n, latest v0.3.1) - LLM-driven hallucination-rejection benchmark: 675 tool calls\nacross 5 LLMs / 4 vendors, prompt-injection category instantiated\nfrom AgentDojo's attack templates. DCP catches 100% of capability-\nescalation and 78% of prompt-injection attempts vs 0–1% for MCP/\nIoT-MCP. See\n`tools/gen_llm_corpus.py`\n\n+`tools/bench_hallucination_empirical.py`\n\n. - DCP vs IoT-MCP wire-latency A/B on identical ESP32-S3 hardware:\n15.60 ms vs 15.59 ms median, within 5 µs. See\n`firmware/esp32/examples/iotmcp_echo/`\n\n+`tools/bench_latency_iotmcp.py`\n\n. - arXiv preprint published:\n[arXiv:2605.26159](https://arxiv.org/abs/2605.26159)(v0.3.1). Source bundle and rendered PDF also mirrored on the v0.3.1[release page](https://github.com/device-context-protocol/dcp/releases/tag/v0.3.1). - T-Panel S3 + CAN bus demo (firmware ready, awaiting hardware)\n- ESP32-P4 port for native CAN FD\n- Multi-MCU footprint matrix (nRF52840, Cortex-M0+, RP2040)", "url": "https://wpnews.pro/news/device-context-protocol-bridge-llm-agents-to-physical-devices", "canonical_source": "https://github.com/device-context-protocol/dcp", "published_at": "2026-07-13 08:35:55+00:00", "updated_at": "2026-07-13 09:06:04.070280+00:00", "lang": "en", "topics": ["large-language-models", "ai-agents", "ai-safety", "ai-infrastructure", "developer-tools"], "entities": ["Device Context Protocol", "DCP", "MCP", "ESP32-WROOM-32", "ESP32-S3", "LILYGO T-Panel S3", "Claude Desktop", "Claude Code"], "alternates": {"html": "https://wpnews.pro/news/device-context-protocol-bridge-llm-agents-to-physical-devices", "markdown": "https://wpnews.pro/news/device-context-protocol-bridge-llm-agents-to-physical-devices.md", "text": "https://wpnews.pro/news/device-context-protocol-bridge-llm-agents-to-physical-devices.txt", "jsonld": "https://wpnews.pro/news/device-context-protocol-bridge-llm-agents-to-physical-devices.jsonld"}}