hotelzero 1.0.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 ADDED
@@ -0,0 +1,521 @@
1
+ # HotelZero
2
+
3
+ An MCP (Model Context Protocol) server that searches hotels on Booking.com using Playwright browser automation. Features 80+ filter options for precise hotel searches.
4
+
5
+ ## Features
6
+
7
+ - **Comprehensive Filtering**: 80+ filters covering property types, amenities, accessibility, activities, and more
8
+ - **Real Booking.com Data**: Uses actual Booking.com filter codes reverse-engineered from their URL parameters
9
+ - **Sponsored Ad Filtering**: Automatically excludes paid/promoted listings (native ads with `nad_` tracking)
10
+ - **Smart Scoring**: Results are scored and ranked by how well they match your criteria
11
+ - **Match Transparency**: Each result shows why it matched your filters
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install -g hotelzero
17
+
18
+ # Install Playwright browser (Chromium)
19
+ npx playwright install chromium
20
+ ```
21
+
22
+ Or run directly with npx:
23
+
24
+ ```bash
25
+ npx hotelzero
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ### Run as MCP Server
31
+
32
+ Add to your MCP client configuration (e.g., Claude Desktop, OpenCode):
33
+
34
+ ```json
35
+ {
36
+ "mcpServers": {
37
+ "hotelzero": {
38
+ "command": "npx",
39
+ "args": ["hotelzero"]
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
45
+ ## Available Tools
46
+
47
+ ### `find_hotels`
48
+
49
+ Search for hotels with comprehensive filtering. This is the primary tool with all 80+ filter options.
50
+
51
+ **Example:**
52
+ ```json
53
+ {
54
+ "destination": "San Juan, Puerto Rico",
55
+ "checkIn": "2026-03-07",
56
+ "checkOut": "2026-03-14",
57
+ "beachfront": true,
58
+ "freeWifi": true,
59
+ "fitness": true,
60
+ "minRating": 8
61
+ }
62
+ ```
63
+
64
+ ### `search_hotels`
65
+
66
+ Basic hotel search without filters. Use this for simple queries when you don't need specific criteria.
67
+
68
+ **Example:**
69
+ ```json
70
+ {
71
+ "destination": "Paris, France",
72
+ "checkIn": "2026-06-01",
73
+ "checkOut": "2026-06-05",
74
+ "guests": 2,
75
+ "rooms": 1
76
+ }
77
+ ```
78
+
79
+ ### `get_hotel_details`
80
+
81
+ Get detailed information about a specific hotel including full amenity list, description, and photos.
82
+
83
+ **Example:**
84
+ ```json
85
+ {
86
+ "url": "https://www.booking.com/hotel/pr/condado-vanderbilt.html"
87
+ }
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Complete Filter Reference
93
+
94
+ ### Basic Search Parameters
95
+
96
+ | Parameter | Type | Required | Description |
97
+ |-----------|------|----------|-------------|
98
+ | `destination` | string | Yes | City or location (e.g., "San Juan, Puerto Rico") |
99
+ | `checkIn` | string | Yes | Check-in date (YYYY-MM-DD) |
100
+ | `checkOut` | string | Yes | Check-out date (YYYY-MM-DD) |
101
+ | `guests` | number | No | Number of guests (default: 2) |
102
+ | `rooms` | number | No | Number of rooms (default: 1) |
103
+
104
+ ### Rating & Price
105
+
106
+ | Filter | Type | Description |
107
+ |--------|------|-------------|
108
+ | `minRating` | number | Minimum review score: 6=Pleasant, 7=Good, 8=Very Good, 9=Wonderful |
109
+ | `maxPrice` | number | Maximum price per night in USD (client-side filter) |
110
+
111
+ ### Property Type
112
+
113
+ | Filter | Type | Options |
114
+ |--------|------|---------|
115
+ | `propertyType` | enum | `hotel`, `apartment`, `resort`, `villa`, `vacation_home`, `hostel`, `bnb`, `guesthouse`, `homestay`, `motel`, `inn`, `lodge`, `chalet`, `campground`, `glamping`, `boat`, `capsule`, `ryokan`, `riad`, `country_house`, `farm_stay` |
116
+ | `starRating` | number | 1, 2, 3, 4, or 5 stars |
117
+
118
+ ### Beach & Location
119
+
120
+ | Filter | Type | Description |
121
+ |--------|------|-------------|
122
+ | `beachfront` | boolean | Property is directly on the beach |
123
+ | `beachAccess` | boolean | Property has beach access |
124
+ | `oceanView` | boolean | Room with ocean/sea view |
125
+ | `maxDistanceFromCenter` | enum | `half_mile`, `1_mile`, `2_miles` |
126
+
127
+ ### Hotel Facilities
128
+
129
+ | Filter | Description |
130
+ |--------|-------------|
131
+ | `freeWifi` | Free WiFi throughout property |
132
+ | `pool` | Swimming pool |
133
+ | `spa` | Spa/wellness center |
134
+ | `fitness` | Fitness center/gym |
135
+ | `parking` | Parking available |
136
+ | `restaurant` | On-site restaurant |
137
+ | `bar` | On-site bar/lounge |
138
+ | `roomService` | 24-hour front desk/room service |
139
+ | `airportShuttle` | Airport shuttle service |
140
+ | `hotTub` | Hot tub/Jacuzzi |
141
+ | `sauna` | Sauna |
142
+ | `garden` | Garden |
143
+ | `terrace` | Terrace |
144
+ | `nonSmokingRooms` | Non-smoking rooms available |
145
+ | `familyRooms` | Family rooms |
146
+ | `evCharging` | Electric vehicle charging station |
147
+ | `casino` | Casino |
148
+ | `golf` | Golf course nearby (within 2 miles) |
149
+ | `tennis` | Tennis court |
150
+ | `bbqFacilities` | BBQ facilities |
151
+ | `laundry` | Laundry service |
152
+ | `concierge` | Concierge service |
153
+ | `businessCenter` | Business center |
154
+
155
+ ### Room Facilities
156
+
157
+ | Filter | Description |
158
+ |--------|-------------|
159
+ | `airConditioning` | Air conditioning |
160
+ | `kitchen` | Kitchen or kitchenette |
161
+ | `balcony` | Private balcony |
162
+ | `privatePool` | Private pool |
163
+ | `privateBathroom` | Private bathroom |
164
+ | `bath` | Bathtub |
165
+ | `tv` | Television |
166
+ | `minibar` | Minibar |
167
+ | `safe` | In-room safe |
168
+ | `washingMachine` | Washing machine in unit |
169
+ | `soundproofing` | Soundproofed rooms |
170
+
171
+ ### Bed Type
172
+
173
+ | Filter | Options |
174
+ |--------|---------|
175
+ | `bedType` | `king`, `queen`, `double`, `twin`, `single` |
176
+
177
+ ### Meal Plans
178
+
179
+ | Filter | Description |
180
+ |--------|-------------|
181
+ | `breakfast` | Breakfast included in rate |
182
+ | `allInclusive` | All-inclusive package |
183
+ | `selfCatering` | Self-catering with kitchen amenities |
184
+
185
+ ### Stay Type & Policies
186
+
187
+ | Filter | Description |
188
+ |--------|-------------|
189
+ | `petFriendly` | Pets allowed |
190
+ | `adultsOnly` | Adults-only property |
191
+ | `lgbtqFriendly` | LGBTQ+ friendly (Booking.com Travel Proud) |
192
+ | `freeCancellation` | Free cancellation available |
193
+ | `noPrepayment` | No prepayment required |
194
+ | `noBookingFee` | Book without credit card |
195
+
196
+ ### Sustainability
197
+
198
+ | Filter | Description |
199
+ |--------|-------------|
200
+ | `sustainabilityCertified` | Has sustainability certification |
201
+
202
+ ### Activities
203
+
204
+ | Filter | Description |
205
+ |--------|-------------|
206
+ | `snorkeling` | Snorkeling available |
207
+ | `diving` | Diving/scuba available |
208
+ | `fishing` | Fishing available |
209
+ | `hiking` | Hiking trails nearby |
210
+ | `cycling` | Cycling/biking available |
211
+ | `skiing` | Skiing nearby |
212
+ | `waterSports` | Water sports available |
213
+ | `horseRiding` | Horse riding available |
214
+
215
+ ### Accessibility - Property Level
216
+
217
+ | Filter | Description |
218
+ |--------|-------------|
219
+ | `grabRails` | Grab rails in bathroom |
220
+ | `raisedToilet` | Raised toilet |
221
+ | `loweredSink` | Lowered sink |
222
+ | `braille` | Braille signage |
223
+ | `tactileSigns` | Tactile signs |
224
+ | `auditoryGuidance` | Auditory guidance |
225
+
226
+ ### Accessibility - Room Level
227
+
228
+ | Filter | Description |
229
+ |--------|-------------|
230
+ | `wheelchairAccessible` | Entire unit wheelchair accessible |
231
+ | `groundFloor` | Ground floor unit available |
232
+ | `elevatorAccess` | Upper floors accessible by elevator |
233
+ | `walkInShower` | Walk-in shower |
234
+ | `rollInShower` | Roll-in shower (wheelchair accessible) |
235
+ | `showerChair` | Shower chair available |
236
+
237
+ ### Hotel Chains
238
+
239
+ | Filter | Options |
240
+ |--------|---------|
241
+ | `hotelChain` | `marriott`, `hilton`, `hyatt`, `ihg`, `wyndham`, `best_western`, `accor`, `choice`, `radisson`, `ritz_carlton`, `four_seasons`, `fairmont`, `sheraton`, `westin`, `w_hotels`, `courtyard`, `residence_inn`, `hampton`, `embassy_suites`, `doubletree` |
242
+
243
+ ---
244
+
245
+ ## Example Queries
246
+
247
+ ### Beach Vacation in Puerto Rico
248
+
249
+ ```json
250
+ {
251
+ "destination": "San Juan, Puerto Rico",
252
+ "checkIn": "2026-03-07",
253
+ "checkOut": "2026-03-14",
254
+ "beachfront": true,
255
+ "freeWifi": true,
256
+ "fitness": true,
257
+ "pool": true,
258
+ "minRating": 8
259
+ }
260
+ ```
261
+
262
+ ### Luxury Ski Resort
263
+
264
+ ```json
265
+ {
266
+ "destination": "Aspen, Colorado",
267
+ "checkIn": "2026-01-15",
268
+ "checkOut": "2026-01-22",
269
+ "propertyType": "resort",
270
+ "starRating": 5,
271
+ "skiing": true,
272
+ "spa": true,
273
+ "hotTub": true,
274
+ "minRating": 9
275
+ }
276
+ ```
277
+
278
+ ### Family Beach Trip with All-Inclusive
279
+
280
+ ```json
281
+ {
282
+ "destination": "Cancun, Mexico",
283
+ "checkIn": "2026-07-01",
284
+ "checkOut": "2026-07-08",
285
+ "guests": 4,
286
+ "rooms": 2,
287
+ "beachfront": true,
288
+ "allInclusive": true,
289
+ "familyRooms": true,
290
+ "pool": true,
291
+ "freeCancellation": true
292
+ }
293
+ ```
294
+
295
+ ### Accessible City Center Hotel
296
+
297
+ ```json
298
+ {
299
+ "destination": "London, UK",
300
+ "checkIn": "2026-04-01",
301
+ "checkOut": "2026-04-05",
302
+ "maxDistanceFromCenter": "half_mile",
303
+ "wheelchairAccessible": true,
304
+ "elevatorAccess": true,
305
+ "walkInShower": true,
306
+ "freeWifi": true
307
+ }
308
+ ```
309
+
310
+ ### Pet-Friendly Road Trip Stop
311
+
312
+ ```json
313
+ {
314
+ "destination": "Portland, Oregon",
315
+ "checkIn": "2026-05-10",
316
+ "checkOut": "2026-05-12",
317
+ "petFriendly": true,
318
+ "parking": true,
319
+ "freeCancellation": true,
320
+ "maxPrice": 200
321
+ }
322
+ ```
323
+
324
+ ### Digital Nomad Long Stay
325
+
326
+ ```json
327
+ {
328
+ "destination": "Lisbon, Portugal",
329
+ "checkIn": "2026-06-01",
330
+ "checkOut": "2026-06-30",
331
+ "propertyType": "apartment",
332
+ "kitchen": true,
333
+ "freeWifi": true,
334
+ "washingMachine": true,
335
+ "maxDistanceFromCenter": "1_mile",
336
+ "maxPrice": 150
337
+ }
338
+ ```
339
+
340
+ ### Romantic Getaway
341
+
342
+ ```json
343
+ {
344
+ "destination": "Santorini, Greece",
345
+ "checkIn": "2026-09-15",
346
+ "checkOut": "2026-09-20",
347
+ "adultsOnly": true,
348
+ "oceanView": true,
349
+ "privatePool": true,
350
+ "breakfast": true,
351
+ "spa": true,
352
+ "minRating": 9
353
+ }
354
+ ```
355
+
356
+ ### Japanese Cultural Experience
357
+
358
+ ```json
359
+ {
360
+ "destination": "Kyoto, Japan",
361
+ "checkIn": "2026-04-01",
362
+ "checkOut": "2026-04-07",
363
+ "propertyType": "ryokan",
364
+ "breakfast": true,
365
+ "minRating": 8
366
+ }
367
+ ```
368
+
369
+ ### Eco-Friendly Adventure
370
+
371
+ ```json
372
+ {
373
+ "destination": "Costa Rica",
374
+ "checkIn": "2026-02-01",
375
+ "checkOut": "2026-02-08",
376
+ "sustainabilityCertified": true,
377
+ "hiking": true,
378
+ "snorkeling": true,
379
+ "diving": true
380
+ }
381
+ ```
382
+
383
+ ### Golf Trip
384
+
385
+ ```json
386
+ {
387
+ "destination": "Scottsdale, Arizona",
388
+ "checkIn": "2026-03-01",
389
+ "checkOut": "2026-03-05",
390
+ "propertyType": "resort",
391
+ "golf": true,
392
+ "spa": true,
393
+ "restaurant": true,
394
+ "bar": true
395
+ }
396
+ ```
397
+
398
+ ---
399
+
400
+ ## How It Works
401
+
402
+ ### Server-Side Filtering
403
+
404
+ Filters are applied via Booking.com's `nflt` URL parameter using reverse-engineered filter codes. For example:
405
+
406
+ - `beachfront: true` adds `ht_beach=1`
407
+ - `freeWifi: true` adds `hotelfacility=107`
408
+ - `fitness: true` adds `popular_activities=11`
409
+ - `minRating: 8` adds `review_score=80`
410
+
411
+ ### Client-Side Scoring
412
+
413
+ After fetching results, each hotel is scored based on how well it matches your criteria:
414
+
415
+ - **+20 points**: Beach-related filters when property mentions beach
416
+ - **+15 points**: Rating 9.0+ ("Excellent")
417
+ - **+10 points**: Each matched amenity (WiFi, pool, gym, etc.)
418
+ - **+5 points**: 500+ reviews (trustworthiness bonus)
419
+
420
+ Results are sorted by match score, so the best matches appear first.
421
+
422
+ ### Sponsored Ad Filtering
423
+
424
+ Booking.com injects paid "native ads" into search results. These are identified and excluded by:
425
+
426
+ 1. Detecting `nad_` (native ad tracking) in the hotel card HTML or links
427
+ 2. Checking for explicit "Ad", "Sponsored", or "Promoted" labels
428
+
429
+ This ensures you only see organic results, not paid placements.
430
+
431
+ ---
432
+
433
+ ## Output Format
434
+
435
+ Each hotel result includes:
436
+
437
+ ```
438
+ 1. Hotel Name
439
+ Price: $XXX per night
440
+ Rating: X.X/10 Rating Text (XXX reviews)
441
+ Location: X.X miles from center
442
+ Amenities: Pool, Free WiFi, Gym, ...
443
+ Match Score: XX
444
+ Why it matches: Near beach, Has WiFi, Has gym, ...
445
+ Book: https://www.booking.com/hotel/...
446
+ ```
447
+
448
+ ---
449
+
450
+ ## Technical Details
451
+
452
+ ### Architecture
453
+
454
+ ```
455
+ src/
456
+ ├── index.ts # MCP server with tool definitions
457
+ ├── browser.ts # Playwright automation & filter mappings
458
+ └── test*.ts # Test scripts
459
+ ```
460
+
461
+ ### Dependencies
462
+
463
+ - `@modelcontextprotocol/sdk` - MCP server SDK
464
+ - `playwright` - Browser automation
465
+ - `zod` - Schema validation
466
+
467
+ ### Browser Configuration
468
+
469
+ - **Headless Mode**: Runs without visible browser window
470
+ - **Anti-Detection**: Custom user agent and disabled automation flags
471
+ - **Auto-Scrolling**: Loads more results by scrolling the page
472
+ - **Popup Handling**: Automatically dismisses cookie banners and sign-in modals
473
+
474
+ ### Filter Code Mappings
475
+
476
+ All Booking.com filter codes are mapped in `browser.ts`:
477
+
478
+ ```typescript
479
+ const FILTER_CODES = {
480
+ propertyType: { hotel: "ht_id=204", resort: "ht_id=206", ... },
481
+ hotelfacility: { freeWifi: 107, pool: 433, spa: 54, ... },
482
+ roomfacility: { airConditioning: 11, kitchen: 999, ... },
483
+ popularActivities: { fitness: 11, golf: 12, skiing: 13, ... },
484
+ chaincode: { marriott: 1080, hilton: 1078, ... },
485
+ // ... 20+ filter categories
486
+ };
487
+ ```
488
+
489
+ ---
490
+
491
+ ## Limitations
492
+
493
+ - **Rate Limiting**: Booking.com may rate-limit or block automated requests
494
+ - **Results Cap**: Returns ~25 results per search (first page + scroll load)
495
+ - **Price Accuracy**: Prices may vary based on availability and timing
496
+ - **Filter Availability**: Some filters may not apply to all destinations
497
+
498
+ ---
499
+
500
+ ## Troubleshooting
501
+
502
+ ### "Browser not initialized"
503
+
504
+ Run `npx playwright install chromium` to install the browser.
505
+
506
+ ### No results returned
507
+
508
+ - Check that dates are in the future
509
+ - Verify destination spelling
510
+ - Try removing some filters (too restrictive)
511
+
512
+ ### Blocked by Booking.com
513
+
514
+ - Wait a few minutes before retrying
515
+ - The server uses anti-detection measures, but excessive requests may trigger blocks
516
+
517
+ ---
518
+
519
+ ## License
520
+
521
+ MIT
@@ -0,0 +1,119 @@
1
+ export interface HotelSearchParams {
2
+ destination: string;
3
+ checkIn: string;
4
+ checkOut: string;
5
+ guests: number;
6
+ rooms: number;
7
+ }
8
+ export interface HotelFilters {
9
+ minRating?: number;
10
+ maxPrice?: number;
11
+ propertyType?: "hotel" | "apartment" | "resort" | "villa" | "vacation_home" | "hostel" | "bnb" | "guesthouse" | "homestay" | "motel" | "inn" | "lodge" | "chalet" | "campground" | "glamping" | "boat" | "capsule" | "ryokan" | "riad" | "country_house" | "farm_stay";
12
+ starRating?: 1 | 2 | 3 | 4 | 5;
13
+ beachfront?: boolean;
14
+ beachAccess?: boolean;
15
+ oceanView?: boolean;
16
+ freeWifi?: boolean;
17
+ pool?: boolean;
18
+ spa?: boolean;
19
+ fitness?: boolean;
20
+ parking?: boolean;
21
+ freeParking?: boolean;
22
+ restaurant?: boolean;
23
+ bar?: boolean;
24
+ roomService?: boolean;
25
+ airportShuttle?: boolean;
26
+ hotTub?: boolean;
27
+ sauna?: boolean;
28
+ garden?: boolean;
29
+ terrace?: boolean;
30
+ nonSmokingRooms?: boolean;
31
+ familyRooms?: boolean;
32
+ disabledFacilities?: boolean;
33
+ evCharging?: boolean;
34
+ golf?: boolean;
35
+ tennis?: boolean;
36
+ casino?: boolean;
37
+ bbqFacilities?: boolean;
38
+ laundry?: boolean;
39
+ concierge?: boolean;
40
+ currencyExchange?: boolean;
41
+ businessCenter?: boolean;
42
+ meetingRooms?: boolean;
43
+ airConditioning?: boolean;
44
+ kitchen?: boolean;
45
+ balcony?: boolean;
46
+ privatePool?: boolean;
47
+ privateBathroom?: boolean;
48
+ bath?: boolean;
49
+ tv?: boolean;
50
+ coffeemaker?: boolean;
51
+ minibar?: boolean;
52
+ safe?: boolean;
53
+ washingMachine?: boolean;
54
+ soundproofing?: boolean;
55
+ bedType?: "king" | "queen" | "double" | "twin" | "single";
56
+ breakfast?: boolean;
57
+ allInclusive?: boolean;
58
+ selfCatering?: boolean;
59
+ petFriendly?: boolean;
60
+ adultsOnly?: boolean;
61
+ lgbtqFriendly?: boolean;
62
+ freeCancellation?: boolean;
63
+ noPrepayment?: boolean;
64
+ noBookingFee?: boolean;
65
+ sustainabilityCertified?: boolean;
66
+ wheelchairAccessible?: boolean;
67
+ groundFloor?: boolean;
68
+ elevatorAccess?: boolean;
69
+ grabRails?: boolean;
70
+ raisedToilet?: boolean;
71
+ loweredSink?: boolean;
72
+ emergencyCord?: boolean;
73
+ braille?: boolean;
74
+ tactileSigns?: boolean;
75
+ auditoryGuidance?: boolean;
76
+ walkInShower?: boolean;
77
+ rollInShower?: boolean;
78
+ showerChair?: boolean;
79
+ maxDistanceFromCenter?: "half_mile" | "1_mile" | "2_miles";
80
+ snorkeling?: boolean;
81
+ diving?: boolean;
82
+ fishing?: boolean;
83
+ hiking?: boolean;
84
+ cycling?: boolean;
85
+ skiing?: boolean;
86
+ waterSports?: boolean;
87
+ horseRiding?: boolean;
88
+ hotelChain?: "marriott" | "hilton" | "hyatt" | "ihg" | "wyndham" | "best_western" | "accor" | "choice" | "radisson" | "ritz_carlton" | "four_seasons" | "fairmont" | "sheraton" | "westin" | "w_hotels" | "courtyard" | "residence_inn" | "hampton" | "embassy_suites" | "doubletree";
89
+ }
90
+ export interface HotelResult {
91
+ name: string;
92
+ price: number | null;
93
+ priceDisplay: string;
94
+ rating: number | null;
95
+ ratingText: string;
96
+ reviewCount: number | null;
97
+ location: string;
98
+ distanceToCenter: string;
99
+ amenities: string[];
100
+ highlights: string[];
101
+ link: string;
102
+ matchScore?: number;
103
+ matchReasons?: string[];
104
+ }
105
+ export declare class HotelBrowser {
106
+ private browser;
107
+ private page;
108
+ init(headless?: boolean): Promise<void>;
109
+ close(): Promise<void>;
110
+ private buildBookingUrl;
111
+ searchHotels(params: HotelSearchParams, filters?: HotelFilters): Promise<HotelResult[]>;
112
+ private dismissPopups;
113
+ private scrollToLoadMore;
114
+ private extractHotelDetails;
115
+ private scoreAndFilterHotels;
116
+ getHotelDetails(hotelUrl: string): Promise<Record<string, unknown>>;
117
+ takeScreenshot(path: string): Promise<void>;
118
+ getPageContent(): Promise<string>;
119
+ }