Skip to content

Protocol Specification

MCP/U uses JSON-RPC 2.0 over a newline-delimited stream (Serial or TCP). Each message is a single JSON object terminated by \n.


TransportNotes
Serial UARTPrimary. 115200 baud default.
TCP (WiFi)MCU listens on a configurable port.
FramingEach message ends with \n. No embedded newlines.

{"jsonrpc": "2.0", "id": 1, "method": "gpio_write", "params": {"pin": 2, "value": true}}
FieldTypeRequiredDescription
jsonrpc"2.0"YesJSON-RPC version
idintegerYesRequest ID (echoed in response)
methodstringYesTool/method name
paramsobjectNoMethod parameters

Success:

{"jsonrpc": "2.0", "id": 1, "result": {"pin": 2, "name": "led", "value": true}}

Error:

{"jsonrpc": "2.0", "id": 1, "error": {"code": -32602, "message": "Bad params"}}

CodeMeaningWhen
-32700Parse errorInvalid JSON received
-32600Invalid requestMissing jsonrpc or method
-32601Method not foundUnknown method name
-32602Invalid paramsMissing or wrong-typed parameter

Returns device metadata.

Request:

{"jsonrpc":"2.0","id":1,"method":"get_info"}

Response:

{
"jsonrpc": "2.0", "id": 1,
"result": {
"device": "esp32-demo",
"version": "1.0.0",
"platform": "arduino",
"pin_count": 3
}
}

Discovery endpoint. Returns all tools with JSON Schema + pin registry.

Request:

{"jsonrpc":"2.0","id":1,"method":"list_tools"}

Response:

{
"jsonrpc": "2.0", "id": 1,
"result": {
"device": "esp32-demo",
"version": "1.0.0",
"tools": [
{
"name": "gpio_write",
"description": "Write HIGH or LOW to a digital output pin",
"inputSchema": {
"type": "object",
"properties": {
"pin": { "type": "integer", "description": "GPIO pin number" },
"value": { "type": "boolean", "description": "true = HIGH, false = LOW" }
},
"required": ["pin", "value"]
}
},
{
"name": "read_touch",
"description": "Read capacitive touch sensor buffer on GPIO4",
"inputSchema": { "type": "object", "properties": {}, "required": [] },
"polling": { "enabled": true, "interval_ms": 2000 }
}
],
"pins": [
{ "pin": 2, "name": "led", "type": "digital_output", "description": "Onboard LED" },
{
"pin": 34, "name": "sensor", "type": "adc_input", "description": "Analog Sensor",
"capabilities": { "summary": true, "buffer": true, "events": false },
"sampling": { "interval_ms": 500, "buffer_size": 20 }
}
]
}
}

When a tool is registered with McpPolling(ms) in firmware, the polling object appears in its list_tools entry. The client reads this and auto-schedules periodic calls — no client-side configuration needed.

FieldTypeDescription
polling.enabledbooleanAlways true when present
polling.interval_msintegerSuggested call interval in milliseconds

Input pins registered with sampling options include extra metadata the client uses to configure automatic buffer draining.

FieldDescription
capabilities.bufferRing buffer is enabled
capabilities.summaryRolling statistics (min/max/avg) are enabled
sampling.interval_msMilliseconds between samples
sampling.buffer_sizeNumber of samples in the ring buffer

Params: { "pin": <integer>, "value": <boolean> }

Response: { "pin": 2, "name": "led", "value": true }


Params: { "pin": <integer> }

Response: { "pin": 2, "name": "led", "value": true }


Uses analogWrite — default 5 kHz. For custom frequency use a custom LEDC tool.

Params: { "pin": <integer>, "duty": <0–255> }

Response: { "pin": 18, "name": "led_pwm", "duty": 128 }


Params: { "pin": <integer> }

Response (ESP32 / ESP8266): { "pin": 34, "name": "sensor", "value": 2048, "volts": 1.65 }

Response (AVR — Uno/Mega/Nano): { "pin": 0, "name": "sensor", "value": 512, "mv": 1651 }


Type stringMeaningValid operations
digital_outputDigital write pingpio_write, gpio_read
digital_inputDigital read pingpio_read
pwm_outputPWM output pinpwm_write
adc_inputAnalog input pinadc_read

sequenceDiagram
participant Client
participant MCU
Client->>MCU: connect (serial/TCP)
Client->>MCU: get_info
MCU-->>Client: {device, version, ...}
Client->>MCU: list_tools
MCU-->>Client: {tools[], pins[]}
Note over Client: register MCP tools
Client->>MCU: gpio_write {pin:2, val:1}
MCU-->>Client: {pin:2, name:"led", ...}