Vacation-quoting MCP server for travel agents, plus a cross-platform assistant skill that turns a plain-language client brief ("family of four, Lisbon, spring break, $8k") into a priced, bookable proposal with stays, activities, and dining.
One stdio MCP server composes three paid APIs:
| Leg | Source | What you get | Cost shape |
|---|---|---|---|
| Stays | Bright Data Web Scraper API (Booking.com) | Live-scraped hotel listings with nightly rates | Per record (~$1–1.5/1K); 30–120s per search |
| Activities | Viator Partner API v2 | 300k+ bookable tours/activities, real availability, affiliate links | Free (commission model) |
| Dining & POIs | Google Places API (New) | Restaurants, ratings, price level, hours, Maps links | Per request, tiered by field mask |
Every proposal carries an indicative-rates disclaimer: prices are captured live at quote time and must be re-confirmed at booking. There are no booking transactions — proposals link out (Viator links carry your affiliate campaign for commission attribution).
build_proposal— one-shot: full request in, ranked itinerary + cost breakdown + Markdown proposal outbuild_options_page— interactive HTML options page (lodging, transfers, experiences, day trips, dining); the agent picks options with the client and clicks "Generate quote" in-page for the final branded, printable quotesearch_stays— live Booking.com scrape (slow, per-record billed; keepmaxResults≤10)search_activities— Viator product search with persona-aware tagsget_activity_availability— firm per-person pricing for specific datessearch_dining— Google Places search, profile-awareenrich_place— Place Details for shortlist finalists only
Profiles (family, bachelorette, couples, solo, seniors, adventure, luxury) drive activity tags, dining types, and scoring. A "family of four" yields kid-friendly activities and suites; a bachelorette yields adult group experiences and nightlife-adjacent dining.
Requires Node ≥ 20. The installer detects the platform, checks Node, installs dependencies, builds, walks you through credentials, validates the config, and optionally registers the server with Claude Desktop:
# macOS / Linux (Git Bash on Windows also works)
./install.sh# Windows (PowerShell)
powershell -ExecutionPolicy Bypass -File install.ps1Manual equivalent:
npm install
npm run build
cp .env.example .env # then fill in keys
npm run check-configNote: the project .env is authoritative — it overrides inherited shell variables, so a stale exported key in your shell profile cannot silently win over the configured .env.
Bright Data (stays) — optional; search_stays returns a setup error until configured, the other legs work without it
- Sign up at brightdata.com → account settings → copy your API key →
BRIGHTDATA_API_KEY - Dashboard → Web Scraper API → dataset library → find the Booking.com listings search scraper → copy its dataset ID →
BRIGHTDATA_BOOKING_DATASET_ID - Note: the exact input schema (URL vs structured search fields) depends on the dataset variant; if
search_stayserrors on input validation, check the dataset's input spec in the dashboard and adjustsrc/providers/brightdata.ts.
Google Places (New) (lodging + dining)
- Google Cloud Console → create project → enable billing
- Enable "Places API (New)" (not the legacy Places API)
- Create an API key →
GOOGLE_MAPS_API_KEY. If you restrict the key, make sureplaces.googleapis.comis in the allowed list — a key restricted to other Google services fails withAPI_KEY_SERVICE_BLOCKED.
Viator Partner API v2 (activities)
- Sign up at partners.viator.com (free) → request a Basic Access API key
- Sandbox key is issued immediately →
VIATOR_API_KEYwithVIATOR_ENV=sandbox - Production key is generated separately in the portal and can take ~24h to activate. Sandbox and production keys are not interchangeable.
- Copy your affiliate campaign value →
VIATOR_CAMPAIGN_VALUE(appended to every activity link for commission tracking)
BRIGHTDATA_API_KEY=
BRIGHTDATA_BOOKING_DATASET_ID=
GOOGLE_MAPS_API_KEY=
VIATOR_API_KEY=
VIATOR_ENV=sandbox # switch to production once your prod key activates
VIATOR_CAMPAIGN_VALUE=
AGENCY_CURRENCY=USDKeys are shared agency-wide: every agent's client quotes against the same accounts and affiliate ID.
Proposals render with your letterhead when branding is configured — logo, agency name, tagline, contact line at the top and a "Prepared by …" sign-off at the foot:
AGENCY_NAME=Sunrise Travel Co
AGENCY_LOGO_URL=https://your-domain.com/logo.png # hosted URL renders in Markdown viewers
AGENCY_CONTACT=+1 555 0100 · hello@sunrise.travel
AGENCY_TAGLINE=Tailor-made tripsPer-proposal overrides are supported via build_proposal's optional branding argument (agencyName, logoUrl, contactLine, tagline) — useful for multi-brand agencies or co-branded documents. The resolved branding is also exposed as proposal.agency in the structured JSON for downstream renderers (PDF, email).
The fastest paths, in order:
- Claude Desktop, guided: run
./install.sh/install.ps1and answer "y" at the registration prompt. It merges anxcapeentry intoclaude_desktop_config.json(backing up the existing file first) with credentials taken from.env. Restart Claude Desktop afterwards. - One-click bundle (DXT):
npm run pack:dxtbuilds a.dxtdesktop-extension file (seemanifest.json); double-clicking it in Claude Desktop installs the server and prompts for the API keys through the UI. - Any other client:
npm run print-configprints a ready-to-pastemcpServerssnippet with absolute paths and the current credentials, plus the config-file location for this machine.
Claude Code:
claude mcp add xcape -- node /absolute/path/to/xcape/dist/index.jsKimi Code / Cursor / others — same command/args/env shape as the --print-config snippet in their MCP settings.
ChatGPT — MCP support varies by client; where custom MCP servers are configurable, use the same command/args/env. Otherwise paste skills/xcape-trip-planner/SKILL.md into the conversation as instructions and drive the server through any MCP bridge.
skills/xcape-trip-planner/ is a platform-neutral assistant skill (Claude Agent Skills format — YAML frontmatter + Markdown, equally usable as Kimi skill or ChatGPT custom instructions). It teaches the assistant to:
- Run intake on the agent's brief (party, dates, destination, budget, vibe) and pick a profile
- Drive the tools in a cost-aware order
- Write the proposal from a fixed template: totals + per-person pricing, day-by-day itinerary, alternatives, verbatim booking links, indicative-rates disclosure, and an explicit Gaps section when a data leg fails
Install it alongside the MCP server so the model knows how to use the tools well.
npm test # vitest + msw; no real keys needed, no network
npm run build # tsc
npx @modelcontextprotocol/inspector node dist/index.js # manual tool testing- Bright Data: results hard-capped at 20/call;
build_proposaldefaults to ≤10 - Google: field masks pinned to narrow constants — tools never accept arbitrary field lists (a snapshot test guards this)
- Viator: search counts clamped to provider max (50);
Retry-Afterhonored on 429 - Google ToS: no long-term warehousing of place data — caching is in-memory, per-process only
- Stays latency: live scraping takes 30–120s and bills per record. If this proves too slow in practice, the fix is adding a hotel affiliate/rates API as a fast path — not built yet.
- No flights: a Bright Data Google Flights scraper can be added as
search_flightslater. - No booking: quoting + links only. In-chat Viator booking requires Viator Full+Booking approval, certification, and PCI-aware payments.
- Local stdio only: each agent installs the server on their own machine with the shared keys. A hosted multi-tenant version is a separate project.