- Replace main.py references with gnuradio-mcp entry point - Add block-dev.mdx reference page (18 tools documented) - Add block-development.mdx workflow guide - Update architecture diagram with BlockDevProvider column - Update dynamic-tools.mdx with three-group model - Add block dev section to tools-overview.mdx - Add OOT export workflow to oot-modules.mdx - Update tool counts and MCP resource listings
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://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
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/