Metadata-Version: 2.5
Name: eqsl-mcp
Version: 0.3.8
Summary: MCP server for eQSL.cc — inbox download, QSO verification, AG status checks
Project-URL: Homepage, https://qso-graph.io
Project-URL: Documentation, https://qso-graph.io/servers/eqsl/
Project-URL: Repository, https://github.com/qso-graph/eqsl-mcp
Project-URL: Issues, https://github.com/qso-graph/eqsl-mcp/issues
Author-email: "Greg Beam, KI7MT" <maintainers@qso-graph.io>
License: GPL-3.0-or-later
License-File: LICENSE
Keywords: amateur-radio,confirmation,eqsl,ham-radio,mcp,model-context-protocol,qsl,qso
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Ham Radio
Requires-Python: >=3.10
Requires-Dist: fastmcp<5,>=4.0
Requires-Dist: qso-graph-auth>=0.1.1
Description-Content-Type: text/markdown

<!-- mcp-name: io.github.qso-graph/eqsl-mcp -->
# eqsl-mcp

[![PyPI](https://img.shields.io/pypi/v/eqsl-mcp?label=PyPI&color=blue)](https://pypi.org/project/eqsl-mcp/)
[![MCP Registry](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fregistry.modelcontextprotocol.io%2Fv0%2Fservers%3Fsearch%3Dio.github.qso-graph%2Feqsl-mcp%26version%3Dlatest&query=%24.servers%5B0%5D.server.version&label=MCP%20Registry&color=blue)](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.qso-graph/eqsl-mcp&version=latest)

MCP server for [eQSL.cc](https://www.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](https://qso-graph.io/) project. Uses [qso-graph-auth](https://pypi.org/project/qso-graph-auth/) for credential management.

## Install

```bash
uvx eqsl-mcp            # run it; nothing to install
```

## 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](https://qso-graph.io/servers/qso-graph-auth/) personas for credential management:

```bash
# 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-auth persona add --name ki7mt --callsign KI7MT --start 2020-01-01
qso-auth provider enable ki7mt eqsl
qso-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):

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

#### Claude Code

Add to `.claude/settings.json`:

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

#### ChatGPT Desktop

ChatGPT supports MCP via the [OpenAI Agents SDK](https://developers.openai.com/api/docs/mcp/). Add under Settings > Apps & Connectors, or configure in your agent definition:

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

#### Cursor

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

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

#### VS Code / GitHub Copilot

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

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

#### Gemini CLI

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

```json
{
  "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:

```bash
EQSL_MCP_MOCK=1 eqsl-mcp
```

Or point to a local ADIF file:

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

## MCP Inspector

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

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

## Development

```bash
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
