This lesson upgrades the single-server hotel agent into a travel planner that orchestrates two MCP servers at once — Airbnb for accommodations and Google Calendar for itineraries — plus weather and web search. We also add memory so the agent remembers the conversation across turns.
You will configure Google Cloud OAuth for the Calendar server, centralize server configs in a JSON file, and build a date-aware agent that plans a trip end to end and writes it to your calendar.
Note
This builds directly on Build a Hotel Search AI Agent with MCP. Make sure Node.js and uv are installed and the Airbnb server works before adding Calendar.
Google Cloud OAuth Setup
Unlike Airbnb, the Google Calendar server requires OAuth. This is a one-time setup that also covers Google Sheets and Gmail used in later lessons.
Step 1: Create a Project and Enable APIs
- Go to the Google Cloud Console and create a new project (e.g., "AI Agent MCP Integration").
- Open APIs & Services → Library and enable: Google Calendar API, Google Sheets API, Google Drive, and Gmail API.
Step 2: Configure the OAuth Consent Screen
- Open APIs & Services → OAuth consent screen and select External.
- Fill in the app name and your support/developer email, then save.
- Under Test users, add the Google account you will use with the agent.
Step 3: Create OAuth Client Credentials
- Open APIs & Services → Credentials → Create Credentials → OAuth client ID.
- Choose Desktop app, name it, and click Create.
- Click Download JSON on the new credential.
Step 4: Save the Credentials File
Windows (PowerShell): create the folder and move the renamed file:
mkdir ~/.gmail-mcp
Rename the downloaded JSON to gcp-oauth.keys.json and move it to C:\Users\your-username\.gmail-mcp\gcp-oauth.keys.json.
Important
Replace your-username with your actual Windows username. The agents reference this exact path, so the filename must be gcp-oauth.keys.json.
On Linux/macOS: create the folder with mkdir -p ~/.gmail-mcp and move the file to ~/.gmail-mcp/gcp-oauth.keys.json.
Step 5: Authenticate the Calendar Server
Set the credentials path and run the Calendar server's one-time auth command, which opens a browser to grant permission:
$env:GOOGLE_OAUTH_CREDENTIALS="C:\Users\your-username\.gmail-mcp\gcp-oauth.keys.json"
npx @cocal/google-calendar-mcp auth
On Linux/macOS:
export GOOGLE_OAUTH_CREDENTIALS="$HOME/.gmail-mcp/gcp-oauth.keys.json"
npx @cocal/google-calendar-mcp auth
A browser opens — sign in with your test-user account, review the permissions, and click Allow. If you see "Google hasn't verified this app," click Continue. When the browser shows "Authentication successful," you are done.
Warning
Test-mode OAuth tokens expire after 7 days. You will need to re-authenticate weekly unless you publish your Google Cloud app. If auth ever breaks, delete the token files and re-run the command.
Centralizing MCP Server Configs
Rather than hard-coding each server, this series stores all server launch configs in scripts/mcp_config.json and loads the ones you need by name. The Airbnb and Calendar entries look like this:
{
"airbnb": {
"command": "npx",
"args": ["-y", "@openbnb/mcp-server-airbnb", "--ignore-robots-txt"],
"transport": "stdio"
},
"google-calendar": {
"command": "npx",
"args": ["@cocal/google-calendar-mcp"],
"env": {
"GOOGLE_OAUTH_CREDENTIALS": "C:\\Users\\your-username\\.gmail-mcp\\gcp-oauth.keys.json"
},
"transport": "stdio"
}
}
Important
Replace your-username in the GOOGLE_OAUTH_CREDENTIALS path with your actual Windows username. On Linux/macOS, use /home/your-username/.gmail-mcp/gcp-oauth.keys.json (forward slashes, no double backslashes).
A small helper in scripts/utils.py reads the JSON and returns only the servers you ask for:
import os
import json
def load_mcp_config(*server_names):
config_path = os.path.join(os.path.dirname(__file__), 'mcp_config.json')
with open(config_path, 'r') as f:
all_configs = json.load(f)
if len(server_names) == 0:
return all_configs
selected_configs = {}
for name in server_names:
if name in all_configs:
selected_configs[name] = all_configs[name]
return selected_configs
Now any agent can pull exactly the servers it needs with utils.load_mcp_config("airbnb", "google-calendar").
Building the Travel Planner Agent
The planner uses the same async pattern as the hotel agent but adds two things: a second MCP server and a checkpointer for memory.
import sys
import os
root_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(root_dir)
from dotenv import load_dotenv
load_dotenv()
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain.agents import create_agent
from langchain.messages import HumanMessage
from langgraph.checkpoint.memory import InMemorySaver
from langchain_mcp_adapters.client import MultiServerMCPClient
import asyncio
from scripts import base_tools, prompts, utils
if sys.platform == "win32":
sys.stdout.reconfigure(encoding="utf-8")
model = ChatGoogleGenerativeAI(model="gemini-3-flash-preview")
checkpointer = InMemorySaver()
Loading Two Servers at Once
load_mcp_config returns both server configs; MultiServerMCPClient connects to both and merges their tools. We append the local tools as before:
async def get_tools():
mcp_config = utils.load_mcp_config("airbnb", "google-calendar")
client = MultiServerMCPClient(mcp_config)
mcp_tools = await client.get_tools()
tools = mcp_tools + [base_tools.web_search, base_tools.get_weather]
print(f"Loaded {len(tools)} Tools")
print(f"Tools Available\n{[tool.name for tool in tools]}")
return tools
A Date-Aware System Prompt
A travel agent needs to know "today" to set check-in and checkout dates. The prompt is generated dynamically with the current date and a default 5-day stay:
from datetime import datetime, timedelta
def get_travel_planner_prompt():
"""Generate travel planner prompt with current date context."""
today = datetime.now()
checkin_date = today
checkout_date = today + timedelta(days=5)
return f"""You are a travel planning assistant.
Today: {str(today.date())}
Default dates: Check-in {str(checkin_date.date())}, Checkout {str(checkout_date.date())} (5 days)
Tools: Airbnb search, weather, web search, Google Calendar
Instructions:
- Search Airbnb (default: 2 adults, no price filters unless requested)
- Present listings with https://www.airbnb.com/rooms/{{listing_id}}
- Add events to Google Calendar with times, locations and itinerary descriptions"""
Memory with Thread IDs
Pass the system prompt and the checkpointer to create_agent, and supply a thread_id in the config so each conversation keeps its history:
async def plan_trip(query, thread_id="default"):
tools = await get_tools()
system_prompt = prompts.get_travel_planner_prompt()
agent = create_agent(
model=model, tools=tools, system_prompt=system_prompt, checkpointer=checkpointer
)
config = {"configurable": {"thread_id": thread_id}}
result = await agent.ainvoke({"messages": [HumanMessage(query)]}, config=config)
response = result['messages'][-1].text
print("\n============== Output =============")
print(response)
Add the chat loop and entry point:
async def ask():
print("\nChat mode started. Type 'q' or 'quite' to exit.\n")
while True:
query = input("You: ").strip()
if query.lower() in ["q", "quite"]:
print("Exiting chat mode.")
break
await plan_trip(query)
if __name__ == "__main__":
asyncio.run(ask())
Running the Planner
Run the script and give it a complete planning task. Because memory is on, you can refine the plan over several turns:
python "03 AI Projects/02_travel_planner_agent/travel_planner_agent.py"
You: Plan a romantic 5-day trip to Mumbai. Find romantic hotels for 2 adults,
check weather, and add the trip to my primary Google Calendar. Add the
itinerary in the calendar description.
Loaded 5 Tools
Tools Available
['airbnb_search', 'airbnb_listing_details', 'list-calendars', 'create-event', ..., 'web_search', 'get_weather']
============== Output =============
Here's your romantic 5-day Mumbai getaway:
Stays (2 adults):
1. Sea-view apartment in Bandra — https://www.airbnb.com/rooms/...
2. Boutique suite near Marine Drive — https://www.airbnb.com/rooms/...
Weather: ~30°C, clear evenings — great for seaside dinners.
I've added a "Romantic Mumbai Trip" event to your primary Google Calendar with
the full day-by-day itinerary in the description.
The agent searched Airbnb, checked the weather, and created a calendar event in one flow — each across a different MCP server, coordinated by a single agent.
Tip
Because the agent has memory, follow up naturally: "make day 3 a beach day" or "move check-in to next Friday." It updates the plan and the calendar event without you repeating context.
You can now orchestrate multiple authenticated MCP servers with memory. Next, we give an agent a secure sandbox to run code and analyze data files in Build a Code Execution Agent with E2B Sandbox.