Skip to main content
Glama
shayben

All Flights MCP

by shayben
README.md
# All Flights MCP

A federated [Model Context Protocol](https://modelcontextprotocol.io/) server
that searches multiple flight inventory sources concurrently and returns one
normalized, deduplicated result set.

## Providers

| Provider | Status | Inventory role |
|---|---|---|
| ITA Matrix | Supported through an existing Streamable HTTP ITA MCP | Fare research and routing |
| Google Flights | Supported through the pinned Fli MCP | Live metasearch fares and Google booking links |
| Duffel | Supported directly | Live NDC, GDS, and selected low-cost-carrier offers |
| Skyscanner | Supported directly | Metasearch suppliers and booking deep links |
| Standard MCP | Extensible adapter | Additional providers that implement this server's normalized `search_flights` schema |

No provider guarantees complete global inventory. Configure more than one
source for better coverage. Provider errors are isolated: one failed or slow
source does not discard results from the others.

## MCP tools

- `list_providers`: reports configured and unavailable providers.
- `search_flights`: searches providers concurrently, normalizes offers, and
  groups equivalent itineraries with provider-specific alternatives.
- `search_date_range`: scans up to 60 outbound-date/stay-length combinations.
- `get_offer`: retrieves a recent offer and its alternatives from the
  in-memory cache.

## Quick start

Requires Node.js 22 or newer.

```bash
npm install
cp .env.example .env
npm run build
npm start
```

The server automatically loads `.env`. The default transport is `stdio`. Set
`MCP_TRANSPORT=http` to expose stateless
Streamable HTTP at `http://127.0.0.1:3000/mcp`. The HTTP server also exposes
`GET /health`.

### Local MCP client

```json
{
  "mcpServers": {
    "all-flights": {
      "command": "node",
      "args": ["C:\\Repos\\all-flights-mcp\\dist\\index.js"],
      "env": {
        "ITA_MCP_URL": "https://your-ita-mcp.example/mcp",
        "ITA_MCP_BEARER_TOKEN": "${input:ita-token}",
        "DUFFEL_ACCESS_TOKEN": "${input:duffel-token}"
      }
    }
  }
}
```

## Configuration

Copy `.env.example` and enable any providers for which you have access:

- `ITA_MCP_URL` and optional `ITA_MCP_BEARER_TOKEN`
- or `ITA_MCP_COMMAND` and optional `ITA_MCP_ARGS_JSON` for a local stdio server
- `GOOGLE_FLIGHTS_MCP_URL` or `GOOGLE_FLIGHTS_MCP_COMMAND=fli-mcp`
- `DUFFEL_ACCESS_TOKEN`
- `SKYSCANNER_API_KEY` plus market and locale

Skyscanner, Sabre, and Travelport generally require commercial approval.
Credentials are never returned in tool output or written to disk by this
server.

### Additional MCP providers

`UPSTREAM_MCP_PROVIDERS_JSON` adds providers that expose a normalized
`search_flights` tool compatible with this repository:

```json
[
  {
    "id": "partner",
    "name": "Partner inventory",
    "url": "https://partner.example/mcp",
    "tokenEnv": "PARTNER_MCP_TOKEN",
    "toolName": "search_flights"
  }
]
```

`tokenEnv` names an environment variable; do not place secrets directly in the
JSON configuration.

## HTTP deployment

```bash
cp .env.example .env
# Edit .env and set MCP_TRANSPORT=http and MCP_BEARER_TOKEN.
docker compose up -d --build
```

When `MCP_BEARER_TOKEN` is set, `/mcp` requires
`Authorization: Bearer <token>`. Use TLS in front of the container.

### HomeAssistant OCI deployment

The repository includes the deployment used by HomeAssistant. It runs beside
the existing ITA MCP container and a pinned Fli Google Flights container, publishes
`https://flights.159-54-184-44.sslip.io/mcp` through Caddy, stores the bearer
token in Azure Key Vault, and registers the server in the agent's MCP registry.
The OCI Fli container uses the existing residential SOCKS tunnel because
Google returns empty inventory from the datacenter address.

```powershell
.\deploy-oci.ps1
```

Provider credentials can be added to `/opt/n8n/all-flights-mcp.env` before
restarting the service. ITA is reached over the private Compose network.

## Normalization and deduplication

Each offer retains its source, provider offer ID, total price, currency,
segments, carriers, booking URL or booking-item links, and expiry. Equivalent itineraries are grouped
by segment airports, times, carriers, and flight numbers. The cheapest
alternative in the requested currency becomes the primary result; every
provider alternative remains attached.

Prices are not currency-converted. ITA Matrix results are marked non-bookable
because ITA does not return durable booking links. Always revalidate a selected
offer before purchase. Google Flights support uses an unofficial reverse-engineered
interface provided by Fli; it may change without notice.

## Development

```bash
npm run check
```

The test suite uses Node's built-in test runner and does not call live provider
APIs.

TDQS

A3.7/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a distinct purpose: listing providers, searching flights across providers, and searching across date ranges. No overlaps or ambiguity.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case: list_providers, search_flights, search_date_range. No deviations.

Tool Count5/5

Three tools is well-scoped for a flight search server, covering configuration listing, general search, and date-range search without excess or deficiency.

Completeness4/5

The set covers core flight search functionality, but lacks filters (e.g., by airline, price) or provider-specific queries. Minor gap but sufficient for the stated purpose.

Maintenance

ActivityStale
ResponsivenessNo issues