docs: add block dev tools, fix entry points, update architecture

- 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
This commit is contained in:
Ryan Malloy 2026-02-24 10:25:26 -07:00
parent ce785029f4
commit bbcf4e784c
8 changed files with 783 additions and 105 deletions

View File

@ -21,54 +21,48 @@ objects into clean, serializable models suitable for the MCP protocol.
┌─────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────┐
│ FastMCP App │ │ FastMCP App │
(main.py) │ (server.py) │
└─────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────┘
┌───────────────┴───────────────┐ ┌───────────────┴───────────────┐
▼ ▼ ▼ ▼ ▼
┌─────────────────────────┐ ┌─────────────────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐
│ McpPlatformProvider │ │ McpRuntimeProvider │ │ McpPlatformProvider │ │ McpBlockDevProvider │ │ McpRuntimeProvider │
│ (29 tools) │ │ (5 always + ~40 dynamic) │ │ (~30 tools, always) │ │ (~18 tools, dynamic) │ │ (~40 tools, dynamic) │
│ │ │ │ │ │ │ │ │ │
│ • get_blocks │ │ Always: │ │ • get_blocks │ │ enable_block_dev_mode │ │ enable_runtime_mode │
│ • make_block │ │ • get_runtime_mode │ │ • make_block │ │ generate_sync_block │ │ launch_flowgraph │
│ • connect_blocks │ │ • enable_runtime_mode │ │ • connect_blocks │ │ validate_block_code │ │ connect_to_container │
│ • validate_flowgraph │ │ • disable_runtime_mode │ │ • validate_flowgraph │ │ generate_grc_yaml │ │ set_variable │
│ • generate_code │ │ • get_client_capabilities │ │ • generate_code │ │ export_block_to_oot │ │ install_oot_module │
│ • ... │ │ • list_client_roots │ │ • ... │ │ ... │ │ ... │
│ │ │ │ └───────────────────────┘ └───────────────────────┘ └───────────────────────┘
│ │ │ Dynamic (when enabled): │ │ │ │
│ │ │ • launch_flowgraph │ ▼ ▼ ▼
│ │ │ • connect_to_container │ ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐
│ │ │ • set_variable │ │ PlatformProvider │ │ BlockDevProvider │ │ RuntimeProvider │
│ │ │ • ... │ │ (Business Logic) │ │ (Business Logic) │ │ (Business Logic) │
└─────────────────────────┘ └─────────────────────────────────┘ └───────────────────────┘ └───────────────────────┘ └───────────────────────┘
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌─────────────────────────┐ ┌─────────────────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐
│ PlatformProvider │ │ RuntimeProvider │ │ Middlewares │ │ Middlewares │ │ Middlewares │
│ (Business Logic) │ │ (Business Logic) │ │ │ │ │ │ │
└─────────────────────────┘ └─────────────────────────────────┘ │ • PlatformMiddleware │ │ • BlockGenerator │ │ • DockerMiddleware │
│ │ │ • FlowGraphMiddleware │ │ • ProtocolAnalyzer │ │ • XmlRpcMiddleware │
▼ ▼ │ • BlockMiddleware │ │ • OOTExporter │ │ • ThriftMiddleware │
┌─────────────────────────┐ ┌─────────────────────────────────┐ │ │ │ │ │ • OOTInstaller │
│ Middlewares │ │ Middlewares │ └───────────────────────┘ └───────────────────────┘ └───────────────────────┘
│ │ │ │ │ │ │
│ • PlatformMiddleware │ │ • DockerMiddleware │ ▼ ▼ ▼
│ • FlowGraphMiddleware │ │ • XmlRpcMiddleware │ ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐
│ • BlockMiddleware │ │ • ThriftMiddleware │ │ GNU Radio Objects │ │ Code Generation │ │ External Services │
│ │ │ • OOTInstallerMiddleware │ │ │ │ │ │ │
└─────────────────────────┘ └─────────────────────────────────┘ │ • Platform │ │ • AST validation │ │ • Docker daemon │
│ │ │ • FlowGraph │ │ • Prompt templates │ │ • XML-RPC servers │
▼ ▼ │ • Block │ │ • GRC YAML templates │ │ • Thrift servers │
┌─────────────────────────┐ ┌─────────────────────────────────┐ │ • Connections │ │ • OOT scaffolding │ │ • Container processes │
│ GNU Radio Objects │ │ External Services │ └───────────────────────┘ └───────────────────────┘ └───────────────────────┘
│ │ │ │
│ • Platform │ │ • Docker daemon │
│ • FlowGraph │ │ • XML-RPC servers │
│ • Block │ │ • Thrift servers │
│ • Connections │ │ • Container processes │
└─────────────────────────┘ └─────────────────────────────────┘
``` ```
## Layer Responsibilities ## Layer Responsibilities
@ -84,6 +78,7 @@ objects into clean, serializable models suitable for the MCP protocol.
Business logic that doesn't know about MCP: Business logic that doesn't know about MCP:
- **PlatformProvider**: All flowgraph operations (create, edit, validate, save) - **PlatformProvider**: All flowgraph operations (create, edit, validate, save)
- **BlockDevProvider**: Block generation, protocol analysis, OOT export
- **RuntimeProvider**: All runtime operations (launch, connect, control) - **RuntimeProvider**: All runtime operations (launch, connect, control)
### Middleware Layer ### Middleware Layer
@ -93,6 +88,9 @@ Wraps external systems with validation and normalization:
- **PlatformMiddleware**: Wraps GNU Radio's `Platform` class - **PlatformMiddleware**: Wraps GNU Radio's `Platform` class
- **FlowGraphMiddleware**: Wraps `FlowGraph` with block/connection management - **FlowGraphMiddleware**: Wraps `FlowGraph` with block/connection management
- **BlockMiddleware**: Wraps `Block` with parameter/port access - **BlockMiddleware**: Wraps `Block` with parameter/port access
- **BlockGeneratorMiddleware**: Code generation and validation for custom blocks
- **ProtocolAnalyzerMiddleware**: Protocol parsing, decoder chain generation, IQ analysis
- **OOTExporterMiddleware**: OOT skeleton creation, block export, GRC YAML generation
- **DockerMiddleware**: Wraps Docker SDK operations - **DockerMiddleware**: Wraps Docker SDK operations
- **XmlRpcMiddleware**: Wraps XML-RPC client - **XmlRpcMiddleware**: Wraps XML-RPC client
- **ThriftMiddleware**: Wraps ControlPort Thrift client - **ThriftMiddleware**: Wraps ControlPort Thrift client
@ -167,16 +165,26 @@ Return: True
## Dynamic Tool Registration ## Dynamic Tool Registration
Runtime tools are registered dynamically to minimize context usage: Both runtime and block dev tools are registered dynamically to minimize context usage:
```python ```python
# At startup: only 5 mode control tools # At startup: ~38 always-on tools (platform + mode control)
get_runtime_mode() # Check status get_runtime_mode() # Check runtime status
enable_runtime_mode() # Register all runtime tools enable_runtime_mode() # Register runtime tools
disable_runtime_mode() # Unregister runtime tools disable_runtime_mode() # Unregister runtime tools
get_block_dev_mode() # Check block dev status
enable_block_dev_mode() # Register block dev tools
disable_block_dev_mode() # Unregister block dev tools
get_client_capabilities() # Debug client info get_client_capabilities() # Debug client info
list_client_roots() # Debug client roots list_client_roots() # Debug client roots
# After enable_block_dev_mode(): ~18 additional tools
generate_sync_block()
validate_block_code()
generate_grc_yaml()
export_block_to_oot()
# ...etc
# After enable_runtime_mode(): ~40 additional tools # After enable_runtime_mode(): ~40 additional tools
launch_flowgraph() launch_flowgraph()
connect_to_container() connect_to_container()
@ -185,8 +193,9 @@ set_variable()
``` ```
<Aside type="tip"> <Aside type="tip">
This design reduces the tool list from ~70 to ~35 when only doing flowgraph design, This design reduces the tool list from ~90+ to ~38 when only doing flowgraph design,
saving context tokens in LLM applications. saving context tokens in LLM applications. Block dev and runtime modes can be enabled
independently or together.
</Aside> </Aside>
## Key Design Decisions ## Key Design Decisions
@ -218,6 +227,7 @@ With 70+ tools, this wastes significant context. Dynamic registration:
``` ```
src/gnuradio_mcp/ src/gnuradio_mcp/
├── server.py # FastMCP app entry point + Platform init
├── models.py # All Pydantic models ├── models.py # All Pydantic models
├── utils.py # Helper functions ├── utils.py # Helper functions
├── oot_catalog.py # OOT module catalog ├── oot_catalog.py # OOT module catalog
@ -225,13 +235,19 @@ src/gnuradio_mcp/
│ ├── platform.py # PlatformMiddleware │ ├── platform.py # PlatformMiddleware
│ ├── flowgraph.py # FlowGraphMiddleware │ ├── flowgraph.py # FlowGraphMiddleware
│ ├── block.py # BlockMiddleware │ ├── block.py # BlockMiddleware
│ ├── block_generator.py # BlockGeneratorMiddleware
│ ├── protocol_analyzer.py # ProtocolAnalyzerMiddleware
│ ├── oot_exporter.py # OOTExporterMiddleware
│ ├── docker.py # DockerMiddleware │ ├── docker.py # DockerMiddleware
│ ├── xmlrpc.py # XmlRpcMiddleware │ ├── xmlrpc.py # XmlRpcMiddleware
│ ├── thrift.py # ThriftMiddleware │ ├── thrift.py # ThriftMiddleware
│ └── oot.py # OOTInstallerMiddleware │ └── oot.py # OOTInstallerMiddleware
├── prompts/ # LLM prompt templates for block generation
└── providers/ └── providers/
├── base.py # PlatformProvider ├── base.py # PlatformProvider
├── mcp.py # McpPlatformProvider ├── mcp.py # McpPlatformProvider
├── block_dev.py # BlockDevProvider
├── mcp_block_dev.py # McpBlockDevProvider
├── runtime.py # RuntimeProvider ├── runtime.py # RuntimeProvider
└── mcp_runtime.py # McpRuntimeProvider └── mcp_runtime.py # McpRuntimeProvider
``` ```

View File

@ -6,8 +6,9 @@ draft: false
import { Aside, Steps } from '@astrojs/starlight/components'; import { Aside, Steps } from '@astrojs/starlight/components';
GR-MCP uses **dynamic tool registration** to minimize context usage. Runtime tools GR-MCP uses **dynamic tool registration** to minimize context usage. Runtime and block
are only registered when needed, keeping the tool list small during flowgraph design. development tools are only registered when needed, keeping the tool list small during
flowgraph design.
## The Problem ## The Problem
@ -22,9 +23,9 @@ For LLM applications, this is wasteful when you only need flowgraph design tools
## The Solution ## The Solution
GR-MCP splits tools into two groups: GR-MCP splits tools into three groups:
### Always Available (34 tools) ### Always Available (~38 tools)
Platform tools for flowgraph design: Platform tools for flowgraph design:
- `get_blocks`, `make_block`, `remove_block` - `get_blocks`, `make_block`, `remove_block`
@ -32,16 +33,24 @@ Platform tools for flowgraph design:
- `validate_flowgraph`, `generate_code` - `validate_flowgraph`, `generate_code`
- etc. - etc.
Plus 5 runtime mode control tools: Plus mode control tools (always registered):
- `get_runtime_mode` - `get_runtime_mode`, `enable_runtime_mode`, `disable_runtime_mode`
- `enable_runtime_mode` - `get_block_dev_mode`, `enable_block_dev_mode`, `disable_block_dev_mode`
- `disable_runtime_mode` - `get_client_capabilities`, `list_client_roots`
- `get_client_capabilities`
- `list_client_roots`
### Dynamically Registered (~40 tools) ### Block Dev Tools (~18 tools)
Runtime tools loaded via `enable_runtime_mode()`: Loaded via `enable_block_dev_mode()`:
- 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`
- Protocol: `parse_protocol_spec`, `generate_decoder_chain`
- Signal: `analyze_iq_file`
- Export: `generate_grc_yaml`, `generate_oot_skeleton`, `export_block_to_oot`
### Runtime Tools (~40 tools)
Loaded via `enable_runtime_mode()`:
- Container lifecycle: `launch_flowgraph`, `stop_flowgraph` - Container lifecycle: `launch_flowgraph`, `stop_flowgraph`
- XML-RPC: `connect`, `set_variable`, `get_variable` - XML-RPC: `connect`, `set_variable`, `get_variable`
- ControlPort: `connect_controlport`, `get_knobs`, `get_performance_counters` - ControlPort: `connect_controlport`, `get_knobs`, `get_performance_counters`
@ -51,7 +60,7 @@ Runtime tools loaded via `enable_runtime_mode()`:
## Usage Pattern ## Usage Pattern
<Steps> <Steps>
1. **Flowgraph Design** (29 platform tools + 5 mode tools = 34 total) 1. **Flowgraph Design** (~38 always-on tools)
```python ```python
make_block(block_type="osmosdr_source") make_block(block_type="osmosdr_source")
@ -60,27 +69,34 @@ Runtime tools loaded via `enable_runtime_mode()`:
generate_code(output_dir="/tmp") generate_code(output_dir="/tmp")
``` ```
2. **Enable Runtime** (adds ~40 tools = ~74 total) 2. **Enable Block Dev** (adds ~18 tools)
```python
enable_block_dev_mode()
# Generate blocks, analyze protocols, export to OOT
generate_sync_block(
name="my_gain", description="Multiply by gain",
input_signature=[{"dtype": "float", "vlen": 1}],
output_signature=[{"dtype": "float", "vlen": 1}],
)
generate_grc_yaml(source_code="...", block_name="my_gain")
```
3. **Enable Runtime** (adds ~40 more tools)
```python ```python
enable_runtime_mode() enable_runtime_mode()
# Now runtime tools are available # Now runtime tools are available
```
3. **Runtime Control**
```python
launch_flowgraph(flowgraph_path="/tmp/fm.py") launch_flowgraph(flowgraph_path="/tmp/fm.py")
connect_to_container(name="gr-fm") connect_to_container(name="gr-fm")
set_variable(name="freq", value=101.1e6) set_variable(name="freq", value=101.1e6)
capture_screenshot()
``` ```
4. **Disable Runtime** (back to 34 tools) 4. **Scale Down** (disable either group independently)
```python ```python
disable_runtime_mode() disable_runtime_mode() # Removes runtime tools
# Runtime tools removed, back to design mode disable_block_dev_mode() # Removes block dev tools
``` ```
</Steps> </Steps>
@ -189,8 +205,9 @@ status = get_runtime_mode()
## Benefits ## Benefits
1. **Reduced Context** — ~35 tools instead of ~75 during design 1. **Reduced Context** — ~38 tools instead of ~90+ during design
2. **Faster Responses** — Less prompt processing for simple queries 2. **Faster Responses** — Less prompt processing for simple queries
3. **Clear Separation** — Design vs runtime is explicit 3. **Clear Separation** — Design, generation, and runtime are explicit phases
4. **Graceful Degradation** — Missing Docker doesn't break design tools 4. **Independent Modes** — Enable block dev and runtime separately or together
5. **Discovery** — `get_runtime_mode()` shows what's available 5. **Graceful Degradation** — Missing Docker doesn't break design or generation tools
6. **Discovery** — `get_runtime_mode()` and `get_block_dev_mode()` show what's available

View File

@ -85,7 +85,7 @@ sudo usermod -aG docker $USER
4. **Verify the installation** 4. **Verify the installation**
```bash ```bash
uv run main.py uv run gnuradio-mcp
``` ```
You should see the FastMCP server start. Press `Ctrl+C` to stop. You should see the FastMCP server start. Press `Ctrl+C` to stop.
@ -104,7 +104,7 @@ Edit `~/.config/claude/claude_desktop_config.json`:
"mcpServers": { "mcpServers": {
"gr-mcp": { "gr-mcp": {
"command": "uv", "command": "uv",
"args": ["--directory", "/path/to/gr-mcp", "run", "main.py"] "args": ["--directory", "/path/to/gr-mcp", "run", "gnuradio-mcp"]
} }
} }
} }
@ -112,7 +112,7 @@ Edit `~/.config/claude/claude_desktop_config.json`:
</TabItem> </TabItem>
<TabItem label="Claude Code"> <TabItem label="Claude Code">
```bash ```bash
claude mcp add gr-mcp -- uv --directory /path/to/gr-mcp run main.py claude mcp add gr-mcp -- uv --directory /path/to/gr-mcp run gnuradio-mcp
``` ```
Or add to your project's `.mcp.json`: Or add to your project's `.mcp.json`:
@ -122,7 +122,7 @@ Or add to your project's `.mcp.json`:
"mcpServers": { "mcpServers": {
"gr-mcp": { "gr-mcp": {
"command": "uv", "command": "uv",
"args": ["--directory", "/path/to/gr-mcp", "run", "main.py"] "args": ["--directory", "/path/to/gr-mcp", "run", "gnuradio-mcp"]
} }
} }
} }
@ -136,7 +136,7 @@ Edit your Cursor settings or `.cursor/mcp.json`:
"mcpServers": { "mcpServers": {
"gr-mcp": { "gr-mcp": {
"command": "uv", "command": "uv",
"args": ["--directory", "/path/to/gr-mcp", "run", "main.py"] "args": ["--directory", "/path/to/gr-mcp", "run", "gnuradio-mcp"]
} }
} }
} }

View File

@ -0,0 +1,229 @@
---
title: Block Development
description: Generate custom GNU Radio blocks and export to OOT modules
draft: false
---
import { Steps, Aside, Tabs, TabItem } from '@astrojs/starlight/components';
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:
```python
enable_block_dev_mode()
# Registers ~18 tools + 5 prompt resources
```
## Generate a Block
<Steps>
1. **Describe what you want**
```python
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**
```python
validation = validate_block_code(source_code=result.source_code)
# Checks: ast.parse, imports, class hierarchy, work() signature
```
3. **Test in Docker** (optional)
```python
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]
```
</Steps>
## Block Types
Choose the right block type for your use case:
| Type | Tool | When to Use |
|------|------|-------------|
| `sync_block` | `generate_sync_block` | 1:1 input/output ratio (most common) |
| `basic_block` | `generate_basic_block` | Variable I/O rates, custom forecast |
| `interp_block` | `generate_interp_block` | More outputs than inputs (upsampling) |
| `decim_block` | `generate_decim_block` | Fewer outputs than inputs (downsampling) |
## Generate GRC YAML
For blocks to appear in GNU Radio Companion's graphical editor, they need a `.block.yml` definition:
```python
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`, `int` → `int`, `complex` → `complex`
- **Callbacks**: Detects `set_*()` methods for runtime parameter updates
- **Asserts**: Generates validation from `min_value`/`max_value` constraints
- **Documentation**: Extracts class docstrings
<Aside type="tip">
If `notes` mentions missing `set_*()` methods, add setter methods to your block for
runtime parameter updates in GRC:
```python
def set_gain(self, gain):
self.gain = gain
```
</Aside>
## Export to OOT Module
Once your block is working, export it to a proper Out-of-Tree module:
<Steps>
1. **Export the block** (creates OOT skeleton if needed)
```python
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**
```python
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)
```python
enable_runtime_mode()
install_oot_module(
git_url="file:///tmp/gr-custom",
branch="main"
)
```
</Steps>
## Protocol-Driven Development
Generate decoder pipelines from protocol specifications:
```python
# 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:
```python
# 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:
| Resource | Content |
|----------|---------|
| `prompts://block-generation/sync-block` | `gr.sync_block` patterns and examples |
| `prompts://block-generation/basic-block` | `gr.basic_block` with forecast patterns |
| `prompts://block-generation/common-patterns` | Reusable idioms (history, tags, PMTs) |
| `prompts://block-generation/grc-yaml` | `.block.yml` format reference |
| `prompts://protocol-analysis/decoder-chain` | Decoder pipeline patterns |
These are accessible to any MCP client and contain the patterns needed to generate
correct GNU Radio block code.
## Next Steps
- [Block Dev Tools Reference](/reference/tools/block-dev/) — Complete parameter reference
- [Working with OOT Modules](/guides/oot-modules/) — Install and manage OOT modules
- [Tools Overview](/reference/tools-overview/) — All available tools

View File

@ -245,7 +245,69 @@ launch_flowgraph(
) )
``` ```
## Export Custom Blocks to OOT
GR-MCP can also create OOT modules from scratch using the block development tools:
<Steps>
1. **Enable block dev mode**
```python
enable_block_dev_mode()
```
2. **Generate a block**
```python
result = generate_sync_block(
name="my_filter",
description="Custom bandpass filter",
input_signature=[{"dtype": "complex", "vlen": 1}],
output_signature=[{"dtype": "complex", "vlen": 1}],
)
```
3. **Generate GRC YAML** (for GUI integration)
```python
yaml_result = generate_grc_yaml(
source_code=result.source_code,
block_name="my_filter",
module_name="custom",
category="Filters"
)
```
4. **Export to OOT module**
```python
export_block_to_oot(
source_code=result.source_code,
block_name="my_filter",
module_name="custom",
output_dir="/tmp/gr-custom"
)
# Creates: CMakeLists.txt, python/custom/my_filter.py, grc/custom_my_filter.block.yml
```
5. **Build as Docker image** (for container deployment)
```python
enable_runtime_mode()
install_oot_module(
git_url="file:///tmp/gr-custom",
branch="main"
)
```
</Steps>
<Aside type="tip">
See the [Block Development guide](/guides/block-development/) for the full workflow
including protocol analysis and signal analysis.
</Aside>
## Next Steps ## Next Steps
- [Block Development](/guides/block-development/) — Generate custom blocks and export to OOT
- [Runtime Control](/guides/runtime-control/) — Control variables while the flowgraph runs - [Runtime Control](/guides/runtime-control/) — Control variables while the flowgraph runs
- [OOT Catalog Reference](/reference/oot-catalog/) — Full module list with install examples - [OOT Catalog Reference](/reference/oot-catalog/) — Full module list with install examples

View File

@ -27,18 +27,18 @@ GR-MCP is a [FastMCP](https://gofastmcp.com) server that exposes GNU Radio's flo
- **OOT module management** — Install and combine Out-of-Tree modules on demand - **OOT module management** — Install and combine Out-of-Tree modules on demand
<CardGrid stagger> <CardGrid stagger>
<Card title="29 Platform Tools" icon="puzzle"> <Card title="34 Platform Tools" icon="puzzle">
Create blocks, connect ports, validate flowgraphs, and generate Python code Create blocks, connect ports, validate flowgraphs, and generate Python code
</Card> </Card>
<Card title="40+ Runtime Tools" icon="rocket"> <Card title="40+ Runtime Tools" icon="rocket">
Launch containers, control XML-RPC variables, monitor ControlPort knobs Launch containers, control XML-RPC variables, monitor ControlPort knobs
</Card> </Card>
<Card title="Block Development" icon="seti:python">
Generate blocks from descriptions, analyze protocols, export to OOT modules with GRC YAML
</Card>
<Card title="24 OOT Modules" icon="add-document"> <Card title="24 OOT Modules" icon="add-document">
Curated catalog with gr-osmosdr, gr-satellites, gr-lora_sdr, and more Curated catalog with gr-osmosdr, gr-satellites, gr-lora_sdr, and more
</Card> </Card>
<Card title="Dynamic Registration" icon="setting">
Runtime tools load on-demand to minimize context usage
</Card>
</CardGrid> </CardGrid>
## Quick Example ## Quick Example
@ -113,4 +113,14 @@ launch_flowgraph(
[Follow the tutorial →](/getting-started/first-flowgraph/) [Follow the tutorial →](/getting-started/first-flowgraph/)
</Card> </Card>
<Card title="Block Development" icon="seti:python">
Generate blocks, analyze protocols, export to OOT
[Start building →](/guides/block-development/)
</Card>
<Card title="OOT Modules" icon="add-document">
Install and combine Out-of-Tree modules
[Browse the catalog →](/guides/oot-modules/)
</Card>
</CardGrid> </CardGrid>

View File

@ -6,16 +6,20 @@ draft: false
import { CardGrid, Card, Aside } from '@astrojs/starlight/components'; import { CardGrid, Card, Aside } from '@astrojs/starlight/components';
GR-MCP exposes tools in two groups: **platform tools** (always available) for flowgraph GR-MCP exposes tools in three groups: **platform tools** (always available) for flowgraph
design, and **runtime tools** (loaded on demand) for container control. design, **block development tools** (loaded on demand) for code generation and protocol analysis,
and **runtime tools** (loaded on demand) for container control.
## Tool Organization ## Tool Organization
<CardGrid> <CardGrid>
<Card title="29 Platform Tools" icon="puzzle"> <Card title="34 Platform Tools" icon="puzzle">
Always available for flowgraph building, validation, and code generation. Always available for flowgraph building, validation, and code generation.
No Docker required. No Docker required.
</Card> </Card>
<Card title="~18 Block Dev Tools" icon="seti:python">
Loaded via `enable_block_dev_mode()`. Generate blocks, analyze protocols, export to OOT.
</Card>
<Card title="~40 Runtime Tools" icon="rocket"> <Card title="~40 Runtime Tools" icon="rocket">
Loaded via `enable_runtime_mode()`. Requires Docker for container features. Loaded via `enable_runtime_mode()`. Requires Docker for container features.
</Card> </Card>
@ -83,6 +87,61 @@ design, and **runtime tools** (loaded on demand) for container control.
| [`evaluate_expression`](/reference/tools/codegen#evaluate_expression) | Evaluate Python expression | | [`evaluate_expression`](/reference/tools/codegen#evaluate_expression) | Evaluate Python expression |
| [`create_embedded_python_block`](/reference/tools/codegen#create_embedded_python_block) | Create embedded Python block | | [`create_embedded_python_block`](/reference/tools/codegen#create_embedded_python_block) | Create embedded Python block |
## Block Development Tools (Enable with `enable_block_dev_mode()`)
<Aside>
Block dev tools provide code generation and protocol analysis. No Docker required
for generation — only `test_block_in_docker` needs Docker.
</Aside>
### Block Dev Mode Control
| Tool | Description |
|------|-------------|
| [`get_block_dev_mode`](/reference/tools/block-dev#get_block_dev_mode) | Check block dev mode status |
| [`enable_block_dev_mode`](/reference/tools/block-dev#enable_block_dev_mode) | Enable block dev tools |
| [`disable_block_dev_mode`](/reference/tools/block-dev#disable_block_dev_mode) | Disable block dev tools |
### Block Generation
| Tool | Description |
|------|-------------|
| [`generate_sync_block`](/reference/tools/block-dev#generate_sync_block) | Generate `gr.sync_block` from description |
| [`generate_basic_block`](/reference/tools/block-dev#generate_basic_block) | Generate `gr.basic_block` with custom forecast |
| [`generate_interp_block`](/reference/tools/block-dev#generate_interp_block) | Generate interpolation block |
| [`generate_decim_block`](/reference/tools/block-dev#generate_decim_block) | Generate decimation block |
| [`validate_block_code`](/reference/tools/block-dev#validate_block_code) | Validate syntax, imports, signatures |
| [`parse_block_prompt`](/reference/tools/block-dev#parse_block_prompt) | Parse natural language into block spec |
### Block Testing
| Tool | Description |
|------|-------------|
| [`test_block_in_docker`](/reference/tools/block-dev#test_block_in_docker) | Test block in isolated Docker container |
### Protocol Analysis
| Tool | Description |
|------|-------------|
| [`parse_protocol_spec`](/reference/tools/block-dev#parse_protocol_spec) | Parse protocol description into structured model |
| [`generate_decoder_chain`](/reference/tools/block-dev#generate_decoder_chain) | Generate multi-block decoder pipeline |
| [`get_missing_oot_modules`](/reference/tools/block-dev#get_missing_oot_modules) | Identify OOT modules needed for a protocol |
### Signal Analysis
| Tool | Description |
|------|-------------|
| [`analyze_iq_file`](/reference/tools/block-dev#analyze_iq_file) | Analyze IQ capture characteristics |
### OOT Export
| Tool | Description |
|------|-------------|
| [`generate_grc_yaml`](/reference/tools/block-dev#generate_grc_yaml) | Generate `.block.yml` for GRC integration |
| [`generate_oot_skeleton`](/reference/tools/block-dev#generate_oot_skeleton) | Generate gr_modtool-compatible OOT scaffold |
| [`export_block_to_oot`](/reference/tools/block-dev#export_block_to_oot) | Export block to full OOT module structure |
| [`export_from_flowgraph`](/reference/tools/block-dev#export_from_flowgraph) | Export embedded block from flowgraph to OOT |
## Runtime Tools (Enable with `enable_runtime_mode()`) ## Runtime Tools (Enable with `enable_runtime_mode()`)
<Aside> <Aside>
@ -163,9 +222,19 @@ won't be registered.
## MCP Resources ## MCP Resources
In addition to tools, GR-MCP exposes resources for OOT module discovery: In addition to tools, GR-MCP exposes resources for OOT module discovery and block development prompts:
| URI | Description | | URI | Description |
|-----|-------------| |-----|-------------|
| `oot://directory` | Index of all OOT modules in the catalog | | `oot://directory` | Index of all OOT modules in the catalog |
| `oot://directory/{name}` | Detailed info for a specific module | | `oot://directory/{name}` | Detailed info for a specific module |
### Block Development Prompts (available when block dev mode is enabled)
| URI | Description |
|-----|-------------|
| `prompts://block-generation/sync-block` | Patterns for `gr.sync_block` generation |
| `prompts://block-generation/basic-block` | Patterns for `gr.basic_block` generation |
| `prompts://block-generation/common-patterns` | Reusable block patterns and idioms |
| `prompts://block-generation/grc-yaml` | GRC YAML `.block.yml` format guide |
| `prompts://protocol-analysis/decoder-chain` | Decoder pipeline generation patterns |

View File

@ -0,0 +1,275 @@
---
title: Block Development Tools
description: Reference for block generation, protocol analysis, and OOT export tools
draft: false
---
import { Aside, Tabs, TabItem } from '@astrojs/starlight/components';
Block development tools are loaded dynamically via `enable_block_dev_mode()`. They provide
code generation, validation, protocol analysis, signal analysis, and OOT module export.
<Aside>
These tools register 5 MCP prompt resources for guiding code generation. Read them
via `prompts://block-generation/sync-block`, `prompts://block-generation/grc-yaml`, etc.
</Aside>
## Mode Control
### `get_block_dev_mode`
Check whether block development mode is enabled.
**Returns:** `BlockDevModeStatus` with `enabled`, `tools_registered`
### `enable_block_dev_mode`
Enable block development tools. Registers ~15 tools and 5 prompt resources.
**Returns:** `BlockDevModeStatus` with list of registered tools
### `disable_block_dev_mode`
Disable block development tools, removing them from the tool list.
**Returns:** `BlockDevModeStatus`
---
## Block Generation
### `generate_sync_block`
Generate a `gr.sync_block` from a natural language description. The 1:1 input-to-output
ratio makes this the most common block type.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name` | string | Yes | Block name (e.g., `"configurable_gain"`) |
| `description` | string | Yes | Natural language description of block behavior |
| `input_signature` | list | Yes | Input port specs: `[{"dtype": "float", "vlen": 1}]` |
| `output_signature` | list | Yes | Output port specs |
| `parameters` | list | No | Constructor params: `[{"name": "gain", "dtype": "float", "default": 1.0}]` |
| `work_logic` | string | No | Description of the work function logic |
**Returns:** `GeneratedBlockCode` with `source_code`, `is_valid`, `validation_errors`
### `generate_basic_block`
Generate a `gr.basic_block` with custom `forecast()` and `general_work()`. Use this
when input/output rates differ in non-trivial ways.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name` | string | Yes | Block name |
| `description` | string | Yes | Block behavior description |
| `input_signature` | list | Yes | Input port specs |
| `output_signature` | list | Yes | Output port specs |
| `parameters` | list | No | Constructor parameters |
| `forecast_logic` | string | No | How to predict input requirements |
| `work_logic` | string | No | Processing logic description |
**Returns:** `GeneratedBlockCode`
### `generate_interp_block`
Generate an interpolation block (`gr.interp_block`) that produces more output samples
than input samples.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name` | string | Yes | Block name |
| `description` | string | Yes | Block behavior description |
| `interpolation` | int | Yes | Interpolation factor |
| `input_signature` | list | Yes | Input port specs |
| `output_signature` | list | Yes | Output port specs |
| `parameters` | list | No | Constructor parameters |
**Returns:** `GeneratedBlockCode`
### `generate_decim_block`
Generate a decimation block (`gr.decim_block`) that produces fewer output samples
than input samples.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name` | string | Yes | Block name |
| `description` | string | Yes | Block behavior description |
| `decimation` | int | Yes | Decimation factor |
| `input_signature` | list | Yes | Input port specs |
| `output_signature` | list | Yes | Output port specs |
| `parameters` | list | No | Constructor parameters |
**Returns:** `GeneratedBlockCode`
---
## Validation
### `validate_block_code`
Validate generated block code without execution. Checks syntax (`ast.parse`), required
imports, class hierarchy, `work()` method signature, and I/O signature consistency.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `source_code` | string | Yes | Python source code to validate |
**Returns:** `ValidationResult` with `is_valid`, `errors`, `warnings`
### `parse_block_prompt`
Parse a natural language description into a structured block specification. Useful for
multi-step workflows where you want to review the spec before generating code.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `prompt` | string | Yes | Natural language block description |
**Returns:** Structured block specification with inferred name, I/O, parameters
---
## Block Testing
### `test_block_in_docker`
Test a generated block in an isolated Docker container. Creates a test harness flowgraph
with `vector_source` → block → `vector_sink`, runs it, and collects output.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `source_code` | string | Yes | Block source code |
| `test_input` | list | No | Input samples (e.g., `[1.0, 2.0, 3.0]`) |
| `parameters` | dict | No | Constructor args (e.g., `{"gain": 2.0}`) |
| `timeout` | int | No | Max execution time in seconds (default: 30) |
**Returns:** `DockerTestResult` with `success`, `output_data`, `errors`, `duration`
<Aside type="caution">
Requires Docker. The `gnuradio-runtime` base image must be built first.
</Aside>
---
## Protocol Analysis
### `parse_protocol_spec`
Parse a protocol description (natural language or structured) into a `ProtocolModel`.
Identifies modulation scheme, framing, encoding, and relevant parameters.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `spec` | string | Yes | Protocol description or specification |
**Returns:** `ProtocolModel` with `modulation`, `framing`, `encoding` details
### `generate_decoder_chain`
Generate a complete multi-block decoder pipeline from a protocol specification.
Selects existing GNU Radio blocks where possible, generates custom blocks for gaps.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `protocol` | string | Yes | Protocol name or specification |
| `sample_rate` | float | No | Target sample rate |
| `center_freq` | float | No | Center frequency |
**Returns:** `DecoderPipelineModel` with `blocks`, `connections`, and required OOT modules
### `get_missing_oot_modules`
Identify which OOT modules are needed for a protocol but aren't installed.
Cross-references the protocol's block requirements against the OOT catalog.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `protocol` | string | Yes | Protocol name |
**Returns:** List of missing module names with install instructions
---
## Signal Analysis
### `analyze_iq_file`
Analyze a captured IQ file to determine signal characteristics. Performs FFT analysis,
estimates bandwidth, detects signal presence, and estimates modulation parameters.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `file_path` | string | Yes | Path to IQ capture file |
| `sample_rate` | float | Yes | Sample rate of the capture |
| `dtype` | string | No | Data type (default: `"complex64"`) |
**Returns:** Analysis results including bandwidth, center frequency offset, SNR estimate
---
## OOT Export
### `generate_grc_yaml`
Generate a GRC block definition (`.block.yml`) file for a block. This is required for
blocks to appear in GNU Radio Companion's graphical editor.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `source_code` | string | Yes | Block Python source code |
| `block_name` | string | Yes | Block name |
| `module_name` | string | No | Module prefix (default: `"custom"`) |
| `inputs` | list | No | Input port specs |
| `outputs` | list | No | Output port specs |
| `parameters` | list | No | Block parameters with types and defaults |
| `category` | string | No | GRC palette category |
**Returns:** `GrcYamlResult` with `yaml_content`, `filename`, `block_id`, `notes`
<Aside type="tip">
The generated YAML includes `flags: [ python ]`, parameter dtype mapping (Python `float` →
GRC `real`), setter method detection for callbacks, and `asserts` from parameter min/max values.
</Aside>
### `generate_oot_skeleton`
Generate a gr_modtool-compatible Out-of-Tree module skeleton with `CMakeLists.txt`,
Python package structure, and `grc/` directory.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `module_name` | string | Yes | Module name (e.g., `"custom"`, not `"gr-custom"`) |
| `output_dir` | string | Yes | Where to create the module directory |
| `author` | string | No | Module author name |
**Returns:** `OOTSkeletonResult` with `success`, `module_name`, `path`
### `export_block_to_oot`
Export a generated block into a full OOT module structure. Creates the Python source file,
GRC YAML block definition, and updates `__init__.py`. Creates the OOT skeleton if it
doesn't exist.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `source_code` | string | Yes | Block source code |
| `block_name` | string | Yes | Block name |
| `module_name` | string | Yes | Target OOT module name |
| `output_dir` | string | Yes | OOT module root directory |
**Returns:** `ExportResult` with `success`, file paths created
### `export_from_flowgraph`
Export an embedded Python block from the current flowgraph into an OOT module.
Extracts the block's source code and metadata, then calls `export_block_to_oot`.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `block_id` | string | Yes | Block ID in the flowgraph (e.g., `"epy_block_0"`) |
| `module_name` | string | Yes | Target OOT module name |
| `output_dir` | string | Yes | OOT module root directory |
**Returns:** `ExportResult`