Skip to main content
Glama
vandamd

UK Bus Departures MCP Server

by vandamd
README.md
# UK Bus Departures MCP Server

An MCP (Model Context Protocol) server for UK bus departures and nearby bus stop discovery.

## Features

- 🚌 Real-time bus departure information for UK stops via bustimes.org
- 📍 Nearby bus stop lookup from a place name or coordinates
- 🔍 ATCO code validation
- ⚡ Built-in caching and respectful rate limiting
- 🗄️ Cloudflare D1-backed local stop lookup using NaPTAN
- 🌐 Cloudflare Workers compatible

## Tools

### `get_bus_departures`

Fetches real-time bus departures for a UK bus stop.

**Parameters**
- `stop_code` (string): UK bus stop ATCO code
- `date` (optional string): `YYYY-MM-DD`
- `time` (optional string): `HH:MM`

**Example**
```json
{
  "tool": "get_bus_departures",
  "arguments": {
    "stop_code": "0100BRP90023"
  }
}
```

### `find_nearby_bus_stops`

Finds the nearest active UK bus stops and their ATCO codes.

Provide either:
- `query` for free-text search such as `"Ada Lovelace Building"` or a postcode
- or `latitude` and `longitude`

Optional parameters:
- `radius_m` default `750`, max `5000`
- `limit` default `5`, max `10`

**Example: free-text**
```json
{
  "tool": "find_nearby_bus_stops",
  "arguments": {
    "query": "Ada Lovelace Building",
    "limit": 5
  }
}
```

**Example: coordinates**
```json
{
  "tool": "find_nearby_bus_stops",
  "arguments": {
    "latitude": 51.4545,
    "longitude": -2.5879,
    "radius_m": 1000
  }
}
```

**Response shape**
```json
{
  "resolved_location": {
    "name": "Ada Lovelace Building, Upper Richardson, Tithebarn, Broadclyst, Exeter, Devon, EX5 2FN, United Kingdom",
    "latitude": 50.7330647,
    "longitude": -3.4595234,
    "source": "nominatim"
  },
  "alternatives": [],
  "used_radius_m": 750,
  "expanded_search": false,
  "stops": [
    {
      "atco_code": "0100BRP90311",
      "naptan_code": "bstgwpm",
      "stop_name": "Temple Meads Stn",
      "indicator": "T7",
      "locality_name": "Temple Meads",
      "distance_m": 184,
      "latitude": 51.45014,
      "longitude": -2.5856
    }
  ]
}
```

### `validate_atco_code`

Validates an ATCO code format and returns stop metadata if valid.

## D1 Setup

`find_nearby_bus_stops` requires a D1 database bound as `bustimes_mcp_db`.

1. Create the database:
```bash
bunx wrangler d1 create bustimes-mcp-db
```
2. The repo is already configured with your `database_id` in [wrangler.jsonc](/Users/vandam/Developer/bustimes-mcp/wrangler.jsonc).
3. Apply migrations locally:
```bash
npm run d1:migrate:local
```
4. Apply migrations remotely:
```bash
npm run d1:migrate:remote
```
5. Import NaPTAN bus stops locally:
```bash
npm run import:naptan -- --database bustimes_mcp_db --local
```
6. Import NaPTAN bus stops remotely:
```bash
npm run import:naptan -- --database bustimes_mcp_db --remote
```

The import script downloads the national NaPTAN CSV, filters to active bus stops, and loads them into the `stops` table.

## Development

### Prerequisites

- Node.js 18+
- Wrangler CLI

### Local Development

```bash
npm install
npm run d1:migrate:local
npm run import:naptan -- --database bustimes_mcp_db --local
npm run dev
```

### Deployment

```bash
npm run deploy
```

### Type Checking

```bash
npm run type-check
```

## Connect to Claude Desktop

```json
{
  "mcpServers": {
    "uk-bus-departures": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "http://localhost:8787/sse"
      ]
    }
  }
}
```

## Technical Details

### Data Sources

- **bustimes.org API**: stop metadata
- **bustimes.org HTML**: real-time departures via scraping
- **NaPTAN**: UK stop index used for nearby stop lookup
- **Nominatim**: free-text geocoding for place-name search

### Nearby Stop Lookup

- NaPTAN data is loaded into D1 and queried locally at runtime
- Free-text location search is resolved with Nominatim and cached in D1 for 30 days
- Nearby stop lookup uses a bounding-box SQL prefilter and Haversine distance sorting
- If no stops are found within the requested radius and the radius is below 2000m, the search expands once to 2000m

### Rate Limiting and Caching

- 2-second delay between bustimes.org requests
- 5-minute in-memory cache for bustimes stop metadata
- 30-day D1 cache for Nominatim geocoding results

## Nominatim Notes

- This integration is for end-user-triggered lookups only
- Do not use it for autocomplete or background/systematic geocoding
- The server sends a custom `User-Agent` and caches results
- If you surface geocoded results to end users, include OpenStreetMap attribution where appropriate

## Limitations

- **UK only**: text geocoding is constrained to Great Britain
- **Nearby stops require D1**: the tool will fail until the D1 binding is configured, migrated, and populated
- **HTML dependency**: departures scraping is fragile to bustimes.org layout changes
- **Geocoding ambiguity**: building names can resolve to multiple plausible matches; alternatives are returned for inspection
- **No combined departures-by-nearby-stop tool**: v1 stops at discovery of nearby stops and ATCO codes

## License

MIT License

## Disclaimer

This server uses public data from bustimes.org, NaPTAN, and OpenStreetMap/Nominatim. Use responsibly and respect each upstream service's terms and usage policies.