An MCP server for controlling the fldigi digital-modem application over XML-RPC.
fldigi-mcp uses a grouped-tool pattern with operation parameters rather than verb_noun naming. While this reduces tool count, it obscures intent: 'modem' with operation='set' is less discoverable than 'set_modem'. Descriptions are present (avg ~150 chars) but lack actionable guidance on when to use each operation. Schemas are visible but incomplete: most tools accept generic 'value' or 'operation' params with minimal type constraints. No output schemas documented. Error handling is minimal, no recovery guidance or categorization. Security: transmit gate via callsign is good, but no audit logging or rate limiting visible.
The fldigi program and its process. Info operations: version, version_struct, name, name_version, config_dir, list_methods. Process operations: launch, stop, terminate, is_running. `launch` starts fldigi pointed at the configured XML-RPC endpoint; `stop`/`terminate` ask it to quit (saving options; optionally the log/macros) and fall back to ending a process this server started.
fldigi operating controls (the AFC / SQL / Rev / Lock / RxID / TxID buttons) and status. operations: get/set/toggle_afc, get/set/toggle_squelch (SQL), get/set/inc_squelch_level, get/set/toggle_reverse (Rev), get/set/toggle_lock (Lock), get/set/toggle_rxid (RxID), get/set/toggle_txid (TxID), get_status1, get_status2, get_trx_status, get_trx_state.
Host + network diagnostics for troubleshooting connectivity. Does NOT connect to fldigi. Reports the resolved FLDIGI_HOST/PORT, this process's Python and hostname, the transmit-gate state, and the host's network interfaces — so you can tell whether the process can even see the target's network (e.g. when running host-side vs. sandboxed). If a non-loopback host times out, see mcp-host-bridge (docs/INSTALL.md).
Escape hatch: call any fldigi XML-RPC method by dotted name. Requires a callsign for keying methods (main.tx, main.tune, main.run_macro, wefax.send_file, navtex.send_message). Use sparingly; prefer the grouped tools above.
Grouped-tool anti-pattern: 16 tools use generic 'operation' parameter instead of verb_noun naming (e.g., 'modem' with operation='set' vs. 'set_modem'). LLMs cannot infer intent from tool name alone; discovery requires reading full descriptions for each operation variant.
No output schemas documented. Tools return dicts but LLMs cannot plan downstream calls without knowing field names, types, and availability. E.g., 'status' returns 'band' conditionally (if _bandplan is not None), undocumented optional fields cause parsing errors.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | F | 45 | 2026-07-28+ | v2 |
RF frequency and waterfall sideband. operations: get, set (value=Hz), increment (value=Hz), get_sideband, set_sideband (value='USB'|'LSB').
Signal hunt: analyse receiver audio to find and name signals. Tap live audio from the input device (optional extra fldigi-mcp[hunt]: numpy + sounddevice) or read a WAV file. Returns ranked list of signals with mode, carrier, strength, persistence, and periodicity. Requires numpy; sounddevice for live tap.
List audio input devices available for signal hunt live tap. Returns device name, index, and default sample rate.
Logbook and QSO logging. operations: clear, last_record, all_records, get_record (value=index), add_record (value=dict), delete_record (value=index).
Operating mode (the fldigi "Op Mode" menu) and modem settings. operations: get, list, get_id, get_max_id, set (value=mode name e.g. 'BPSK31'), set_by_id (value=id), get_io_names (modems usable for KISS/ARQ I/O), get/set/inc_carrier, get/set/inc_afc_range, get/set/inc_bandwidth, get_quality, search_up, search_down, olivia_get/set_bandwidth, olivia_get/set_tones.
NAVTEX (maritime safety information) reception and transmission. operations: state, send_message (value=message text).
Rig (CAT) control via hamlib. operations: get_name, set_name, get_frequency, set_frequency, get_mode, set_mode, get_modes, set_modes, get_bandwidth, set_bandwidth, get_bandwidths, set_bandwidths, get_notch, set_notch, enable_qsy, set_smeter, set_pwrmeter.
Spotting and reporting. operations: get_auto, set_auto, toggle_auto, pskrep_count.
Snapshot: version, modem, frequency (Hz), TX/RX state, transmit gate, region, band.
Received and outgoing text. operations: rx_length, get_rx (value=[start, length]), clear_rx, add_tx, add_tx_queue, add_tx_bytes, clear_tx, get_rxtx_data, get_rx_data, get_tx_data.
Transmitter control. operations: tx, tune, rx, abort, disable_tx, enable_tx, run_macro (value=id), get_max_macro_id, send (text=...), and timing information: tx_timing (value=test string), char_rates, char_timing (value=one character); both timings return 'samples : sample rate : seconds'. Keying operations (tx, tune, run_macro, send) require a configured callsign; rx, abort, disable_tx and the timing operations never key and are always allowed. `send` queues text and transmits, auto-returning to receive by default.
WEFAX (weather facsimile) reception and transmission. operations: state, skip_apt, skip_phasing, send_file (value=path).
Generic parameter schemas: 'value' param in 10+ tools lacks type constraints. Accepts 'number|string' but no enum, pattern, or range. LLMs cannot validate input before calling; errors occur at runtime with no recovery guidance.
No error handling guidance. TransmitNotAllowed exception exists but no recovery hint in tool descriptions. LLMs see 'No callsign configured' but don't know to check 'status' or 'diagnostics' first, or how to configure one.
No audit logging or rate limiting visible. Transmit operations (keying, sending) are gated by callsign but no trace of who called what, when, or with what parameters. Compliance and incident response are blind.