velxio/docs/MCP.md

301 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Velxio MCP Server
Velxio exposes a [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server that allows AI agents (e.g. Claude, Cursor) to:
- **Create and update circuits** using a structured JSON format
- **Import and export** circuits in the Wokwi `diagram.json` format
- **Generate Arduino code** from circuit definitions
- **Compile projects** and receive structured results (hex/binary, logs)
---
## Tools
| Tool | Description |
|------|-------------|
| `compile_project` | Compile Arduino sketch files → Intel HEX / binary |
| `run_project` | Compile and mark artifact as simulation-ready |
| `import_wokwi_json` | Parse a Wokwi `diagram.json` → Velxio circuit |
| `export_wokwi_json` | Serialise a Velxio circuit → Wokwi `diagram.json` |
| `create_circuit` | Create a new circuit definition |
| `update_circuit` | Merge changes into an existing circuit |
| `generate_code_files` | Generate starter `.ino` code from a circuit |
---
## Transport Options
### 1. stdio (Claude Desktop / CLI agents)
Run the MCP server as a child process:
```bash
cd backend
python mcp_server.py
```
**Claude Desktop config** (`~/.claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"velxio": {
"command": "python",
"args": ["/absolute/path/to/velxio/backend/mcp_server.py"]
}
}
}
```
### 2. SSE / HTTP (web agents, Cursor IDE)
Run the MCP SSE server on a separate port (default: **8002**):
```bash
cd backend
python mcp_sse_server.py --port 8002
```
**MCP client config (SSE transport)**:
```json
{
"mcpServers": {
"velxio": {
"url": "http://localhost:8002/sse"
}
}
}
```
> **Note**: The SSE server runs separately from the main FastAPI backend (port 8001) to avoid Starlette version conflicts. Both can run simultaneously.
---
## Setup
1. **Install dependencies**:
```bash
cd backend
pip install -r requirements.txt
```
2. **Ensure arduino-cli is installed** (required for `compile_project` / `run_project`):
```bash
arduino-cli version
arduino-cli core update-index
arduino-cli core install arduino:avr
```
---
## Example Walkthroughs
### Example 1 — Blink LED (from scratch)
**Step 1** — Create a circuit:
```json
{
"tool": "create_circuit",
"arguments": {
"board_fqbn": "arduino:avr:uno",
"components": [
{ "id": "led1", "type": "wokwi-led", "left": 150, "top": 100, "attrs": { "color": "red" } },
{ "id": "r1", "type": "wokwi-resistor", "left": 150, "top": 180, "attrs": { "value": "220" } }
],
"connections": [
{ "from_part": "uno", "from_pin": "13", "to_part": "led1", "to_pin": "A", "color": "green" },
{ "from_part": "led1", "from_pin": "C", "to_part": "r1", "to_pin": "1", "color": "black" },
{ "from_part": "r1", "from_pin": "2", "to_part": "uno", "to_pin": "GND.1", "color": "black" }
]
}
}
```
**Step 2** — Generate code:
```json
{
"tool": "generate_code_files",
"arguments": {
"circuit": "<result from Step 1>",
"sketch_name": "blink",
"extra_instructions": "Blink the red LED every 500ms"
}
}
```
**Step 3** — Compile the generated code (edit the sketch content as needed):
```json
{
"tool": "compile_project",
"arguments": {
"files": [
{
"name": "blink.ino",
"content": "void setup() { pinMode(13, OUTPUT); }\nvoid loop() { digitalWrite(13, HIGH); delay(500); digitalWrite(13, LOW); delay(500); }"
}
],
"board": "arduino:avr:uno"
}
}
```
**Response**:
```json
{
"success": true,
"hex_content": ":100000000C9434000C943E000C943E000C943E...",
"binary_content": null,
"binary_type": null,
"stdout": "",
"stderr": ""
}
```
---
### Example 2 — Import a Wokwi Circuit
**Import**:
```json
{
"tool": "import_wokwi_json",
"arguments": {
"diagram_json": "{\"version\":1,\"author\":\"example\",\"editor\":\"wokwi\",\"parts\":[{\"type\":\"wokwi-arduino-uno\",\"id\":\"uno\",\"top\":0,\"left\":0,\"attrs\":{}},{\"type\":\"wokwi-led\",\"id\":\"led1\",\"top\":100,\"left\":200,\"attrs\":{\"color\":\"green\"}}],\"connections\":[[\"uno:13\",\"led1:A\",\"green\",[]]]}"
}
}
```
**Response**:
```json
{
"board_fqbn": "arduino:avr:uno",
"components": [
{ "id": "uno", "type": "wokwi-arduino-uno", "left": 0, "top": 0, "rotate": 0, "attrs": {} },
{ "id": "led1", "type": "wokwi-led", "left": 200, "top": 100, "rotate": 0, "attrs": { "color": "green" } }
],
"connections": [
{ "from_part": "uno", "from_pin": "13", "to_part": "led1", "to_pin": "A", "color": "#00ff00" }
],
"version": 1
}
```
---
### Example 3 — Export to Wokwi Format
```json
{
"tool": "export_wokwi_json",
"arguments": {
"circuit": {
"board_fqbn": "arduino:avr:uno",
"components": [
{ "id": "led1", "type": "wokwi-led", "left": 200, "top": 100, "rotate": 0, "attrs": {} }
],
"connections": [
{ "from_part": "uno", "from_pin": "13", "to_part": "led1", "to_pin": "A", "color": "green" }
],
"version": 1
},
"author": "my-agent"
}
}
```
**Response** (Wokwi diagram.json format):
```json
{
"version": 1,
"author": "my-agent",
"editor": "velxio",
"parts": [
{ "type": "wokwi-arduino-uno", "id": "uno", "top": 0, "left": 0, "attrs": {} },
{ "type": "wokwi-led", "id": "led1", "top": 100, "left": 200, "rotate": 0, "attrs": {} }
],
"connections": [
["uno:13", "led1:A", "green", []]
]
}
```
---
## Circuit Data Format
Velxio circuits are plain JSON objects:
```json
{
"board_fqbn": "arduino:avr:uno",
"version": 1,
"components": [
{
"id": "led1",
"type": "wokwi-led",
"left": 200,
"top": 100,
"rotate": 0,
"attrs": { "color": "red" }
}
],
"connections": [
{
"from_part": "uno",
"from_pin": "13",
"to_part": "led1",
"to_pin": "A",
"color": "green"
}
]
}
```
### Supported Board FQBNs
| Board | FQBN |
|-------|------|
| Arduino Uno | `arduino:avr:uno` |
| Arduino Mega | `arduino:avr:mega` |
| Arduino Nano | `arduino:avr:nano` |
| Raspberry Pi Pico | `rp2040:rp2040:rpipico` |
| ESP32 DevKit | `esp32:esp32:esp32` |
### Common Component Types (Wokwi element names)
- `wokwi-led` — LED (attrs: `color`)
- `wokwi-resistor` — Resistor (attrs: `value` in Ω)
- `wokwi-pushbutton` — Push button
- `wokwi-buzzer` — Passive buzzer
- `wokwi-servo` — Servo motor
- `wokwi-lcd1602` — 16×2 LCD display
- `wokwi-neopixel` — NeoPixel RGB LED
---
## Sandboxing & Limits
- Compilation runs in a **temporary directory** cleaned up after each call.
- arduino-cli is invoked as a **subprocess** with no elevated privileges.
- There is no explicit CPU/memory timeout in the default configuration. For production deployments, set `COMPILATION_TIMEOUT_SECONDS` in the environment and enforce it at the process level.
---
## Running Tests
```bash
cd backend
pip install pytest pytest-asyncio
python -m pytest tests/test_mcp_tools.py -v
```