Skip to content

Commit 19b5a12

Browse files
committed
Add MCP server for AI-assisted device interaction
Host-side MCP (Model Context Protocol) server in C that provides tools for AI assistants to interact with MIOS devices over USB. Tools: - configure: set USB VID/PID for device discovery - cli: send CLI commands via USB MCP interface - read_memory: read raw device memory (max 32 bytes) - flash_dfu: flash firmware via USB DFU with auto-detach - flash_stlink: flash via OpenOCD TCL interface - sigcapture_list: list recent signal captures from background thread - sigcapture_save: export captures to CSV for analysis Also refactors support/dfu/dfu.c to reuse shared code from host/dfu.c which handles DFU runtime detection, detach, and flashing. Build with: make -C host/mcp Configure in ~/.claude.json as an MCP server. See docs/mcp.md for setup and usage details.
1 parent bde79b1 commit 19b5a12

13 files changed

Lines changed: 5865 additions & 748 deletions

File tree

docs/mcp.md

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# MIOS MCP Server
2+
3+
MCP (Model Context Protocol) server that allows AI assistants to interact
4+
with MIOS devices over USB. Supports CLI command execution, memory reads,
5+
firmware flashing (DFU and ST-Link), and signal capture.
6+
7+
## Device-side setup
8+
9+
Add the USB interfaces to your platform's interface queue:
10+
11+
```c
12+
#include <usb/usb.h>
13+
14+
struct usb_interface_queue q;
15+
STAILQ_INIT(&q);
16+
17+
usb_cdc_create_shell(&q); // Optional: serial console
18+
usb_dfu_runtime_create(&q); // Optional: in-app DFU detach
19+
usb_mcp_create(&q, 0x01); // MCP command interface (subclass 0x01)
20+
21+
your_platform_usb_create(vid, pid, manufacturer, product, &q);
22+
```
23+
24+
The MCP command interface uses USB vendor class (0xFF) with subclass
25+
0x01. Sigcapture uses subclass 192. These are separate USB interfaces.
26+
27+
Rebuild and flash your firmware.
28+
29+
## Building the MCP server
30+
31+
```
32+
make -C host/mcp
33+
```
34+
35+
Produces `host/mcp/mios-mcp`. Requires `libusb-1.0` development
36+
headers (`apt install libusb-1.0-0-dev` on Debian/Ubuntu).
37+
38+
## Claude Code integration
39+
40+
Add to `~/.claude.json`:
41+
42+
```json
43+
{
44+
"mcpServers": {
45+
"mios": {
46+
"command": "/path/to/mios/host/mcp/mios-mcp"
47+
}
48+
}
49+
}
50+
```
51+
52+
Restart Claude Code. The following tools become available:
53+
54+
### configure
55+
56+
Set the USB VID/PID used to find the MIOS device. Affects all
57+
subsequent tool calls. Default VID is 0x6666, PID is 0 (match any).
58+
59+
```
60+
configure(vid: 0x1234, pid: 0x5678)
61+
```
62+
63+
### cli
64+
65+
Send a CLI command to the device via the USB MCP interface and get
66+
the text output back.
67+
68+
```
69+
cli(command: "uptime")
70+
cli(command: "i2c scan 0", timeout_ms: 10000)
71+
```
72+
73+
### read_memory
74+
75+
Read raw memory from the device (max 32 bytes per call). Returns
76+
a hex dump.
77+
78+
```
79+
read_memory(address: 0x08000000, length: 32)
80+
```
81+
82+
### flash_dfu
83+
84+
Flash firmware via USB DFU. Automatically handles DFU Runtime detach
85+
if the device is running (requires `usb_dfu_runtime_create` on device).
86+
87+
```
88+
flash_dfu(elf_path: "/path/to/build.elf")
89+
flash_dfu(elf_path: "/path/to/build.elf", force: true)
90+
```
91+
92+
### flash_stlink
93+
94+
Flash firmware via a running OpenOCD instance (TCL interface, default
95+
port 6666). Auto-detects flash vs RAM targets from the ELF load address.
96+
97+
```
98+
flash_stlink(elf_path: "/path/to/build.elf")
99+
flash_stlink(elf_path: "/path/to/build.elf", host: "127.0.0.1", port: 6666)
100+
```
101+
102+
### sigcapture_list
103+
104+
List recent signal captures stored in memory. A background thread
105+
continuously receives captures from the device and stores up to 16
106+
in a ring buffer. Returns metadata only (no sample data).
107+
108+
```
109+
sigcapture_list()
110+
```
111+
112+
### sigcapture_save
113+
114+
Export a capture to CSV for analysis. The CSV has a `time_s` column
115+
(relative to trigger) followed by one column per channel with scaled
116+
values. Use the capture ID from `sigcapture_list`.
117+
118+
```
119+
sigcapture_save(id: 42, path: "/tmp/capture.csv")
120+
```
121+
122+
The CSV can be loaded with Python/pandas/matplotlib for analysis.
123+
124+
## USB MCP command protocol
125+
126+
The MCP command interface (`usb_mcp_create`, subclass 0x01) uses
127+
64-byte bulk transfers with a single-byte message type prefix:
128+
129+
| Type | Direction | Name | Payload |
130+
|------|------------- |------------------|----------------------------------|
131+
| 0x01 | Host->Device | CLI Execute | Command string (max 63 bytes) |
132+
| 0x02 | Device->Host | CLI Response | Output text (up to 63 bytes) |
133+
| 0x03 | Device->Host | CLI Complete | int32_t error code (LE) |
134+
| 0x04 | Host->Device | Read Memory | uint32_t addr + uint32_t length |
135+
| 0x05 | Device->Host | Memory Response | Raw data bytes |
136+
137+
CLI flow: host sends 0x01, device sends N x 0x02 packets with output
138+
text, then 0x03 with the error code.
139+
140+
## Sigcapture protocol
141+
142+
Sigcapture uses a separate vendor-class USB interface (subclass 192)
143+
with a single bulk IN endpoint. The device pushes capture data after
144+
a trigger event. The MCP server receives this in a background thread.
145+
146+
Packet dispatch by size:
147+
- 10 bytes: preamble (channels, depth, sample rate, trigger offset)
148+
- 20 bytes: channel descriptor (name, unit, scale)
149+
- 64 bytes: data (columnar int16_t samples)
150+
- 1 byte: trailer (0xfe, capture complete)

0 commit comments

Comments
 (0)