Trip Scout
README.md
# Trip Scout — an agentic travel planner for Alexa+
> "Alexa, plan a long weekend in Barcelona in November — we have $2,500."
>
> "Best value: fly Friday, November 13, back Monday the 16th, and stay at Casa Jam, rated 4.7. $1,394 in total — $1,106 under your budget. Want me to watch this price?"
Trip Scout is a **self-hosted MCP server** (spec **2025-11-25**, **Streamable HTTP**) plus an **Agent Skill** that gives Alexa+ a real travel planner. One spoken request fans out into dozens of live Google Flights and Google Hotels searches, and comes back as one sentence for the ear and an **MCP Apps** card for the Echo Show screen.
It is not a wrapper around one API. It is an **agentic workflow**:
1. compares round-trip fares across a whole travel window (up to 14 departure days, in parallel),
2. takes the three cheapest dates and pulls hotels for exactly those nights,
3. filters hotels by the traveler's standards (review-weighted rating, stars, no dorm beds for couples),
4. builds and ranks complete flight + hotel packages against the budget,
5. remembers the traveler (home airport, party size, cabin, nonstop) and **watches prices across sessions**.
| | |
|---|---|
| **Track** | Alexa+ (self-hosted MCP server + Agent Skill, with a simulated Alexa+ host) |
| **MCP** | protocol `2025-11-25`, Streamable HTTP at `/mcp`, DNS-rebinding protection, optional bearer auth |
| **MCP Apps** | `ui://trip-scout/view.html` (`text/html;profile=mcp-app`, SEP-1865) linked from tools via `_meta.ui.resourceUri`; the view calls tools back (`tools/call`) and opens links (`ui/open-link`) |
| **Agent Skill** | [`skills/trip-scout/SKILL.md`](skills/trip-scout/SKILL.md), agentskills.io format — voice rules, tool routing, examples |
| **State** | SQLite: traveler profiles, price watches with history, saved trips — per `x-user-id` |
| **Data** | live Google Flights + Google Hotels, no API keys, no browser automation |
| **License** | MIT |
## Try it in 60 seconds
```bash
git clone https://github.com/janik4321sdfa/trip-scout && cd trip-scout
python -m venv .venv && .venv/Scripts/activate # Windows (macOS/Linux: source .venv/bin/activate)
pip install -r requirements.txt
python run_demo.py # starts the MCP server (:8765) and the Alexa+ simulator (:8770)
```
Open **http://127.0.0.1:8770**, press the mic (Chrome/Edge) or type. Try the chips: *"I live in New York"* → *"Plan a long weekend in Barcelona in November under 2500 dollars"* → *"Watch that price"* → *"Did any of my prices drop?"*
Use the MCP server from any MCP client (Claude Desktop, Cursor, MCP Inspector, Alexa+):
```bash
python -m trip_scout.server # http://127.0.0.1:8765/mcp
npx @modelcontextprotocol/inspector # connect to the URL above, transport "Streamable HTTP"
```
## Architecture
```mermaid
flowchart LR
U[User voice] --> A[Alexa+ / simulator host<br/>LLM + Agent Skill]
A -- MCP 2025-11-25<br/>Streamable HTTP --> S[Trip Scout MCP server]
S --> P[Planner<br/>parallel fan-out, ranking]
P --> F[Google Flights engine<br/>tfs protobuf]
P --> H[Google Hotels engine<br/>ts/qs protobuf, paging]
S --> DB[(SQLite<br/>profiles, price watches, trips)]
S -- ui://trip-scout/view.html --> V[MCP Apps view<br/>Echo Show cards]
V -- tools/call, ui/open-link --> A
```
| Component | File | What it does |
|---|---|---|
| MCP server | [`trip_scout/server.py`](trip_scout/server.py) | 10 tools, 1 MCP Apps resource, progress notifications, Origin/Host validation, optional bearer auth |
| Planner | [`trip_scout/planner.py`](trip_scout/planner.py) | date-window fan-out, hotel matching, Bayesian rating, budget-aware package ranking |
| Flights engine | [`trip_scout/engines/flights.py`](trip_scout/engines/flights.py) | builds Google Flights' `tfs` protobuf by hand; parses server-rendered results incl. price insights and 60-day price history |
| Hotels engine | [`trip_scout/engines/hotels.py`](trip_scout/engines/hotels.py) | builds Google Hotels' `ts` search state and `qs` page cursor; real prices for dates, guests and currency |
| Places & dates | [`trip_scout/places.py`](trip_scout/places.py), [`trip_scout/dates.py`](trip_scout/dates.py) | "Heathrow", "New York" → IATA/metro codes (OurAirports, public domain); "next friday", "november", "this weekend" |
| State | [`trip_scout/store.py`](trip_scout/store.py) | profiles, price watches with history, saved trips |
| MCP Apps view | [`trip_scout/ui/view.html`](trip_scout/ui/view.html) | dependency-free SEP-1865 view: packages, price calendar, flights, hotels, price watches |
| Agent Skill | [`skills/trip-scout/SKILL.md`](skills/trip-scout/SKILL.md) | how a voice agent should use the tools |
| Alexa+ simulator | [`web/app.py`](web/app.py), [`web/static/index.html`](web/static/index.html) | the host: loads the Skill, lets an LLM call MCP tools, speaks, renders the MCP App, shows every MCP call |
## Tools
| Tool | Example utterance | Notes |
|---|---|---|
| `plan_trip` | "Plan a long weekend in Lisbon in November under 2,000 dollars" | the agentic workflow above; reports progress |
| `find_cheapest_dates` | "When is it cheapest to fly to Tokyo next month?" | up to 14 days compared in parallel, price calendar card |
| `search_flights` | "Flights to London on December 3rd, back the 10th" | typical price range + low/typical/high verdict |
| `search_hotels` | "A hotel in Rome for three nights from Friday" | review-weighted ranking, filters |
| `watch_price` / `check_price_watches` / `list_price_watches` / `stop_watching` | "Watch that price" … a week later: "Did any of my prices drop?" | persistent, per user, with history |
| `set_travel_profile` / `get_travel_profile` | "I live in Chicago, we're two adults, nonstop only" | asked once, remembered forever |
Every tool returns `structuredContent` (for the screen) plus a **voice-ready `speech` sentence** — so the host can answer immediately after the tool call without a second LLM round trip.
## Design decisions (and why)
- **Voice first.** Answers are one or two sentences, dates are spoken ("Friday, November 13"), prices rounded, no IDs or flight numbers read aloud — the card carries the detail.
- **Latency.** Flight searches take ~1.2 s; a 14-date comparison ~3 s; a complete trip plan ~10–15 s with live progress notifications. The host skips the second LLM call when a tool already produced the sentence.
- **Trustworthy picks.** A 5.0 hotel with 12 reviews does not beat a 4.7 with 3,000 (Bayesian average); dorms and single rooms are excluded for groups.
- **Honest budgets.** If nothing fits, Trip Scout says the cheapest total instead of pretending.
- **No lock-in.** The simulator's LLM is any OpenAI-compatible endpoint — a free public one by default, **Amazon Bedrock** by setting `LLM_BASE_URL` / `LLM_MODEL`. If the LLM is down, a rule-based intent router keeps the demo alive.
- **Security.** Origin and Host headers are validated (DNS-rebinding protection per the spec), the server binds to localhost by default, `TRIP_SCOUT_TOKEN` enables bearer auth for deployments, user data is isolated per `x-user-id`.
## Tests
```bash
python -m pytest tests/test_units.py # offline: dates, places, protobuf encoders, persistence, intents
python tests/smoke_mcp.py # live: real MCP client over Streamable HTTP, every tool
python tests/conversation.py # live: the full demo conversation through the Alexa+ simulator
```
## Configuration
| Variable | Default | |
|---|---|---|
| `TRIP_SCOUT_PORT` / `TRIP_SCOUT_HOST` | `8765` / `127.0.0.1` | MCP server bind |
| `TRIP_SCOUT_TOKEN` | – | require `Authorization: Bearer …` |
| `TRIP_SCOUT_ALLOWED_HOSTS` / `_ORIGINS` | localhost | DNS-rebinding allow-lists (comma separated) |
| `TRIP_SCOUT_DB` | `~/.trip_scout/trip_scout.db` | SQLite state |
| `LLM_BASE_URL` / `LLM_API_KEY` / `LLM_MODEL` | Pollinations `openai` | simulator's LLM (e.g. Bedrock OpenAI-compatible endpoint) |
## Built during the hackathon
Everything in this repository was written for the Build, Ship, Shape hackathon (September–October 2026). The flight and hotel engines are also published as standalone open-source libraries: [google-flights-python](https://github.com/janik4321sdfa/google-flights-python) and [google-hotels-python](https://github.com/janik4321sdfa/google-hotels-python).
Product feedback and the friction log for the Amazon teams: [`docs/FEEDBACK.md`](docs/FEEDBACK.md).
## Disclaimer
Unofficial; not affiliated with Google. Uses publicly available search results at human-like request rates. Prices change constantly — always confirm on the booking site.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues