Skip to content

MCP Server

The Birdcage MCP server (mcbirdcage) exposes the full dish control surface as MCP tools, resources, and prompts. Any MCP-compatible client — Claude Code, Claude Desktop, a custom agent, anything that speaks the protocol — can connect a serial port, slew motors, measure signal strength, query orbital catalogs, and read firmware registers. Demo mode works without hardware.

The same device layer that backs the TUI backs the MCP server. The difference is who’s driving: a person pressing arrow keys, or a language model calling move_to(azimuth=180, elevation=45).

Terminal window
# Demo mode — no hardware, no serial port
BIRDCAGE_DEMO=true uvx mcbirdcage
# Add to Claude Code
claude mcp add mcbirdcage -- uvx mcbirdcage
# With hardware
BIRDCAGE_PORT=/dev/ttyUSB0 uvx mcbirdcage
VariableDefaultDescription
BIRDCAGE_DEMOfalseSet true to use DemoDevice (simulated motors, RSSI, full NVS table)
BIRDCAGE_PORT/dev/ttyUSB0Serial port path for hardware mode
BIRDCAGE_FIRMWAREg2Firmware variant: g2, hal205, or hal000
BIRDCAGE_CRAFT_URLhttps://space.warehack.ingOrbital catalog API endpoint

36 tools across 6 modules. Every tool that touches hardware requires a prior connect call (or demo mode).

ToolParametersDescription
connectport? firmware? skip_init?Open serial port, optionally run firmware init sequence
disconnectClose serial port, return to root menu
statusConnection state, port, firmware variant, current menu
ToolParametersDescription
get_positionCurrent AZ/EL in degrees
move_toazimuth elevationMove both axes to absolute position (AZ 0-455, EL 18-65 for G2)
move_motormotor_id degreesMove single axis (0=AZ, 1=EL) to absolute angle
home_motormotor_idStall-detect homing to reference position (audible grinding)
engage_motorsEnergize steppers (apply holding torque)
release_motorsDe-energize steppers (dish free under wind/gravity)
stowMove to AZ=0, EL=65 (transport-safe with stock feed)
get_step_positionsRaw step counts (G2: 40000 steps/rev AZ, 24960 EL)
get_el_limitsFirmware EL limits: min, max, home (degrees)
ToolParametersDescription
get_rssiiterations? (default 10)Averaged DVB tuner RSSI (noise floor ~500)
get_adc_rssiSingle-shot raw ADC count (bypasses DVB averaging)
get_lock_statusDVB signal lock, RSSI, glitch count
enable_lnaSet LNB to 13V / V-pol (powers LNA for radio work)
set_lnb_voltagemode (odu or stb)13V/V-pol (odu) or 18V/H-pol (stb). Boot default is 18V.
get_dvb_configBCM4515 chip ID, revision, firmware version
get_channel_paramsFrequency, symbol rate, modulation, LNB polarity
az_sweepstart_az span step_cdeg? num_xponders? timeout?Firmware-accelerated AZ sweep (azscanwxp). Returns per-point RSSI/lock/SNR. Requires homed motors.
ToolParametersDescription
get_firmware_idFull MCU/firmware ID: version, silicon, board, clock, flash layout
get_motor_dynamicsMax velocity and acceleration for both axes
set_max_velocitymotor_id deg_per_secSet motor max velocity (G2 defaults: AZ=65, EL=45 deg/s)
set_max_accelerationmotor_id accelSet motor max acceleration (G2 default: 400 deg/s^2)
get_motor_lifeLifetime stats: total moves, degrees traveled, uptime hours
get_pid_gainsPID gains for both axes (Kp, Kv, Ki)
set_pid_gainsmotor_id kp kv kiSet PID gains. Bad values cause oscillation or motor damage.
get_a3981_diagAllegro A3981 stepper driver fault status (OK or FAULT per axis)
get_a3981_modesStep mode (AUTO/fixed), current mode, step size per driver
nvs_dumpFull 134-entry NVS table: name, current, saved, default
nvs_readindexSingle NVS value (key indices: 20=tracker, 80=AZ vel, 101=min EL)

Satellite tools use the Craft API for orbital predictions. The API computes AZ/EL server-side from TLE data — no local propagation needed.

ToolParametersDescription
search_satellitesquery limit?Search catalog by name (“ISS”, “NOAA”, “Moon”). Returns NORAD ID, type, group.
get_passesnorad_id hours?Upcoming passes: AOS/TCA/LOS times, max EL, duration
get_next_passnorad_idSingle soonest pass prediction
get_visible_targetsmin_alt?All objects currently above horizon with live AZ/EL
ToolParametersDescription
send_raw_commandcommandSend arbitrary firmware command, return raw response. The q command is blocked (kills UART shell, requires power cycle).

Five read-only MCP resources provide live dish state without tool calls. Clients can subscribe to these for continuous monitoring.

URIDescription
birdcage://configConnection config: demo mode, port, firmware variant, connected flag
birdcage://positionLive AZ/EL (queries hardware on each read)
birdcage://firmwareFirmware identification string
birdcage://motor-dynamicsMax velocity and acceleration for both axes
birdcage://el-limitsElevation min/max/home in degrees

Three guided workflows that walk an LLM through multi-step operations. Call them to get a structured plan with tool names and sequencing.

PromptWorkflow
setup_wizardConnect to serial port, verify firmware, home both motors, confirm position and EL limits
satellite_tracking_guideSearch catalog, get passes, wait for AOS, poll get_visible_targets + move_to at 1 Hz
rf_sweep_guideEnable LNA, baseline RSSI, configure and run az_sweep, analyze peaks above noise floor

These are things an LLM can do with the tool set — not scripts to execute, but descriptions of how the tools compose.

Search the catalog for “ISS”. The result includes NORAD ID 25544. Call get_passes with that ID to see upcoming passes — pick one with max elevation above 30 degrees for a decent arc. When the AOS time arrives, start a loop: call get_visible_targets to get the ISS’s current AZ/EL (computed server-side from fresh TLEs), then move_to with those coordinates. Repeat every second. The firmware queues motor commands, so the dish follows the arc smoothly even if individual moves are still in progress. Stop when the satellite drops below the dish’s minimum elevation (18 degrees on the G2). The whole sequence is about 5-10 minutes for a typical LEO pass.

Enable the LNA with enable_lna (switches LNB from 18V boot default to 13V / V-pol). Call get_rssi to read the noise floor — should be around 500 ADC counts with no signal present. Move the dish to a starting position with move_to(0, 30). Run az_sweep with a wide span (e.g., 180 degrees, 100 centidegree steps, 1 transponder). The firmware handles the sweep natively — no serial round-trips per point. Repeat at EL 35, 40, 45, … up to 60, using move_motor(1, el) between sweeps. The result is a 2D grid of RSSI values mapped to AZ/EL coordinates. Peaks above the noise floor correspond to geostationary satellites, terrestrial interference, or (at Ku-band) the Sun.

Call get_firmware_id for the full MCU identification — version 02.02.48, NXP K60 at 96 MHz, 512 KB flash. Call get_a3981_diag to confirm both stepper drivers report OK. Call nvs_dump for the complete 134-entry non-volatile storage table, then spot-check critical values: NVS 20 (tracker disabled), NVS 80-81 (motor velocity/acceleration), NVS 101-102 (elevation limits). For anything not covered by a dedicated tool, drop to send_raw_command — enter a submenu with mot or dvb, issue the command, and read the raw response.