# 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)