Skip to main content
Glama
README.md
<div align="center">
  <h1>@cyanheads/faa-traffic-delays-mcp-server</h1>
  <p><b>Track FAA ground stops, delay programs, airport delays, the operations plan, and ATCSCC advisories via MCP. STDIO or Streamable HTTP.</b>
  <div>6 Tools</div>
  </p>
</div>

<div align="center">

[![Version](https://img.shields.io/badge/Version-0.2.1-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/faa-traffic-delays-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.3.1-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/faa-traffic-delays-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/faa-traffic-delays-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.4.3-blueviolet.svg?style=flat-square)](https://bun.sh/)

</div>

<div align="center">

[![Install in Claude Desktop](https://img.shields.io/badge/Install_in-Claude_Desktop-D97757?style=for-the-badge&logo=anthropic&logoColor=white)](https://github.com/cyanheads/faa-traffic-delays-mcp-server/releases/latest/download/faa-traffic-delays-mcp-server.mcpb) [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=faa-traffic-delays-mcp-server&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBjeWFuaGVhZHMvZmFhLXRyYWZmaWMtZGVsYXlzLW1jcC1zZXJ2ZXIiXX0=) [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=for-the-badge&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect?url=vscode:mcp/install?%7B%22name%22%3A%22faa-traffic-delays-mcp-server%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40cyanheads%2Ffaa-traffic-delays-mcp-server%22%5D%7D)

[![Framework](https://img.shields.io/badge/Built%20on-@cyanheads/mcp--ts--core-67E8F9?style=flat-square)](https://www.npmjs.com/package/@cyanheads/mcp-ts-core)

</div>

<div align="center">

**Public Hosted Server:** [https://faa-traffic-delays.caseyjhand.com/mcp](https://faa-traffic-delays.caseyjhand.com/mcp)

</div>

---

## Overview

Live US air traffic status from the FAA Command Center, the source behind [nasstatus.faa.gov](https://nasstatus.faa.gov). Check airports for ground stops, Ground Delay Programs, delays, and closures; see every active event nationwide; read today's operations plan; and pull the full advisory behind any program, past dates included.

### Tools

| Tool | Description |
|:---|:---|
| `faa_delays_get_airport_status` | Current status of up to 25 distinct US airports per call, with the remainder named: ground stops, delay programs, delays, closures, deicing, and runway configuration |
| `faa_delays_list_active_events` | Every active event across the National Airspace System, Airspace Flow Programs included, sorted by severity with per-type counts |
| `faa_delays_get_operations_plan` | The Command Center's operations plan: programs and initiatives expected later today, with planned time and likelihood |
| `faa_delays_get_advisory` | Full text of one ATCSCC advisory by number and UTC date: program rate, scope, comments, and the plan's constraints |
| `faa_delays_list_advisories` | The ATCSCC advisories issued on one UTC date, newest first, with their numbers: programs as issued, proposed, revised, and canceled, reroutes, and the operations plan |
| `faa_delays_list_reference` | Decode event types, traffic-management terms, ARTCC codes, the FAA pacing airports, and identifier formats |

## Capability reference

### `faa_delays_get_airport_status` <sub>tool</sub>

- `airports`: 1–100 codes, each a 3-character FAA identifier (`SEA`) or ICAO code (`KSEA`, `PHNL`), as an array or comma-separated string. An unknown code fails the whole call as `unknown_airport`. Only the first 25 distinct airports are processed (`cap: 25`); `processedCount` and `omittedAirports` give the remainder to pass in the next call
- One row per airport, in request order: `status` (`closed`, `ground_stop`, `ground_delay_program`, `delays`, `restrictions_only`, `no_active_events`), `listedInFeed`, `airportName`, `artcc`, coordinates, and each active event (`groundStop`, `groundDelayProgram` with a per-15-minute `delayProfile`, `arrivalDelay` / `departureDelay`, `closure`, `closureNotam`, `deicing`)
- `runwayConfiguration` (runways and `arrivalRatePerHour`) appears only for airports the feed lists. PHX reports `timezone: "America/Phoenix"` with `reportedTimezone: "US/Mountain"`

---

### `faa_delays_list_active_events` <sub>tool</sub>

- Optional `event_types` filter over `ground_stop`, `ground_delay_program`, `airspace_flow_program`, `arrival_delay`, `departure_delay`, `airport_closure`, `closure_notam`, `deicing` (aliases `gs`, `gdp`, `afp`). Rows are sorted by severity, with `reason`, delay figures, times, and an `advisory` reference where the FAA links one
- `totalActive` and `countsByType` cover the whole feed before the filter. `airspace_flow_program` rows carry `afp` detail (constrained area, filters, altitudes, delay profile)
- `enRouteFeed` (`ok`, `unavailable`, `format_changed`) says whether Airspace Flow Programs were read; if they can't be, they are omitted with a `notice` unless they were the only type requested

---

### `faa_delays_get_operations_plan` <sub>tool</sub>

- No input; `terminalPlanned` and `enRoutePlanned` items carry `text`, `timeQualifier` (`after`, `until`, `by`, `between`), `timeUtc` (`HHMM` with no date), and `likelihood` (`possible`, `probable`, `expected`)
- `announcements` lists current ATCSCC announcements (omitted with a `notice` if unreadable); `advisory` points to the full plan text for `faa_delays_get_advisory`

---

### `faa_delays_get_advisory` <sub>tool</sub>

- `advisory_number` (1–999) and `date` (UTC, `YYYY-MM-DD`; `MM/DD/YYYY` accepted), taken from a `faa_delays_list_advisories` row or an `advisory` reference. Numbers restart at 1 each UTC day; past advisories stay readable
- Returns `title`, `controlElement`, `subject`, `effectiveTime`, `sentAt`, and the full `text`. An unknown number returns `found: false` with `guidance` pointing to `faa_delays_list_advisories`
- Text past 50,000 characters is cut and flagged with `truncated` and `totalChars`; failures surface as `advisory_service_unavailable` or `advisory_contract_changed`

---

### `faa_delays_list_advisories` <sub>tool</sub>

- `date` (UTC, `YYYY-MM-DD`; `MM/DD/YYYY` accepted; no later than tomorrow; default today), optional `categories` (`ground_stop`, `ground_delay_program`, `airspace_flow_program`, `ctop`, `route`, `other`; aliases `gs`, `gdp`, `afp`), `control_element` (an airport by FAA or ICAO code, an ARTCC, or `DCC` for national advisories), `limit` 1–200 (default 50), and `offset`
- `query` matches a case-insensitive substring in `subject` or `details`, e.g. `query: "FCA005"` for a named FCA in the plan
- Rows are newest first: `number` and `date` (for `faa_delays_get_advisory`), `controlElement`, `subject`, `details`, and `sentAt`. `totalCount` counts every match and `nextOffset` is present while more remain; no matches returns an empty list with a `notice`

---

### `faa_delays_list_reference` <sub>tool</sub>

- `topic`: `event_types`, `terms`, `artccs`, `pacing_airports`, or `identifiers`
- Only `pacing_airports` calls the FAA (live, cached 6 hours); `identifiers` also reports the bundled airport directory's cycle date and airport count

## Features

Built on [`@cyanheads/mcp-ts-core`](https://github.com/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.

FAA-specific:

- Reads the NAS Status feed (`nasstatus.faa.gov/api`) and the ATCSCC advisories database (`www.fly.faa.gov/adv`), keyless; FAA data is in the public domain (17 U.S.C. §105)
- Airport codes are checked against a bundled FAA NASR airport directory, with ICAO codes mapped to FAA identifiers (`KSEA` → `SEA`), so a mistyped code fails instead of reading as a quiet airport
- Feeds are cached for 60 seconds (the pacing-airport list for 6 hours), and requests to each FAA host are paced
- Parsing is tolerant of the undocumented feed: unreadable rows are skipped and counted in a `notice`

Agent-friendly output:

- Typed failure reasons separate an outage (`feed_unavailable`), a slow or throttled FAA (`retry_deadline_exceeded`, `upstream_rate_limited`, `pacer_shed`), and a format change (`feed_contract_changed`, not retryable); recovery hints name the next tool to call
- A secondary list that can't be read (pacing airports, en-route events, announcements) is omitted with a `notice` instead of failing the call
- `fetchedAt` dates the snapshot, and a `notice` flags delays last updated more than 6 hours ago
- FAA-authored text is quoted in `content[]` so it reads as data, and stays verbatim in `structuredContent`

Limitations:

- **Informational, not operational.** No substitute for an official preflight briefing or airline operations data.
- **Undocumented upstream.** `nasstatus.faa.gov/api/*` is the dashboard's private backend and can change without notice; the server fails with `feed_contract_changed` rather than guess.
- **Airport coverage is event-driven.** The feed lists only airports with an active event, so `no_active_events` means no FAA program, not on-time flights. Per-flight EDCTs are not in the feed.
- **The airport directory is a snapshot.** An identifier the FAA assigns after the bundled NASR cycle is rejected as unknown until the next refresh. US airports only.

## Getting started

### Public Hosted Instance

A public instance is available at `https://faa-traffic-delays.caseyjhand.com/mcp` — no installation required. Point any MCP client at it via Streamable HTTP:

```json
{
  "mcpServers": {
    "faa-traffic-delays-mcp-server": {
      "type": "streamable-http",
      "url": "https://faa-traffic-delays.caseyjhand.com/mcp"
    }
  }
}
```

### Self-Hosted / Local

Add the following to your MCP client configuration file.

```json
{
  "mcpServers": {
    "faa-traffic-delays-mcp-server": {
      "type": "stdio",
      "command": "bunx",
      "args": ["@cyanheads/faa-traffic-delays-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info"
      }
    }
  }
}
```

Or with npx (no Bun required):

```json
{
  "mcpServers": {
    "faa-traffic-delays-mcp-server": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@cyanheads/faa-traffic-delays-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info"
      }
    }
  }
}
```

Or with Docker:

```json
{
  "mcpServers": {
    "faa-traffic-delays-mcp-server": {
      "type": "stdio",
      "command": "docker",
      "args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/faa-traffic-delays-mcp-server:latest"]
    }
  }
}
```

For Streamable HTTP, set the transport and start the server:

```sh
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
```

### Prerequisites

- [Bun v1.4.0](https://bun.sh/) or higher (or Node.js v24+).
- No API key or account: the FAA feeds are public.

### Installation

1. **Clone the repository:**

```sh
git clone https://github.com/cyanheads/faa-traffic-delays-mcp-server.git
```

2. **Navigate into the directory:**

```sh
cd faa-traffic-delays-mcp-server
```

3. **Install dependencies:**

```sh
bun install
```

4. **Configure environment (optional):**

```sh
cp .env.example .env
# every variable has a default; edit .env only to change transport, logging, or telemetry
```

## Configuration

The server reads no environment variables of its own: the FAA hosts, cache lifetimes, and request pacing are fixed in the services. These framework variables cover transport, logging, and telemetry.

| Variable | Description | Default |
|:---|:---|:---|
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
| `MCP_HTTP_PORT` | HTTP server port. | `3010` |
| `MCP_HTTP_HOST` | HTTP server host. | `127.0.0.1` |
| `MCP_SESSION_MODE` | HTTP session mode: `stateless`, `stateful`, or `auto`. | `stateless` |
| `MCP_AUTH_MODE` | Authentication: `none`, `jwt`, or `oauth`. | `none` |
| `MCP_LOG_LEVEL` | Log level (`debug`, `info`, `warning`, `error`, etc.). | `info` |
| `LOGS_DIR` | Directory for log files (Node.js only). | `<app-root>/logs` |
| `OTEL_ENABLED` | Enable [OpenTelemetry](https://github.com/cyanheads/mcp-ts-core/tree/main/docs/telemetry). | `false` |

See [`.env.example`](./.env.example) for the common framework overrides.

## Running the server

### Local development

- **Build and run the production version**:

  ```sh
  # One-time build
  bun run rebuild

  # Run the built server
  bun run start:http
  # or
  bun run start:stdio
  ```

- **Run checks and tests**:
  ```sh
  bun run devcheck  # Lints, formats, type-checks, and more
  bun run test      # Runs the test suite
  ```

- **Refresh the airport directory** from the current FAA NASR cycle (needs network access and the system `unzip`):
  ```sh
  bun run refresh:airports
  ```

## Project structure

| Directory | Purpose |
|:---|:---|
| `src/mcp-server/tools` | Tool definitions (`*.tool.ts`), plus shared output schemas, the advisory date input, notice fragments, and Markdown helpers for FAA-authored text. |
| `src/services/nas-status` | NAS Status feed client and tolerant feed parsers. |
| `src/services/advisory` | ATCSCC advisories database client, advisory page and index parsers, and the advisory and index URL builders. |
| `src/services/airport-directory` | Bundled FAA NASR airport directory (name, place, ARTCC, coordinates) and ICAO → FAA crosswalk (generated module). |
| `src/services/upstream` | Shared FAA fetch boundary (pacing, retry, status classification) and the in-process cache. |
| `scripts/refresh-airport-directory.ts` | Regenerates the airport directory module (`bun run refresh:airports`). |
| `tests/` | Unit and integration tests, mirroring the `src/` structure, with synthetic FAA fixtures. |
| `docs/design.md` | Tool surface design, upstream API notes, design decisions, and known limitations. |

## Development guide

See [`CLAUDE.md`](./CLAUDE.md) for development guidelines and architectural rules. The short version:

- Handlers throw, framework catches — no `try/catch` in tool logic
- Use `ctx.log` for logging; FAA feeds are cached in process, not in `ctx.state`
- Register new tools in `allToolDefinitions` in `src/mcp-server/tools/definitions/index.ts`
- Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields

## Contributing

Issues are welcome. Run checks and tests before submitting:

```sh
bun run devcheck
bun run test
```

## License

This project is licensed under the Apache 2.0 License. See the [LICENSE](./LICENSE) file for details.