{
  "markdown": "# n3fjp-mcp\n\n<!-- mcp-name: io.github.sbrunner-atx/n3fjp-mcp -->\n\nAn [MCP](https://modelcontextprotocol.io/) server for **logging amateur-radio\nQSOs** to [N3FJP logging software](https://www.n3fjp.com/) — Amateur Contact Log\nand the 100-plus N3FJP contest loggers — from MCP-aware clients such as Claude\nDesktop.\n\nEvery program in the N3FJP suite shares one TCP control API. `n3fjp-mcp` speaks\nthat protocol directly (Python's standard-library `socket`, no third-party\nwrapper) and exposes it as a small set of logically-grouped MCP tools, so an\nassistant can log contacts, read the log, run dupe checks, and manage band/mode\nthrough plain language.\n\nIt is the **logging** half of an \"operate → log\" workflow; its sibling project\n[`fldigi-mcp`](https://github.com/sbrunner-atx/fldigi-mcp) operates the radio.\n\n> **Status:** experimental (v0.3). Verified live against N3FJP's ARRL Field Day\n> Contest Log, **API version 2.2**. The protocol is shared across the suite, but\n> field sets vary per contest — confirm with the `fields` tool.\n\n> ## ⚠️ Independent project — not affiliated with N3FJP\n>\n> `n3fjp-mcp` is an independent, community project by **Stefan Brunner (AE5VG)**,\n> using the \"N3FJP\" name with the permission of its owner. It is **not affiliated\n> with, endorsed by, or supported by N3FJP Software / Affirmatech**. Please direct\n> **all support questions for this app to\n> [its issue tracker](https://github.com/sbrunner-atx/n3fjp-mcp/issues) — not to\n> N3FJP**. MIT licensed. \"N3FJP\" is the callsign and trademark of its owner.\n\n## Highlights\n\n- **Automatic logging** — the headline `log` tool runs the real N3FJP flow:\n  set the call → `CALLTAB` (dupe check + previous-contact lookup) → set the\n  exchange → `ENTER`, surfacing the dupe response and the number of records added.\n- **Broad coverage** — read queries, field read/write, search/list, dupe and\n  entity checks, band/mode/frequency, direct database operations, and opt-in\n  push notifications, grouped into 9 tools (one permission each) plus an\n  `n3fjp_call` escape hatch for the long tail and future commands.\n- **Safe by design** for a tool that can touch your log database:\n  - **Reads** are marked read-only so clients can default them to *Always Allow*.\n  - **Writes** (logging, band/mode) default to *Needs Approval*.\n  - **Destructive** operations (add-direct, delete a record, raw SQL)\n    additionally require `confirm=true`.\n  - **Whole-database** wipes/overwrites are refused outright unless you flip a\n    dedicated, off-by-default `N3FJP_ALLOW_DB_WIPE` switch.\n- **Names match N3FJP** — tools and fields mirror N3FJP's own terminology\n  (Action `ENTER`, `CALLTAB`, the `TXTENTRY…` boxes, Class/Section, etc.).\n- **No fragile dependencies** — the only runtime dependency is the MCP SDK.\n\n## Requirements\n\nTo **install the desktop extension** (`.mcpb`):\n\n- An **N3FJP program** running, with **Settings → Application Program Interface →\n  \"TCP API Enabled\"** checked (default API port `1100`).\n\nClaude Desktop's `uv` runtime supplies Python and the dependencies, so end users\ndo **not** install Python or `uv` themselves.\n\nFor **development from source** you additionally need **Python 3.10+** and\n**[uv](https://docs.astral.sh/uv/)** (and **Node.js**, only for the MCP Inspector).\n\n## Install\n\n### Easiest: one-click desktop extension\n\nDownload `n3fjp-mcp.mcpb` from the latest\n[release](https://github.com/sbrunner-atx/n3fjp-mcp/releases), then in Claude\nDesktop go to **Settings → Extensions → Advanced settings → Install Extension…**\nand choose the file. A short settings form asks for the host/port (defaults to\n`127.0.0.1:1100`). **No terminal, no Python, no uv to install.**\n\n👉 New to this? Follow the step-by-step [install guide](docs/INSTALL.md).\n\n### From source (development)\n\n```bash\ngit clone https://github.com/sbrunner-atx/n3fjp-mcp.git\ncd n3fjp-mcp\nuv sync\n```\n\nThen add it to Claude Desktop's config\n(`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):\n\n```json\n{\n  \"mcpServers\": {\n    \"contest\": {\n      \"command\": \"uv\",\n      \"args\": [\"--directory\", \"/absolute/path/to/n3fjp-mcp\", \"run\", \"n3fjp-mcp\"],\n      \"env\": { \"N3FJP_HOST\": \"127.0.0.1\", \"N3FJP_PORT\": \"1100\" }\n    }\n  }\n}\n```\n\nRestart Claude Desktop and ask *\"What's the N3FJP status?\"*.\n\n### Try it with the MCP Inspector\n\n```bash\nuv run mcp dev src/n3fjp_mcp/server.py\n```\n\n## Tools\n\nEach tool is one permission and takes an `operation` argument.\n\n| Tool | Default | Controls |\n| --- | --- | --- |\n| `status` | read | snapshot: program, version, API version, QSO count, band/mode/frequency |\n| `query` | read | program, qso_count, next_serial, log/settings/shared paths, qso_rate, band_mode_freq |\n| `fields` | read | read one entry box, or list visible / all fields with values |\n| `search` | read | list recent, search, dupecheck (no side effects), entity status |\n| `log` | **approval** | `log_qso` (set call → CALLTAB → exchange → ENTER), set, set_many, calltab, enter, clear, focus |\n| `bandmode` | **approval** | change_freq, set_band, set_mode, ignore_rig_polls |\n| `notifications` | **approval** | enable / disable push events, drain buffered events |\n| `database` | **approval** | add_direct, delete a record, raw sql, checklog, openlog, sqlclose |\n| `n3fjp_call` | **approval** | escape hatch — send any raw command, incl. future ones |\n\nAll write tools sit at the **Needs Approval** tier, so you can set them to *Always\nAllow* in the client for hands-off automation. The single exception is a\nwhole-database wipe (see below), which is hard-blocked regardless.\n\nThe headline is `log` → `log_qso`:\n\n```\nlog_qso  call=\"W1AW\"  contest=\"field_day\"  exchange={\"class\":\"2A\",\"section\":\"CT\"}\n```\n\nThis sets the call, fires `CALLTAB` (dupe check), fills the exchange, sends\n`ENTER`, and reports records added plus any dupe detail.\n\n## Configuration\n\n| Variable | Default | Purpose |\n| --- | --- | --- |\n| `N3FJP_HOST` | `127.0.0.1` | N3FJP API host |\n| `N3FJP_PORT` | `1100` | N3FJP API port (the suite's default) |\n| `N3FJP_TIMEOUT` | `6` | Socket/response timeout, seconds |\n| `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 |\n\nIn the packaged desktop extension these appear as a settings form.\n\n### Safety model\n\nLogging doesn't key a transmitter, so there is no transmit gate. The protection\nhere is about your **log database**:\n\n- **Read** operations (`status`, `query`, `fields`, `search`) are marked\n  read-only — clients can default them to *Always Allow*.\n- **Write** operations — logging (`log`), band/mode (`bandmode`),\n  notifications, and **adding, editing, or deleting individual records**\n  (`database`), plus the `n3fjp_call` escape hatch — all sit at the *Needs\n  Approval* tier. There is no extra in-band confirmation, so you can set them to\n  *Always Allow* in the client and let automation run hands-off.\n- **Whole-database** operations — raw SQL that could delete or overwrite the\n  entire log (`DROP`, `TRUNCATE`, a `DELETE`/`UPDATE` with no `WHERE`) — are the\n  one exception: **refused** unless `N3FJP_ALLOW_DB_WIPE` is on. This switch is\n  separate from, and stricter than, the client's approval prompts, and carries a\n  stern warning in the settings form. **Back up your log before ever enabling\n  it.**\n\nWherever possible, `n3fjp-mcp` leans on N3FJP's own validation (it dupe-checks\nand reports oddities) and surfaces those responses rather than re-implementing\nthem.\n\n### Remote / contest-station setups (N3FJP on another computer)\n\nIf N3FJP runs on the **same** computer as Claude Desktop (the common case), leave\n`N3FJP_HOST` at `127.0.0.1` and you're done.\n\nIf N3FJP runs on a **different** computer, there's a catch: a **sandboxed** MCP\nclient (notably Claude Desktop) runs the connector so it can only reach\n`127.0.0.1`, not LAN addresses — so putting N3FJP's LAN IP in the settings will\ntime out even though `telnet` to that IP works. Fix it with the standalone\n[mcp-host-bridge](https://github.com/sbrunner-atx/mcp-host-bridge) tool on the\nclient computer, then set the host to `127.0.0.1`:\n\n```\npipx install mcp-host-bridge            # or download a binary from its releases\nmcp-host-bridge install n3fjp --to 192.168.1.50   # knows n3fjp = port 1100; auto-starts\n```\n\nManage it with `mcp-host-bridge status n3fjp` / `uninstall n3fjp`. Full details\nare in [docs/REMOTE-HOST.md](docs/REMOTE-HOST.md) and the\n[mcp-host-bridge README](https://github.com/sbrunner-atx/mcp-host-bridge#readme).\nThe `diagnostics` tool helps confirm whether you need it. Keep the link on a\ntrusted LAN — the API is unauthenticated.\n\n## Documentation\n\n### 📻 A field-tested N3FJP API reference (free community resource)\n\nBuilding this server meant reverse-engineering and **live-verifying** the N3FJP\nTCP API, including several places where today's API (v2.2) differs from the\npublic 0.9 documentation. We've written that up as a complete, human-readable\nguide and are sharing it freely to give back to the community:\n\n- **[The N3FJP TCP API — A Field-Tested Reference](docs/N3FJP-API.md)**\n  ([PDF](docs/N3FJP-API.pdf)) — transport, every command grouped by area,\n  verified response examples, contest exchange fields, and a hard-won\n  **gotchas** section (the API vs. networking ports, `CMD_NOT_FOUND`, commands\n  removed since 0.9, the `CALLTABEVENT` lookup, and why `ENTER` can report 0 yet\n  still log in networked mode).\n- **[Machine-readable spec](docs/N3FJP-API-SPEC.md)** — the same information in a\n  terse, structured command catalog suitable for code generation.\n\nCorrections and additions are welcome — please\n[open an issue or PR](https://github.com/sbrunner-atx/n3fjp-mcp/issues).\n\n### Project docs\n\n- [Install guide](docs/INSTALL.md) and [Test plan](docs/TEST-PLAN.md).\n- [Field Day 2026 lessons learned](docs/LESSONS-FIELD-DAY-2026.md) — the\n  full after-action report from running an autonomous BPSK31 Field Day\n  station (class 2A, callsigns anonymized) with n3fjp-mcp + fldigi-mcp: the operating\n  loop, special cases encountered live, and recommended improvements.\n\n## Skills\n\nThe [`skills/`](skills/) directory contains agent skills — operating\nprocedures distilled from live on-air use — bundled with the repo and the\n`.mcpb` package:\n\n- **[contest-operating](skills/contest-operating/SKILL.md)** — the contest\n  QSO state machine (CQ → exchange → TU → log), the special-case playbook\n  (QRM, garbled callsigns, doubling, no-copy repeats, callsign-only\n  callers), and the verified N3FJP logging sequence with its known quirks.\n  Field-proven during ARRL Field Day 2026.\n\nThe **[Operating Skills Field Guide](docs/operating-skills-field-guide.pdf)**\n(PDF) documents this skill and its companion `fldigi-operating` from the\nsibling [fldigi-mcp](https://github.com/sbrunner-atx/fldigi-mcp) — skills at\na glance, installation, a plain-language \"first session\" chapter for hams\nnew to Claude, the operating standard, the special-case playbook, and worked\nexamples transcribed from ARRL Field Day 2026.\n\nTo use with Claude Code / Cowork, copy the skill directory into your\n`~/.claude/skills/` (or a project's `.claude/skills/`). Pair it with the\n`fldigi-operating` skill from fldigi-mcp for radio control.\n\n## Development\n\n```bash\nuv sync\nuv run ruff check .      # lint\nuv run pytest            # tests (no running N3FJP required)\npython3 smoke_test.py 192.168.1.50 1100   # Phase 0: prove the link to N3FJP\n```\n\nThe test suite covers the wire protocol, the operation maps and field catalog,\ntype coercion, and the permission/confirm safety model; none of it requires a\nrunning N3FJP.\n\n## License\n\n[MIT](LICENSE) © 2026 Stefan Brunner (AE5VG)\n",
  "bytes": 11695,
  "sha": "cb2423f0675b02aa9eb824f77e386d833143666e22f29bbdb3fe217c1117a5fe",
  "repo_slug": "sbrunner-atx/n3fjp-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_sbrunner_atx_n3fjp_mcp_7de35bf4/readme"
}