gnuradio-mcp 2026.2.20
MCP server for GNU Radio — build, validate, run, and export flowgraphs programmatically.
Requires Python: >=3.14

# GR-MCP: GNU Radio MCP Server

[![Python Version](https://img.shields.io/badge/python-3.14%2B-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

**GR-MCP** is a [FastMCP](https://gofastmcp.com) server for [GNU Radio](https://www.gnuradio.org/) that enables programmatic, automated, and AI-driven creation of GNU Radio flowgraphs. It exposes 80+ MCP tools for building, validating, running, and exporting `.grc` files — plus block development, protocol analysis, and OOT module management.

> **What can you do with it?**
> - Build and validate flowgraphs programmatically
> - Generate custom GNU Radio blocks from natural language descriptions
> - Parse protocol specifications into decoder pipelines
> - Analyze IQ recordings to detect signal characteristics
> - Export blocks to distributable OOT modules
> - Run flowgraphs in Docker containers with real-time variable control
> - Install and manage OOT modules via Docker


## Quickstart

### 1. Install

```bash
git clone https://git.supported.systems/MCP/gr-mcp
cd gr-mcp

# Create venv with system site-packages (required for gnuradio)
uv venv --system-site-packages --python 3.14
uv sync
```

### 2. Run

```bash
uv run gnuradio-mcp
```

### 3. Add to your MCP client

**Claude Code:**
```bash
claude mcp add gnuradio-mcp -- uv run --directory /path/to/gr-mcp gnuradio-mcp
```

**Claude Desktop / Cursor / other MCP clients:**
```json
{
  "mcpServers": {
    "gnuradio-mcp": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/gr-mcp", "gnuradio-mcp"]
    }
  }
}
```

### Requirements

- Python >= 3.14
- GNU Radio (tested with GRC v3.10.12.0)
- Docker (optional — for runtime control, block testing, OOT builds)
- [uv](https://docs.astral.sh/uv/) package manager

> **Note:** GR-MCP is designed for single-session use. All connected MCP clients share the same flowgraph state. Run one server instance per concurrent session.


## Features

### Flowgraph Building (30 tools)

Build, edit, validate, and export `.grc` files:

| Category | Tools |
|----------|-------|
| Blocks | `make_block`, `remove_block`, `get_blocks` |
| Parameters | `get_block_params`, `set_block_params` |
| Ports | `get_block_sources`, `get_block_sinks` |
| Connections | `connect_blocks`, `disconnect_blocks`, `get_connections` |
| Validation | `validate_block`, `validate_flowgraph`, `get_all_errors` |
| Persistence | `save_flowgraph`, `load_flowgraph` |
| Code Gen | `generate_code` |
| Discovery | `get_all_available_blocks`, `search_blocks`, `get_block_categories` |
| Options | `get_flowgraph_options`, `set_flowgraph_options` |
| Python | `create_embedded_python_block`, `evaluate_expression` |
| Bypass | `bypass_block`, `unbypass_block` |
| Import/Export | `export_flowgraph_data`, `import_flowgraph_data` |
| OOT Paths | `load_oot_blocks`, `add_block_path`, `get_block_paths` |

### Block Development (18 tools, dynamically registered)

Generate, validate, test, and export custom blocks. These tools are registered on-demand via `enable_block_dev_mode` to minimize context usage:

| Category | Tools |
|----------|-------|
| Generation | `generate_sync_block`, `generate_basic_block`, `generate_interp_block`, `generate_decim_block` |
| Validation | `validate_block_code`, `parse_block_prompt` |
| Testing | `test_block_in_docker` |
| Integration | `inject_generated_block` |
| Protocol | `parse_protocol_spec`, `generate_decoder_chain`, `get_missing_oot_modules` |
| Signal | `analyze_iq_file` |
| OOT Export | `generate_oot_skeleton`, `export_block_to_oot`, `export_from_flowgraph` |
| Mode | `enable_block_dev_mode`, `disable_block_dev_mode`, `get_block_dev_mode` |

### Runtime Control (36 tools)

Run flowgraphs in Docker containers with real-time control:

| Category | Tools |
|----------|-------|
| XML-RPC | `connect`, `disconnect`, `get_status`, `list_variables`, `get_variable`, `set_variable` |
| Execution | `start`, `stop`, `lock`, `unlock` |
| ControlPort | `connect_controlport`, `disconnect_controlport`, `get_knobs`, `set_knobs`, `get_knob_properties`, `get_performance_counters`, `post_message` |
| Docker | `launch_flowgraph`, `list_containers`, `stop_flowgraph`, `remove_flowgraph`, `connect_to_container`, `capture_screenshot`, `get_container_logs` |
| Coverage | `collect_coverage`, `generate_coverage_report`, `combine_coverage`, `delete_coverage` |
| OOT Mgmt | `detect_oot_modules`, `install_oot_module`, `list_oot_images`, `remove_oot_image`, `build_multi_oot_image`, `list_combo_images`, `remove_combo_image` |

### MCP Resources

| Resource URI | Description |
|-------------|-------------|
| `oot://directory` | Curated directory of 20 OOT modules (12 preinstalled) |
| `oot://directory/{module}` | Details for a specific OOT module |
| `prompts://block-generation/*` | Block generation patterns and templates |
| `prompts://protocol-analysis/*` | Decoder pipeline guidance |


## Usage Examples

### Building a flowgraph

```python
# Create blocks
make_block(block_type="analog_sig_source_x", name="sig_source")
make_block(block_type="audio_sink", name="speaker")

# Configure
set_block_params(block_name="sig_source", params={
    "freq": "1000",
    "amplitude": "0.5",
    "waveform": "analog.GR_COS_WAVE"
})

# Wire and save
connect_blocks(
    source_block="sig_source", source_port="0",
    sink_block="speaker", sink_port="0"
)
validate_flowgraph()
save_flowgraph(path="/tmp/my_flowgraph.grc")
```

### Generating a custom block

```python
enable_block_dev_mode()

generate_sync_block(
    name="pm_demod",
    description="Phase modulation demodulator",
    inputs=[{"dtype": "complex", "vlen": 1}],
    outputs=[{"dtype": "float", "vlen": 1}],
    parameters=[{"name": "sensitivity", "dtype": "float", "default": 1.0}],
    work_logic="Extract instantaneous phase from complex samples"
)
```

### Protocol analysis to decoder chain

```python
enable_block_dev_mode()

# Parse a protocol spec
protocol = parse_protocol_spec(
    "GFSK at 250k baud, deviation: 25khz, preamble 0xAA, sync 0x2DD4"
)

# Generate the decoder pipeline
chain = generate_decoder_chain(protocol=protocol, sample_rate=2000000.0)
# Returns: blocks, connections, variables, missing_oot_modules
```

### Exporting to an OOT module

```python
enable_block_dev_mode()

# Generate block
block = generate_sync_block(name="my_filter", ...)

# Export to distributable OOT module
export_block_to_oot(
    generated=block,
    module_name="mymodule",
    output_dir="/path/to/gr-mymodule",
    author="Your Name"
)
# Creates: CMakeLists.txt, python/mymodule/my_filter.py, grc/mymodule_my_filter.block.yml
```

### Runtime control (Docker)

```python
# Launch flowgraph in container
launch_flowgraph(
    flowgraph_path="/path/to/flowgraph.py",
    name="my-sdr",
    xmlrpc_port=8080,
    enable_vnc=True
)

# Tune in real-time
connect_to_container(name="my-sdr")
set_variable(name="freq", value=2.4e9)

# Inspect and clean up
capture_screenshot(name="my-sdr")
stop_flowgraph(name="my-sdr")
```


## Architecture

```
src/gnuradio_mcp/
├── server.py                    # FastMCP app entry point
├── models.py                    # Pydantic models for all tools
├── utils.py                     # Unique IDs, error formatting
├── oot_catalog.py               # Curated OOT module directory
├── middlewares/
│   ├── platform.py              # GNU Radio Platform wrapper
│   ├── flowgraph.py             # Block/connection management
│   ├── block.py                 # Parameter/port access
│   ├── ports.py                 # Port resolution utilities
│   ├── docker.py                # Docker container lifecycle
│   ├── xmlrpc.py                # XML-RPC variable control
│   ├── thrift.py                # ControlPort/Thrift client
│   ├── oot.py                   # OOT module Docker builds
│   ├── block_generator.py       # Code generation for custom blocks
│   ├── oot_exporter.py          # Export blocks to OOT modules
│   └── protocol_analyzer.py     # Protocol parsing, decoder chains, IQ analysis
└── providers/
    ├── base.py                  # PlatformProvider (flowgraph tools)
    ├── mcp.py                   # McpPlatformProvider (registers tools)
    ├── runtime.py               # RuntimeProvider (Docker/XML-RPC/Thrift)
    ├── mcp_runtime.py           # McpRuntimeProvider (registers tools)
    ├── block_dev.py             # BlockDevProvider (generation/analysis)
    └── mcp_block_dev.py         # McpBlockDevProvider (dynamic registration)
```

**Data flow:** GNU Radio objects → Middlewares (validation/rewrite) → Pydantic Models (serialization) → MCP Tools


## Development

```bash
# Install all dependencies
uv sync --all-extras

# Run tests
pytest

# Run specific test suite
pytest tests/unit/
pytest tests/integration/

# Pre-commit hooks (black, flake8, isort, mypy)
pre-commit run --all-files
```


## Docker Images (Optional)

For runtime control and block testing:

```bash
# Runtime image (Xvfb + VNC + ImageMagick)
docker build -f docker/Dockerfile.gnuradio-runtime -t gnuradio-runtime:latest docker/

# Coverage image (adds python3-coverage)
docker build -f docker/Dockerfile.gnuradio-coverage -t gnuradio-coverage:latest docker/
```


## License

[MIT](LICENSE)