@striderlabs/mcp-booking 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -0
- package/dist/auth.d.ts +41 -0
- package/dist/auth.js +96 -0
- package/dist/browser.d.ts +145 -0
- package/dist/browser.js +834 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +612 -0
- package/package.json +36 -0
- package/server.json +16 -0
- package/src/auth.ts +118 -0
- package/src/browser.ts +1281 -0
- package/src/index.ts +865 -0
- package/tsconfig.json +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# @striderlabs/mcp-booking
|
|
2
|
+
|
|
3
|
+
MCP server for Booking.com — search hotels, check availability, manage reservations, and more via AI agents.
|
|
4
|
+
|
|
5
|
+
By [Strider Labs](https://striderlabs.ai)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
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.
|
|
12
|
+
|
|
13
|
+
## Tools
|
|
14
|
+
|
|
15
|
+
| Tool | Description |
|
|
16
|
+
|------|-------------|
|
|
17
|
+
| `booking_status` | Check login/session status |
|
|
18
|
+
| `booking_login` | Initiate login flow (returns URL for manual login) |
|
|
19
|
+
| `booking_logout` | Clear saved session and cookies |
|
|
20
|
+
| `booking_search` | Search hotels by destination, dates, guests, rooms |
|
|
21
|
+
| `booking_get_property` | Get property details (amenities, description, policies) |
|
|
22
|
+
| `booking_check_availability` | Check room availability for specific dates |
|
|
23
|
+
| `booking_get_prices` | Get pricing for a property |
|
|
24
|
+
| `booking_filter_results` | Filter last search by price, rating, amenities |
|
|
25
|
+
| `booking_sort_results` | Sort last search by price/rating/distance/reviews |
|
|
26
|
+
| `booking_save_property` | Save to wishlist/favorites |
|
|
27
|
+
| `booking_book` | Book a room (requires `confirm=true`) |
|
|
28
|
+
| `booking_get_reservations` | List current/upcoming reservations |
|
|
29
|
+
| `booking_cancel_reservation` | Cancel a booking (requires `confirm=true`) |
|
|
30
|
+
| `booking_get_reviews` | Get guest reviews for a property |
|
|
31
|
+
|
|
32
|
+
## Requirements
|
|
33
|
+
|
|
34
|
+
- Node.js 18+
|
|
35
|
+
- A Booking.com account (for bookings, reservations, and wishlist)
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install @striderlabs/mcp-booking
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Or install Playwright browsers after install:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx playwright install chromium
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Configuration
|
|
50
|
+
|
|
51
|
+
Add to your MCP config (e.g. `~/.claude/mcp_servers.json`):
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"mcpServers": {
|
|
56
|
+
"booking": {
|
|
57
|
+
"command": "npx",
|
|
58
|
+
"args": ["-y", "@striderlabs/mcp-booking"]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Authentication
|
|
65
|
+
|
|
66
|
+
The server uses cookie-based session persistence. Cookies are stored at `~/.strider/booking/`.
|
|
67
|
+
|
|
68
|
+
1. Run `booking_login` to get the login URL
|
|
69
|
+
2. Open the URL in your browser and sign in
|
|
70
|
+
3. Run `booking_status` to verify the session is active
|
|
71
|
+
|
|
72
|
+
## Usage Examples
|
|
73
|
+
|
|
74
|
+
### Search hotels
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
booking_search(destination="Paris", checkIn="2026-06-01", checkOut="2026-06-05", adults=2, rooms=1)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Filter and sort results
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
booking_filter_results(maxPrice=200, minRating=8.0, freeCancellation=true)
|
|
84
|
+
booking_sort_results(sortBy="rating")
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Check availability and prices
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
booking_check_availability(propertyUrl="https://www.booking.com/hotel/fr/...", checkIn="2026-06-01", checkOut="2026-06-05")
|
|
91
|
+
booking_get_prices(propertyUrl="...", checkIn="2026-06-01", checkOut="2026-06-05")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Book a room
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
# Preview first (no confirm flag)
|
|
98
|
+
booking_book(propertyUrl="...", checkIn="2026-06-01", checkOut="2026-06-05", adults=2)
|
|
99
|
+
|
|
100
|
+
# Confirm booking (only after explicit user approval)
|
|
101
|
+
booking_book(propertyUrl="...", checkIn="2026-06-01", checkOut="2026-06-05", adults=2, confirm=true)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Manage reservations
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
booking_get_reservations()
|
|
108
|
+
booking_cancel_reservation(reservationId="12345678", confirm=true)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Safety
|
|
112
|
+
|
|
113
|
+
- `booking_book` requires `confirm=true` and should only be called with explicit user confirmation
|
|
114
|
+
- `booking_cancel_reservation` requires `confirm=true` and is irreversible
|
|
115
|
+
- Both tools return a preview/warning when called without the confirm flag
|
|
116
|
+
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npm install
|
|
121
|
+
npm run build
|
|
122
|
+
npm start
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
MIT — Strider Labs
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strider Labs - Booking.com Auth/Session Management
|
|
3
|
+
*
|
|
4
|
+
* Handles cookie persistence and session management for Booking.com.
|
|
5
|
+
*/
|
|
6
|
+
import type { BrowserContext } from "playwright";
|
|
7
|
+
export interface SessionInfo {
|
|
8
|
+
isLoggedIn: boolean;
|
|
9
|
+
userEmail?: string;
|
|
10
|
+
userName?: string;
|
|
11
|
+
lastUpdated: string;
|
|
12
|
+
currency?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Save cookies from browser context to disk
|
|
16
|
+
*/
|
|
17
|
+
export declare function saveCookies(context: BrowserContext): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Load cookies from disk and apply to browser context
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadCookies(context: BrowserContext): Promise<boolean>;
|
|
22
|
+
/**
|
|
23
|
+
* Save session info to disk
|
|
24
|
+
*/
|
|
25
|
+
export declare function saveSessionInfo(info: SessionInfo): void;
|
|
26
|
+
/**
|
|
27
|
+
* Load session info from disk
|
|
28
|
+
*/
|
|
29
|
+
export declare function loadSessionInfo(): SessionInfo | null;
|
|
30
|
+
/**
|
|
31
|
+
* Clear all saved auth data
|
|
32
|
+
*/
|
|
33
|
+
export declare function clearAuthData(): void;
|
|
34
|
+
/**
|
|
35
|
+
* Check if we have saved cookies (may or may not still be valid)
|
|
36
|
+
*/
|
|
37
|
+
export declare function hasSavedCookies(): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Get the config directory path (useful for debugging)
|
|
40
|
+
*/
|
|
41
|
+
export declare function getConfigDir(): string;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strider Labs - Booking.com Auth/Session Management
|
|
3
|
+
*
|
|
4
|
+
* Handles cookie persistence and session management for Booking.com.
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
import * as os from "os";
|
|
9
|
+
const CONFIG_DIR = path.join(os.homedir(), ".strider", "booking");
|
|
10
|
+
const COOKIES_FILE = path.join(CONFIG_DIR, "cookies.json");
|
|
11
|
+
const SESSION_FILE = path.join(CONFIG_DIR, "session.json");
|
|
12
|
+
/**
|
|
13
|
+
* Ensure config directory exists
|
|
14
|
+
*/
|
|
15
|
+
function ensureConfigDir() {
|
|
16
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
17
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Save cookies from browser context to disk
|
|
22
|
+
*/
|
|
23
|
+
export async function saveCookies(context) {
|
|
24
|
+
ensureConfigDir();
|
|
25
|
+
const cookies = await context.cookies();
|
|
26
|
+
fs.writeFileSync(COOKIES_FILE, JSON.stringify(cookies, null, 2));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Load cookies from disk and apply to browser context
|
|
30
|
+
*/
|
|
31
|
+
export async function loadCookies(context) {
|
|
32
|
+
if (!fs.existsSync(COOKIES_FILE)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const cookiesJson = fs.readFileSync(COOKIES_FILE, "utf-8");
|
|
37
|
+
const cookies = JSON.parse(cookiesJson);
|
|
38
|
+
// Filter out expired cookies
|
|
39
|
+
const now = Date.now() / 1000;
|
|
40
|
+
const validCookies = cookies.filter((c) => !c.expires || c.expires > now);
|
|
41
|
+
if (validCookies.length > 0) {
|
|
42
|
+
await context.addCookies(validCookies);
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
console.error("Failed to load cookies:", error);
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Save session info to disk
|
|
53
|
+
*/
|
|
54
|
+
export function saveSessionInfo(info) {
|
|
55
|
+
ensureConfigDir();
|
|
56
|
+
fs.writeFileSync(SESSION_FILE, JSON.stringify(info, null, 2));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Load session info from disk
|
|
60
|
+
*/
|
|
61
|
+
export function loadSessionInfo() {
|
|
62
|
+
if (!fs.existsSync(SESSION_FILE)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const sessionJson = fs.readFileSync(SESSION_FILE, "utf-8");
|
|
67
|
+
return JSON.parse(sessionJson);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.error("Failed to load session info:", error);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Clear all saved auth data
|
|
76
|
+
*/
|
|
77
|
+
export function clearAuthData() {
|
|
78
|
+
if (fs.existsSync(COOKIES_FILE)) {
|
|
79
|
+
fs.unlinkSync(COOKIES_FILE);
|
|
80
|
+
}
|
|
81
|
+
if (fs.existsSync(SESSION_FILE)) {
|
|
82
|
+
fs.unlinkSync(SESSION_FILE);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if we have saved cookies (may or may not still be valid)
|
|
87
|
+
*/
|
|
88
|
+
export function hasSavedCookies() {
|
|
89
|
+
return fs.existsSync(COOKIES_FILE);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get the config directory path (useful for debugging)
|
|
93
|
+
*/
|
|
94
|
+
export function getConfigDir() {
|
|
95
|
+
return CONFIG_DIR;
|
|
96
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strider Labs - Booking.com Browser Automation
|
|
3
|
+
*
|
|
4
|
+
* Playwright-based browser automation for Booking.com operations.
|
|
5
|
+
*/
|
|
6
|
+
import { type SessionInfo } from "./auth.js";
|
|
7
|
+
export interface PropertyResult {
|
|
8
|
+
propertyId: string;
|
|
9
|
+
name: string;
|
|
10
|
+
location: string;
|
|
11
|
+
rating?: number;
|
|
12
|
+
reviewScore?: number;
|
|
13
|
+
reviewCount?: number;
|
|
14
|
+
pricePerNight?: string;
|
|
15
|
+
totalPrice?: string;
|
|
16
|
+
currency?: string;
|
|
17
|
+
imageUrl?: string;
|
|
18
|
+
url?: string;
|
|
19
|
+
distanceFromCenter?: string;
|
|
20
|
+
stars?: number;
|
|
21
|
+
freeCancellation?: boolean;
|
|
22
|
+
breakfastIncluded?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface RoomOption {
|
|
25
|
+
roomId?: string;
|
|
26
|
+
name: string;
|
|
27
|
+
maxGuests?: number;
|
|
28
|
+
bedType?: string;
|
|
29
|
+
price?: string;
|
|
30
|
+
totalPrice?: string;
|
|
31
|
+
freeCancellation?: boolean;
|
|
32
|
+
breakfastIncluded?: boolean;
|
|
33
|
+
available: boolean;
|
|
34
|
+
}
|
|
35
|
+
export interface Reservation {
|
|
36
|
+
reservationId: string;
|
|
37
|
+
propertyName: string;
|
|
38
|
+
checkIn: string;
|
|
39
|
+
checkOut: string;
|
|
40
|
+
guests?: number;
|
|
41
|
+
totalPrice?: string;
|
|
42
|
+
status: string;
|
|
43
|
+
confirmationNumber?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface Review {
|
|
46
|
+
reviewer?: string;
|
|
47
|
+
date?: string;
|
|
48
|
+
score?: number;
|
|
49
|
+
title?: string;
|
|
50
|
+
positives?: string;
|
|
51
|
+
negatives?: string;
|
|
52
|
+
country?: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Close browser and save state
|
|
56
|
+
*/
|
|
57
|
+
export declare function closeBrowser(): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Check Booking.com login status
|
|
60
|
+
*/
|
|
61
|
+
export declare function checkLoginStatus(): Promise<SessionInfo>;
|
|
62
|
+
/**
|
|
63
|
+
* Initiate login flow
|
|
64
|
+
*/
|
|
65
|
+
export declare function initiateLogin(): Promise<{
|
|
66
|
+
loginUrl: string;
|
|
67
|
+
instructions: string;
|
|
68
|
+
}>;
|
|
69
|
+
/**
|
|
70
|
+
* Search hotels on Booking.com
|
|
71
|
+
*/
|
|
72
|
+
export declare function searchProperties(destination: string, checkIn: string, checkOut: string, adults?: number, rooms?: number, children?: number, maxResults?: number): Promise<PropertyResult[]>;
|
|
73
|
+
/**
|
|
74
|
+
* Get property details by URL or property ID
|
|
75
|
+
*/
|
|
76
|
+
export declare function getPropertyDetails(propertyUrlOrId: string): Promise<Record<string, unknown>>;
|
|
77
|
+
/**
|
|
78
|
+
* Check room availability for a property
|
|
79
|
+
*/
|
|
80
|
+
export declare function checkAvailability(propertyUrlOrId: string, checkIn: string, checkOut: string, adults?: number, rooms?: number): Promise<{
|
|
81
|
+
available: boolean;
|
|
82
|
+
rooms: RoomOption[];
|
|
83
|
+
message: string;
|
|
84
|
+
}>;
|
|
85
|
+
/**
|
|
86
|
+
* Get prices for a property
|
|
87
|
+
*/
|
|
88
|
+
export declare function getPrices(propertyUrlOrId: string, checkIn: string, checkOut: string, adults?: number, rooms?: number): Promise<{
|
|
89
|
+
prices: RoomOption[];
|
|
90
|
+
currency: string;
|
|
91
|
+
lowestPrice?: string;
|
|
92
|
+
}>;
|
|
93
|
+
/**
|
|
94
|
+
* Filter cached search results
|
|
95
|
+
*/
|
|
96
|
+
export declare function filterResults(filters: {
|
|
97
|
+
minPrice?: number;
|
|
98
|
+
maxPrice?: number;
|
|
99
|
+
minRating?: number;
|
|
100
|
+
freeCancellation?: boolean;
|
|
101
|
+
breakfastIncluded?: boolean;
|
|
102
|
+
stars?: number;
|
|
103
|
+
keyword?: string;
|
|
104
|
+
}): PropertyResult[];
|
|
105
|
+
/**
|
|
106
|
+
* Sort cached search results
|
|
107
|
+
*/
|
|
108
|
+
export declare function sortResults(sortBy: "price_asc" | "price_desc" | "rating" | "distance" | "reviews"): PropertyResult[];
|
|
109
|
+
/**
|
|
110
|
+
* Save a property to favorites (wishlist)
|
|
111
|
+
*/
|
|
112
|
+
export declare function saveProperty(propertyUrlOrId: string): Promise<{
|
|
113
|
+
success: boolean;
|
|
114
|
+
message: string;
|
|
115
|
+
}>;
|
|
116
|
+
/**
|
|
117
|
+
* Book a room (with explicit confirmation required)
|
|
118
|
+
*/
|
|
119
|
+
export declare function bookRoom(propertyUrlOrId: string, checkIn: string, checkOut: string, adults?: number, rooms?: number, confirmBooking?: boolean): Promise<{
|
|
120
|
+
requiresConfirmation: true;
|
|
121
|
+
summary: Record<string, unknown>;
|
|
122
|
+
} | {
|
|
123
|
+
success: boolean;
|
|
124
|
+
bookingId?: string;
|
|
125
|
+
message: string;
|
|
126
|
+
}>;
|
|
127
|
+
/**
|
|
128
|
+
* Get current reservations
|
|
129
|
+
*/
|
|
130
|
+
export declare function getReservations(): Promise<Reservation[]>;
|
|
131
|
+
/**
|
|
132
|
+
* Cancel a reservation
|
|
133
|
+
*/
|
|
134
|
+
export declare function cancelReservation(reservationId: string, confirmCancellation?: boolean): Promise<{
|
|
135
|
+
success: boolean;
|
|
136
|
+
message: string;
|
|
137
|
+
}>;
|
|
138
|
+
/**
|
|
139
|
+
* Get reviews for a property
|
|
140
|
+
*/
|
|
141
|
+
export declare function getPropertyReviews(propertyUrlOrId: string, maxReviews?: number): Promise<{
|
|
142
|
+
reviews: Review[];
|
|
143
|
+
averageScore?: number;
|
|
144
|
+
totalReviews?: number;
|
|
145
|
+
}>;
|