Skip to main content
Glama
gvdeepthi

fare-data MCP server

by gvdeepthi
README.md
# fare-data MCP server

> **New here?** Follow the step-by-step [SETUP.md](SETUP.md) to get running.

Exposes ATPCO fare CSV snapshots (the ~119-column fare feed layout: CXR, ORIG,
DEST, Fare Class, Fare AMT, Tax AMT, Total Price AMT, Cabin, restrictions, …)
from a local folder to Claude via the Model Context Protocol, plus a live
fare-shopping tool backed by engine-wrapper-service.

## Data directory

Drop your fare CSVs into the data folder. Resolution order:

1. `FARE_DATA_DIR` environment variable, if set
2. `../fare-data` (a folder named `fare-data` next to this repo), if it exists
3. `./data` inside this repo

Any `*.csv` with the fare-feed header layout is picked up automatically; no
restart needed when you add or replace files (each tool call re-reads the
directory).

## Tools

| Tool | What it does |
|---|---|
| `list_fare_files` | List available CSVs with fare counts, markets, carriers |
| `get_schema` | Column names + a sample row for one file |
| `query_fares` | Filter fares (exact-match on any column, price range), sorted, compact column projection |
| `fare_summary` | Count/min/avg/max of Fare AMT and Total Price AMT grouped by any column (default Cabin) |
| `compare_files` | Diff two snapshots of a market: added / removed / repriced fares |
| `shop_fares` | Live fare shop via engine-wrapper-service — POST to frmwithtotalpricewrapperstream |

### shop_fares notes

- Requires the internal engine-wrapper endpoint (corporate network/VPN).
  Configure it via `ENGINE_WRAPPER_URL` — copy `.env.example` to `.env` and
  fill in the URL (ask your team; it is deliberately not committed) — or pass
  `endpoint_url` per call (e.g. to hit the historical wrapper).
- `origin`, `destination`, `carrier` are required; everything else defaults to
  the standard request: dates (`travelDate`, `asOfDateTime`, `ticketDate`)
  default to the current date/time in engine format (e.g. `02AUG26T1119`),
  `hostCarrier` defaults to `carrier`, `userId` defaults to `ATP1XXX`,
  trip type `OW`, `daysStay` 7.
- Any other request field can be set through the `overrides` dict, which is
  merged last and wins (e.g. `{"taxes": false, "validateCategories": "15"}`).
  An override set to `null` removes that field from the request entirely.
- Responses whose parsed JSON exceeds `max_response_chars` (default 200000)
  return a preview only, to protect the LLM context window. Programmatic
  callers should pass `max_response_chars: 0` for complete data.

## Setup

```bash
cd fare-mcp-server
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
cp .env.example .env   # then fill in ENGINE_WRAPPER_URL
```

## Running without Claude

Claude is just one MCP client — the server runs standalone and anything that
speaks MCP (or plain Python) can drive it.

**Raw stdio mode** (what any MCP client spawns):

```bash
.venv/bin/python server.py
```

It waits silently for JSON-RPC on stdin — normal for a stdio server. Ctrl+C
to exit.

**MCP Inspector** — interactive web UI to browse and call the tools (best for
development, debugging, and demos; requires Node):

```bash
npx @modelcontextprotocol/inspector .venv/bin/python server.py
```

**From a Python script** — the MCP client library is already installed in the
server's venv:

```python
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def main():
    params = StdioServerParameters(command=".venv/bin/python", args=["server.py"])
    async with stdio_client(params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool("list_fare_files", {})
            print(result.content[0].text)

asyncio.run(main())
```

**No MCP at all** — the tools are plain Python functions:

```bash
.venv/bin/python -c "import server, json; print(json.dumps(server.list_fare_files(), indent=2))"
```

## Register with Claude Code

From the directory where you cloned this repo:

```bash
claude mcp add --scope user fare-data \
  --env FARE_DATA_DIR="$(pwd)/../fare-data" \
  -- "$(pwd)/.venv/bin/python" "$(pwd)/server.py"
```

(`--env FARE_DATA_DIR=...` is optional — see the resolution order above.)

## Register with Claude Desktop

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`,
replacing `<repo>` with your clone's absolute path:

```json
{
  "mcpServers": {
    "fare-data": {
      "command": "<repo>/.venv/bin/python",
      "args": ["<repo>/server.py"]
    }
  }
}
```

Then restart Claude Desktop.

## Use from FarePulse-Agent

FarePulse-Agent can route its wrapper snapshot calls and competitor probes
through this server: clone the two repos side by side and set
`FARE_MCP_ENABLED=1` in FarePulse-Agent's `.env` (see the "fare-data MCP
server" section of its README).

## Example prompts once connected

- "What fare files are available?"
- "Show me the cheapest business-class fares in MEX_LAX_28Jul.csv"
- "Summarize fares by cabin in the 28Jul file"
- "What changed between the 10Jul and 28Jul MEX-LAX snapshots?"
- "Shop live fares for ADL-LAX on FJ, one way"