Skip to main content
Glama
README.md
# @striderlabs/mcp-booking

MCP server for Booking.com — search hotels, check availability, manage reservations, and more via AI agents.

By [Strider Labs](https://striderlabs.ai)

---

## Overview

This MCP (Model Context Protocol) server gives AI agents the ability to interact with Booking.com using browser automation (Playwright). It supports 14 tools covering the full hotel booking workflow.

## Tools

| Tool | Description |
|------|-------------|
| `booking_status` | Check login/session status |
| `booking_login` | Open a browser window to sign in (non-blocking; returns immediately) |
| `booking_login_status` | Check progress of an in-flight `booking_login` |
| `booking_logout` | Clear saved session and cookies |
| `booking_search` | Search hotels by destination, dates, guests, rooms, and amenities (pets, parking, pool, …) |
| `booking_get_property` | Get property details (amenities, description, policies, structured `facilitySummary`) |
| `booking_check_availability` | Check room availability for specific dates |
| `booking_get_prices` | Get pricing for a property |
| `booking_filter_results` | Filter last search by price, rating, amenities |
| `booking_sort_results` | Sort last search by price/rating/distance/reviews |
| `booking_save_property` | Save to wishlist/favorites |
| `booking_book` | Get a "continue in your browser" booking link (does not place the booking) |
| `booking_get_reservations` | List current/upcoming reservations |
| `booking_cancel_reservation` | Cancel a booking (requires `confirm=true`) |
| `booking_get_reviews` | Get guest reviews for a property |

## Requirements

- Node.js 18+
- A Booking.com account (for bookings, reservations, and wishlist)

## Installation

```bash
npm install @striderlabs/mcp-booking
```

Or install Playwright browsers after install:

```bash
npx playwright install chromium
```

## Configuration

Add to your MCP config (e.g. `~/.claude/mcp_servers.json`):

```json
{
  "mcpServers": {
    "booking": {
      "command": "npx",
      "args": ["-y", "@striderlabs/mcp-booking"]
    }
  }
}
```

## Authentication

The server uses cookie-based session persistence. Login is **non-blocking** (two
steps) so it won't hang your MCP client while you wait on an emailed verification
code:

1. Run `booking_login`. It opens a **visible browser window** at the Booking.com sign-in page and returns immediately.
2. Sign in in that window (including any email/SMS code or 2FA/CAPTCHA). A background poller watches for completion.
3. Run `booking_login_status` to check progress — it reports `in_progress`, `success`, `failed`, or `idle`. Poll it until it's no longer `in_progress`.
4. On `success` the session is captured and saved automatically; `booking_status` will then show you as logged in.

The background poller waits up to ~10 min by default; pass `timeoutSeconds` to
`booking_login` to extend it (up to 30 min) if a verification code is slow to
arrive. If the window is closed or the deadline passes before sign-in completes,
the status becomes `failed` and the window is cleaned up — just call
`booking_login` again.

Because login drives a real browser window, it requires **Google Chrome installed and a desktop display** — it cannot run on a headless server.

### Cookie storage

- Session cookies are stored at `~/.strider/booking/cookies.json`, scoped to **Booking.com domains only** (unrelated third-party/tracking cookies are not persisted).
- The config directory (`0700`) and the cookie/session files (`0600`) are created with owner-only permissions. The files are **not encrypted** — protect your home directory accordingly.
- `booking_logout` deletes the saved cookies and session.

## Usage Examples

### Search hotels

```
booking_search(destination="Paris", checkIn="2026-06-01", checkOut="2026-06-05", adults=2, rooms=1)
```

### Search with flexible dates (±N days)

Use `flex_window` to widen the search around your exact dates, like the Android app "I'm flexible" feature:

```
# ±2 days flexibility around July 10-13
booking_search(destination="Paris", checkIn="2026-07-10", checkOut="2026-07-13", flex_window=2)

# ±7 days (full week flexibility)
booking_search(destination="Paris", checkIn="2026-07-10", checkOut="2026-07-13", flex_window=7)
```

`flex_window` values: `0` (exact, default), `1` (±1 day), `2` (±2 days), `3` (±3 days), `7` (±7 days).

### Understanding price fields

The price returned by `booking_search` is **usually the total stay price** (not per-night) on multi-night searches:

- **`pricePerNight`** / **`totalPrice`**: same numeric value — the price shown on the Booking.com card
- **`priceIsTotal`**: `true` when the card shows total stay price; `false` only when explicitly labelled "per night"
- **`priceNote`**: raw text from the card (e.g. "CHF 450 for 3 nights") — use this to verify context
- **`currency`**: auto-detected from the card (CHF, EUR, USD, etc.)

For multi-night stays, divide `totalPrice` by number of nights to get the actual nightly rate.

### Search by amenities (pets, parking, pool, …)

Amenity filters are applied **server-side** via Booking.com's `nflt` parameter, so results only contain matching properties.

```
# Pet-friendly hotels with parking and a pool
booking_search(destination="Rome", checkIn="2026-06-01", checkOut="2026-06-05", amenities=["pets", "parking", "pool"])
```

Supported amenity keys: `pets`, `parking`, `pool`, `restaurant`, `room_service`, `front_desk_24h`, `fitness`, `non_smoking`, `airport_shuttle`, `family_rooms`, `ev_charging`, `spa`, `hot_tub`, `sauna`, `free_wifi`, `air_conditioning`.

For a single property, `booking_get_property` returns a structured `facilitySummary` (e.g. `petsAllowed`, `parking`, `pool`, `spa`) where `true` = offered/allowed, `false` = not allowed, `null` = not mentioned on the page.

> Note: amenity → filter codes are reverse-engineered from Booking.com's UI (undocumented but stable). If a filter behaves unexpectedly, supply an exact chip via `rawNflt` (e.g. `rawNflt="hotelfacility=4;popular_activities=2"`).

### Filter and sort results

```
booking_filter_results(maxPrice=200, minRating=8.0, freeCancellation=true)
booking_sort_results(sortBy="rating")
```

### Check availability and prices

```
booking_check_availability(propertyUrl="https://www.booking.com/hotel/fr/...", checkIn="2026-06-01", checkOut="2026-06-05")
booking_get_prices(propertyUrl="...", checkIn="2026-06-01", checkOut="2026-06-05")
```

### Book a room

`booking_book` does **not** place a booking. Booking.com checkout is a multi-step
wizard (room selection → guest contact details → payment) that can't be reliably
completed via automation, so this returns a `bookingUrl` to finish in a browser.

```
# Returns a bookingUrl (property page with dates/occupancy pre-filled,
# opening on the room list with "Reserve" buttons) to complete in a browser.
booking_book(propertyUrl="...", checkIn="2026-06-01", checkOut="2026-06-05", adults=2)

# Optional: also best-effort capture a deeper checkoutUrl with the first
# available room pre-selected (still stops before any guest/payment details).
booking_book(propertyUrl="...", checkIn="2026-06-01", checkOut="2026-06-05", adults=2, advanceToCheckout=true)
```

### Manage reservations

```
# List current/upcoming reservations. Each result's reservationId is the trip id
# (or "<tripId>-<n>" for a specific booking within a multi-booking trip).
booking_get_reservations()

# Cancel walks Booking.com's multi-step flow: confirmation page -> "Cancel your
# booking" -> reason survey (Step 1 of 2) -> final confirm (Step 2). The final
# step is irreversible, so it only runs with confirm=true.
booking_cancel_reservation(reservationId="308612662158023")           # no-op preview
booking_cancel_reservation(reservationId="308612662158023", confirm=true)  # actually cancels
```

## Safety

- `booking_book` never places a booking — it returns a link to complete checkout (contact details + payment) in a browser
- `booking_cancel_reservation` requires `confirm=true`; without it, it returns a no-op warning and never opens a browser. With it, it drives the multi-step cancel flow (reason survey + final confirm) and the last step is irreversible

## Development

```bash
npm install
npm run build
npm start
```

## License

MIT — Strider Labs

TDQS

A3.9/5.0

Scored across 15 tools

Disambiguation5/5

Every tool has a clearly distinct purpose: search, filter, sort, check availability, get prices, get property details, book (with caveat), cancel, get reservations, save property, login/logout/status. No two tools overlap in functionality; each targets a specific action or resource.

Naming Consistency4/5

Tools consistently use the 'booking_' prefix followed by a verb_noun pattern (e.g., booking_cancel_reservation, booking_get_prices). Minor inconsistency: 'booking_status' uses a noun alone (no verb), which deviates from the predominant verb-first pattern.

Tool Count5/5

With 15 tools covering search, filtering, pricing, property details, reservations, authentication, and wishlist management, the count is well-scoped for a booking service. Each tool has a clear role, neither too few nor too many for the domain.

Completeness3/5

The tool set covers most of the booking lifecycle but has a notable gap: 'booking_book' explicitly does not complete a booking (only provides a link for manual finishing). This means the primary action is missing from automation. Otherwise, CRUD-like operations (search, get, cancel, save) are present.

Maintenance

ActivityStale
ResponsivenessUnresponsive