Skip to content

Block Development

GR-MCP provides tools for generating custom GNU Radio blocks from descriptions, testing them in isolation, and exporting them to full Out-of-Tree modules with GRC integration.

Enable Block Dev Mode

Block development tools are dynamically registered to keep the tool list lean:

enable_block_dev_mode()
# Registers ~18 tools + 5 prompt resources

Generate a Block

  1. Describe what you want

    result = generate_sync_block(
    name="configurable_gain",
    description="Multiply input samples by a configurable gain factor",
    input_signature=[{"dtype": "float", "vlen": 1}],
    output_signature=[{"dtype": "float", "vlen": 1}],
    parameters=[{
    "name": "gain",
    "dtype": "float",
    "default": 1.0,
    "description": "Gain factor"
    }],
    work_logic="Multiply each input sample by self.gain"
    )
  2. Validate the generated code

    validation = validate_block_code(source_code=result.source_code)
    # Checks: ast.parse, imports, class hierarchy, work() signature
  3. Test in Docker (optional)

    test = test_block_in_docker(
    source_code=result.source_code,
    test_input=[1.0, 2.0, 3.0],
    parameters={"gain": 2.0}
    )
    # Expected output: [2.0, 4.0, 6.0]

Block Types

Choose the right block type for your use case:

TypeToolWhen to Use
sync_blockgenerate_sync_block1:1 input/output ratio (most common)
basic_blockgenerate_basic_blockVariable I/O rates, custom forecast
interp_blockgenerate_interp_blockMore outputs than inputs (upsampling)
decim_blockgenerate_decim_blockFewer outputs than inputs (downsampling)

Generate GRC YAML

For blocks to appear in GNU Radio Companion’s graphical editor, they need a .block.yml definition:

yaml_result = generate_grc_yaml(
source_code=result.source_code,
block_name="configurable_gain",
module_name="custom",
inputs=[{"dtype": "float", "vlen": 1}],
outputs=[{"dtype": "float", "vlen": 1}],
parameters=[{
"name": "gain",
"dtype": "float",
"default": 1.0,
"min_value": 0.0,
"description": "Gain factor"
}],
category="Signal Processing"
)
# yaml_result.yaml_content contains the full .block.yml
# yaml_result.filename = "custom_configurable_gain.block.yml"
# yaml_result.notes may warn about missing setter methods

The generated YAML handles:

  • dtype mapping: Python float → GRC real, intint, complexcomplex
  • Callbacks: Detects set_*() methods for runtime parameter updates
  • Asserts: Generates validation from min_value/max_value constraints
  • Documentation: Extracts class docstrings

Export to OOT Module

Once your block is working, export it to a proper Out-of-Tree module:

  1. Export the block (creates OOT skeleton if needed)

    export = export_block_to_oot(
    source_code=result.source_code,
    block_name="configurable_gain",
    module_name="custom",
    output_dir="/tmp/gr-custom"
    )

    This creates:

    /tmp/gr-custom/
    ├── CMakeLists.txt
    ├── python/custom/
    │ ├── __init__.py
    │ └── configurable_gain.py
    └── grc/
    └── custom_configurable_gain.block.yml
  2. Or generate the skeleton first

    generate_oot_skeleton(
    module_name="custom",
    output_dir="/tmp/gr-custom",
    author="Your Name"
    )
    # Then export multiple blocks into it
    export_block_to_oot(...)
    export_block_to_oot(...)
  3. Build and install (requires runtime mode)

    enable_runtime_mode()
    install_oot_module(
    git_url="file:///tmp/gr-custom",
    branch="main"
    )

Protocol-Driven Development

Generate decoder pipelines from protocol specifications:

# Parse a protocol description
protocol = parse_protocol_spec("""
Chirp Spread Spectrum (CSS) signal:
- Spreading factor: 7
- Bandwidth: 125 kHz
- Preamble: 8 upchirps
- Sync word: 0x34
""")
# Generate the decoder chain
pipeline = generate_decoder_chain(protocol=protocol.name)
# Selects existing blocks + generates custom ones
# Check what OOT modules you need
missing = get_missing_oot_modules(protocol=protocol.name)

Signal Analysis Workflow

Start from a captured IQ file and work backwards to a decoder:

# Analyze the capture
analysis = analyze_iq_file(
file_path="/tmp/capture.raw",
sample_rate=2e6,
dtype="complex64"
)
# Returns: bandwidth, center freq offset, SNR, modulation hints
# Use the analysis to guide block generation
result = generate_sync_block(
name="matched_demod",
description=f"Demodulator for {analysis.estimated_modulation} signal "
f"with {analysis.estimated_bandwidth} Hz bandwidth",
...
)

Prompt Resources

Block dev mode registers prompt resources that guide code generation:

ResourceContent
prompts://block-generation/sync-blockgr.sync_block patterns and examples
prompts://block-generation/basic-blockgr.basic_block with forecast patterns
prompts://block-generation/common-patternsReusable idioms (history, tags, PMTs)
prompts://block-generation/grc-yaml.block.yml format reference
prompts://protocol-analysis/decoder-chainDecoder pipeline patterns

These are accessible to any MCP client and contain the patterns needed to generate correct GNU Radio block code.

Next Steps