MolTravel
Aggregated travel MCP β flights, tours, activities, price checks, visas, and more.
Ask AI about MolTravel
Powered by Claude Β· Grounded in docs
I know everything about MolTravel. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
MoltTravel
One MCP server. Every travel tool.
Search flights, compare prices, check visas, look up airports,
get travel advisories β through a single endpoint.
Kiwi.com Navifare Peek.com LastMinute
(flights) (prices) (experiences) (flights)
\ | | /
\ | | /
+--------+-----------+--------+
| |
| MoltTravel MCP Server |
| |
| Airports Airlines Visas |
| Countries FCDO Gemini AI |
| |
+-------------|---------------+
|
MCP over HTTP
|
Any MCP Client
(Claude, Cursor, your app)
Why?
Travel data is scattered across dozens of APIs, each with its own auth, format, and quirks. MoltTravel aggregates them behind a single Model Context Protocol endpoint:
- 21+ tools from 4 upstream MCP providers + 6 built-in datasets
- Zero config for static data β airports, airlines, and visas load lazily with no API keys
- Schema-transparent proxy β clients see the real upstream JSON Schema; upstream servers validate their own args
- One line to connect from Claude Desktop, Claude Code, Cursor, or any MCP client
Quick Start
git clone https://github.com/navifare/moltravel-mcp.git
cd moltravel-mcp
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
python molttravel_server.py
Server starts at http://localhost:8000/mcp. That's it.
Connect Your Client
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"molttravel": {
"url": "http://localhost:8000/mcp"
}
}
}
Claude Code
Add to .claude/settings.json:
{
"mcpServers": {
"molttravel": {
"url": "http://localhost:8000/mcp"
}
}
}
Python (programmatic)
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
async with streamablehttp_client("http://localhost:8000/mcp") as (r, w, _):
async with ClientSession(r, w) as session:
await session.initialize()
tools = await session.list_tools()
result = await session.call_tool("airports_lookup", {"code": "ZRH"})
Tools
Flights & Pricing
| Tool | Provider | What it does |
|---|---|---|
kiwi_search-flight | Kiwi.com | Search flights by route, date, passengers, cabin class |
navifare_format_flight_pricecheck_request | Navifare | Parse flight details from natural language into structured data |
navifare_flight_pricecheck | Navifare | Compare a flight's price across multiple booking sites |
Experiences & Activities
| Tool | Provider | What it does |
|---|---|---|
peek_search_experiences | Peek.com | Search 300K+ verified activities worldwide |
peek_experience_details | Peek.com | Full details, reviews, and photos for an experience |
peek_experience_availability | Peek.com | Check availability and pricing for specific dates |
peek_search_regions | Peek.com | Find region IDs by name |
peek_list_tags | Peek.com | Browse activity categories and tags |
peek_render_activity_tiles | Peek.com | Render embeddable activity widgets |
Reference Data (built-in, no API keys needed)
| Tool | Dataset | What it does |
|---|---|---|
airports_lookup | OurAirports | Look up by IATA or ICAO code |
airports_search | OurAirports | Search by name, filter by country or type |
airports_near | OurAirports | Find airports within a radius of any coordinates |
airlines_lookup | OpenFlights | Look up by IATA or ICAO code |
airlines_search | OpenFlights | Search by name, filter by country or active status |
visa_check | Passport Index | Check visa requirement between two countries |
visa_summary | Passport Index | Full visa-free/VOA/e-visa breakdown for a passport |
restcountries_country_info | REST Countries | Capital, currencies, languages, timezones, population |
fcdo_travel_advice | UK FCDO | Safety advisories, entry requirements, health warnings |
fcdo_list_countries | UK FCDO | List all countries with travel advisories |
data_status | β | Check which datasets are loaded and record counts |
Natural Language (optional)
| Tool | What it does |
|---|---|
travel_agent | Ask any travel question β Gemini routes to the right tools and returns a combined answer |
Requires
GEMINI_API_KEY. Example: "Cheapest flights from Zurich to Rome next week, and do I need a visa?"
How It Works
1. Tool Discovery
On startup, MoltTravel connects to each upstream MCP server, calls tools/list, and registers every discovered tool with a {provider}_{tool_name} prefix:
kiwi β kiwi_search-flight, kiwi_feedback-to-devs
navifare β navifare_flight_pricecheck, navifare_format_flight_pricecheck_request
peek β peek_search_experiences, peek_experience_details, ...
lastminute β (discovered at runtime)
Native tools (airports, airlines, visas, countries, FCDO) are registered directly.
2. Schema-Transparent Proxy
Clients see the original upstream JSON Schema for each tool β enums, nested objects, $ref, everything. Internally, MoltTravel uses a permissive Pydantic model (Any for all fields) so arguments pass through without lossy validation. The upstream MCP server validates its own args.
# Client sees the real schema
parameters = input_schema # original from upstream
# Server doesn't re-validate types β just passes through
fields[prop_name] = (Any, Field(default=None))
3. Lazy Data Loading
Static datasets (airports, airlines, visas) download on first use behind async locks. No startup penalty, no wasted bandwidth if you only use flight tools.
Configuration
| Variable | Default | Description |
|---|---|---|
PORT | 8000 | Server port |
GEMINI_API_KEY | β | Enables the travel_agent natural-language routing tool |
Deployment
Docker
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "molttravel_server.py"]
docker build -t molttravel .
docker run -p 8000:8000 molttravel
Render / Railway / Fly.io
The server reads PORT from the environment and binds to 0.0.0.0 β it works out of the box on any container platform. Just point the start command at python molttravel_server.py.
Project Structure
moltravel-mcp/
βββ molttravel_server.py # Server core β proxy logic, native tools, routing
βββ requirements.txt # mcp[cli], httpx
βββ test_search.py # Integration test client
βββ providers/
βββ __init__.py # MCP_PROVIDERS registry + exports
βββ mcp_client.py # Generic HTTP client for upstream MCP servers
βββ data_loader.py # CSV downloader + haversine distance
βββ airports.py # 45K airports from OurAirports
βββ airlines.py # 7K airlines from OpenFlights
βββ visas.py # Visa requirements from Passport Index
βββ restcountries.py # REST Countries API
βββ fcdo.py # UK FCDO travel advisories
βββ gemini.py # Gemini Flash tool router
Extending
Add an MCP provider
Add one line to providers/__init__.py and restart:
MCP_PROVIDERS = {
"kiwi": McpClient("https://mcp.kiwi.com/mcp"),
"navifare": McpClient("https://mcp.navifare.com/mcp"),
"peek": McpClient("https://mcp.peek.com/mcp"),
"your_provider": McpClient("https://mcp.example.com/mcp"), # new
}
Tools are discovered and registered automatically as your_provider_{tool_name}.
Add a native tool
@server.tool(name="my_tool")
async def my_tool(query: str) -> str:
"""Description shown to MCP clients."""
return "result"
Data Sources & Licenses
| Dataset | Source | License |
|---|---|---|
| Airports | OurAirports | Public Domain |
| Airlines | OpenFlights | ODbL 1.0 |
| Visa Requirements | Passport Index | MIT |
| Country Info | REST Countries | MPL 2.0 |
| Travel Advisories | UK FCDO | OGL v3.0 |
Contributing
- Fork the repo
- Create a branch (
git checkout -b feature/my-feature) - Make changes and test (
python molttravel_server.py) - Open a pull request
