trip-search-mcp
# trip-search-mcp
**Let Claude plan trips for you, in plain English.** Live searches against Google Flights, Google Hotels, vacation rentals, Airbnb, Tripadvisor activities, and event ticket vendors β plus weather forecasts, currency conversion, persistent price watches, and per-property detail drill-downs. Eleven tools, one config block.
```
You: Find me round-trip flights Helsinki β Washington DC for May 18,
returning May 29, one stop or fewer.
Claude: [calls search_flights with WAS auto-expanded to IAD, DCA, BWI;
merges 3 parallel results, ranks cheapest first, returns a
summary with "Book on Google Flights" links]
```
π **[FEATURES.md](./FEATURES.md)** has the full plain-English feature list with paste-ready example prompts for every capability β read that to see what's possible.
π **[TRIP-PLANNING-EXPANSION-SPEC.md](./TRIP-PLANNING-EXPANSION-SPEC.md)** tracks the five-track expansion plan (weather, currency, events, activities, drill-down). Weather is shipped; the other four are queued.
---
## Before you start
You need:
- A computer running **macOS, Windows, or Linux**
- **[Claude Desktop](https://claude.ai/download)**, signed in
- About **5 minutes** the first time
You do NOT need an account anywhere except Claude β unless you also want hotel search, which uses a free SerpAPI key (covered as an optional step below).
---
## Install β step by step
Everything below happens in your **Terminal app** (macOS/Linux) or **PowerShell** (Windows).
> **Don't know what a terminal is?** macOS: press `β+Space`, type `Terminal`, press Enter. Windows: press the Win key, type `PowerShell`, press Enter.
### 1. Install Python 3.12 (skip if you already have it)
```bash
python3 --version
```
If you see `Python 3.12.x` or higher, jump to step 2. Otherwise install `uv` β one line, brings Python with it:
```bash
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
```
```powershell
# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```
**Open a fresh terminal window** after the installer finishes so the `uv` command is on your path.
### 2. Download the project
```bash
git clone https://github.com/nanwer/trip-search-mcp.git
cd trip-search-mcp
```
Missing `git`? macOS: run `xcode-select --install`. Windows: install from [git-scm.com](https://git-scm.com/download/win) and reopen PowerShell.
### 3. Install the package
```bash
uv venv
uv pip install -e .
```
Creates `.venv/` and installs everything. About 30 seconds.
### 4. Find the absolute path to the venv Python
You'll paste this into Claude Desktop's config in the next step.
```bash
# macOS / Linux
echo "$(pwd)/.venv/bin/python"
```
```powershell
# Windows
echo "$(Resolve-Path .\.venv\Scripts\python.exe)"
```
Copy what it prints β looks like `/Users/you/trip-search-mcp/.venv/bin/python` (macOS) or `C:\Users\you\trip-search-mcp\.venv\Scripts\python.exe` (Windows).
### 5. Add a `trip-search` entry to Claude Desktop's config
This is the one step where you have to edit a text file by hand (or get Claude to edit it for you β see the callout below). The file is JSON; if you've never edited JSON before, just be careful with commas and quotes.
**Where is the file?**
| OS | Path | Quickest way to find it |
|---|---|---|
| **macOS** | `~/Library/Application Support/Claude/claude_desktop_config.json` | In Finder, hit `β+Shift+G` and paste `~/Library/Application Support/Claude/`. Or run the `open -e` command below. |
| **Windows** | `%APPDATA%\Claude\claude_desktop_config.json` | In File Explorer, paste `%APPDATA%\Claude\` into the address bar. Or run the `notepad` command below. |
| **Linux** | `~/.config/Claude/claude_desktop_config.json` | Open in your favorite text editor. |
Open the config file:
```bash
# macOS
open -e "$HOME/Library/Application Support/Claude/claude_desktop_config.json"
```
```powershell
# Windows
notepad "$env:APPDATA\Claude\claude_desktop_config.json"
```
### 5a. Pick your scenario
The config file is shared across every MCP server Claude Desktop knows about. **Read the right scenario below before editing β adding trip-search to a file that already has other servers in it is different from setting it up from scratch.**
> π **Not sure which scenario you're in or worried about breaking things?**
> Take a screenshot of your current config file (or copy-paste its contents) into a Claude chat and ask:
> *"Merge a trip-search block into this MCP config without removing my existing servers. My venv Python path is /PASTE/PATH/FROM/STEP-4/HERE."*
> Claude will hand back the full merged JSON. Paste that back into the file. No JSON wrangling required.
---
#### Scenario A β You've never set up an MCP server before (fresh file)
The file probably doesn't exist yet. Create it:
```bash
# macOS
mkdir -p "$HOME/Library/Application Support/Claude"
cat > "$HOME/Library/Application Support/Claude/claude_desktop_config.json" << 'JSON'
{
"mcpServers": {
"trip-search": {
"command": "/PASTE/PATH/FROM/STEP-4/HERE",
"args": ["-m", "trip_search_mcp.server"]
}
}
}
JSON
```
```powershell
# Windows
New-Item -ItemType Directory -Path "$env:APPDATA\Claude" -Force | Out-Null
@'
{
"mcpServers": {
"trip-search": {
"command": "C:\\PASTE\\PATH\\FROM\\STEP-4\\python.exe",
"args": ["-m", "trip_search_mcp.server"]
}
}
}
'@ | Out-File -Encoding utf8 "$env:APPDATA\Claude\claude_desktop_config.json"
```
Then open it in a text editor and replace `/PASTE/PATH/FROM/STEP-4/HERE` with the path you copied in step 4. **Windows users:** every `\` in the path must be doubled to `\\`.
---
#### Scenario B β You already have other MCP servers configured
Your file looks something like this (the names will differ β yours might have Outline, Slack, Figma, etc.):
```json
{
"mcpServers": {
"outline": {
"command": "...",
"args": [...],
"env": {...}
}
}
}
```
You need to **add** the trip-search block alongside your existing one(s). Open the file:
```bash
# macOS
open -e "$HOME/Library/Application Support/Claude/claude_desktop_config.json"
```
```powershell
# Windows
notepad "$env:APPDATA\Claude\claude_desktop_config.json"
```
Then add `"trip-search": { ... }` inside `mcpServers`. The result should look like this:
```json
{
"mcpServers": {
"outline": {
"command": "...",
"args": [...],
"env": {...}
},
"trip-search": {
"command": "/PASTE/PATH/FROM/STEP-4/HERE",
"args": ["-m", "trip_search_mcp.server"]
}
}
}
```
β οΈ **Two things to watch out for:**
1. **Don't forget the comma** after the closing `}` of your existing server block, before `"trip-search":`. Without it, the file is invalid JSON and Claude Desktop will load *no* MCP servers.
2. **Windows paths:** every `\` in the `command` field must be doubled (`\\`). Example:
```json
"command": "C:\\Users\\you\\trip-search-mcp\\.venv\\Scripts\\python.exe"
```
Save the file when done.
> **Lost the formatting?** Paste your file's current contents (and the path from step 4) into a Claude chat and ask it to add the trip-search block for you. Way safer than hand-editing if you're not comfortable with JSON.
### 6. Fully quit and reopen Claude Desktop
**Closing the window isn't enough.** Quit from the menu bar (macOS: `βQ` or right-click the dock icon β Quit) or from the system tray (Windows: right-click the Claude icon β Quit). Then reopen.
### 7. Test it
Open a new chat in Claude Desktop. Click the hammer/tools icon at the bottom of the message box β you should see `trip-search` with **7 always-on tools** plus 4 more after step 8 below:
| Tool | Needs SERPAPI_KEY? |
|---|---|
| `search_flights` | No |
| `search_cheapest_dates` | No |
| `search_stays` with `category="airbnb"` | No |
| `get_weather_forecast` | No |
| `convert_currency` | No |
| `watch_flight_price` / `list_active_watches` / `cancel_watch` | No |
| `search_stays` (default / hotels / vacation_rentals) | **Yes** |
| `get_stay_details` | **Yes** |
| `search_events` | **Yes** |
| `search_activities` | **Yes** |
Ask Claude:
> *"Find me round-trip flights from JFK to LHR, leaving July 12 returning July 22, 1 adult, economy."*
If you get a summary with prices and a "Book on Google Flights" link, you're done. Browse [FEATURES.md](./FEATURES.md) for everything else you can ask.
---
## Step 8 (optional) β turn on hotel + event + activity search
Hotels, vacation rentals, events, activities, and `get_stay_details` use [SerpAPI](https://serpapi.com) β free tier 100 searches/month. The flight tools, the Airbnb category, weather, currency, and watches all work without it.
1. Sign up at [serpapi.com](https://serpapi.com) (Google login works).
2. Copy your key from [serpapi.com/manage-api-key](https://serpapi.com/manage-api-key).
3. Open your config file again and **add** an `env` block to the trip-search entry. Two scenarios:
**If trip-search is your only MCP server**, your file becomes:
```json
{
"mcpServers": {
"trip-search": {
"command": "/PASTE/PATH/FROM/STEP-4/HERE",
"args": ["-m", "trip_search_mcp.server"],
"env": {
"SERPAPI_KEY": "paste-your-key-here"
}
}
}
}
```
**If you have other MCP servers** alongside trip-search, only modify the trip-search block β leave the others untouched:
```json
{
"mcpServers": {
"outline": { ... }, // leave alone
"slack": { ... }, // leave alone
"trip-search": {
"command": "/PASTE/PATH/FROM/STEP-4/HERE",
"args": ["-m", "trip_search_mcp.server"],
"env": { // β add this block
"SERPAPI_KEY": "paste-your-key-here"
}
}
}
}
```
β οΈ Don't forget the **comma** after `"args": [...]` before `"env":` β without it, the JSON is invalid.
4. **βQ and reopen Claude Desktop.** The four SerpAPI-gated tools (`search_stays` hotels mode, `get_stay_details`, `search_events`, `search_activities`) now work.
> π Again, if you'd rather not hand-edit JSON, paste your current config plus the API key into a Claude chat and ask it to add the SerpAPI env block for you. Faster than chasing missing commas.
---
## If something doesn't work
| Symptom | Fix |
|---|---|
| The `trip-search` server doesn't appear in Claude's tools menu | You forgot to fully quit. βQ (or quit from the system tray on Windows), then reopen. |
| `search_stays` says "SERPAPI_KEY is not set" | The `env` block is missing or you reopened Claude before saving the config. Re-check step 8, then βQ + reopen. |
| Claude says "the tool call timed out" | A previous Claude Desktop quit may have left a stale MCP subprocess running. Run `pgrep -f trip_search_mcp` β if more than 2 PIDs show up, run `pkill -f trip_search_mcp.server` (macOS/Linux) or End Task on every `Claude` process in Task Manager (Windows), then βQ + reopen. |
| `ModuleNotFoundError: No module named 'trip_search_mcp'` | The `command` path in your config points to the wrong Python. Re-run step 4 and paste that exact path. |
| Airbnb search returns an `upstream_error` | Airbnb sometimes pushes back on scraping during high traffic. Wait a few minutes and retry. If it keeps failing, [pyairbnb](https://github.com/johnbalvin/pyairbnb) may need a release. |
[docs/SETUP.md](./docs/SETUP.md) has a longer, verbose walkthrough.
---
## Card / button rendering β baked into the server
The MCP server publishes **server-level instructions** at handshake time that tell Claude:
1. Render multi-result tool output as an HTML artifact with one card per result (not as prose).
2. Every booking partner gets its own button, side-by-side.
These instructions load **once** when Claude Desktop connects to the server and persist for the whole chat β you don't have to remember to add anything to your prompts.
If you still see prose-with-markdown-links for a specific query (Claude has discretion), you can reinforce with:
> *"Render every multi-result tool output as an HTML/React artifact card with prominent buttons β don't summarize as prose."*
Or for a single combined trip-plan artifact:
> *"Put the final trip plan in a single HTML artifact. Each item is a card with a big rounded 'Book on X' button β not a markdown link."*
The directive lives in `src/trip_search_mcp/server.py` as `_SERVER_INSTRUCTIONS`. Edit it there if you want to tune the behavior for your own use.
---
## Updating to the latest version
Claude Desktop spawns the MCP subprocess **once** at launch and keeps running it. Pulling new code doesn't reload the running process β you have to βQ and reopen Claude Desktop after every update.
### Recent install (within the last few weeks)
```bash
cd /path/to/trip-search-mcp
git pull
uv pip install -e . # reinstalls in case dependencies changed
```
Then **βQ Claude Desktop and reopen.**
Verify:
```bash
.venv/bin/python -c "from trip_search_mcp.server import mcp; print(mcp.name)"
# β trip-search-mcp
```
### Updating from an older version (before the `flights-mcp` β `trip-search-mcp` rename)
Older installs used the module name `flights_mcp` (now `trip_search_mcp`). If your Claude Desktop config still says `-m flights_mcp.server`, the server will fail to start with `ModuleNotFoundError` after the update. Three things to fix:
1. **Pull and reinstall:**
```bash
cd /path/to/trip-search-mcp # path is unchanged; GitHub redirects the old repo URL
git pull
uv pip install -e . # picks up new deps including pyairbnb
```
2. **Edit your Claude Desktop config.** Open
`~/Library/Application Support/Claude/claude_desktop_config.json`
(macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows)
and update the `args` array:
```diff
- "args": ["-m", "flights_mcp.server"]
+ "args": ["-m", "trip_search_mcp.server"]
```
Optionally rename the JSON key from `"flights"` to `"trip-search"`
so the entry in Claude Desktop's tools menu matches the new docs.
3. **βQ Claude Desktop and reopen.**
### Common gotchas during an update
| Symptom | Cause / Fix |
|---|---|
| `ModuleNotFoundError: No module named 'trip_search_mcp'` | Your config still points at the old module name. See "Updating from an older version" above. |
| `ModuleNotFoundError: No module named 'pyairbnb'` | New dependency added since your install. Run `uv pip install -e .` to pick it up. |
| `trip-search` server shows "running" but new tools (`search_stays`, `get_stay_details`, `watch_flight_price`, β¦) don't appear | You didn't fully quit. Closing the window doesn't kill the subprocess on macOS or Windows. Use βQ (macOS) or the system-tray Quit (Windows). |
| Updates seem to apply but a specific tool times out | Two MCP subprocesses may be running (Claude Desktop occasionally fails to kill the old one). Check with `pgrep -f trip_search_mcp.server` β if you see more than 2 PIDs, run `pkill -f trip_search_mcp.server` and reopen Claude Desktop. |
| The Claude Code CLI (not Desktop) doesn't see the updates | `claude mcp` commands cache server metadata. Restart your Claude Code session, or remove and re-add the server: `claude mcp remove trip-search && claude mcp add trip-search -- /ABSOLUTE/PATH/TO/.venv/bin/python -m trip_search_mcp.server` |
---
## For developers
```bash
.venv/bin/pytest -q # 350 tests, all fixture-driven, no live API calls
```
Source layout:
```
src/trip_search_mcp/
βββ server.py FastMCP entry point β registers 7 tools
βββ models.py Pydantic I/O models
βββ cache.py TTL response cache (tool-namespaced keys)
βββ cities.py City code β airport list map (27 cities)
βββ errors.py ErrorCode enum, ToolError, envelope helpers
βββ logging_config.py JSON-line file logger
βββ tools/
β βββ search_flights.py
β βββ search_cheapest_dates.py
β βββ search_stays.py
β βββ get_stay_details.py
β βββ watch_flight_price.py
β βββ list_active_watches.py
β βββ cancel_watch.py
βββ fli_backend/ flights β via fli library, no auth
βββ serpapi_hotels_backend/ hotels + vacation rentals β SerpAPI
βββ serpapi_events_backend/ concerts + festivals + sports β SerpAPI google_events
βββ tripadvisor_backend/ things-to-do β SerpAPI Tripadvisor (ssrc=A)
βββ airbnb_backend/ Airbnb direct β pyairbnb + Nominatim geocoding
βββ open_meteo_backend/ weather forecasts β Open-Meteo, no auth
βββ ecb_backend/ currency conversion β ECB daily feed, no auth
βββ monitoring/ SQLite-backed price watches (lazy refresh)
```
Capture fresh real-data fixtures (uses live APIs β burns 1 call each):
```bash
.venv/bin/python scripts/verify_fli.py # flights
.venv/bin/python scripts/verify_serpapi_hotels.py # hotels
.venv/bin/python scripts/verify_vacation_rentals.py # rentals
.venv/bin/python scripts/verify_property_details.py # property details
```
Further docs:
- [FEATURES.md](./FEATURES.md) β every capability, plain English, with example prompts and combined-workflow scenarios.
- [docs/SETUP.md](./docs/SETUP.md) β verbose install + troubleshooting.
- [AGENTS.md](./AGENTS.md) β notes for AI coding agents working on this repo (topology, gotchas, hallucination traps).
- [BACKLOG.md](./BACKLOG.md) β completed items + new follow-ups surfaced during the work.
---
## License
MIT.
TDQS
Scored across 11 tools
Each tool targets a distinct domain or action: flight searching, price watching, stays, activities, events, weather, and currency conversion. There is no overlap between tools; even the flight-related tools (search_flights, search_cheapest_dates, watch_flight_price, list_active_watches, cancel_watch) have clearly differentiated purposes.
Tool names use a mix of verb styles: 'search_' for five tools, 'get_' for two, and individual verbs like 'cancel_', 'convert_', 'list_', and 'watch_'. While each name is clear, the lack of a uniform pattern makes the set slightly less predictable.
With 11 tools, the server covers essential trip planning needsβflight search, price monitoring, stay search, activities, events, weather, and currency conversionβwithout unnecessary bloat. The count is well-scoped for its domain.
The tool surface covers core trip planning tasks comprehensively. Minor gaps exist: get_activity_details is referenced but not implemented, and there is no tool for booking flights or stays (though that may be out of scope). Overall, agents can accomplish most planning workflows without dead ends.