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.
Two 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 |
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.
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. MIT licensed, like the servers it documents. GL es 73 de AE5VG sk.