What it does
fldigi-mcp operates the radio, and n3fjp-mcp logs the contacts. The log_qso operation goes through the same steps you would take at the keyboard. It sets the call and fires CALLTAB, which runs the dupe check and looks up any previous contact. Then it fills in the exchange, sends ENTER, and reports how many records were added and any dupe details. To decide whether the QSO was logged, it watches for the QSO count to change or for an ENTEREVENT. It does not rely on ENTERRESPONSE, which can report 0 for a QSO that was written.
The server talks to N3FJP through Python's standard socket library, with no third-party wrapper. Its only runtime dependency is the MCP SDK. It has been verified live against N3FJP's ARRL Field Day Contest Log, API version 2.2. Every program in the suite uses the same protocol, but each contest has its own set of fields. The fields tool shows which fields the running program uses.
n3fjp-mcp is an independent, community project by Stefan Brunner (AE5VG), using the N3FJP name with the permission of its owner. It is not affiliated with, endorsed by, or supported by N3FJP Software / Affirmatech. Please direct all support questions for this app to its issue tracker, not to N3FJP. MIT licensed. "N3FJP" is the callsign and trademark of its owner.
Features and benefits
| Feature | What it gives you |
|---|---|
| Logging with log_qso | One operation runs the keyboard sequence that was verified against N3FJP: set the call, CALLTAB, exchange, ENTER. It returns N3FJP's dupe response. It also returns a logged flag, set from the QSO count changing or from an ENTEREVENT. ENTERRESPONSE is not used for this, because it can report 0 for a QSO that was written. Clients retry only when logged is false. |
| Call lookup from CALLTAB | After CALLTAB, N3FJP sends back a CALLTABEVENT with country, DXCC, zones, bearing and distance. n3fjp-mcp passes that on to you, and tells you if the call is a dupe. |
| What the tools cover | Read queries, reading and writing fields, search and list, dupe and entity checks, band, mode and frequency, direct database operations, and push notifications that you turn on if you want them. They are grouped into tools, and each tool is one permission. For less common commands, and for commands N3FJP adds later, there is the n3fjp_call escape hatch. |
| Per-contest exchange presets | log_qso takes a contest and its exchange, for example contest="field_day" with class and section. Each contest has its own fields. The fields tool shows which ones the running program uses. |
| Read tools marked read-only | Your client can set status, query, fields and search to Always Allow. |
| Writes need approval | Logging, band and mode, notifications, adding, editing or deleting single records, and the escape hatch are all set to Needs Approval. The server adds no confirmation step of its own, so you can set them to Always Allow for hands-off automation. |
| Switch for wiping the database | This is the only hard block. Raw SQL that could delete or overwrite the whole log (DROP, TRUNCATE, a DELETE or UPDATE with no WHERE) is refused unless the N3FJP_ALLOW_DB_WIPE switch is on. That switch is used for nothing else, and it is off by default. Operations limited to specific records run without it. |
| Names match N3FJP | Tools and fields use N3FJP's own terms: Action ENTER, CALLTAB, the TXTENTRY boxes, Class and Section. |
| Dependencies | The server uses Python's standard socket library for the protocol, with no third-party wrapper. The only runtime dependency is the MCP SDK. |
| diagnostics tool | It is read-only and does not connect to N3FJP. It reports the resolved N3FJP_HOST and N3FJP_PORT, this process's hostname and Python, and the host's network interfaces. From that you can tell whether the process can reach the target network at all. |
| N3FJP on another computer | A sandboxed client can only reach 127.0.0.1. Run mcp-host-bridge on the client computer and it relays to N3FJP on the LAN. The connector's host setting remains 127.0.0.1. |
| contest-operating skill | It covers the steps of a contest QSO (CQ, exchange, TU, log) and a playbook for special cases: QRM, garbled callsigns, doubling, repeats after no copy, and callers who send only their callsign. It also covers the verified N3FJP logging sequence and its known quirks. It was used on the air during ARRL Field Day 2026. |
| Operating Skills Field Guide | A PDF about contest-operating and its companion skill, fldigi-operating, which comes with fldigi-mcp. It covers installation, a chapter on the first session for hams new to Claude, the operating standard, the special-case playbook, and worked examples from ARRL Field Day 2026. |
| Free N3FJP API reference | A reference for the N3FJP TCP API, tested in the field and verified live against API 2.2. It lists every place where 2.2 differs from the public 0.9 documentation. That includes commands that were removed or renamed, CMD_NOT_FOUND, the API port versus the networking port, the CALLTABEVENT lookup, and why ENTER can report 0 and still log in networked mode. A machine-readable spec comes with it. |
How it works
The N3FJP TCP protocol
Each item below was checked live against N3FJP's ARRL Field Day Contest Log 6.6.10, which reports API version 2.2. The details come from the N3FJP TCP API reference.
| Topic | What was verified |
|---|---|
| Transport | Plain TCP. N3FJP is the server and the connector is the client. Default port 1100. Each command ends with CR LF. |
| Envelope | Every command and response is wrapped as <CMD><COMMANDID><TAG>value</TAG></CMD>. One packet can carry several blocks, so the stream is read continuously and split on </CMD>, never on newlines. |
| Stream | Responses and opt-in notifications share one socket. A background reader sends each block to the request that is waiting for it, or to a notification buffer. |
| API port, not networking port | Port 1100 is the API. Port 1000 is N3FJP's multi-PC networking socket. API commands sent there return nothing. |
| Unknown commands | N3FJP answers <CMD><CMD_NOT_FOUND></CMD> instead of staying silent. That lets you tell "not supported" apart from "wrong port". |
| Changed since 0.9 | There is no APIVERSION command. Read the APIVER tag from PROGRAM instead. READQSOCOUNT became QSOCOUNT. ALLFIELDSVALUES is gone because ALLFIELDS now includes the values. READUSERDATA is not present. |
| Logging flow | UPDATE TXTENTRYCALL, ACTION CALLTAB, UPDATE the exchange boxes, correct band and mode, ACTION ENTER, read the response. |
| CALLTABEVENT | A moment after CALLTAB, one block arrives with country, DXCC, both zones, prefix, continent, bearing, long path and distance. If the call is a dupe, a CALLTABDUPEEVENT follows. |
| ENTER can report 0 yet still log | In Network mode the master-table commit is asynchronous, so ENTERRESPONSE can return 0 for a QSO that was written. Success is checked by the QSOCOUNT change instead. |
Where the connector runs
If N3FJP runs on the same computer as the client, leave the host at 127.0.0.1 and enable Settings → Application Program Interface → TCP API Enabled, port 1100, and you are done.
If N3FJP runs on a different computer, a sandboxed MCP client gets in the way. It runs the connector in a sandbox that can only reach loopback. If you put N3FJP's LAN IP in the settings, the connection times out, even though telnet to that IP works. Running mcp-host-bridge on the client computer fixes this. The diagnostics tool helps you confirm whether you need it. Keep the link on a trusted LAN, because the N3FJP API has no authentication.
Ask it
Tools
Each tool is one permission and takes an operation argument.
| Tool | Default | Controls |
|---|---|---|
status | read | snapshot: program, version, API version, QSO count, band/mode/frequency |
query | read | program, qso_count, next_serial, log/settings/shared paths, qso_rate, band_mode_freq |
fields | read | read one entry box, or list visible / all fields with values |
search | read | list recent, search, dupecheck (no side effects), entity status |
log | approval | log_qso (set call → CALLTAB → exchange → ENTER), set, set_many, calltab, enter, clear, focus |
bandmode | approval | change_freq, set_band, set_mode, ignore_rig_polls |
notifications | approval | enable / disable push events, drain buffered events |
database | approval | add_direct, delete a record, raw sql, checklog, openlog, sqlclose |
n3fjp_call | approval | escape hatch: send any raw command, incl. future ones |
A tenth tool, diagnostics, is read-only and does not connect to N3FJP. It reports the resolved host and port, this process's hostname and Python, and the host's network interfaces.
Settings
| Variable | Default | Purpose |
|---|---|---|
N3FJP_HOST | 127.0.0.1 | N3FJP API host |
N3FJP_PORT | 1100 | N3FJP API port (the suite's default) |
N3FJP_TIMEOUT | 6 | Socket/response timeout, seconds |
N3FJP_ALLOW_DB_WIPE | off | Danger. Allow whole-database delete/overwrite (raw SQL DROP/TRUNCATE/unscoped DELETE/UPDATE). Leave off unless you really mean it |
Safety
Logging does not key a transmitter, so the protection here is for the log. Reads (status, query, fields, search) are marked read-only. Writes are set to Needs Approval, and the server adds no confirmation step of its own. Writes are logging, band and mode, notifications, adding, editing or deleting single records, and the n3fjp_call escape hatch. Raw SQL that could delete or overwrite the whole log is refused unless N3FJP_ALLOW_DB_WIPE is on. That switch is separate from the client's approval prompts, and stricter. Back up your log before you ever turn it on. Where it can, the server relies on N3FJP's own checks and passes N3FJP's responses back to you, instead of repeating those checks itself.
Documents
- Operating Skills Field Guide (PDF) · read it online
- N3FJP TCP API reference: PDF · Markdown · machine-readable spec
- INSTALL · REMOTE-HOST · TEST-PLAN · Field Day 2026 lessons learned · README · CHANGELOG
- PyPI · GitHub repository