mcp-tellus-search
by senzg
README.md
# mcp-tellus-search
A Model Context Protocol (MCP) server that exposes Skyscanner's Tellus (Travel API v2) to Claude.
---
## What is MCP?
MCP (Model Context Protocol) is a protocol that lets Claude call external tools. This project packages Tellus API functions as MCP tools so Claude can search geo entities (cities, airports, hotels, etc.) directly during a conversation.
When Claude is connected to this MCP server, it can:
- Look up entities by ID
- Search entities by type or location
- Fetch child entities of a parent (e.g. all hotels in a city)
- Find nearby entities by radius
- Get suggested airports for a city
---
## How it works
### Architecture
```
Claude Code
│
│ stdio (JSON messages)
▼
Docker Container ←── mcp.run() blocks here, waiting for requests
│
└── python src/server.py
│
└── FastMCP registers all @mcp.tool() functions
│
└── requests → Tellus API (gateway.skyscanner.net)
```
### Key concepts
- `@mcp.tool()` decorator registers a function as an MCP tool. Claude sees the function name, docstring, and type annotations — it never sees the raw source code.
- `mcp.run()` starts the server and blocks, listening on stdin. The container stays alive for the entire Claude session (one container per session).
- The container is started automatically by Claude Code when it reads `.mcp.json`, and destroyed on exit (`--rm`).
---
## Project structure
```
.
├── Dockerfile # Packages the server into a Docker image
├── .mcp.json # Tells Claude Code how to launch the server
├── requirements.txt # Python dependencies installed inside the image
└── src/
└── server.py # MCP tools + Tellus API helper functions
```
---
## Available tools
| Tool | Description |
|---|---|
| `get_entities` | Fetch entities by ID list (up to 200) via GET /v2/entities |
| `search_entities` | Search entities by type/ID with optional name filter via POST /v2/search |
| `fetch_children` | Fetch child entities of a parent, auto-selects filter strategy by type |
| `fetch_nearby_entities` | Fetch entities within a radius of an entity or lat/lon |
| `get_entity_type` | Resolve the type of a single entity |
| `get_suggested_airports` | Get suggested airports for a city (deprecated endpoint, limited coverage) |
| `fetch_children_parallel` | `fetch_children` for multiple parents in parallel |
| `fetch_nearby_entities_parallel` | `fetch_nearby_entities` for multiple locations in parallel |
| `search_entities_parallel` | `search_entities` for multiple queries in parallel |
### Filter strategy by entity type
| Entity type | Filter used |
|---|---|
| Hotel, Airport, CarHireOffice | `relations.geopolitical_parents:containsAny` |
| TouristAttraction, MetroStation, District, City | `hierarchy:isChildOf` |
---
## Build and deploy
### Prerequisites
- Docker Desktop installed and running
- Claude Code
### 1. Build the image
```bash
cd /path/to/this/project
docker build -t mcp-tellus-search .
```
`docker build` executes all `RUN` instructions in the Dockerfile (installs dependencies, copies source). The resulting image is stored in your local Docker registry.
`docker run` is what actually starts the container and triggers `CMD ["python", "src/server.py"]`.
### 2. Configure Claude Code
**Project-level** (only active when Claude Code is opened in this directory):
`.mcp.json` is already configured:
```json
{
"mcpServers": {
"mcp-tellus-search": {
"command": "docker",
"args": ["run", "--rm", "-i", "mcp-tellus-search"]
}
}
}
```
**Global** (active in any directory):
Add to `~/.claude.json` under `mcpServers`:
```json
"mcp-tellus-search": {
"type": "stdio",
"command": "docker",
"args": ["run", "--rm", "-i", "mcp-tellus-search"]
}
```
### 3. Restart Claude Code
Run `/mcp` to verify the server shows as connected.
---
## How Claude Code finds .mcp.json
Claude Code scans upward from the current working directory for `.mcp.json`, the same way git looks for `.git`. It also loads global MCP servers from `~/.claude.json`. Project-level config takes precedence over global config for servers with the same name.
---
## Distributing the image
To share this server with others without requiring them to build from source:
```bash
# Push to Docker Hub
docker push your-username/mcp-tellus-search
# Others only need .mcp.json pointing to the image name
# Docker pulls it automatically on first run
```
This is the key advantage of Docker packaging: the recipient needs no Python, no pip install — just Docker and the `.mcp.json` config file.
---
## Tellus API reference
- Base URL: `https://gateway.skyscanner.net/travel-api/v2`
- Docs: [Travel API v2 User Guide](https://skyscanner.atlassian.net/wiki/spaces/AS/pages/154286038/Travel+API+v2+User+Guide)
- Use `geometry_centroid` instead of `geometry` (per API guidelines)
- Parallel fetch functions use `ThreadPoolExecutor` with `MAX_WORKERS=10` (~8x speedup)
- Do not use `requests.Session()` in parallel code — use plain `requests.post()` which is thread-safe
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues