MCP server for GNU Radio — build, validate, run, and export flowgraphs programmatically.
Project description
GR-MCP: GNU Radio MCP Server
GR-MCP is a FastMCP server for GNU Radio 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
git clone https://github.com/rsp2k/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
uv run gnuradio-mcp
3. Add to your MCP client
Claude Code:
claude mcp add gnuradio-mcp -- uv run --directory /path/to/gr-mcp gnuradio-mcp
Claude Desktop / Cursor / other MCP clients:
{
"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 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
# 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
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
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
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)
# 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
# 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:
# 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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gnuradio_mcp-0.2.0.tar.gz.
File metadata
- Download URL: gnuradio_mcp-0.2.0.tar.gz
- Upload date:
- Size: 91.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"EndeavourOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86821918a5f09468adeb8d36a91dadf7d0fe89bab9fb62747313a1a2af17a2c3
|
|
| MD5 |
6ae509d6914f495fb9cebbcecdb13a5e
|
|
| BLAKE2b-256 |
5eca6ee2bc5e6bcb394f3b33a29859f09e3fd902307e7f07d3da3f918984fe09
|
File details
Details for the file gnuradio_mcp-0.2.0-py3-none-any.whl.
File metadata
- Download URL: gnuradio_mcp-0.2.0-py3-none-any.whl
- Upload date:
- Size: 101.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"EndeavourOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ac4f6d6a53f26bc630b20b27c086b59405d342dbe1b1c7e5a46cdcf67f94d777
|
|
| MD5 |
90e63b35fbd2f83a88853491aaca4e1c
|
|
| BLAKE2b-256 |
4806a9a5c1f7e230fd4295a48ce484748d90a4731add0cbc8027a6c01f1cfec6
|