Releases: device-context-protocol/dcp
v0.3.1 — string pattern + max_length, empirical study
What's new
Param gains string constraints (pattern, max_length)
intents:
- name: set_label
params:
text:
type: string
max_length: 64
pattern: '[A-Za-z0-9 .,!?-]+'Both optional, backwards-compatible. Enforced at the Bridge in dcp.safety.check_call; violations surface as range reply status on the wire.
Why this matters
An empirical adversarial-prompt study (see paper §3, tools/gen_llm_corpus.py) fed 295 real tool calls from DeepSeek V3 and Qwen 2.5-72B through every protocol's host-side validator. The study exposed a prompt-injection gap: DCP let every label payload through because there was no pattern field to declare. v0.3.1 closes that gap — DCP now ties OpenAPI at 50% prompt-injection rejection, matching its expressiveness at ~1/1000 the runtime footprint.
Bug fixes
examples/smart_panel_manifest.yaml:play_tone.durationwastype: duration, which the safety layer coerces to float and the firmware reads withread_int()→ every call returnedrange. Nowtype: intwithunit: ms.- LILYGO T-Panel S3 bring-up (
firmware/esp32/examples/smart_panel): GPIO 19 → 38 for the buzzer (GPIO 19 is ESP32-S3 USB D-), Wire clock 800 → 400 kHz for XL9535 compatibility, TouchLib CST3240 model define added.
New tools
tools/gen_llm_corpus.py— adversarial prompt → real LLM → captured tool callstools/bench_hallucination_empirical.py— corpus → 4-protocol rejection rates → JSON for paper figuretools/bench_latency_iotmcp.py+firmware/esp32/examples/iotmcp_echo— DCP vs IoT-MCP wire latency on identical hardware (result: 15.60 vs 15.59 ms, within 5 µs)
Paper
docs/paper/dcp-arxiv-v0.3.1.tar.gz (160 KB) — arXiv-ready source bundle with the empirical study and the IoT-MCP A/B latency comparison. See full CHANGELOG for details.
arXiv preprint now live (added 2026-05-27)
The DCP position paper matching this release's source bundle is now published on arXiv:
arXiv:2605.26159 — please cite this version when referring to DCP in academic work. See CITATION.cff for a ready-made BibTeX block, or use:
@misc{yang2026dcp,
title = {Device Context Protocol: A Compact, Safety-First Architecture
for LLM-Driven Control of Constrained Devices},
author = {Yang, Dongxu},
year = {2026},
eprint = {2605.26159},
archivePrefix= {arXiv},
primaryClass = {cs.NI},
url = {https://arxiv.org/abs/2605.26159},
}Discussion on the MCP project: modelcontextprotocol/discussions/2798.
v0.3.0 - hardware-validated draft
DCP v0.3.0 — hardware-validated draft
The first release where every line of the protocol stack — Python Bridge,
ESP32 firmware, conformance suite — runs end-to-end on a real
$5 microcontroller, with an LLM at the other end of the wire.
This is a draft release: the spec is stable for v0.x but unsigned, the
hardware matrix is still single-MCU, and the empirical safety study is
future work (see docs/RATIONALE.md §7 and docs/paper/main.tex §7).
Headline numbers
- 88 / 88 Python unit and conformance tests pass
- 10 / 10 round-trip tests pass against ESP32-WROOM-32 (CH340, 115 200 baud)
- Frame size: 19 bytes for a typical
set_brightness(50)call;
35 bytes with the optional HMAC tail - Firmware footprint: ~14 KB of pure DCP over an empty Arduino sketch
- Five transports ship: loopback, UART (COBS + CRC-16), MQTT,
BLE GATT, in-process simulator. Plus the MCP server wrapper that
surfaces every intent to any MCP host
What's in this release
Wire & protocol
- v0.3 spec at SPEC.md: 6-byte header + CBOR map +
optional 16-byte HMAC-SHA256, with all five status codes and the
manifest schema documented normatively. - Language-neutral conformance suite (golden
YAML + Python runner).
Reference implementations
- Python Bridge (asyncio): manifest loader, range/type/capability
enforcement, dry-run wire bit, HMAC-SHA256 capability tokens, wire-level
HMAC. - MCP server wrapper: every manifest intent → MCP tool, zero code
per device. - ESP32 firmware (Arduino-compatible C++): hand-rolled CBOR subset,
self-contained SHA-256 (no mbedTLS dep), COBS framing, constexpr
DCP_ID(name)macro for compile-time intent IDs. Also includes BLE
GATT peripheral via NimBLE-Arduino.
Developer experience
dcpCLI:serve / inspect / codegen / token.docs/ADDING_FEATURES.md: the
5-step loop to add a new intent (manifest → handler → test → flash →
LLM picks it up).tools/test_uart_roundtrip.py:
hardware integration harness.
Docs & design
docs/RATIONALE.md: why not MCP-on-MCU,
why not WoT, why not Matter, why not Sparkplug B, why not OpenAPI.docs/paper/main.tex: position paper
with figures, ready for arXiv submission.docs/site/: Vue 3 + Vite 7 + Tailwind v4 landing.
Release prep
- MIT, CONTRIBUTING, CODE_OF_CONDUCT, SECURITY, issue / PR templates,
GitHub Actions CI (Linux + Windows × Python 3.11 / 3.12 / 3.13).
Honest caveats
- Only one MCU validated so far (ESP32-WROOM-32). Cortex-M0+ port is
v0.4's headline. - No measured A/B against IoT-MCP — that's the follow-up paper.
- Spec is draft: a v1.0 freeze is gated on a second-implementer
port (we're hoping for community C or Rust). - Wire-level HMAC has no in-band marker — deliberate, but means
configuration discipline matters. SeeSPEC.md §7.
Try it in five minutes
pip install -e ".[mcp,serial,dev]" # all extras: ,mqtt,ble for those
dcp inspect examples/lamp_manifest.yaml
dcp serve examples/lamp_manifest.yaml --simulator
# in another shell, point any MCP host at the simulatorFor real hardware, see firmware/esp32/README.md.
Thanks
To the IoT-MCP team (Yang et al., arXiv:2510.01260) for proving the
direction; to the W3C WoT working group for the description-layer
prior art; and to the MCP team at Anthropic for the upstream we extend.