.codex-plugin — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited .codex-plugin (MCP Server) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
<div align="center"> <h1>@cyanheads/ourairports-mcp-server</h1> <p><b>Resolve airport codes (IATA/ICAO/GPS/local), search airports, find the nearest by coordinate, and look up runways, navaids, and radio frequencies from the bundled public-domain OurAirports dataset via MCP. STDIO or Streamable HTTP.</b> <div>5 Tools • 1 Resource</div> </p> </div>
<div align="center">
</div>
<div align="center">
</div>
<div align="center">
</div>
<div align="center">
Public Hosted Server: https://ourairports.caseyjhand.com/mcp
</div>
ourairports-mcp-server is the static aviation reference layer for resolving airport identifiers and grounding coordinates. It answers what exists — the catalog of airports, their codes, runways, navaids, and radio frequencies — to complement live aviation services that answer what is happening (weather, positions).
The entire OurAirports dataset is dedicated to the public domain and published as flat CSVs. Those six CSV files — airports, runways, navaids, airport frequencies, countries, and regions (~178k rows, ~20 MB) — are bundled into the package and baked into the Docker image at build time. At startup the server parses them into in-memory indices; every tool is then a local query. The result has no API key, no rate limit, and no upstream dependency to inherit an outage from.
How the working model fits together:
ident. A single code parameter resolves against a unified index (priority: ident → ICAO → IATA → GPS → local), and the response echoes the full code set so an ambiguous national code is self-correcting. A missing code (no IATA for a small field) is reported as null, never a 404.Float64Array of every airport (or navaid) position and return the nearest results ranked by distance, each with its bearing — sub-millisecond at this scale, no spatial index needed.OurAirports is community-edited. The data is surfaced as-is and is not authoritative for real flight operations — treat it the way you would any crowd-sourced reference.
Five read-only tools, all local queries against the bundled index — code resolution and detail, search, coordinate grounding, navaids, and the country/region lookup table:
| Tool | Description |
|---|---|
ourairports_search_airports | Full-text and faceted search over the airport corpus by name, municipality, country, region, or type. Ranked summaries, closed airports excluded by default. |
ourairports_get_airport | Full record for one airport resolved by any code (IATA/ICAO/GPS/local/ident), with its runways and radio frequencies inline. |
ourairports_find_airports | Airports within a radius of a coordinate, ranked nearest-first by great-circle distance, with distance and bearing. |
ourairports_find_navaids | Navigation aids (VOR, VOR-DME, DME, NDB, NDB-DME, TACAN, VORTAC) near a coordinate or serving a specific airport. |
ourairports_list_countries | Countries present in the dataset with ISO codes and airport counts; optional continent filter and nested regions. The lookup table for valid country/region filter values. |
ourairports_search_airportsThe common entry point — search by free text, facets, or both.
country (ISO 3166-1 alpha-2), region (ISO 3166-2), and typeinclude_closedourairports_get_airportourairports_get_airportThe detail tool — one call returns everything the common case needs.
code case-insensitively across all five identifier spaces (priority: ident → ICAO → IATA → GPS → local)include trims the response to a subsetresolvedVia / resolutionNote, with an ambiguity warning for shared national codes so a wrong resolution is self-correctingnull; closed airports always resolveunknown_code error with a recovery hint when no identifier space matchesourairports_find_airportsThe grounding tool — turn a latitude/longitude into the nearest airport(s).
distanceKm and bearingDeg (degrees true) from the query pointradius_km (1–500, default 100), optional type filter, include_closed opt-inradius_kmourairports_find_navaidsNavigation aids two ways — spatially or by airport.
latitude + longitude (+ optional radius_km) ranks navaids nearest-first with distance and bearingairport_code returns the navaids serving that airportfrequencyKhz 114500) and MHzunknown_code error) from "airport found but has no associated navaids" (empty list with a note)| Type | Name | Description |
|---|---|---|
| Resource | airport://{code} | Single airport record by any code (IATA/ICAO/GPS/local/ident), with runways and frequencies inline. |
The airport://{code} resource is a stable-URI twin of ourairports_get_airport for clients that inject resource context. All data is reachable from the tools alone — tool-only clients lose nothing. The corpus is not exposed as a resource list (enumerating 85k airports is a dump, not a discovery aid); discovery is ourairports_search_airports.
Built on @cyanheads/mcp-ts-core:
none, jwt, oauthin-memory, filesystem, Supabase, Cloudflare KV/R2/D1OurAirports-specific:
Float64Array of coordinates, country/region maps, and a tokenized text-search indexAgent-friendly output:
null, never fabricatedresolvedVia / resolutionNote, with an ambiguity warning for shared national codesA public instance is available at https://ourairports.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP, with this client config:
{
"mcpServers": {
"ourairports-mcp-server": {
"type": "streamable-http",
"url": "https://ourairports.caseyjhand.com/mcp"
}
}
}Add the following to your MCP client configuration file.
{
"mcpServers": {
"ourairports-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/ourairports-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}Or with npx (no Bun required):
{
"mcpServers": {
"ourairports-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/ourairports-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}Or with Docker:
{
"mcpServers": {
"ourairports-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"ghcr.io/cyanheads/ourairports-mcp-server:latest"
]
}
}
}No API key is required — the dataset ships with the package and the image.
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/mcpgit clone https://github.com/cyanheads/ourairports-mcp-server.gitcd ourairports-mcp-serverbun installdata/):bun run build:dataThe bundled snapshot is as fresh as the last build:data run (or, for the Docker image, the last build). To pull the latest daily drop from the OurAirports mirror, re-run bun run build:data and rebuild. To point at an existing local data drop without rebuilding, set OURAIRPORTS_DATA_DIR.
| Variable | Description | Default |
|---|---|---|
OURAIRPORTS_DATA_DIR | Directory holding the six OurAirports CSV files. Overridable to point at a fresher local data drop. | Bundled data/ |
OURAIRPORTS_DEFAULT_SEARCH_LIMIT | Default result cap for the search/find tools when the caller omits limit (1–100). | 20 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | Port for the HTTP server. | 3010 |
MCP_HTTP_ENDPOINT_PATH | HTTP endpoint path where the server is mounted. | /mcp |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424). | info |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend (unused on the data path — the index is in-memory). | in-memory |
OTEL_ENABLED | Enable OpenTelemetry instrumentation. | false |
See .env.example for the full list of optional overrides.
# One-time data fetch + build
bun run build:data
bun run rebuild
# Run the built server
bun run start:stdio
# or
bun run start:http bun run devcheck # Lint, format, typecheck, security
bun run test # Vitest test suite
bun run lint:mcp # Validate MCP definitions against specdocker build -t ourairports-mcp-server .
docker run --rm -e MCP_TRANSPORT_TYPE=stdio ourairports-mcp-serverThe build stage runs bun run build:data so the dataset is fetched and baked into the image — the resulting container is fully self-contained and makes no network calls at runtime. The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/ourairports-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/resources and loads the bundled index at setup(). |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts). Five read-only airport/navaid tools. |
src/mcp-server/resources | Resource definitions. The airport://{code} record. |
src/services/airport-data | The bundled-data service — CSV parsing, in-memory indices, code resolution, search, and the haversine geo scan. |
scripts/build-data.ts | Build-time fetcher that bundles the six OurAirports CSVs into data/. |
tests/ | Unit and integration tests mirroring src/. |
See CLAUDE.md/AGENTS.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 storagesrc/mcp-server/*/definitions/index.tsnull, never fabricate missing valuesAirport, runway, navaid, and frequency data from OurAirports, dedicated to the public domain. Attribution is a courtesy, not a requirement. Source CSVs are published daily at davidmegginson.github.io/ourairports-data.
Issues and pull requests are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testApache-2.0 — see LICENSE for details.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.