eqsl-mcp
MCP server for eQSL.cc that lets AI assistants retrieve eQSL inbox data, verify QSOs, check AG status, and inspect upload/version information.
Download incoming eQSLs with optional date, QTH, confirmed-only, and unconfirmed-only filters.
Verify whether a specific QSO exists on eQSL using callsigns, band, date, and optional exact mode.
Check whether a callsign has eQSL Authenticity Guaranteed (AG) status.
Download the full eQSL inbox as raw ADIF text for logger import.
Check when a persona last uploaded QSOs to eQSL.
Get eqsl-mcp service version and upstream eQSL.cc endpoint/spec version for fleet alignment.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@eqsl-mcpShow me all new eQSL cards received this week"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
eqsl-mcp
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 installRelated MCP server: hamqth-mcp
Tools
Tool | Auth | Description |
| Yes | Download incoming eQSLs with date/confirmation filters |
| No | Check if a specific QSO exists in eQSL |
| No | Check if a callsign has AG (Authenticity Guaranteed) status |
| Yes | Download your eQSL inbox as raw ADIF, to import into your logger |
| No | When did a persona last upload to eQSL |
| 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-mcpOr point to a local ADIF file:
EQSL_MCP_MOCK=1 EQSL_MCP_ADIF=/path/to/test.adi eqsl-mcpMCP Inspector
eqsl-mcp --transport streamable-http --port 8001Then 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 pytestDate Formats
eQSL uses different date formats across endpoints. eqsl-mcp normalizes everything — you always use YYYY-MM-DD:
You provide | eqsl-mcp sends | Endpoint |
|
| DownloadInBox (RcvdSince) |
|
| 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_HOMEif set;%LOCALAPPDATA%\eqsl-mcp\on Windows).Inbox download: eQSL returns an HTML page that links to the
.adifile, 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 toolseqsl_ag_checkEqsl Ag CheckARead-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).
| Name | Required | Description | Default |
|---|---|---|---|
| callsign | Yes | The callsign to check. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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 DownloadARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Only records added since this date (YYYY-MM-DD). Omit for full history. | |
| persona | Yes | Persona name configured in adif-mcp. | |
| qth_nickname | No | QTH profile name (for multi-QTH callsigns). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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 InboxBRead-onlyIdempotent
Download incoming eQSLs (confirmations others have sent you).
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Only records added since this date (YYYY-MM-DD). Default: last 30 days. | |
| persona | Yes | Persona name configured in adif-mcp. | |
| qth_nickname | No | QTH profile name (for multi-QTH callsigns). | |
| confirmed_only | No | Only return records you have confirmed back. | |
| unconfirmed_only | No | Only return records you have NOT confirmed. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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 UploadARead-onlyIdempotent
Check when a persona last uploaded QSOs to eQSL.
| Name | Required | Description | Default |
|---|---|---|---|
| persona | Yes | Persona name configured in adif-mcp. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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 VerifyARead-onlyIdempotent
Check if a specific QSO exists in eQSL (public, no auth required).
| Name | Required | Description | Default |
|---|---|---|---|
| band | Yes | Band (e.g., '20m'). | |
| mode | No | Mode (exact match — use 'USB' not 'SSB', 'PSK31' not 'PSK'). | |
| to_call | Yes | Receiver's callsign. | |
| qso_date | Yes | QSO date in YYYY-MM-DD format. | |
| from_call | Yes | Sender's callsign. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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 InfoARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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 tool update
v0.6.0- Added
get_version_info
5 tool updates
v0.3.2- First observed
eqsl_ag_check - First observed
eqsl_download - First observed
eqsl_inbox - First observed
eqsl_last_upload - First observed
eqsl_verify
TDQS
Scored across 6 tools
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.
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.
Six tools is a well-scoped surface for an eQSL.cc client. Each tool covers a distinct enough function without excessive breadth.
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
Related MCP Connectors
- ZapierOAuthcom.zapier
Hosted MCP server connecting AI assistants to 9,000+ apps and 40,000+ actions via Zapier.
MCP server that lets your AI assistant build and deploy apps, hosting each one at a live URL.
MCP server for OnceAsk, the AI-native current-address layer for people and agents.
- UnifAPIOAuthcom.unifapi
Hosted MCP server for live public-data APIs and Skills for AI agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn 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.2MIT
- AlicenseAqualityAmaintenanceMCP server for HamQTH.com — callsign lookup, DX cluster spots, Reverse Beacon Network, DXCC resolution, and more through any MCP-compatible AI assistant.8586 PyPIGPL 3.0
- AlicenseAqualityAmaintenanceMCP server for QRZ.com — callsign lookups, DXCC entity resolution, and logbook queries through any MCP-compatible AI assistant.6575 PyPI4GPL 3.0
- AlicenseAqualityAmaintenanceMCP 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.11612 PyPI3GPL 3.0