METARs, TAFs, PIREPs, domestic/international SIGMETs and CWAs via NWS AWC. AIRMETs not served.
One address for any MCP client. No sign-in needed on this server.
5 read
Grouped by tool name. At most: only reads or looks up information.
Odel charges nothing per call. The publisher may charge for its own service.
Fetch METARs, TAFs, PIREPs, domestic/international SIGMETs and CWAs from NWS AWC via MCP. AIRMETs not served. STDIO or Streamable HTTP.
Public Hosted Server: https://aviation-weather.caseyjhand.com/mcp
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.
| 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. |
| 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. |
aviation_find_stations toolKSEA, K0S9); a 3-letter IATA code never resolves, though each record includes its IATA/FAA aliases when availabledata_types (METAR, TAF, etc.) so agents can confirm what's available before queryinglimit (1–400) bounds how many stations a bbox or state search returns, ordered by ICAO identifier ascending with identifier-less stations last — rejected alongside station_ids, since that mode already names the set. An area search returning more than 130 stations with no limit says so and names the lever; omitting limit still returns every matchaviation_get_metar toolstation_ids (1–10 per call — 4 ASCII letters or digits, case-insensitive and normalized to uppercase, so ksea and K0S9 work) for named airports, or bbox to survey every reporting station in an area — mutually exclusivehours (1–12) is a lookback window, not a row limit: with station_ids every observation inside it is returned, and with bbox the result is the latest observation per stationflight_category (e.g., ["IFR", "LIFR"]) narrows a bbox survey to the stations in those categories — judged on each station's latest observation, applied before limit, 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 alongside station_idsbbox survey states whether the upstream 400-row cap cut it and, above hours: 1, names hours as 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 alongside station_ids. A survey returning more than 40 stations with no limit says so and names the levers; omitting limit still returns every stationsky_condition distinguishes a reported clear sky from an unreported one when clouds is emptymetar_type distinguishes routine METAR from special SPECI observationsaviation_get_taf toolFM, TEMPO, BECMG) and probabilities; weather decoded group by group beside the raw groupssky_condition distinguishes an unamended period from a stated clear skynot_decoded rather than droppedWS020/20040KT) decoded to the shear-layer top and forecast wind at that heightvalid_from / valid_to in ISO 8601 for time comparisonsaviation_get_pireps toolstation_id (4 ASCII letters or digits in either case, normalized to uppercase) + distance_nm (10–500 nm, 100 when omitted) for radial search, or bbox for area search — mutually exclusive; a station_id AWC does not recognize as a search center returns a typed error pointing to aviation_find_stations or bboxaltitude_min_ft / altitude_max_ft filter 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 layerstemp_c), wind aloft (wind), and the /WX flight weather decoded beside its raw groups (weather), for PIREPs and AIREPs alike. The wind direction is published as reported, with no conversion — a PIREP /WV direction is magnetic, unlike the true-north METAR and TAF windslimit (1–400) bounds how many reports come back, ordered by recency. A result of more than 50 reports with no limit says so and names the lever; omitting limit still returns every matchaviation_get_advisories tooladvisory_type: sigmet (domestic), isigmet (international, including oceanic), cwa (Center Weather Advisories), or all (default: all three independent products)hazard is applied upstream: domestic supports CONVECTIVE, TURBULENCE, ICING, IFR; international supports TS, TURBULENCE, ICING, MTW, DS, SS, TC, VA; CWA supports TS, TURBULENCE, ICING, IFR, PCPN, UNK. Incompatible sources are not_applicable; a selection with no compatible source is rejectedcoverage reports each selected source as ok, failed or not_applicable, with decoded drawn counts only for readable sources. partial marks 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 legsbbox uses each geometry part's bounding envelope, including date-line crossings, rather than exact polygon intersection. Input remains ordered (minLat <= maxLat, minLon <= maxLon). With bbox, drawn counts rows after product/hazard selection, matched counts geographic matches, returned counts rows after any limit, and unlocated separately counts rows without decoded geometrylimit is optional with no default: omitted means every available match. An explicit limit orders by source, issuer, series and validity, reports total/returned/truncated, and explains how to retrieve withheld matches by omitting or raising itgeometry.parts preserves separate rings/lines and source-native kind (including null); compatibility polygon is null for multipart, line or missing geometry. Domestic numeric severity/movement stay unchanged; international movement preserves direction_text and decoded knots. CWA severity/movement remain null, and altitudes are never inferred from bulletin textMTN OBSCN / SURFACE WIND / LLWS) are rejected with guidance to separate AIRMET productsaviation_preflight_brief promptdeparture_icao and destination_icao required; alternates (comma-separated ICAOs), departure_time (ISO 8601 UTC), cruise_altitude (feet MSL), and route_waypoints (semicolon-separated lat,lon pairs) optionalaviation_find_stations with state or bbox to find the ICAO ID; no mapping is inferred. Direct IDs reject surrounding whitespace; comma-separated alternates allow itaviation_get_metar, aviation_get_taf, aviation_get_pireps, and aviation_get_advisories in sequence, chunked to each tool's station-per-call limitdeparture_time selects the TAF forecast period the briefing is read against; cruise_altitude bounds the PIREP search to a ±3,000 ft band; route_waypoints become the advisories bbox, widened by 1° on each sideBuilt 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:
aviation-weather-service) with retry + exponential backoff for the keyless public endpointraw_metar, raw_taf, raw_pirep, raw_text) surfaced alongside decoded fields so agents have both layersinstructions field surfaces the "not an official briefing" safety disclaimer to all clients on initializeAgent-friendly output:
VFR/MVFR/IFR/LIFR) as a typed string field, so agents branch on it without parsing ceiling and visibilityreason fields with recovery hints (e.g., "Verify ICAO IDs with aviation_find_stations")requested / returned / missing / partial fields, so a short batch is never mistaken for full coverageaviation_preflight_brief prompt encodes the correct METAR → TAF → PIREPs → advisories sequence, chunks each step to the tool's station limit, and names the assessments it could not makeA 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"
}
}
}
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
git clone https://github.com/cyanheads/aviation-weather-mcp-server.git
cd aviation-weather-mcp-server
bun install
cp .env.example .env
# edit .env if you need to override AWC_BASE_URL or AWC_TIMEOUT_MS
| 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.
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 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.
| 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/. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for request-scoped logging, ctx.state for tenant-scoped storagecreateApp() arrays in src/index.tsNot 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.
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.