A field guide to the operating skills bundled with fldigi-mcp and n3fjp-mcp — how an agent keys the transmitter and returns to receive at the exact instant an over ends, runs a contest QSO from CQ to logged contact, and survives everything a real band throws at it. Every rule in this guide was proven on the air.
Three skills, one operating system. Each in one view — what it governs, and what you get. One full page per skill inside.
| # | Skill | Ships with | What it governs | What you get |
|---|---|---|---|---|
| 01 | fldigi-operating | fldigi-mcp | The radio: keying the transmitter, returning to receive the instant an over ends, and polling the RX stream so no caller is missed. | Instant TX→RX handoff + a caller never ignored |
| 02 | contest-operating | n3fjp-mcp | The contest: the QSO state machine from CQ to logged contact, the special-case playbook, and verified N3FJP logging. | Completed exchanges + a clean, duplicate-free log |
| 03 | signal-hunting | fldigi-mcp | The band: naming each signal's mode from the audio, ranking the station that sits still and calls CQ, tuning to it, and reading fldigi's Signal Browser where the proposed browser.* patch is present. | The right station found, named and tuned before you call |
You don't invoke these skills by name — the agent does, when you say things like “call CQ on 20 meters” or “run the Field Day loop.” The skills are the agent's operating procedures. This guide is for the human at the station: what the agent will do on your behalf, and how to verify it is doing it right.
Each skill ships inside its MCP package — install the server, and the skill travels with it. Nothing is configured separately.
fldigi-mcp.mcpb and n3fjp-mcp.mcpb (or add them
under Settings → Extensions). Each bundle carries its skill at
skills/<name>/SKILL.md plus this guide.~/.claude/skills/ (or a project's
.claude/skills/): skills/fldigi-operating/ and
skills/contest-operating/.uvx fldigi-mcp, uvx n3fjp-mcp or from the repos) so the tools
the skills reference are available.diagnostics tool tells you whether it's a network
problem before you blame fldigi.fldigi's XML-RPC default port is 7362. A different configured port (e.g. 7372)
usually means a localhost→remote forwarder such as mcp-host-bridge is intended —
check FLDIGI_PORT before concluding fldigi is down.
You do not need to know anything about AI to run this station. If you can install fldigi and type a sentence, you can operate. This chapter is the whole learning curve.
Claude is an assistant made by Anthropic. It runs in an ordinary desktop program — the Claude Desktop app (Windows or Mac), which looks like a messaging window: you type at the bottom, answers appear above. The two MCP servers in this project are best thought of as rig-interface cables: one plugs Claude into fldigi, the other into N3FJP. You type plain English; Claude works the programs. Nothing about your fldigi or N3FJP setup changes — they run exactly as they always have.
claude.ai/download, install like any program, and sign in
(create the account on the same page). A paid plan is recommended — the free tier can run
out of messages mid-QSO.fldigi-mcp.mcpb, click Install when Claude Desktop opens, and
enter your callsign when asked — that callsign is the transmit gate. Repeat with
n3fjp-mcp.mcpb. Done — this is a one-time step.There are no commands to memorize and no syntax to get wrong. You type what you would tell a competent operator sitting at your rig:
| You type | What happens |
|---|---|
| What's the fldigi status? | Mode, frequency, T/R, and callsign gate — your pre-flight check. |
| Set the rig to 14.070 USB and BPSK31. | Claude QSYs the rig and sets the modem. |
| Call CQ Field Day until someone answers. Work them — our exchange is 2A STX — log the contact to N3FJP, then keep calling. | The full loop in this guide: CQ, listen, exchange, TU, log, repeat. Claude narrates each QSO as it happens. |
| stop | Transmission stops immediately and the radio returns to receive. Works at any moment, mid-over included. |
Claude operates; you hold the license. Part 97 responsibility — supervision, station identification, staying in the band — remains yours, exactly as if a guest operator sat at your key. Stay at the station while it transmits. Two safeguards are built in: with no callsign configured the station physically cannot key up, and “stop” always works.
Run your first full session into a dummy load: “call CQ and work whoever comes back”, watch one complete cycle — TX drop, listen window, log entry — then connect the antenna. If anything misbehaves, type “run the fldigi diagnostics” and read the answer; it distinguishes a network problem from an fldigi problem.
A QSO is a loop with four states. fldigi-operating governs the radio in every state; contest-operating decides what to say and when to log.
^r handoff is not optional.transmit → abort drops PTT immediately and discards queued text. The
callsign gate means an unconfigured station cannot transmit at all.Run it on a live band, not a tour. Put fldigi on a dummy load, say “call CQ and work whoever comes back,” and watch one full cycle — TX drop, listen window, log entry — before you connect the antenna.
Six rules, inherited by both skills. Every one of them exists because we broke it once — on the air, at Field Day 2026.
^r
(via transmit → send) and fldigi drops to receive at the exact sample the last
character finishes. Polling always lags; the lag is transmitted on top of your caller.logged: true, nothing else.
N3FJP's ENTERRESPONSE can report 0 for a QSO that was written (networked mode commits
asynchronously). Blind retries on records_added: 0 produced duplicate log
records. Retry only when logged is false.2A 2A STX STX, callsign twice on CQ, and echo the other station's exchange back
in your TU so they can verify what you logged before you QRZ.These skills were built by running one real autonomous Field Day session and keeping the
after-action report — the full account is in
n3fjp-mcp/docs/LESSONS-FIELD-DAY-2026.md, and the worked examples in chapter F
retell it verbatim.
Governs the radio: transmit, hand off to receive, listen properly.
transmit → send "<over text>\n" (return_to_rx=true, the default)
One call: clears the TX buffer, appends ^r, keys the radio. End messages with a
real newline (\n) — the two-character string ^n transmits literally.
If building an over incrementally with text → add_tx, the last fragment must end
in ^r, with nothing added after it.
| Operation | Behavior | Use for |
|---|---|---|
| ^r via transmit → send | Graceful auto-return the moment the over ends | Every normal over |
| transmit → abort | Immediate stop, discards queued text | Panic button — caller back early, wrong message, operator says stop |
| transmit → rx | Returns to RX only after the buffer drains | Almost never — slow, and not the stop button |
text → rx_length for the end position, then
text → read from your last position. Save the new position.rx_length smaller than your last position means
fldigi restarted — re-baseline and continue.get_trx_status returns "rx", listen
~10 seconds (1–2 polls) before the next CQ. PSK31 operators type slowly.[A-Z0-9]{1,3}[0-9][A-Z]{1,3} before any
directed reply — QRM garbage looks call-ish.loop: transmit → send "CQ CQ de <MYCALL> <MYCALL> pse k\n" poll controls → get_trx_status until "rx" listen ~10 s (1–2 polls of text → rx_length) if plausible callsign in new RX text → work the station else → loop
Governs the contest: what to say in each state, when a QSO is real, and when it goes in the log.
2A 2A STX STX copies far better than
2A STX through QSB and QRM.QSL 1D AZ TU W7XYZ …) — the other
station verifies you logged them correctly before you QRZ.log → log_qso {"call": "W7XYZ", "contest": "field_day",
"exchange": {"class": "1D", "section": "AZ"}}
Exchange fields go in the exchange dict — they are not top-level
parameters. Success is logged: true in the response; chapter G has the full
protocol and its quirks.
Never retry on records_added: 0 alone — that value can be 0 for a QSO that
was written. Retry only when logged is false. Blind retries are where duplicate
log records come from.
Finds a station worth working the way an operator reads the waterfall: name what is there, rank the one that sits still and calls CQ, tune to it, confirm in twenty seconds.
fldigi's XML-RPC exposes no spectrum, so signal_hunt taps the audio fldigi is listening to
(the Audio input device setting names it) and returns ranked candidates. It
needs the optional extra fldigi-mcp[hunt], numpy and sounddevice. Each candidate is where
the cursor goes, what modem to run, and why it ranks where it does.
| Field | Meaning |
|---|---|
| carrier_hz | The audio carrier: where the waterfall cursor goes. fldigi's Freq is dial + carrier. |
| mode, fldigi_modem | RTTY with its shift, CW, BPSK31/63/125, Olivia with tones and bandwidth (OLIVIA-8/250), MFSK16, DominoEX, MT63, or unknown. |
| db_over_floor | Strength, from a max-hold spectrum so a station that transmits for part of the window still shows at full strength. |
| persistence | Fraction of the window the signal was present at that carrier. A CQ loop is near 1; the other side of a QSO comes and goes. |
| periodicity | How strongly the on/off pattern repeats at lags of 8 to 60 seconds. A CQ loop repeats; a QSO in progress does not. |
| score | Strength weighted by persistence and periodicity. The CQing station wins. |
The browser tool and signal_hunt method="browser" call two XML-RPC methods
that stock fldigi does not have: browser.get_channels (one struct per channel:
channel, freq, active, text) and browser.clear. They come from a
four-file patch offered to Dave W1HKJ on 11 September 2026 (w1hkj/fldigi issue 55) and shipped in
fldigi-mcp under patches/. Until he merges it, the names and fields are a
proposal and may change. On an unpatched fldigi both calls answer with a hint and nothing else in this
chapter changes.
fldigi's own Signal Browser, the left-hand panel, is a bank of thirty demodulators with DCD; it copies
PSK, RTTY and CW stations too faint for any spectrum to rank. On a build that carries the patch,
browser channels or signal_hunt method="browser" returns every channel with its
carrier and the text already copied, line breaks kept: the confirm step is done before you tune. Four
synthetic PSK31 stations from 0 to −26 dB: all four copied in full. The browser names no mode; hunt the
audio first when the band's mode is unknown. Building it yourself is three lines, in the README.
The rsid tool calls rsid.get_hits and rsid.clear, from a second
four-file patch offered to Dave W1HKJ on 16 September 2026 (w1hkj/fldigi issue 55) and shipped in
fldigi-mcp under patches/, on top of the browser patch. Until it is merged the
names and fields are a proposal. On an unpatched fldigi the tool answers with a hint and nothing else in
this chapter changes.
Naming a mode from its shape is guesswork for the hopping modes: Olivia and Contestia share a grid, so do
THOR and DominoEX. Most operators on those modes send an RSID burst at the start of an over, and fldigi's
detector hears it across the whole passband. Set RxID to notify only and the
detector reports the mode without switching the modem, so the pass you are running keeps its browser.
rsid hits then gives {utc, mode, hz} for every burst: the mode name
is exactly what tune_to takes, and the frequency is where the cursor goes. Ask the band before
you guess at it, especially when the analyser says unknown on a strong signal.
From the signal's shape, the way you would from the waterfall, with the numbers checked against the Signal Identification Wiki. Two narrow lines a standard shift apart (170 Hz in amateur use) is RTTY, carrier at the midpoint. One 30 Hz line is PSK31, unless it is keyed on and off with gaps of 40 ms or more, which makes it CW. The hopping modes show as a grid of discrete dots when you look at where the energy is from one 30 ms frame to the next: Olivia, with tones = bandwidth / spacing; MFSK16, 16 tones at 15.6 Hz; DominoEX and THOR, 18 tones. MT63 is a flat continuous block. Contestia looks like Olivia and THOR like DominoEX; only RSID separates those.
signal_hunt seconds=20 (contest: mode="RTTY", seconds=40) read candidates highest score first tune_to carrier_hz, fldigi_modem (RxID off during a classified pass) wait 20 s, then text → read if CQ and a callsign-shaped token, twice → hand to fldigi-operating elif modem → get_quality below 30 → next candidate else a QSO in progress → wait for SK or 73
Verified on five recordings of known mode, PSK31, CW, RTTY at 170 and 450 Hz, Olivia 8/250: 5 of 5.
A small set; treat unknown as honest. Symbol rate is not measured yet, which is what would
separate Contestia from Olivia without RSID. Without audio access the tool falls back to stepping
fldigi's own search_up and reading get_quality: slow, and blind to mode.
Receive only; nothing in this skill keys the transmitter.
All seven encountered live at Field Day 2026 — none of them hypothetical.
| Situation | What the agent does |
|---|---|
| Callsign only, no exchange | Normal. Send your exchange; theirs arrives in the next over. |
| Exchange arrives with the first call | Also normal (K6ABC de W7XYZ 1D AZ 1D AZ pse k). Send yours; they QSL; straight to TU. |
| “No copy” / “repeat” | Resend once, abbreviated: <CALL> de <MYCALL> · 2A STX 2A STX · BK. Still nothing → QRZ once, then CQ. |
| Garbled / partial callsign | de <MYCALL> AGN AGN pse k, one listen window. Still unreadable → CQ. Two overs maximum. |
| Two stations doubled | Interleaved callsigns and control garbage. One AGN, then CQ — usually one calls again alone. |
| Another station CQing on frequency | PSK's narrow passband decodes neighbors. CQ … de <OTHERCALL> is not a caller — ignore and continue. |
| Signal lost mid-QSO | Exchange never completed → do not log. An incomplete QSO is not a contact. |
Modal dialogs on the logging PC block the entire N3FJP API. If logging calls stop responding mid-contest, a dialog is open and needs human attention — nothing the agent can clear remotely.
Three real QSOs from the session log, 14.070 MHz BPSK31 — transcribed as decoded, garble included. All callsigns are anonymized (ARRL-style sample calls) out of respect for the stations worked; the exchanges, flow, and garble are verbatim.
The verified protocol, and every quirk we hit on the air.
log → log_qso {"call": "W7XYZ", "contest": "field_day",
"exchange": {"class": "1D", "section": "AZ"}}
log → set_many {"CALL": "W7XYZ", "CLASS": "1D", "SECTION": "AZ"} log → enter
Both paths return a logged boolean derived from the QSO-count delta and/or an
ENTEREVENT push. records_added can report 0 for a QSO that was
written — N3FJP networked (master-table) mode commits asynchronously. Retry only when
logged is false.
set_many → calltab can trigger an ENTEREVENT directly (the band/mode/dupe
check fires on callsign entry). If it does, the QSO is logged — do not send another
enter.calltab also populates COUNTRY/STATE/section lookups — useful for checking
that the section you copied is plausible for the callsign.CALLTABDUPEEVENT means the call is already in the log for this band/mode —
usually a sign you (or a retry) already logged it.exchange dict of log_qso — passing
them as top-level parameters silently logs nothing.These skills were not designed on paper. They are the distillate of one real autonomous contest session.
At ARRL Field Day 2026, a class-2A club station ran 20-meter
BPSK31 with an agent operating fldigi and N3FJP through fldigi-mcp and
n3fjp-mcp — calling CQ, working callers, and logging contacts, with the human
operator supervising and able to stop transmission at any moment. Every rule, timing, and
special case in this guide comes from that session's after-action report,
n3fjp-mcp/docs/LESSONS-FIELD-DAY-2026.md.
| Resource | Where |
|---|---|
| fldigi-mcp | github.com/sbrunner-atx/fldigi-mcp · PyPI: fldigi-mcp |
| n3fjp-mcp | github.com/sbrunner-atx/n3fjp-mcp · PyPI: n3fjp-mcp |
| Skill sources | <repo>/skills/<name>/SKILL.md |
| This guide's sources | <repo>/docs/brand/ (HTML + CSS, WeasyPrint) |
| After-action report | n3fjp-mcp/docs/LESSONS-FIELD-DAY-2026.md |
Corrections and additions are welcome — open an issue on either repository.
This is private, personal work by Stefan Brunner, AE5VG — built for amateur radio operators. Not affiliated with fldigi, N3FJP, or any employer. GPL-3.0-or-later, like fldigi itself. GL es 73 de AE5VG sk.