adif-mcp: Unified Plan (Demo → Production)¶
This document consolidates the demo scope with the production-grade baseline, and clarifies where MCP manifests should live as we evolve this repo into a stable MCP server. It’s the single planning page to review and iterate on.
1. TL;DR (decisions)¶
- Manifests live inside the package so they ship with the server:
- Canonical:
src/adif_mcp/mcp/manifest.json - Provider manifests (optional, only if exposing provider-scoped tools):
src/adif_mcp/providers/<prov>/mcp/manifest.json - Keep one source of truth for each manifest. Remove the legacy root
mcp/folder after moving the manifest. - Probes, CLI and quality gates are ✅. Next up: add CI smoke (no network) and tag
v0.2.0.
2. Current Surface (working today)¶
- Probes: GET-only and safe.
lotw/eqsl/qrz⇒ HTTP 200;clublog⇒ expected 403 with redaction. - CLI:
adif-mcp provider index-check …(no network)adif-mcp provider probe …(network)- Quality:
ruff,mypy --strict,interrogateall green.make gateandmake smoke-allgreen. - DNS:
adif-mcp.com→ GitHub Pageseqsl.adif-mcp.com/lotw.adif-mcp.com→adif-mcp.com
3. Manifests: Placement & Rules¶
Canonical Placement¶
- Server manifest (single contract for the MCP server):
src/adif_mcp/mcp/manifest.json - Optional per-provider manifests (only if you expose provider-scoped tools or ship provider plugins):
src/adif_mcp/providers/eqsl/mcp/manifest.json src/adif_mcp/providers/lotw/mcp/manifest.json
4. Validation¶
The make manifest target scans all tracked manifest.json files and validates them. No changes needed when you move manifests under src/….
One Source of Truth¶
Keep exactly one manifest per server or plugin. After moving the root manifest, remove the root mcp/ to avoid drift.
5. Demo Scope (kept as plan; not all implemented yet)¶
What the demo will do¶
- Fetch new eQSL entries since a date.
- Answer: 1) “What confirmed eQSLs did I get this week?” 2) “How many eQSL confirmations on 20m FT8 in August?”
Minimal Data Surface (from eQSL ADIF)¶
CALL,QSO_DATE,TIME_ONBAND,MODE,FREQ(optional)EQSL_QSL_RCVD,EQSL_QSLRDATE- Optional passthrough:
RST_SENT,RST_RCVD,GRIDSQUARE,COMMENT
Tools (demo)¶
eqsl.fetch_inbox- Input:
{ since?: "YYYY-MM-DD" } - Output:
{ records: QsoRecord[] } - Behavior: real GET to
DownloadInBox.cfmor mock file ifMOCK=1 eqsl.filter_summary- Input:
{ band?, mode?, date_from?, date_to?, confirmed_only? } - Output:
{ "total": 42, "confirmed": 19, "by_band": [{"band":"20m","count":...}], "by_mode": [{"mode":"FT8","count":...}], "sample": [ /* first 10 QSOs */ ] }
Why two tools? fetch_inbox centralizes I/O + normalization; filter_summary gives the agent fast analytics without repeated downloads.
6. Production Baseline (condensed)¶
Structure¶
adif-mcp/
pyproject.toml
src/adif_mcp/
mcp/manifest.json # ← canonical server manifest
probes/… # safe probes (done)
providers/… # adapters (done)
tools/… # manifest validation, future eqsl tools
models.py # ADIF models (present; to expand)
# planned
enums.py
normalize.py
docs/
tests/
(If you later split provider plugins, each plugin repo keeps its own src/adif_mcp_<prov>/mcp/manifest.json.)
Types & Validation¶
- Treat ADIF 3.1.x as a formal schema via Pydantic models.
- Enumerations loaded from data files, not hard-coded.
- JSON Schema exports for tool I/O.
- Normalization: uppercase CALL, YYYYMMDD date, HHMM[SS] time, MHz/frequency, watts/power.
MCP Design¶
- Small, explicit tools with strict schemas and conservative defaults (limits, pagination, timeouts).
- Machine-readable errors; narrow tools over one mega-tool.
Testing & CI¶
- Golden fixtures for valid/invalid ADIF.
- Contract tests for MCP tools (JSON examples & snapshots).
- CI:
uv sync --frozen,ruff,mypy --strict,pytest -q,make manifest.
Security & Ops¶
- Secrets via env/keyring; never log secrets.
- Later: API façade with OAuth2/API keys; strict request bodies (Pydantic + size caps).
7. Immediate Actions (manifests + doc consolidation)¶
Move the server manifest into the package:
mkdir -p src/adif_mcp/mcp
git mv mcp/manifest.json src/adif_mcp/mcp/manifest.json
Docs: Add a pointer in docs/mcp/manifest.md that the canonical manifest now lives under src/adif_mcp/mcp/manifest.json. The existing make manifest target validates all tracked manifests.
Keep this plan checked in as docs/dev/plan.md so there’s one planning page.
8. Roadmap (near-term)¶
CI smoke: run make probe-index (no network) in CI; skip network probes by default.
Version & tag: bump to 0.2.0, update CHANGELOG.md, tag v0.2.0.
Demo tools: implement eqsl.fetch_inbox + eqsl.filter_summary with mock fallback; add examples in manifest.
Docs: docs/integrations/eqsl/index.md quickstart (mock + real creds).
Models: expand ADIF models/enums + normalization helpers.
Acceptance Checks (every merge)¶
make gate✅make smoke-all✅make manifest✅- Probes:
make probe-all✅