---
title: MCP Server
description: Model Context Protocol server that exposes the SkyWalker-1 hardware API to LLMs for autonomous RF exploration.
---

import { Aside, Steps } from '@astrojs/starlight/components';

The `skywalker-mcp` package wraps the entire SkyWalker-1 Python API as an MCP (Model Context Protocol)
server, making every hardware function accessible to LLMs. This enables natural-language signal analysis,
autonomous RF exploration, and scheduled observation campaigns.

## Installation

```bash
cd mcp/skywalker-mcp
uv sync
```

## Running

```bash
# Local development
uv run --directory mcp/skywalker-mcp skywalker-mcp

# Add to Claude Code
claude mcp add skywalker-mcp -- uv run --directory mcp/skywalker-mcp skywalker-mcp
```

## Tools (20)

### Device Status
| Tool | Description |
|---|---|
| `get_device_status` | Firmware version, config bits, USB speed, serial, last error |
| `get_signal_quality` | SNR, AGC, power, lock status |
| `get_stream_diagnostics` | Poll count, overflows, sync loss |

### Spectrum & Tuning
| Tool | Description |
|---|---|
| `sweep_spectrum` | Full-band power measurement with peak detection |
| `tune_frequency` | Tune to specific freq/modulation/FEC, read signal |
| `run_blind_scan` | Symbol rate sweep at single frequency |

### Survey & Catalog
| Tool | Description |
|---|---|
| `run_carrier_survey` | Six-stage pipeline: sweep → peaks → blind → TS → catalog |
| `compare_surveys` | Diff two saved catalogs for changes |
| `list_surveys` | List saved survey files with metadata |

### Dish Motor
| Tool | Description |
|---|---|
| `move_dish` | Halt, east, west, goto slot, USALS GotoX (continuous drive requires explicit opt-in) |
| `jog_dish` | Small steps (1-30) + signal quality readback |
| `store_position` | Save current position to memory slot |

### LNB & I2C
| Tool | Description |
|---|---|
| `set_lnb_config` | Voltage (13V/18V), 22 kHz tone, power off |
| `scan_i2c_bus` | Enumerate all I2C devices |
| `read_i2c_register` | Read single byte from I2C address |

### Transport Stream & Identification
| Tool | Description |
|---|---|
| `capture_transport_stream` | Capture + parse PAT/PMT/SDT for service names |
| `identify_frequency` | Look up frequency against allocation tables |

## Resources

| URI | Description |
|---|---|
| `skywalker://status` | Live device state (firmware, config, signal) |
| `skywalker://catalog/latest` | Most recent survey catalog as JSON |
| `skywalker://allocations/lband` | L-band frequency allocation table |
| `skywalker://modulations` | Supported modulations and FEC rates |

## Prompts

| Prompt | Description |
|---|---|
| `explore_rf_environment` | Strategy for autonomous RF discovery |
| `hydrogen_line_observation` | Guided 21 cm observation procedure |

## Architecture

<Aside type="note" title="Thread safety">
The BCM4500 demodulator cannot handle overlapping USB control transfers. The MCP server
uses the same `DeviceBridge` pattern as the TUI — a `threading.RLock` serializes all
hardware access. Async MCP handlers use `asyncio.to_thread()` to avoid blocking the
event loop during USB I/O.
</Aside>

The server uses FastMCP's lifespan pattern: the USB device opens on server startup and
closes on shutdown. All tools receive the device bridge through the lifespan context.

## Testing

```bash
# Verify the server starts and can talk to hardware
claude -p "What firmware version is loaded?" \
    --mcp-config .mcp.json \
    --allowedTools "mcp__skywalker-mcp__*"

# Run a spectrum sweep via natural language
claude -p "Sweep the full IF band and tell me what you find" \
    --mcp-config .mcp.json \
    --allowedTools "mcp__skywalker-mcp__*"
```
