Skip to main content
Glama
qso-graph

eqsl-mcp

by qso-graph

eqsl-mcp

PyPI MCP Registry

MCP server for eQSL.cc — download incoming eQSLs, verify QSOs, check AG status, and query upload history through any MCP-compatible AI assistant.

Part of the qso-graph project. Uses qso-graph-auth for credential management.

Install

uvx eqsl-mcp            # run it; nothing to install

Related MCP server: hamqth-mcp

Tools

Tool

Auth

Description

eqsl_inbox

Yes

Download incoming eQSLs with date/confirmation filters

eqsl_verify

No

Check if a specific QSO exists in eQSL

eqsl_ag_check

No

Check if a callsign has AG (Authenticity Guaranteed) status

eqsl_download

Yes

Download your eQSL inbox as raw ADIF, to import into your logger

eqsl_last_upload

No

When did a persona last upload to eQSL

get_version_info

No

Service version + upstream eQSL.cc endpoint version (fleet identity attestation)

Quick Start

1. Set up credentials

eqsl-mcp uses qso-graph-auth personas for credential management:

# Install qso-graph-auth if you haven't
uv tool install qso-graph-auth

# A persona (your callsign and the dates it covers), then eQSL for it
qso-graph-auth persona add --name ki7mt --callsign KI7MT --start 2020-01-01
qso-graph-auth provider enable ki7mt eqsl
qso-graph-auth creds set ki7mt eqsl      # asks for your username, then your password (hidden)

All three steps are needed: without provider enable, the server reports that the persona has no eqsl ref.

2. Configure your MCP client

eqsl-mcp works with any MCP-compatible client. Add the server config and restart — tools appear automatically.

Claude Desktop

Add to claude_desktop_config.json (~/Library/Application Support/Claude/ on macOS, %APPDATA%\Claude\ on Windows):

{
  "mcpServers": {
    "eqsl": {
      "command": "uvx",
      "args": ["eqsl-mcp"]
    }
  }
}

Claude Code

Add to .claude/settings.json:

{
  "mcpServers": {
    "eqsl": {
      "command": "uvx",
      "args": ["eqsl-mcp"]
    }
  }
}

ChatGPT Desktop

ChatGPT supports MCP via the OpenAI Agents SDK. Add under Settings > Apps & Connectors, or configure in your agent definition:

{
  "mcpServers": {
    "eqsl": {
      "command": "uvx",
      "args": ["eqsl-mcp"]
    }
  }
}

Cursor

Add to .cursor/mcp.json (project-level) or ~/.cursor/mcp.json (global):

{
  "mcpServers": {
    "eqsl": {
      "command": "uvx",
      "args": ["eqsl-mcp"]
    }
  }
}

VS Code / GitHub Copilot

Add to .vscode/mcp.json in your workspace:

{
  "servers": {
    "eqsl": {
      "command": "uvx",
      "args": ["eqsl-mcp"]
    }
  }
}

Gemini CLI

Add to ~/.gemini/settings.json (global) or .gemini/settings.json (project):

{
  "mcpServers": {
    "eqsl": {
      "command": "uvx",
      "args": ["eqsl-mcp"]
    }
  }
}

3. Ask questions

"Show me all eQSLs received this week"

"How many unconfirmed eQSLs do I have on 20m FT8?"

"Does W1AW have AG status on eQSL?"

"Verify my QSO with KI7MT on 20m on March 1, 2026"

Testing Without Credentials

The two public tools (eqsl_verify and eqsl_ag_check) work without any credentials.

For eqsl_inbox testing, set the mock environment variable:

EQSL_MCP_MOCK=1 eqsl-mcp

Or point to a local ADIF file:

EQSL_MCP_MOCK=1 EQSL_MCP_ADIF=/path/to/test.adi eqsl-mcp

MCP Inspector

eqsl-mcp --transport streamable-http --port 8001

Then open the MCP Inspector at http://localhost:8001.

Development

git clone https://github.com/qso-graph/eqsl-mcp.git
cd eqsl-mcp
uv sync --group dev
uv run pytest

Date Formats

eQSL uses different date formats across endpoints. eqsl-mcp normalizes everything — you always use YYYY-MM-DD:

You provide

eqsl-mcp sends

Endpoint

2026-03-01

202603010000

DownloadInBox (RcvdSince)

2026-03-01

03/01/2026

VerifyQSO (QSODate)

Mode Matching

eQSL requires exact mode matching. SSB won't match USB/LSB. PSK won't match PSK31. Use the exact mode logged by the other station.

Known Quirks

  • AG list cache: the Authenticity Guaranteed member list is cached for 4 hours (eQSL updates it about six times a day), in ~/.cache/eqsl-mcp/ag_members.txt ($XDG_CACHE_HOME if set; %LOCALAPPDATA%\eqsl-mcp\ on Windows).

  • Inbox download: eQSL returns an HTML page that links to the .adi file, so the inbox is fetched in two steps. If eQSL answers with ADIF directly, that is used as is.

License

GPL-3.0-or-later

Available Tools

6 tools
eqsl_ag_checkEqsl Ag CheckA
Read-onlyIdempotent

Check if a callsign has Authenticity Guaranteed (AG) status on eQSL.

Public, no auth required. Uses a cached copy of the AG member list (refreshed every 4 hours).

NameRequiredDescriptionDefault
callsignYesThe callsign to check.

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent, open-world, and non-destructive behavior. The description adds useful context beyond annotations: no authentication is required, and results come from a cached AG list refreshed every 4 hours, which tells the agent the data may be slightly stale.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is short, front-loaded with the primary purpose, and every sentence adds useful context. The public/no-auth note and cache refresh detail are directly relevant and not redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter lookup with an output schema, the description covers the key behavioral context: it is public, requires no auth, and uses a cached list refreshed every four hours. Return values are covered by the output schema, so no further explanation is needed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is only one parameter, and the schema already documents it at 100% coverage as 'The callsign to check.' The description adds no additional format, validation, or syntax details beyond what the schema provides, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: checking whether a callsign has Authenticity Guaranteed (AG) status on eQSL. That AG-status scope distinguishes it from sibling tools like eqsl_verify, eqsl_inbox, and eqsl_download without needing to name them explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes the tool's purpose clear and notes that it is public with no auth required, which implies appropriate usage. However, it does not explicitly say when to use this instead of related siblings such as eqsl_verify, nor does it state exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

eqsl_downloadEqsl DownloadA
Read-onlyIdempotent

Download your complete eQSL inbox as raw ADIF text.

Returns the .adi file content — save to disk for import into your logger. Omit 'since' to download your entire inbox history.

NameRequiredDescriptionDefault
sinceNoOnly records added since this date (YYYY-MM-DD). Omit for full history.
personaYesPersona name configured in adif-mcp.
qth_nicknameNoQTH profile name (for multi-QTH callsigns).

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive and open-world behavior, so the safety profile is covered. The description adds useful context beyond them by stating that the return value is raw .adi file content intended to be written to disk, which tells the agent how to handle the response rather than just displaying it.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences with the purpose front-loaded, followed by the return shape and the default-scope note. No filler and no redundancy beyond a minor overlap with the schema on 'since'.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description needn't document return values, and it still usefully notes the .adi format and disk-save step. It is nearly complete for a low-complexity read tool; only the absence of sibling routing keeps it from full coverage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all three parameters (since, persona, qth_nickname) are already documented with formats and defaults. The description restates the 'since' omission behavior but adds nothing about persona or qth_nickname selection, so it merely duplicates structured data at the baseline level.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource ('Download your complete eQSL inbox') and states the output format ('raw ADIF text', '.adi file content'), which is a concrete and distinguishable purpose. It doesn't explicitly contrast itself with the sibling eqsl_inbox, leaving the agent to infer the difference between a raw file download and an inbox listing.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: 'save to disk for import into your logger' hints at the download-then-import workflow, and 'Omit since to download your entire inbox history' describes parameter behavior rather than when to select this tool over eqsl_inbox. There is no explicit when-to-use versus sibling guidance or statement of exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

eqsl_inboxEqsl InboxB
Read-onlyIdempotent

Download incoming eQSLs (confirmations others have sent you).

NameRequiredDescriptionDefault
sinceNoOnly records added since this date (YYYY-MM-DD). Default: last 30 days.
personaYesPersona name configured in adif-mcp.
qth_nicknameNoQTH profile name (for multi-QTH callsigns).
confirmed_onlyNoOnly return records you have confirmed back.
unconfirmed_onlyNoOnly return records you have NOT confirmed.

Output Schema

NameRequiredDescription

No output parameters

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is covered. The description adds a clarification of what an eQSL is, but says nothing about whether downloading has side effects on server state, pagination, volume limits, or authentication needs beyond the persona parameter.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with a parenthetical clarification and zero waste. Nothing is padded or buried.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 100% schema coverage, an output schema, and annotations covering safety and openness, the description is nearly sufficient. The one real gap is distinguishing this tool from eqsl_download, which matters for a five-sibling eQSL tool set.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the meaning of since, persona, qth_nickname, confirmed_only and unconfirmed_only is fully documented in the schema. The description restates none of this and adds no semantics of its own; baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (download incoming eQSLs) and adds a helpful gloss that these are confirmations sent by others. However it does not differentiate from the sibling eqsl_download, which sounds nearly identical, so an agent cannot fully disambiguate from the description alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to use this versus eqsl_download, eqsl_last_upload, or eqsl_verify, and no exclusions or prerequisites. The agent must infer the difference from the name alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

eqsl_last_uploadEqsl Last UploadA
Read-onlyIdempotent

Check when a persona last uploaded QSOs to eQSL.

NameRequiredDescriptionDefault
personaYesPersona name configured in adif-mcp.

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, and openWorldHint=true, so the safety profile is covered. The description adds the upload-status scope but does not add auth, rate-limit, or return-value details beyond that.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single front-loaded sentence with no wasted wording. It states the operation and scope immediately.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter read-only tool with a complete schema, rich annotations, and an output schema, the description is sufficient to call it correctly. No additional return-value explanation is needed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the only parameter, persona, is documented as a configured persona name. The description does not add meaning beyond the schema, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: “Check when a persona last uploaded QSOs to eQSL.” This clearly scopes the tool to upload-status checking, though it does not explicitly distinguish itself from siblings such as eqsl_download or eqsl_inbox.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the purpose: checking last upload time. However, the description does not state when to use this tool versus eqsl_download, eqsl_inbox, or other siblings, nor does it give exclusions or prerequisites.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

eqsl_verifyEqsl VerifyA
Read-onlyIdempotent

Check if a specific QSO exists in eQSL (public, no auth required).

NameRequiredDescriptionDefault
bandYesBand (e.g., '20m').
modeNoMode (exact match — use 'USB' not 'SSB', 'PSK31' not 'PSK').
to_callYesReceiver's callsign.
qso_dateYesQSO date in YYYY-MM-DD format.
from_callYesSender's callsign.

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds genuinely new behavioral context: the lookup is public and requires no authentication, which matters for how the agent sequences the call. It does not mention rate limits or how partial/mismatched data is treated, keeping it short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence that front-loads the action and scope, then appends the auth condition. There is no filler and nothing redundant with structured fields.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is a simple read-only existence lookup, and its rich annotations plus a 100%-covered schema and an output schema mean the description needn't explain return values or parameters. The only minor gap is that it doesn't say the result is an exact-match existence determination, but that is largely captured elsewhere.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter (from_call, to_call, band, qso_date, mode) is already documented, including the exact-match caveat for mode. The description adds only the implicit notion that these fields identify 'a specific QSO.' With the schema doing the heavy lifting, the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: check whether a specific QSO exists in eQSL. That existence-check framing clearly separates it from siblings like eqsl_inbox, eqsl_download, and eqsl_last_upload, which retrieve data. It does not name a sibling explicitly, but the scope is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'check if a specific QSO exists' implies the use case — confirming a single logged contact — but there is no explicit when-to-use or when-not guidance. Nothing tells the agent how this differs from eqsl_ag_check or when to prefer eqsl_download instead. Usage is inferable but not directed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_version_infoGet Version InfoA
Read-onlyIdempotent

Get eqsl-mcp service version and upstream eQSL.cc endpoint version.

Returns the running PyPI version of eqsl-mcp and the eQSL.cc endpoint contract in use. Use this to confirm fleet alignment across MCP deployments — agents can compare service_version and spec_version across servers to detect drift without going outside the MCP protocol.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive, and closed-world, so the safety profile is covered. The description adds the substantive context that the result pairs a local PyPI version with an upstream endpoint contract version and is intended for cross-server drift comparison, which the annotations do not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the core 'what' before the fleet-alignment rationale. The phrase 'fleet alignment' is slightly jargon-y but still earns its place by explaining intent.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No parameters, rich annotations, and an output schema that documents return values mean the description only needs to supply purpose and intent — which it does. Nothing required to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is no parameter semantics to explain and the baseline of 4 applies. The description correctly implies the call is argument-free by describing only returned version fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Get') and two specific resources (eqsl-mcp service version and upstream eQSL.cc endpoint contract version). No sibling tool in the eQSL family does anything comparable, so an agent can distinguish it immediately without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Use this to confirm fleet alignment across MCP deployments' and describes comparing service_version and spec_version to detect drift. Context is clear; no exclusions are given, but none are needed since there is no overlapping sibling for version data.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev0.6.0
    • Addedget_version_info
  2. 5 tool updatesv0.3.2
    • First observedeqsl_ag_check
    • First observedeqsl_download
    • First observedeqsl_inbox
    • First observedeqsl_last_upload
    • First observedeqsl_verify

TDQS

A3.6/5.0

Scored across 6 tools

Disambiguation3/5

Most tools target distinct operations (version, last upload, verify, AG check), but eqsl_inbox and eqsl_download both download inbox contents. The raw-ADIF distinction helps somewhat, but an agent could easily choose the wrong one.

Naming Consistency3/5

Five tools share an eqsl_ prefix, but the suffixes mix nouns (inbox, last_upload) and verbs (verify, download, ag_check), and get_version_info breaks the pattern entirely. The set is readable but not predictably structured.

Tool Count5/5

Six tools is a well-scoped surface for an eQSL.cc client. Each tool covers a distinct enough function without excessive breadth.

Completeness3/5

The surface covers reading inbox data, verifying QSOs, checking AG status, and reporting upload recency. However, there is no tool to actually upload QSOs, which is a core eQSL workflow, and no obvious way to inspect sent/outbox data.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    An MCP server that integrates with FastMail's JMAP API to manage mailboxes, search for emails, and send messages. It enables users to interact with their FastMail account for tasks like reading email content and managing folders through natural language.
    2
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    MCP server for HamQTH.com — callsign lookup, DX cluster spots, Reverse Beacon Network, DXCC resolution, and more through any MCP-compatible AI assistant.
    8
    586 PyPI
    GPL 3.0
  • A
    license
    A
    quality
    A
    maintenance
    MCP server for QRZ.com — callsign lookups, DXCC entity resolution, and logbook queries through any MCP-compatible AI assistant.
    6
    575 PyPI
    4
    GPL 3.0
  • A
    license
    A
    quality
    A
    maintenance
    MCP server for Parks on the Air (POTA) providing live activator spots, park details, activator/hunter stats, and scheduled activations through any MCP-compatible AI assistant.
    11
    612 PyPI
    3
    GPL 3.0