Runtime Control
Once a flowgraph is running, you can read and modify variables, control execution, and monitor status through XML-RPC. This enables real-time tuning without restarting.
How It Works
Generated flowgraphs expose variables through an XML-RPC server:
┌─────────────────────────────┐ XML-RPC (HTTP) ┌─────────────────┐│ GR-MCP │ ←─────────────────────→ │ Flowgraph ││ (MCP Server) │ get_freq() │ (Python) ││ │ set_freq(101.1e6) │ │└─────────────────────────────┘ └─────────────────┘The flowgraph’s variables become get_X() and set_X() methods automatically.
Prerequisites
Your flowgraph must include an XML-RPC server block, or be launched via GR-MCP’s
launch_flowgraph() which configures this automatically.
Connect to a Flowgraph
# Most common: connect to a GR-MCP containerconnect_to_container(name="fm-radio")# Direct connection to any XML-RPC endpointconnect(url="http://localhost:8080")Both methods return ConnectionInfoModel with endpoint details.
Variable Operations
List Variables
list_variables()# Returns: [# VariableModel(name="freq", value=101100000.0, type="float"),# VariableModel(name="gain", value=40, type="int"),# VariableModel(name="samp_rate", value=2000000.0, type="float"),# ]Get a Variable
get_variable(name="freq")Set a Variable
set_variable(name="freq", value=98.5e6)# Returns: TrueThread-Safe Updates
For multiple parameter changes:
# Pause signal processinglock()
# Make changes (no audio during this)set_variable(name="freq", value=102.7e6)set_variable(name="gain", value=35)set_variable(name="bandwidth", value=200e3)
# Resume processingunlock()The flowgraph buffers input during the lock and processes it on unlock.
Execution Control
# Stop the flowgraph (tb.stop())stop()
# Restart the flowgraph (tb.start())start()Check Connection Status
get_status()# Returns RuntimeStatusModel:# connected: True# connection: ConnectionInfoModel(url="http://localhost:8080", ...)# containers: [ContainerModel(...), ...]Disconnect
disconnect()# Closes XML-RPC connection (and ControlPort if active)Example: FM Band Scanner
#!/usr/bin/env python3"""Scan FM broadcast band and measure signal strength."""
import asyncioimport timefrom fastmcp import Client
FM_STATIONS = [88.1, 90.3, 94.7, 98.5, 101.1, 103.5, 107.9]
async def scan_fm_band(): async with Client("gr-mcp") as client: await client.call_tool("enable_runtime_mode", {})
# Launch with a signal strength indicator await client.call_tool("launch_flowgraph", { "flowgraph_path": "/tmp/fm_scanner.py", "name": "fm-scanner", "xmlrpc_port": 8080 })
time.sleep(3) await client.call_tool("connect_to_container", {"name": "fm-scanner"})
# Scan each station results = [] for freq_mhz in FM_STATIONS: await client.call_tool("set_variable", { "name": "freq", "value": freq_mhz * 1e6 }) time.sleep(0.5) # Allow settling
# Read signal level (if flowgraph exposes it) try: level = await client.call_tool("get_variable", {"name": "signal_level"}) results.append((freq_mhz, level.data)) except Exception: results.append((freq_mhz, None))
# Report findings for freq, level in results: status = f"{level:.1f} dB" if level else "no signal" print(f"{freq:.1f} MHz: {status}")
# Cleanup await client.call_tool("stop_flowgraph", {"name": "fm-scanner"}) await client.call_tool("remove_flowgraph", {"name": "fm-scanner"})
if __name__ == "__main__": asyncio.run(scan_fm_band())Error Handling
Common errors and solutions:
| Error | Cause | Solution |
|---|---|---|
| ”Not connected” | No active XML-RPC connection | Call connect() or connect_to_container() |
| ”Unknown variable” | Variable not exposed via XML-RPC | Check flowgraph has XML-RPC block with callback vars |
| ”Connection refused” | Container not running / wrong port | Verify with list_containers(), get_status() |
| ”Timeout” | Flowgraph unresponsive | Check logs with get_container_logs() |
Next Steps
- ControlPort Monitoring — Advanced monitoring with performance counters
- Code Coverage — Collect coverage from runtime tests