io.github.cyanheads/aviation-weather-mcp-server
METARs, TAFs, PIREPs, domestic/international SIGMETs and CWAs via NWS AWC. AIRMETs not served.
What can you do with io.github.cyanheads/aviation-weather-mcp-server?
- Keyless — no API key or authentication required; all data is from the public AWC Data API
- Single service (
aviation-weather-service) with retry + exponential backoff for the keyless public endpoint - Raw coded strings (
raw_metar,raw_taf,raw_pirep,raw_text) surfaced alongside decoded fields so agents have both layers - State→bbox table enables US-state station queries that the AWC API doesn't natively support
- Server-level
instructionsfield surfaces the "not an official briefing" safety disclaimer to all clients oninitialize - Discriminated output — flight category (
VFR/MVFR/IFR/LIFR) as a typed string field, so agents branch on it without parsing ceiling and visibility - Structured error contracts — typed
reasonfields withrecoveryhints (e.g., "Verify ICAO IDs withaviation_find_stations") - Partial-result reconciliation — batch tools report
requested/returned/missing/partialfields, so a short batch is never mistaken for full coverage
Install
Add this to your client's MCP configuration (Claude Desktop: claude_desktop_config.json; Cursor: .cursor/mcp.json; VS Code and others use the same "mcpServers" shape).
claude mcp add --transport http aviation-weather-mcp-server 'https://aviation-weather.caseyjhand.com/mcp'
{
"mcpServers": {
"aviation-weather-mcp-server": {
"type": "http",
"url": "https://aviation-weather.caseyjhand.com/mcp"
}
}
}
@cyanheads/aviation-weather-mcp-serverclaude mcp add aviation-weather-mcp-server -e 'MCP_LOG_LEVEL=info' -e 'AWC_BASE_URL=https://aviationweather.gov/api/data' -e 'AWC_TIMEOUT_MS=10000' -- npx -y @cyanheads/aviation-weather-mcp-server@0.6.0
{
"mcpServers": {
"aviation-weather-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/aviation-weather-mcp-server@0.6.0"
],
"env": {
"MCP_LOG_LEVEL": "info",
"AWC_BASE_URL": "https://aviationweather.gov/api/data",
"AWC_TIMEOUT_MS": "10000"
}
}
}
}
Environment variables
MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').AWC_BASE_URLBase URL for the AWC Data API. Useful for testing against a mock or staging instance.AWC_TIMEOUT_MSPer-request timeout in milliseconds (1000–60000).
@cyanheads/aviation-weather-mcp-serverclaude mcp add aviation-weather-mcp-server -e 'MCP_TRANSPORT_TYPE=<MCP_TRANSPORT_TYPE>' -e 'MCP_HTTP_HOST=127.0.0.1' -e 'MCP_HTTP_PORT=3010' -e 'MCP_HTTP_ENDPOINT_PATH=/mcp' -e 'MCP_AUTH_MODE=none' -e 'MCP_LOG_LEVEL=info' -e 'AWC_BASE_URL=https://aviationweather.gov/api/data' -e 'AWC_TIMEOUT_MS=10000' -- npx -y @cyanheads/aviation-weather-mcp-server@0.6.0
{
"mcpServers": {
"aviation-weather-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/aviation-weather-mcp-server@0.6.0"
],
"env": {
"MCP_TRANSPORT_TYPE": "<MCP_TRANSPORT_TYPE>",
"MCP_HTTP_HOST": "127.0.0.1",
"MCP_HTTP_PORT": "3010",
"MCP_HTTP_ENDPOINT_PATH": "/mcp",
"MCP_AUTH_MODE": "none",
"MCP_LOG_LEVEL": "info",
"AWC_BASE_URL": "https://aviationweather.gov/api/data",
"AWC_TIMEOUT_MS": "10000"
}
}
}
}
Environment variables
MCP_TRANSPORT_TYPESelects the HTTP transport.MCP_HTTP_HOSTThe hostname for the HTTP server.MCP_HTTP_PORTThe port to run the HTTP server on.MCP_HTTP_ENDPOINT_PATHThe endpoint path for the MCP server.MCP_AUTH_MODEAuthentication mode to use: 'none', 'jwt', or 'oauth'.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').AWC_BASE_URLBase URL for the AWC Data API. Useful for testing against a mock or staging instance.AWC_TIMEOUT_MSPer-request timeout in milliseconds (1000–60000).
Documentation
From the project's README on GitHub, refreshed weekly. Links open on GitHub.
Contents
@cyanheads/aviation-weather-mcp-server
Fetch METARs, TAFs, PIREPs, domestic/international SIGMETs and CWAs from NWS AWC via MCP. AIRMETs not served. STDIO or Streamable HTTP.
5 Tools • 1 Prompt
Public Hosted Server: https://aviation-weather.caseyjhand.com/mcp
Overview
Aviation weather from the NWS Aviation Weather Center — METARs, TAFs, PIREPs, domestic/international SIGMETs, and Center Weather Advisories. Look up stations, fetch current and forecast conditions, and pull pilot reports and hazard advisories. AIRMETs are not served.
Tools
| Tool | Description |
|---|---|
aviation_find_stations | Resolve airports and weather stations by identifier, bounding box, or US state. Returns ICAO/IATA/FAA IDs, coordinates, elevation, and available data types. |
aviation_get_metar | Get current weather observations (METARs) for named airports, or survey every reporting station in a bounding box. Returns decoded wind, visibility, ceiling, present weather, temp/dewpoint, altimeter, cloud layers, flight category (VFR/MVFR/IFR/LIFR), and the raw METAR string. |
aviation_get_taf | Get Terminal Aerodrome Forecasts for one or more airports. Returns each forecast period with valid times, surface wind, low-level wind shear, visibility, decoded weather, cloud layers, and vertical visibility into a forecast obscuration, plus the raw TAF string. |
aviation_get_pireps | Get recent Pilot Reports near an airport or within a bounding box. Returns decoded turbulence, icing, and cloud reports with altitude, aircraft type, intensity, outside air temperature, wind aloft, flight weather, and the raw PIREP string. |
aviation_get_advisories | Get domestic/international SIGMETs and Center Weather Advisories. Returns source coverage, hazard, severity, altitude, validity, movement, multipart geometry and original bulletins; omitted facts stay null. |
Prompts
| Prompt | Description |
|---|---|
aviation_preflight_brief | Structure a preflight weather briefing for a flight, calling the tools above in sequence and synthesizing a weather-risk summary. |
Capability reference
aviation_find_stations tool
- Look up one or more stations by identifier (up to 20 per call) — a lookup matches the registry's own ID, which for an airport is its 4-character ICAO ID (e.g.,
KSEA,K0S9); a 3-letter IATA code never resolves, though each record includes its IATA/FAA aliases when available - Discover stations within a geographic bounding box, or list stations for one of the 50 US states or DC via two-letter USPS code
- Returns
data_types(METAR, TAF, etc.) so agents can confirm what's available before querying - Every result states whether the upstream 400-row cap cut it;
limit(1–400) bounds how many stations abboxorstatesearch returns, ordered by ICAO identifier ascending with identifier-less stations last — rejected alongsidestation_ids, since that mode already names the set. An area search returning more than 130 stations with nolimitsays so and names the lever; omittinglimitstill returns every match - An ID lookup names every identifier that resolved to nothing, separating a 3-letter IATA code (never resolves) from an identifier the registry simply does not list
- Whitespace around an ID is trimmed rather than failing the batch; only an empty or whitespace-only entry is rejected
aviation_get_metar tool
station_ids(1–10 per call — 4 ASCII letters or digits, case-insensitive and normalized to uppercase, sokseaandK0S9work) for named airports, orbboxto survey every reporting station in an area — mutually exclusivehours(1–12) is a lookback window, not a row limit: withstation_idsevery observation inside it is returned, and withbboxthe result is the latest observation per stationflight_category(e.g.,["IFR", "LIFR"]) narrows abboxsurvey to the stations in those categories — judged on each station's latest observation, applied beforelimit, and disclosed with the count surveyed before it; a station AWC could not rate never matches, and a survey the filter empties returns an empty result that says so. Rejected alongsidestation_ids- A
bboxsurvey states whether the upstream 400-row cap cut it and, abovehours: 1, nameshoursas the first lever — a wide window spends the cap on repeat readings rather than on more stations;limit(1–400) bounds how many stations come back, ordered by station ID ascending, and is rejected alongsidestation_ids. A survey returning more than 40 stations with nolimitsays so and names the levers; omittinglimitstill returns every station - Flight category (VFR/MVFR/IFR/LIFR) returned directly from the AWC API; decodes wind, visibility, present weather, and cloud layers alongside the raw METAR string
- Ceiling reports both height and kind (measured, or indefinite for vertical visibility into an obscuration) —
sky_conditiondistinguishes a reported clear sky from an unreported one whencloudsis empty metar_typedistinguishes routineMETARfrom specialSPECIobservations- Every batch reports which requested stations came back, naming missing IDs with recovery guidance
aviation_get_taf tool
- Accepts 1–4 ICAO station IDs per call: 4 ASCII letters or digits in either case, normalized to uppercase
- Structured forecast periods with change types (
FM,TEMPO,BECMG) and probabilities; weather decoded group by group beside the raw groups - Forecast obscurations keep their layer and carry the vertical visibility into them, rather than reading as clear sky;
sky_conditiondistinguishes an unamended period from a stated clear sky - Text the upstream decoder left undecoded — often a fourth cloud layer — is surfaced per period in
not_decodedrather than dropped - Low-level wind shear (
WS020/20040KT) decoded to the shear-layer top and forecast wind at that height valid_from/valid_toin ISO 8601 for time comparisons- Every batch reports which requested stations came back, naming missing IDs with recovery guidance
aviation_get_pireps tool
station_id(4 ASCII letters or digits in either case, normalized to uppercase) +distance_nm(10–500 nm, 100 when omitted) for radial search, orbboxfor area search — mutually exclusive; astation_idAWC does not recognize as a search center returns a typed error pointing toaviation_find_stationsorbboxaltitude_min_ft/altitude_max_ftfilter to a cruise-altitude band in feet MSL, from 0 to 60000 ft (min must not exceed max); a report with unknown altitude is dropped once either bound is setmin_intensity(lgt/mod/sev) restricts to reports carrying a turbulence or icing layer at that intensity or above — a matching report still carries its lighter layers- Turbulence and icing arrays include up to two layers per report; icing layers the API synthesized for a report that never mentioned ice are dropped
- Outside air temperature (
temp_c), wind aloft (wind), and the/WXflight weather decoded beside its raw groups (weather), for PIREPs and AIREPs alike. The wind direction is published as reported, with no conversion — a PIREP/WVdirection is magnetic, unlike the true-north METAR and TAF winds - Every result states whether the upstream 400-row cap cut it, naming only the narrowing levers the call can still use, and
limit(1–400) bounds how many reports come back, ordered by recency. A result of more than 50 reports with nolimitsays so and names the lever; omittinglimitstill returns every match - PIREPs are sparse by nature — absence of reports does not mean smooth conditions
aviation_get_advisories tool
advisory_type:sigmet(domestic),isigmet(international, including oceanic),cwa(Center Weather Advisories), orall(default: all three independent products)hazardis applied upstream: domestic supportsCONVECTIVE,TURBULENCE,ICING,IFR; international supportsTS,TURBULENCE,ICING,MTW,DS,SS,TC,VA; CWA supportsTS,TURBULENCE,ICING,IFR,PCPN,UNK. Incompatible sources arenot_applicable; a selection with no compatible source is rejectedcoveragereports each selected source asok,failedornot_applicable, with decoded drawn counts only for readable sources.partialmarks failed sources or skipped unreadable rows. Independent healthy products survive a failure; all applicable products failing is an error. One 45-second deadline bounds the concurrent advisory reads and retries; caller cancellation aborts all legsbboxuses each geometry part's bounding envelope, including date-line crossings, rather than exact polygon intersection. Input remains ordered (minLat <= maxLat,minLon <= maxLon). With bbox,drawncounts rows after product/hazard selection,matchedcounts geographic matches,returnedcounts rows after any limit, andunlocatedseparately counts rows without decoded geometrylimitis optional with no default: omitted means every available match. An explicit limit orders by source, issuer, series and validity, reportstotal/returned/truncated, and explains how to retrieve withheld matches by omitting or raising it- Missing issuer, series, hazard, validity and raw text stay null.
geometry.partspreserves separate rings/lines and source-nativekind(including null); compatibilitypolygonis null for multipart, line or missing geometry. Domestic numeric severity/movement stay unchanged; international movement preservesdirection_textand decoded knots. CWA severity/movement remain null, and altitudes are never inferred from bulletin text - Original bulletins render in safe code fences preserving blank lines and embedded backticks. An empty result names readable sources and filtering stage; unavailable sources never establish fair weather
- AIRMETs are not served. Requests for one (or
MTN OBSCN/SURFACE WIND/LLWS) are rejected with guidance to separate AIRMET products
aviation_preflight_brief prompt
- Arguments:
departure_icaoanddestination_icaorequired;alternates(comma-separated ICAOs),departure_time(ISO 8601 UTC),cruise_altitude(feet MSL), androute_waypoints(semicolon-separatedlat,lonpairs) optional - Every ICAO argument accepts 4 ASCII letters or digits in either case and generates uppercase IDs. For an IATA/FAA code, use
aviation_find_stationswithstateorbboxto find the ICAO ID; no mapping is inferred. Direct IDs reject surrounding whitespace; comma-separated alternates allow it - Calls
aviation_get_metar,aviation_get_taf,aviation_get_pireps, andaviation_get_advisoriesin sequence, chunked to each tool's station-per-call limit departure_timeselects the TAF forecast period the briefing is read against;cruise_altitudebounds the PIREP search to a ±3,000 ft band;route_waypointsbecome the advisoriesbbox, widened by 1° on each side- Omitting any of the three still generates the briefing, naming the assessment it could not make
- Reports weather risk rather than a go/no-go recommendation — that decision needs pilot, aircraft, and operational-minima context this server does not hold
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
Aviation-weather-specific:
- Keyless — no API key or authentication required; all data is from the public AWC Data API
- Single service (
aviation-weather-service) with retry + exponential backoff for the keyless public endpoint - Raw coded strings (
raw_metar,raw_taf,raw_pirep,raw_text) surfaced alongside decoded fields so agents have both layers - State→bbox table enables US-state station queries that the AWC API doesn't natively support
- Server-level
instructionsfield surfaces the "not an official briefing" safety disclaimer to all clients oninitialize
Agent-friendly output:
- Discriminated output — flight category (
VFR/MVFR/IFR/LIFR) as a typed string field, so agents branch on it without parsing ceiling and visibility - Structured error contracts — typed
reasonfields withrecoveryhints (e.g., "Verify ICAO IDs withaviation_find_stations") - Partial-result reconciliation — batch tools report
requested/returned/missing/partialfields, so a short batch is never mistaken for full coverage - Workflow sequencing — the
aviation_preflight_briefprompt encodes the correct METAR → TAF → PIREPs → advisories sequence, chunks each step to the tool's station limit, and names the assessments it could not make
Getting started
Public Hosted Instance
A public hosted instance is available at https://aviation-weather.caseyjhand.com/mcp. Add it to your MCP client configuration:
{
"mcpServers": {
"aviation-weather": {
"type": "streamable-http",
"url": "https://aviation-weather.caseyjhand.com/mcp"
}
}
}
Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"aviation-weather": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/aviation-weather-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"aviation-weather": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/aviation-weather-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"aviation-weather": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"ghcr.io/cyanheads/aviation-weather-mcp-server:latest"
]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- No API key required — the AWC Data API is fully public and keyless.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/aviation-weather-mcp-server.git
- Navigate into the directory:
cd aviation-weather-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# edit .env if you need to override AWC_BASE_URL or AWC_TIMEOUT_MS
Configuration
| Variable | Description | Default |
|---|---|---|
AWC_BASE_URL | Base URL for the NWS AWC Data API. | https://aviationweather.gov/api/data |
AWC_TIMEOUT_MS | Per-request timeout in milliseconds (1000–60000). | 10000 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | Port for HTTP server. | 3010 |
MCP_SESSION_MODE | HTTP session handling: auto (resolves to stateful), stateful, or stateless. The server declares stateless in code — no tool here needs a multi-round-trip input — and the shipped .env.example and Docker image pin the same value. Setting this overrides the declaration. | stateless |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424). | info |
OTEL_ENABLED | Enable OpenTelemetry instrumentation. | false |
See .env.example for the full list of optional overrides.
Running the server
Local development
- Build and run:
bun run rebuild bun run start:stdio # or bun run start:http - Run checks and tests:
bun run devcheck # Lint, format, typecheck, security bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t aviation-weather-mcp-server .
docker run --rm -p 3010:3010 aviation-weather-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/aviation-weather-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools/prompts and inits services. |
src/config | Server-specific env var parsing (AWC_BASE_URL, AWC_TIMEOUT_MS). |
src/services/aviation-weather | AWC Data API client — HTTP fetch, retry with exponential backoff, response normalization. |
src/mcp-server/tools | Tool definitions (*.tool.ts). |
src/mcp-server/prompts | Prompt definitions (*.prompt.ts). |
tests/ | Unit and integration tests mirroring src/. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storage - Register new tools and prompts in the
createApp()arrays insrc/index.ts - Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Not an official preflight briefing. Data from the AWC is informational only. Real flight planning requires an authorized source (e.g., Leidos/1800wxbrief.com). The server surfaces this disclaimer via its
instructionsfield sent on everyinitialize.
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.
Frequently asked questions
What is io.github.cyanheads/aviation-weather-mcp-server?
METARs, TAFs, PIREPs, domestic/international SIGMETs and CWAs via NWS AWC. AIRMETs not served.
How do I install io.github.cyanheads/aviation-weather-mcp-server?
It runs as a remote server. In Claude Code: claude mcp add --transport http aviation-weather-mcp-server 'https://aviation-weather.caseyjhand.com/mcp'. For other clients, paste the JSON configuration from this page into their MCP settings.
Does io.github.cyanheads/aviation-weather-mcp-server need an API key?
Its registry entry lists no required key or secret. Some features may still need an account with the service it connects to.
Is io.github.cyanheads/aviation-weather-mcp-server open source?
Yes. Its code is on GitHub under the Apache-2.0 license.
Who maintains io.github.cyanheads/aviation-weather-mcp-server?
It is published by cyanheads. AI.tn lists it but does not maintain or endorse it.
From the official MCP Registry. Listing is not an endorsement: review a server's code and permissions before giving it access to your data.