Approach: Page-by-page full-stack development with MCP-first architecture.
Time: 1 day
Backend:
- Initialize Node.js project with Express
- Install dependencies:
express,mongoose,socket.io,@modelcontextprotocol/sdk,@langchain/core,@langchain/langgraph,openai,dotenv - Set up TypeScript configuration
- Configure MongoDB connection
- Set up environment variables
Frontend:
- Initialize Vite React project
- Install:
react,tailwindcss,socket.io-client,axios,mapbox-gl,framer-motion,lucide-react - Configure Tailwind CSS
- Set up folder structure
Deliverable: Empty projects with proper structure, running dev servers.
Time: 2 days
Why Places First?: Simplest API, no auth complexity, good for learning MCP.
File: backend/src/mcp-servers/places/server.ts
Implement:
// MCP Server exposing tools:
// 1. searchDestinations(query: string) - OpenTripMap API
// 2. getPlaceDetails(placeId: string) - OpenTripMap + Google Places
// 3. getNearbyAttractions(lat, lng, radius) - OpenTripMap
// Use @modelcontextprotocol/sdk
// Expose via stdio transportTest with MCP Inspector:
npx @modelcontextprotocol/inspector node places/server.jsDeliverable: Working MCP server that returns tourist attractions.
Time: 2 days
File: backend/src/agents/travel-agent.ts
Implement:
// Simple LangGraph workflow:
// 1. User input → Planner node (GPT-4o-mini)
// 2. Planner decides which MCP tools to call
// 3. Tool executor node calls MCP server
// 4. Response formatter node creates JSON output
// 5. Return to frontend
// Connect to Places MCP server via stdio
// Use LangGraph StateGraphTest: Command-line test script that sends "Show me attractions in Paris" and gets structured response.
Deliverable: Agent that can query Places MCP server and return results.
User Story: "As a user, I can type 'Plan a 3-day trip to Barcelona' and get a conversational response with suggestions."
File: backend/src/routes/chat.ts
// POST /api/chat
// Body: { message: string, conversationId?: string }
//
// 1. Load/create conversation from MongoDB
// 2. Invoke LangGraph agent with message
// 3. Stream response via Socket.io
// 4. Save conversation state
// 5. Return initial response + conversationIdFile: backend/src/models/Conversation.ts
// MongoDB schema:
// - conversationId
// - messages: [{ role, content, timestamp }]
// - metadata: { destination, dates, budget }
// - createdAt, updatedAtSocket.io Integration:
// Real-time streaming of agent thoughts and tool calls
io.on('connection', (socket) => {
socket.on('send-message', async (data) => {
// Stream agent progress:
// - "Searching destinations..."
// - "Found 5 attractions..."
// - "Generating itinerary..."
});
});File: frontend/src/pages/Chat.jsx
UI Components:
- Message input box (bottom)
- Message list (scrollable)
- Typing indicator
- Suggested prompts ("Plan a trip to...", "Show me beach destinations")
File: frontend/src/components/Chat/MessageBubble.jsx
- User messages (right, blue)
- AI messages (left, gray)
- Loading skeleton
File: frontend/src/components/Chat/TypingIndicator.jsx
- Animated dots while agent is thinking
Socket.io Client:
// Connect to backend
// Listen for agent progress updates
// Display streaming responsesStyling: Modern chat UI inspired by ChatGPT (dark mode, clean bubbles, smooth animations).
Test Flow:
- User types: "Plan a 5-day trip to Japan"
- Backend agent calls Places MCP server
- Backend streams progress: "Searching Japanese attractions..."
- Backend returns: "Here's a 5-day itinerary for Japan: Day 1..."
- Frontend displays message in chat
Deliverable: Working chat interface with AI responses using Places MCP server.
User Story: "After chatting, I see my trip broken down by days, times, and places in a clean timeline view."
Add Hotels MCP Server:
File: backend/src/mcp-servers/hotels/server.ts
// Tools:
// 1. searchHotels(destination, checkIn, checkOut, guests)
// - Use Amadeus Hotel Search API (free tier)
// - Fallback: Web scraping Booking.com
// 2. getHotelDetails(hotelId)
// 3. getHotelReviews(hotelId)
// Expose via MCP stdioUpdate Agent to Generate Structured Itinerary:
File: backend/src/agents/travel-agent.ts
// Add "itinerary_generator" node
// Output format:
{
destination: "Barcelona",
dates: { start: "2024-06-15", end: "2024-06-18" },
days: [
{
day: 1,
date: "2024-06-15",
activities: [
{
time: "09:00",
title: "Visit Sagrada Familia",
description: "...",
location: { lat: 41.4036, lng: 2.1744 },
duration: "2 hours",
type: "attraction"
},
{ time: "13:00", title: "Lunch at...", type: "meal" },
...
]
},
...
],
hotel: {
name: "Hotel Barcelona",
location: {...},
price: "$120/night",
bookingLink: "https://..."
}
}API Endpoint:
// GET /api/itinerary/:conversationId
// Returns structured itinerary JSONFile: frontend/src/pages/Itinerary.jsx
Layout:
┌────────────────────────────────────┐
│ Barcelona Trip • Jun 15-18 │
│ [$480 total] [Export] [Share] │
├────────────────────────────────────┤
│ 📅 Day 1 - June 15 │
│ ┌─────────────────────────────┐ │
│ │ 09:00 Sagrada Familia │ │
│ │ Duration: 2h | Attraction │ │
│ │ [View on Map] │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ 13:00 Lunch at La Rambla │ │
│ └─────────────────────────────┘ │
│ ... │
│ 📅 Day 2 - June 16 │
│ ... │
└────────────────────────────────────┘
Components:
ItineraryHeader.jsx: Trip summary, dates, budgetDayCard.jsx: Collapsible day sectionsActivityCard.jsx: Individual activity with time, icon, detailsHotelCard.jsx: Accommodation info with booking link
Features:
- Click activity → highlight on map (prepare for Phase 3)
- Smooth scroll animations (Framer Motion)
- Print/export itinerary as PDF
- Edit mode (future: drag-reorder activities)
Styling: Card-based layout, modern travel app aesthetic (think Airbnb/Booking.com).
Test Flow:
- User completes chat: "Plan a 3-day Barcelona trip"
- Agent generates structured itinerary using Places + Hotels MCP servers
- User clicks "View Itinerary" button in chat
- Navigate to
/itinerary/:conversationId - Display timeline with day-by-day breakdown
Deliverable: Beautiful itinerary view showing structured trip plan.
User Story: "I see all my trip locations on an interactive map with pins I can click for details."
Add Weather MCP Server:
File: backend/src/mcp-servers/weather/server.ts
// Tools:
// 1. getForecast(lat, lng, date)
// - OpenWeatherMap API (free)
// 2. getClimateInfo(location, month)
// Add weather to itinerary responseUpdate Itinerary Endpoint:
// GET /api/itinerary/:conversationId
// Add geoJSON format for Mapbox:
{
...itinerary,
mapData: {
type: "FeatureCollection",
features: [
{
type: "Feature",
geometry: { type: "Point", coordinates: [2.1744, 41.4036] },
properties: {
title: "Sagrada Familia",
description: "...",
day: 1,
time: "09:00"
}
},
...
]
}
}File: frontend/src/components/Map/TripMap.jsx
Implement Mapbox GL JS:
// 1. Initialize map centered on destination
// 2. Add pins for each activity
// 3. Cluster nearby pins
// 4. Draw route lines between activities (day by day)
// 5. Click pin → show popup with activity details
// 6. Click popup → scroll itinerary to that activityPin Types:
- 🏛️ Attractions (red)
- 🏨 Hotel (blue)
- 🍴 Restaurants (orange)
✈️ Airport (green)
Features:
- Zoom to specific day
- Toggle day visibility
- 3D terrain mode (optional)
- Weather overlay (show forecast on pins)
File: frontend/src/components/Map/MapPopup.jsx
// Popup content:
// - Activity name
// - Time
// - Brief description
// - Weather for that time
// - [View Details] buttonLayout Update: Split-screen on desktop
┌─────────────────┬──────────────────┐
│ Itinerary │ Map │
│ (scrollable) │ (interactive) │
│ │ │
│ Day 1 │ 🗺️ │
│ - 09:00 ... │ 📍 📍 │
│ - 13:00 ... │ 📍 │
│ │ 📍 │
└─────────────────┴──────────────────┘
Mobile: Tabs (Itinerary / Map)
Sync: Click activity in itinerary → map zooms to pin. Click pin → itinerary scrolls to activity.
Deliverable: Interactive map showing all trip locations with weather data.
User Story: "Before planning, I browse destination cards and swipe through options to get inspired."
File: backend/src/agents/discovery-agent.ts
New Agent: Destination Recommender
// Input: { interests: [], budget: string, season: string, duration: number }
// Output: [
// {
// destination: "Bosnia and Herzegovina",
// tagline: "Hidden Balkan gem with Ottoman heritage",
// highlights: ["Mostar Bridge", "Sarajevo Old Town", "Kravice Falls"],
// bestTime: "May-September",
// avgBudget: "$50/day",
// image: "url",
// whyGo: "...",
// activities: ["hiking", "history", "food"],
// flightPrice: "$450 (estimated)"
// },
// ...
// ]
// Use Places MCP + flight price estimationAPI Endpoint:
// POST /api/discover
// Body: { interests, budget, season, travelers }
// Returns: Array of destination cardsFile: frontend/src/pages/Discover.jsx
UI: Tinder-style card deck
┌────────────────────────────────┐
│ Card Stack │
│ ┌──────────────────────────┐ │
│ │ 📸 Bosnia Image │ │
│ │ │ │
│ │ Bosnia and Herzegovina │ │
│ │ "Hidden Balkan gem" │ │
│ │ │ │
│ │ 🏔️ Mostar • 🍽️ Food │ │
│ │ $50/day │ │
│ │ │ │
│ │ [← Skip] [❤️ Save] │ │
│ └──────────────────────────┘ │
└────────────────────────────────┘
Libraries:
react-tinder-cardorframer-motionfor swipe gestures- Lazy load images
Features:
- Swipe left: Skip
- Swipe right: Save to "Liked Destinations"
- Tap card: Expand details modal
- After swiping: "Plan a trip to [destination]" button
File: frontend/src/components/Cards/DestinationCard.jsx
// Card with:
// - Hero image (high quality)
// - Destination name
// - Tagline
// - Key stats (budget, best time)
// - Activity tags
// - CTA buttonFlow:
- Homepage → "Discover Destinations" button
- Answer quick questions (interests: [beach, adventure, food], budget: medium, when: summer)
- Agent generates 10 personalized cards
- User swipes through cards
- Click "Plan trip to Montenegro" → Navigate to chat with pre-filled message
Deliverable: Beautiful card-based destination discovery with AI recommendations.
User Story: "I can tell the AI 'make it cheaper' or 'add a day in Dubrovnik' and my trip updates instantly."
Add Flights MCP Server:
File: backend/src/mcp-servers/flights/server.ts
// Tools:
// 1. searchFlights(origin, destination, date, passengers)
// - Amadeus Flight Offers Search API
// 2. getFlightPrice(flightId)
// 3. getAirportInfo(code)
// Return affiliate links to Skyscanner/Google FlightsUpdate Travel Agent with Refinement Logic:
File: backend/src/agents/travel-agent.ts
// Add nodes:
// 1. "intent_classifier" - Detect refinement type:
// - Budget adjustment ("make it cheaper")
// - Duration change ("add 2 days")
// - Location addition ("add Prague")
// - Activity swap ("replace museum with beach")
//
// 2. "itinerary_updater" - Modify existing itinerary based on intent
//
// 3. Use conversation history to maintain contextAPI Endpoints:
// POST /api/chat/refine
// Body: { conversationId, refinementRequest }
// Updates existing itinerary, returns diff
// GET /api/booking-links/:conversationId
// Returns: { flights, hotels, activities } with affiliate URLsUpdate Chat Interface:
File: frontend/src/components/Chat/RefinementSuggestions.jsx
Quick Actions (buttons below chat input):
- "Make it cheaper 💰"
- "Add 1 day ➕"
- "Show luxury options 👑"
- "Remove [activity] ✂️"
Itinerary Comparison View:
Old Itinerary → New Itinerary
Day 1: Museum Day 1: Beach ✨ (changed)
Day 2: Castle Day 2: Castle
Day 3: Market ✨ (added)
File: frontend/src/components/Itinerary/BookingPanel.jsx
Booking Links UI:
┌────────────────────────────────┐
│ Ready to Book? │
│ ┌──────────────────────────┐ │
│ │ ✈️ Flights │ │
│ │ NYC → Barcelona │ │
│ │ $450 round-trip │ │
│ │ [View on Skyscanner] → │ │
│ └──────────────────────────┘ │
│ ┌──────────────────────────┐ │
│ │ 🏨 Hotel Barcelona │ │
│ │ 3 nights • $360 total │ │
│ │ [View on Booking.com] → │ │
│ └──────────────────────────┘ │
└────────────────────────────────┘
Test Refinement Flow:
- User has Barcelona itinerary
- User: "Make it cheaper"
- Agent: Searches cheaper hotels, removes expensive activities, re-generates
- UI shows old vs. new side-by-side
- User: "Perfect! Show booking links"
- Booking panel appears with affiliate links
Deliverable: Full refinement capability + booking link generation.
1. User Accounts (2 days)
- JWT authentication
- Save trips to MongoDB
- View past trips
- Share trips via link
2. Mobile Responsive (1 day)
- Mobile-first chat UI
- Touch-friendly itinerary cards
- Map gestures
3. Export & Share (1 day)
- Export itinerary as PDF
- Share via link (public itineraries)
- Add to Google Calendar
4. Caching & Performance (1 day)
- Redis for API response caching
- Debounce search queries
- Optimize map rendering
- Lazy load images
5. Error Handling (1 day)
- Graceful API failures
- Fallback responses when MCP servers fail
- User-friendly error messages
1. Testing (2 days)
- Unit tests for MCP servers
- Integration tests for agent workflows
- E2E tests (Playwright) for critical flows
- Load testing (simulate 100 concurrent users)
2. Deployment (2 days)
- Frontend: Vercel (free)
- Backend: Railway.app or Render (free tier)
- MongoDB: MongoDB Atlas (free M0 cluster)
- Redis: Upstash (free 10K requests/day)
3. Monitoring (1 day)
- Sentry for error tracking
- PostHog for analytics
- Log LLM costs per user
- All MCP servers working (Places, Hotels, Weather, Flights)
- LangGraph agent handles complex queries
- Chat interface is smooth and responsive
- Itinerary displays correctly on mobile + desktop
- Map pins and routing work
- Destination cards load fast
- Refinement updates itinerary correctly
- Booking links generate properly
- Error handling covers edge cases
- Performance is acceptable (<3s response time)
- Cost monitoring in place
- Legal: Privacy policy, ToS, affiliate disclosures
| Item | Cost |
|---|---|
| OpenAI GPT-4o-mini | $20 |
| Amadeus API | Free (2K calls) |
| MongoDB Atlas | Free (M0) |
| Redis (Upstash) | Free |
| Mapbox | Free (50K loads) |
| Google Places | $50 (with $200 credit) |
| Hosting (Render) | $7/month (free tier + one paid) |
| Total | $27-77 |
Scaling: At 1,000 users: ~$200-300/month.
- Week 2: Chat works with Places MCP
- Week 3: Itinerary displays with Hotels MCP
- Week 4: Map shows all pins with Weather MCP
- Week 5: Cards generate personalized recommendations
- Week 6: Full refinement + booking links with Flights MCP
- Week 8: Deployed and live with 10 beta users
Next Steps: Which phase would you like to start with? I recommend beginning with Phase 0 (Foundation) to set up the project structure and first MCP server.