Skip to main content
Glama
Shivanilarokar

Trip Planner MCP Server

README.md
# Trip Planner — MCP Server + LangGraph Agent

A journey-planning MCP server built with FastMCP, plus a LangGraph agent that
connects to it alongside two public MCP servers. The agent manages a
traveller's itinerary: journeys (trips as a whole), the city stops within a
journey, and the plan items (sights, meals, activities) within each stop.

## Architecture

![Architecture](DocsAndDemo/architecture.png)

The user asks a question. The LangGraph agent thinks: if it needs a tool, it
calls one, gets the result, and thinks again — repeating until it has enough
to answer. `MultiServerMCPClient` connects to all three MCP servers when the
agent starts and hands every discovered tool to the agent. One server is
ours; two are public.

## Data model, tools, resource, prompt

SQLite, three tables, one nesting level each:

| Table | Holds |
|---|---|
| `journeys` | A trip as a whole — title, home city, dates, budget |
| `stops` | A city leg within a journey — city, country, arrival date, nights, transport mode |
| `plan_items` | A sight/meal/activity within a stop — title, category, time window, priority, status |

**Tools** (`backend/mcpserver/TripPlannerServer.py`) — full CRUD plus a live weather lookup:

| Tool | CRUD |
|---|---|
| `create_journey` | Create |
| `add_stop` | Create |
| `add_plan_item` | Create |
| `list_stops` | Read |
| `update_plan_status` | Update |
| `delete_stop` | Delete (cascades to its plan items) |
| `get_destination_weather` | Calls the free Open-Meteo API (geocoding + current weather), no key needed |

**Resources**:
- `journeys://all` — one-line summary of every journey
- `journey://{journey_id}/itinerary` — templated resource, a day-by-day itinerary for one journey (each stop with its plan items underneath)

**Prompt**:
- `suggest_itinerary(stop_id)` — a reusable template that turns a stop's saved plan items into an hour-by-hour day plan

## Public servers used, and why

- **`time`** (`uvx mcp-server-time`, stdio) — official reference MCP server for
  timezone/local-time lookups. Trivial, zero-risk, no genuine remote
  alternative exists for this, so stdio is the right call here.
- **`tavily`** (Streamable HTTP, `https://mcp.tavily.com/mcp`) — a genuinely
  **hosted remote** MCP server (no local process at all) from Tavily, a
  reputable company in the LLM tooling space (the same search backend
  LangChain's own community tools use). It needs a free API key
  (tavily.com, no credit card). Picked over a plain page-`fetch` server
  because it does real-time, ranked web *search* (attractions, travel
  advisories, local facts) rather than fetching one raw page — a much
  stronger fit for a trip planner. Deliberately avoided pulling a server
  from the public MCP registries (`registry.modelcontextprotocol.io`,
  Smithery, Glama) directly — those directories are unvetted, and searching
  them turned up entries with suspicious names during development. Tavily is
  a known, reputable company with a real product, not an anonymous registry
  listing.

## Extras beyond the core CRUD flow

- `get_destination_weather` calls the free Open-Meteo API from inside a tool
  (geocoding + current weather, no key required).
- `backend/integrations/fastapimcp_integration.py` serves REST
  (`/health`, `/journeys`) and MCP (`/mcp`) from one FastAPI ASGI app.
- `add_stop` logs via `ctx.info(...)`, visible live in the MCP Inspector's
  notification panel.
- A browser console (`backend/api/app.py` + `frontend/`) — see below.

## Console UI (bonus)

A small React console for driving the agent from a browser instead of the
CLI: pick one of the 12 test questions (or type your own), watch each tool
call and its result stream in live, tool by tool, as the agent runs.

`backend/api/app.py` wraps the same LangGraph agent from
`backend/client/langgraphagent.py` in a long-lived FastAPI process. It
connects to all three MCP servers once at startup, then streams each
question's step-by-step trace back to the browser as newline-delimited JSON.

Three processes, three terminals:
```
uv run backend/mcpserver/TripPlannerServer.py     # :8000 — the MCP server
uv run python -m backend.api.app                  # :8010 — streaming console API
cd frontend && npm install && npm run dev          # :5173 — the UI
```
Open the printed `localhost` URL. The left rail shows live server/tool
counts from `/api/servers`; the question list is the same 12-question set as
[`DocsAndDemo/question.md`](DocsAndDemo/question.md).

## How to run it

1. Install dependencies (uses `uv`):
   ```
   uv sync
   ```
2. Copy `.env.example` to `.env` and fill in:
   ```
   OPENAI_API_KEY=sk-...
   TAVILY_API_KEY=tvly-...      # free key at https://tavily.com
   ```
3. Start the server (terminal 1):
   ```
   uv run backend/mcpserver/TripPlannerServer.py
   ```
   Live at `http://127.0.0.1:8000/mcp` (note the required `/mcp` suffix).

   Optional — run the combined REST+MCP app instead:
   ```
   uv run python -m backend.integrations.fastapimcp_integration
   ```
4. Run the agent (terminal 2):
   ```
   uv run backend/client/langgraphagent.py "Add a 3-night stop in Kyoto to journey 1 and tell me the local time there"
   ```
5. Optional — test the server directly in the MCP Inspector before running the agent:
   ```
   npx @modelcontextprotocol/inspector
   ```
   Transport: Streamable HTTP, URL: `http://127.0.0.1:8000/mcp`.

Requires `uv` (Python/uvx) and Node.js (`npx`, for the Inspector) installed.

## Example runs

Full tool-call traces are in [`screenshots/demo.txt`](screenshots/demo.txt).
Summary:

1. **Write-only** — *"Create a new journey called 'Bali Getaway' from
   Mumbai, budget 1500, dates 2026-09-01 to 2026-09-10. Then add a 5-night
   stop in Bali, Indonesia to it."* → Created journey #3 and stop #4 on our
   server.
2. **Write + public `time`** — *"Add a 4-night stop in Reykjavik, Iceland to
   journey 3, and tell me the current local time there."* → Added stop #5,
   and called `get_current_time` (both tool calls fired in parallel in one
   turn) → 11:03, Saturday, Atlantic/Reykjavik (UTC+0).
3. **Public `tavily` research** — *"What are the top attractions to see in
   Reykjavik right now, and are there any current travel advisories for
   Iceland?"* → Real-time web search returned 8 ranked attractions and 3
   current government travel advisories, with live sources.

## Why an MCP server instead of plain Python functions in the agent?

Putting tools in an MCP server decouples *what a tool can do* from *which
agent uses it*. The same `trip_planner` server can be called by this
LangGraph agent, tested by hand in the MCP Inspector, or plugged into a
completely different agent or client later, all without touching the tool
code — because the server exposes a stable, self-describing contract
(schemas generated straight from function signatures and docstrings) over a
standard protocol, instead of being tangled into one agent's Python process.
It also means the server can run, scale, and fail independently of the
agent: if the trip-planner logic needs a different host, a different
language, or its own deployment schedule, that's an infrastructure change,
not a rewrite. Writing the same logic as inline Python functions works fine
for a single throwaway script, but it locks the tool to that one agent and
gives up all of that reuse, isolation, and discoverability for no benefit.

## Video walkthrough

[`DocsAndDemo/12.07.2026_22.51.20_REC.mp4`](DocsAndDemo/12.07.2026_22.51.20_REC.mp4) — demo, architecture walkthrough, MCP connection config, and live tool calls across the local and public servers.