propagation-mcp
# propagation-mcp
An MCP server exposing HF band-condition and space-weather tools backed by
[NOAA/SWPC](https://www.swpc.noaa.gov/)'s public JSON feeds. Runs over stdio,
so any MCP-compatible client (Claude Desktop, Claude Code, etc.) can launch it
as a subprocess.
## Installation
```bash
npx @rmp/propagation-mcp
```
## Tools
### `get_band_conditions`
No input. Fetches the current 10.7cm Solar Flux Index (SFI), planetary
K-index, planetary A-index, and NOAA's current G-scale reading, then runs
them through the classic ham-radio SFI/K/A heuristic to produce a per-band
(160m/80m/40m/20m/17m/15m/12m/10m) good/fair/poor call with plain-English
notes, plus an overall status. Day/night bias in the per-band notes is based
on the server's local time (the tool takes no location input).
Example use: "Are the bands open right now?" / "What's a good band for HF
right now?"
Returns text like:
```
Good conditions overall (SFI 145, K 2, A 8, daytime) — high bands should be open, low bands usable.
Per-band:
- 160m: FAIR — 160m is D-layer absorbed during the day...
- ...
- 10m: GOOD — SFI 145 supports good daylight openings on 10m.
Raw inputs: SFI=145 sfu (as of 2026-08-15T20:00:00 UTC), K=2 (as of 2026-08-16T09:00:00 UTC), A=8, NOAA G-scale=0 (none).
```
plus a `structuredContent` object with the same data machine-readable.
**Deliberately stops at 10m — no 6m.** 6m (50MHz) is mostly opened by
mechanisms this tool has no data for: sporadic E (jet-stream/season driven,
essentially uncorrelated with SFI), meteor scatter, TEP, and aurora (which
tracks K-index in the *opposite* direction from HF — high K opens auroral
backscatter rather than blacking the band out). True F2-layer openings on 6m
do exist but are rare even at high SFI. Extending the existing SFI/K/A
heuristic with just a higher SFI threshold for 6m would produce a
confidently-wrong answer on the far more common case of Es being wide open
while SFI/K say "poor" — worse than not answering at all. A correct 6m tool
would need its own data source (e.g. sporadic-E cluster-spot aggregation or
foEs ionosonde data, neither of which NOAA/SWPC's feeds used here provide),
so it's left out rather than faked.
### `get_solar_indices`
No input. Returns the latest raw SFI, Kp, and A-index values with their NOAA
observation timestamps (UTC). Use this when you want the raw numbers rather
than an interpreted band-by-band call.
### `get_kindex_forecast`
No input. Returns NOAA's 3-day-ahead planetary K-index forecast table (one
row per 3-hour period), each with UTC time, predicted Kp, and NOAA G-scale
(when a storm threshold is predicted to be reached).
### `get_space_weather_alerts`
Optional input `{ limit?: number }` (default `5`). Returns the N most recent
active NOAA/SWPC alerts/watches/warnings (geomagnetic K-index warnings, radio
blackout alerts, proton flux alerts, etc.), most-recent-first, each with its
product code, UTC issue time, and a short plain-English extract of the
bulletin (not the full raw text dump).
### `get_solar_wind`
No input. Returns the current real-time solar wind reading: interplanetary
magnetic field strength (Bt) and its north-south GSM component (Bz — a
sustained southward/negative Bz is what actually couples energy into the
magnetosphere and tends to precede a Kp rise by 30-60 minutes), plus proton
speed, density, and temperature. Bt/Bz come from NOAA's pre-resolved "current"
summary endpoints; density/temperature come from the fuller multi-spacecraft
feed, filtered to whichever source NOAA currently flags as authoritative
(that feed carries several spacecraft — ACE, SOLAR1, IMAP as of writing —
at each timestamp, sorted newest-first, so picking the right row takes a
touch more care than the other endpoints here).
### `get_xray_flux`
No input. Returns the latest GOES X-ray flux in both channels (long,
0.1-0.8nm; short, 0.05-0.4nm) plus NOAA's own current flare classification
(e.g. `"C1.5"`, standard A/B/C/M/X logarithmic scale) and the most recent
classified flare event's begin/peak/end times and classes. The flare class
is passed through verbatim from NOAA rather than re-derived from raw flux
here — NOAA already computes and publishes it, so re-implementing the
threshold table ourselves would just be a second place for that logic to
drift out of sync with theirs.
## Development
```bash
npm install
npm run build
npm test
```
Tests use Node's built-in test runner (`node:test`) and stub `globalThis.fetch`
with real sample NOAA payloads — no network access required.
## Using with Claude Desktop / Claude Code
The published package needs no clone or build — point your client straight at
it:
```json
{
"mcpServers": {
"propagation": {
"command": "npx",
"args": ["@rmp/propagation-mcp"]
}
}
}
```
To run from a local checkout instead, build first (`npm run build`) and point
at the built entry point:
```json
{
"mcpServers": {
"propagation": {
"command": "node",
"args": ["/Users/rmp/dev/mcp/propagation-mcp/dist/index.js"]
}
}
}
```
Adjust the path to match where you've cloned this repo. For Claude Desktop
this goes in `claude_desktop_config.json`; for Claude Code, in your MCP
server configuration (e.g. via `claude mcp add` or the project's
`.mcp.json`).
## Standalone binaries (no Node, no `node_modules`)
For deploying to a Raspberry Pi or any other box you don't want carrying a
Node install and this whole source tree, the server is also shipped as a single
self-contained executable per architecture — the Bun runtime is embedded in the
binary, so nothing else needs to be installed on the target.
Every tagged release attaches them, alongside a `SHA256SUMS.txt`:
```bash
gh release download v0.1.0 --pattern 'propagation-mcp-linux-arm64' --pattern 'SHA256SUMS.txt'
sha256sum --check --ignore-missing SHA256SUMS.txt
chmod +x propagation-mcp-linux-arm64
```
To build them yourself, `build:standalone` compiles straight from
`src/index.ts` with [Bun](https://bun.sh) — one x86-64 machine cross-compiles
all three:
```bash
curl -fsSL https://bun.sh/install | bash # one-time, only needed on the build machine
npm run build:standalone
```
Either way you get:
- `propagation-mcp-linux-amd64` — most Linux boxes / generic x86-64 servers (~91MB)
- `propagation-mcp-linux-arm64` — Raspberry Pi 4/5 (64-bit Raspberry Pi OS) and other arm64/aarch64 Linux (~90MB)
- `propagation-mcp-darwin-arm64` — Apple Silicon macOS (~62MB)
The size is the embedded Bun runtime, not this package's own code. The macOS
binary is unsigned and unnotarized, so a downloaded copy needs
`xattr -d com.apple.quarantine propagation-mcp-darwin-arm64` before Gatekeeper
will run it. Each binary runs with no arguments needed — copy it to the target
and point your MCP client's `command` straight at it instead of
`node .../dist/index.js`:
```json
{
"mcpServers": {
"propagation": {
"command": "/home/pi/propagation-mcp-linux-arm64"
}
}
}
```
Both architectures were verified by actually running the compiled binary
under Docker (`--platform linux/amd64` / `--platform linux/arm64`) and
exercising a real MCP handshake, `tools/list`, and a live `get_solar_indices`
call against the real NOAA API — not just checking that the binary exists.
TDQS
Scored across 6 tools
Each tool targets a distinct aspect of space weather and HF propagation: forecast vs current indices, raw data vs interpretation, and separate tools for solar wind, X-ray flux, and alerts. The descriptions explicitly cross-reference each other to disambiguate purposes (e.g., get_band_conditions vs get_solar_indices), leaving no ambiguity about which to use.
All tool names follow a uniform get_<noun_phrase> pattern (get_kindex_forecast, get_band_conditions, etc.), using snake_case consistently. This makes the set predictable and easy to scan.
Six tools is a well-scoped size for a propagation-focused server. Each tool covers a major data category (forecast, current indices, band interpretation, alerts, solar wind, X-ray events) without redundancy or unnecessary bloat.
The server covers the key data sources needed for HF propagation assessment: solar flux, Kp/A indices, Kp forecast, solar wind drivers, X-ray flare activity, and space weather alerts. The band conditions tool nicely synthesizes the raw inputs into actionable HF guidance. No significant gaps for the stated domain.