# MCP Servers for DE10-Nano FPGA Development

Two Model Context Protocol (MCP) servers to automate Intel Quartus FPGA builds and DE10-Nano board management.

## Servers

### quartus-mcp

FPGA build automation for Intel Quartus projects.

> **IMPORTANT: ALWAYS USE ASYNC MODE FOR BUILDS**
>
> Quartus FPGA builds take 20-45 minutes. **Always use `quartus_build_async`** to avoid blocking.
> The synchronous `quartus_build` will block Claude for the entire build duration - don't use it.
>
> Async workflow:
> 1. `quartus_build_async()` - Start build, get task_id, continue working
> 2. `quartus_task_status()` - Check if done (poll periodically)
> 3. `quartus_task_wait()` - Block until complete (when you need the result)
> 4. `quartus_task_cancel()` - Abort if needed

| Tool | Description |
|------|-------------|
| `quartus_build_async(project_path, clean_first?)` | **USE THIS** - Start build in background, returns immediately. |
| `quartus_task_status(task_id?)` | Check build progress without blocking. |
| `quartus_task_wait(timeout?)` | Wait for current build to complete, returns result. |
| `quartus_task_cancel()` | Cancel the currently running build. |
| `quartus_task_list()` | List current + recent completed builds. |
| `quartus_status(project_path)` | Check if build artifacts exist. |
| `quartus_clean(project_path)` | Clean build artifacts. |
| `quartus_build(project_path, clean_first?)` | Sync build - **AVOID** (blocks 20-45 min). |

**Features:**
- Auto-configures `PATH` and `QSYS_ROOTDIR` for Quartus 24.1
- 1-hour build timeout
- Parses build logs for errors
- Returns structured results with RBF path and size
- **Async builds**: Run builds in background without blocking Claude
- **Single build enforcement**: Only one build at a time per machine (via `~/.quartus-mcp/state.json`)
- **Build history**: Keeps last 10 completed builds with results

### de10nano-mcp

Board management and deployment for DE10-Nano (Cyclone V SoC).

| Tool | Description |
|------|-------------|
| `board_status()` | Quick health check - SSH connectivity, serial port, uptime. |
| `ssh_cmd(command, timeout?, sudo?)` | Execute command via SSH. |
| `serial_cmd(command, timeout?)` | Execute command via serial console (pyserial). |
| `sw_sync(local_dir, remote_dir?)` | Rsync entire folder to board (default: ~/sw). |
| `fpga_verify()` | Read registers to verify bitstream is loaded. |
| `fpga_deploy(rbf_path)` | Full deploy: backup, copy, reboot, wait, verify. |
| `fpga_recover()` | U-Boot recovery via serial when board won't boot. |

**Features:**
- Uses `paramiko` for SSH (proper timeout handling)
- Uses `pyserial` for serial (never hangs like shell commands)
- `fpga_deploy` polls for board online after reboot (90s timeout)
- `fpga_recover` auto-calculates hex file size for U-Boot `fatwrite`

## Configuration

Default board settings (hardcoded in `de10nano_mcp/server.py`):

| Setting | Value |
|---------|-------|
| SSH Host | `analog.local` |
| SSH User | `analog` |
| SSH Port | `22` |
| Serial Port | `/dev/ttyUSB0` |
| Serial Baud | `115200` |
| Boot RBF | `/boot/soc_system.rbf` |

Default Quartus settings (in `quartus_mcp/server.py`):

| Setting | Value |
|---------|-------|
| Quartus Path | `/opt/altera_lite/24.1std/quartus/bin` |
| QSYS Root | `/opt/altera_lite/24.1std/quartus/sopc_builder/bin` |
| Build Timeout | `3600` seconds (1 hour) |

## Installation

```bash
cd ~/Documents/dvp/mcp-servers

# Create virtual environment
python3 -m venv .venv

# Install both servers (editable mode)
.venv/bin/pip install -e quartus-mcp -e de10nano-mcp
```

## Claude Code Configuration

Add to your project's `.mcp.json`:

```json
{
  "mcpServers": {
    "quartus": {
      "command": "/home/abb/Documents/dvp/mcp-servers/.venv/bin/quartus-mcp"
    },
    "de10nano": {
      "command": "/home/abb/Documents/dvp/mcp-servers/.venv/bin/de10nano-mcp"
    }
  }
}
```

Restart Claude Code to load the servers.

## Usage Examples

### Build FPGA (Async - Recommended)

```
# Start build in background (returns immediately)
quartus_build_async(project_path="/home/abb/de10-nanon/hdl-phase/projects/cn0579/de10nano")

# Do other work while build runs...

# Check status periodically
quartus_task_status()

# Or wait for completion when you need the result
quartus_task_wait()
```

### Deploy to Board

```
Use fpga_deploy with rbf_path="/home/abb/de10-nanon/hdl-phase/projects/cn0579/de10nano/cn0579_de10nano.rbf"
```

### Sync Software to Board

```
Use sw_sync with local_dir="/home/abb/de10-nanon/hdl-phase/sw"
```

This syncs the entire `sw/` folder to `~/sw/` on the board. Then run scripts as:
```bash
sudo python3 ~/sw/pll_tuner.py monitor
```

### Check Board Status

```
Use board_status (no arguments)
```

### Recover from Bad Bitstream

If the board is stuck at U-Boot prompt after a bad bitstream:

```
Use fpga_recover (no arguments)
```

This will:
1. Connect via serial
2. Load backup RBF from SD card
3. Calculate file size and write to main RBF
4. Reboot and verify

### Async Build Workflow

**FPGA builds take 20-45 minutes. ALWAYS use async mode to avoid blocking Claude.**

```
1. START BUILD (returns immediately):
   quartus_build_async(project_path="/path/to/project")
   -> Returns: task_id (e.g., "build-20240122-153000")
   -> Claude can now do other work!

2. CHECK PROGRESS (non-blocking):
   quartus_task_status()
   -> Returns: RUNNING + elapsed time, or SUCCESS/FAILED + results

3. WAIT FOR COMPLETION (when you need the result):
   quartus_task_wait(timeout=3600)
   -> Blocks until build finishes, returns full result
   -> Use this when you're ready to deploy

4. CANCEL IF NEEDED:
   quartus_task_cancel()
   -> Kills the running build process

5. VIEW HISTORY:
   quartus_task_list()
   -> Shows current task + last 10 completed builds
```

**Why async matters:** Synchronous builds block Claude for 20-45 minutes, wasting context
and preventing any other work. Async lets Claude start a build, do other tasks (edit code,
run tests, answer questions), then check back when the build completes.

## Testing

Run tests with mock mode (no real Quartus needed):

```bash
cd ~/Documents/dvp/mcp-servers-async
QUARTUS_MCP_MOCK=3 .venv/bin/python quartus-mcp/tests/test_quartus_mcp.py
```

Mock mode environment variable:
- `QUARTUS_MCP_MOCK=1` - Enable mock with 10s builds
- `QUARTUS_MCP_MOCK=<N>` - Enable mock with N-second builds

## Dependencies

- Python >= 3.10
- `mcp` >= 1.0.0 (MCP Python SDK)
- `paramiko` >= 3.4.0 (SSH)
- `pyserial` >= 3.5 (Serial)

## License

MIT
