Hotelzero — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Hotelzero (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
An MCP (Model Context Protocol) server that searches hotels on Booking.com using Playwright browser automation. Features 80+ filter options for precise hotel searches.
nad_ tracking)npm install -g hotelzero
# Install Playwright browser (Chromium)
npx playwright install chromiumOr run directly with npx:
npx hotelzeroFor heavy usage or to avoid IP blocks, you can configure a proxy server via the HOTELZERO_PROXY environment variable:
# HTTP proxy
HOTELZERO_PROXY=http://proxy.example.com:8080 npx hotelzero
# HTTP proxy with authentication
HOTELZERO_PROXY=http://user:[email protected]:8080 npx hotelzero
# SOCKS5 proxy
HOTELZERO_PROXY=socks5://proxy.example.com:1080 npx hotelzero
# SOCKS5 proxy with authentication
HOTELZERO_PROXY=socks5://user:[email protected]:1080 npx hotelzeroWhen a proxy is configured, you'll see confirmation in the startup logs:
Proxy enabled: http://proxy.example.com:8080
HotelZero v1.8.0 running on stdioHotelZero uses structured logging via pino. Logs are written to stderr to avoid interfering with the MCP stdio transport.
Control log verbosity with the HOTELZERO_LOG_LEVEL environment variable:
# Available levels: trace, debug, info, warn, error, fatal, silent
# Default: info
# Debug mode - verbose output for troubleshooting
HOTELZERO_LOG_LEVEL=debug npx hotelzero
# Silent mode - no logs
HOTELZERO_LOG_LEVEL=silent npx hotelzero
# Error only - minimal output
HOTELZERO_LOG_LEVEL=error npx hotelzeroLogs are JSON-formatted for easy parsing:
{"level":"info","time":"2026-02-15T12:00:00.000Z","service":"hotelzero","module":"server","version":"1.11.0","transport":"stdio","msg":"HotelZero server started"}
{"level":"info","time":"2026-02-15T12:00:01.000Z","service":"hotelzero","module":"browser","msg":"Browser initialized"}
{"level":"info","time":"2026-02-15T12:00:02.000Z","service":"hotelzero","module":"browser","destination":"Paris","msg":"Starting hotel search"}HotelZero automatically saves browser session data (cookies, localStorage) to reduce bot detection and avoid repeated CAPTCHA challenges.
~/.hotelzero/session.jsonUse HOTELZERO_SESSION_PATH to specify a custom location:
# Custom session file location
HOTELZERO_SESSION_PATH=/path/to/session.json npx hotelzero
# Disable session persistence (use empty string)
HOTELZERO_SESSION_PATH="" npx hotelzeroIf you experience issues, you can delete the session file:
rm ~/.hotelzero/session.jsonAdd to your MCP client configuration (e.g., Claude Desktop, OpenCode):
{
"mcpServers": {
"hotelzero": {
"command": "npx",
"args": ["hotelzero"]
}
}
}find_hotelsSearch for hotels with comprehensive filtering. This is the primary tool with all 80+ filter options.
Example:
{
"destination": "San Juan, Puerto Rico",
"checkIn": "2026-03-07",
"checkOut": "2026-03-14",
"beachfront": true,
"freeWifi": true,
"fitness": true,
"minRating": 8
}search_hotelsBasic hotel search without filters. Use this for simple queries when you don't need specific criteria.
Example:
{
"destination": "Paris, France",
"checkIn": "2026-06-01",
"checkOut": "2026-06-05",
"guests": 2,
"rooms": 1
}get_hotel_detailsGet detailed information about a specific hotel including full amenity list, description, and photos.
Example:
{
"url": "https://www.booking.com/hotel/pr/condado-vanderbilt.html"
}| Parameter | Type | Required | Description |
|---|---|---|---|
destination | string | Yes | City or location (e.g., "San Juan, Puerto Rico") |
checkIn | string | Yes | Check-in date (YYYY-MM-DD) |
checkOut | string | Yes | Check-out date (YYYY-MM-DD) |
guests | number | No | Number of guests (default: 2) |
rooms | number | No | Number of rooms (default: 1) |
currency | string | No | Currency code (USD, EUR, GBP, JPY, etc.) Default: USD |
sortBy | enum | No | Sort results: popularity, price_lowest, price_highest, rating, distance |
| Filter | Type | Description |
|---|---|---|
minRating | number | Minimum review score: 6=Pleasant, 7=Good, 8=Very Good, 9=Wonderful |
minPrice | number | Minimum price per night |
maxPrice | number | Maximum price per night |
| Filter | Type | Options |
|---|---|---|
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 |
starRating | number | 1, 2, 3, 4, or 5 stars |
| Filter | Type | Description |
|---|---|---|
beachfront | boolean | Property is directly on the beach |
beachAccess | boolean | Property has beach access |
oceanView | boolean | Room with ocean/sea view |
maxDistanceFromCenter | enum | half_mile, 1_mile, 2_miles |
| Filter | Description |
|---|---|
freeWifi | Free WiFi throughout property |
pool | Swimming pool |
spa | Spa/wellness center |
fitness | Fitness center/gym |
parking | Parking available |
restaurant | On-site restaurant |
bar | On-site bar/lounge |
roomService | 24-hour front desk/room service |
airportShuttle | Airport shuttle service |
hotTub | Hot tub/Jacuzzi |
sauna | Sauna |
garden | Garden |
terrace | Terrace |
nonSmokingRooms | Non-smoking rooms available |
familyRooms | Family rooms |
evCharging | Electric vehicle charging station |
casino | Casino |
golf | Golf course nearby (within 2 miles) |
tennis | Tennis court |
bbqFacilities | BBQ facilities |
laundry | Laundry service |
concierge | Concierge service |
businessCenter | Business center |
| Filter | Description |
|---|---|
airConditioning | Air conditioning |
kitchen | Kitchen or kitchenette |
balcony | Private balcony |
privatePool | Private pool |
privateBathroom | Private bathroom |
bath | Bathtub |
tv | Television |
minibar | Minibar |
safe | In-room safe |
washingMachine | Washing machine in unit |
soundproofing | Soundproofed rooms |
| Filter | Options |
|---|---|
bedType | king, queen, double, twin, single |
| Filter | Description |
|---|---|
breakfast | Breakfast included in rate |
allInclusive | All-inclusive package |
selfCatering | Self-catering with kitchen amenities |
| Filter | Description |
|---|---|
petFriendly | Pets allowed |
adultsOnly | Adults-only property |
lgbtqFriendly | LGBTQ+ friendly (Booking.com Travel Proud) |
freeCancellation | Free cancellation available |
noPrepayment | No prepayment required |
noBookingFee | Book without credit card |
| Filter | Description |
|---|---|
sustainabilityCertified | Has sustainability certification |
| Filter | Description |
|---|---|
snorkeling | Snorkeling available |
diving | Diving/scuba available |
fishing | Fishing available |
hiking | Hiking trails nearby |
cycling | Cycling/biking available |
skiing | Skiing nearby |
waterSports | Water sports available |
horseRiding | Horse riding available |
| Filter | Description |
|---|---|
grabRails | Grab rails in bathroom |
raisedToilet | Raised toilet |
loweredSink | Lowered sink |
braille | Braille signage |
tactileSigns | Tactile signs |
auditoryGuidance | Auditory guidance |
| Filter | Description |
|---|---|
wheelchairAccessible | Entire unit wheelchair accessible |
groundFloor | Ground floor unit available |
elevatorAccess | Upper floors accessible by elevator |
walkInShower | Walk-in shower |
rollInShower | Roll-in shower (wheelchair accessible) |
showerChair | Shower chair available |
| Filter | Options |
|---|---|
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 |
{
"destination": "San Juan, Puerto Rico",
"checkIn": "2026-03-07",
"checkOut": "2026-03-14",
"beachfront": true,
"freeWifi": true,
"fitness": true,
"pool": true,
"minRating": 8
}{
"destination": "Aspen, Colorado",
"checkIn": "2026-01-15",
"checkOut": "2026-01-22",
"propertyType": "resort",
"starRating": 5,
"skiing": true,
"spa": true,
"hotTub": true,
"minRating": 9
}{
"destination": "Cancun, Mexico",
"checkIn": "2026-07-01",
"checkOut": "2026-07-08",
"guests": 4,
"rooms": 2,
"beachfront": true,
"allInclusive": true,
"familyRooms": true,
"pool": true,
"freeCancellation": true
}{
"destination": "London, UK",
"checkIn": "2026-04-01",
"checkOut": "2026-04-05",
"maxDistanceFromCenter": "half_mile",
"wheelchairAccessible": true,
"elevatorAccess": true,
"walkInShower": true,
"freeWifi": true
}{
"destination": "Portland, Oregon",
"checkIn": "2026-05-10",
"checkOut": "2026-05-12",
"petFriendly": true,
"parking": true,
"freeCancellation": true,
"maxPrice": 200
}{
"destination": "Lisbon, Portugal",
"checkIn": "2026-06-01",
"checkOut": "2026-06-30",
"propertyType": "apartment",
"kitchen": true,
"freeWifi": true,
"washingMachine": true,
"maxDistanceFromCenter": "1_mile",
"maxPrice": 150
}{
"destination": "Santorini, Greece",
"checkIn": "2026-09-15",
"checkOut": "2026-09-20",
"adultsOnly": true,
"oceanView": true,
"privatePool": true,
"breakfast": true,
"spa": true,
"minRating": 9
}{
"destination": "Kyoto, Japan",
"checkIn": "2026-04-01",
"checkOut": "2026-04-07",
"propertyType": "ryokan",
"breakfast": true,
"minRating": 8
}{
"destination": "Costa Rica",
"checkIn": "2026-02-01",
"checkOut": "2026-02-08",
"sustainabilityCertified": true,
"hiking": true,
"snorkeling": true,
"diving": true
}{
"destination": "Scottsdale, Arizona",
"checkIn": "2026-03-01",
"checkOut": "2026-03-05",
"propertyType": "resort",
"golf": true,
"spa": true,
"restaurant": true,
"bar": true
}Filters are applied via Booking.com's nflt URL parameter using reverse-engineered filter codes. For example:
beachfront: true adds ht_beach=1freeWifi: true adds hotelfacility=107fitness: true adds popular_activities=11minRating: 8 adds review_score=80After fetching results, each hotel is scored based on how well it matches your criteria:
Results are sorted by match score, so the best matches appear first.
Booking.com injects paid "native ads" into search results. These are identified and excluded by:
nad_ (native ad tracking) in the hotel card HTML or linksThis ensures you only see organic results, not paid placements.
Each hotel result includes:
1. Hotel Name
Price: $XXX per night
Rating: X.X/10 Rating Text (XXX reviews)
Location: X.X miles from center
Amenities: Pool, Free WiFi, Gym, ...
Match Score: XX
Why it matches: Near beach, Has WiFi, Has gym, ...
Book: https://www.booking.com/hotel/...src/
├── index.ts # MCP server with tool definitions
├── browser.ts # Playwright automation & filter mappings
└── test*.ts # Test scripts@modelcontextprotocol/sdk - MCP server SDKplaywright - Browser automationzod - Schema validationAll Booking.com filter codes are mapped in browser.ts:
const FILTER_CODES = {
propertyType: { hotel: "ht_id=204", resort: "ht_id=206", ... },
hotelfacility: { freeWifi: 107, pool: 433, spa: 54, ... },
roomfacility: { airConditioning: 11, kitchen: 999, ... },
popularActivities: { fitness: 11, golf: 12, skiing: 13, ... },
chaincode: { marriott: 1080, hilton: 1078, ... },
// ... 20+ filter categories
};Run npx playwright install chromium to install the browser.
npx playwright install chromiumIf that doesn't work, try forcing a reinstall:
npx playwright install chromium --forceIf you encounter CAPTCHA challenges:
rm ~/.hotelzero/session.jsonrm ~/.hotelzero/session.json)curl first curl -x http://proxy:8080 https://www.booking.comcurrency: "USD"If you experience inconsistent behavior:
# Clear the session and start fresh
rm ~/.hotelzero/session.json
# Or disable session persistence entirely
HOTELZERO_SESSION_PATH="" npx hotelzeroEnable debug logging to see detailed information:
HOTELZERO_LOG_LEVEL=debug npx hotelzeroThis will show:
If you're running the test suite and tests fail:
find_hotels / search_hotels)interface HotelResult {
name: string; // Hotel name
price: number | null; // Price per night as number (null if not shown)
priceDisplay: string; // Formatted price string (e.g., "$199")
rating: number | null; // Review score 0-10 (null if no reviews)
ratingText: string; // Rating description (e.g., "Excellent", "Very Good")
reviewCount: number | null; // Number of reviews (null if not shown)
location: string; // Neighborhood/area name
distanceToCenter: string; // Distance from center (e.g., "0.5 miles from center")
amenities: string[]; // Detected amenities (e.g., ["Pool", "Free WiFi", "Spa"])
highlights: string[]; // Special highlights (e.g., ["Free Cancellation"])
link: string; // Full Booking.com URL for the hotel
thumbnailUrl: string | null; // Hotel thumbnail image URL (null if not available)
availability: string | null; // Availability status (e.g., "Only 2 rooms left!")
matchScore?: number; // Relevance score based on filters (only with filters)
matchReasons?: string[]; // Why this hotel matched (only with filters)
}get_hotel_details / compare_hotels)interface HotelDetails {
name: string; // Hotel name
url: string; // Booking.com URL
rating: number | null; // Review score 0-10
ratingText: string; // Rating description
reviewCount: number | null; // Total number of reviews
starRating: number | null; // Official star rating 1-5
address: string; // Full address
description: string; // Hotel description text
highlights: string; // Property highlights summary
pricePerNight: number | null; // Price per night as number
priceDisplay: string; // Formatted price per night
totalPrice: string; // Total stay price (formatted)
checkInTime: string; // Check-in time (e.g., "15:00")
checkOutTime: string; // Check-out time (e.g., "11:00")
popularFacilities: string[]; // Top facilities list
allFacilities: string[]; // Complete facilities list
roomTypes: string[]; // Available room type names
photos: string[]; // Photo URLs
nearbyAttractions: string[]; // Nearby points of interest
guestReviewHighlights: string[]; // Notable review excerpts
locationInfo: string; // Location description
}check_availability)interface AvailabilityResult {
available: boolean; // Whether rooms are available
hotelName: string; // Hotel name
checkIn: string; // Check-in date (YYYY-MM-DD)
checkOut: string; // Check-out date (YYYY-MM-DD)
guests: number; // Number of guests searched
rooms: number; // Number of rooms searched
roomOptions: RoomOption[]; // Available room types
lowestPrice: number | null; // Lowest price found
lowestPriceDisplay: string; // Formatted lowest price
message: string; // Status message
url: string; // Booking URL with dates
}
interface RoomOption {
name: string; // Room type name
price: number | null; // Price as number
priceDisplay: string; // Formatted price
sleeps: number | null; // Maximum occupancy
features: string[]; // Room features
bedType: string; // Bed configuration
cancellation: string; // Cancellation policy
breakfast: string; // Meal plan info
}get_reviews)interface ReviewsResult {
hotelName: string; // Hotel name
overallRating: number | null; // Overall score 0-10
totalReviews: number; // Total review count
ratingBreakdown: RatingBreakdown; // Scores by category
reviews: Review[]; // Individual reviews
url: string; // Hotel URL
}
interface RatingBreakdown {
staff: number | null; // Staff rating
facilities: number | null; // Facilities rating
cleanliness: number | null; // Cleanliness rating
comfort: number | null; // Comfort rating
valueForMoney: number | null; // Value rating
location: number | null; // Location rating
freeWifi: number | null; // WiFi rating
}
interface Review {
title: string; // Review title
rating: number | null; // Individual score 0-10
date: string; // Review date
travelerType: string; // Traveler type (e.g., "Couple", "Family")
country: string; // Reviewer's country
stayDate: string; // When they stayed
roomType: string; // Room they booked
nightsStayed: string; // Length of stay
positive: string; // Positive comments
negative: string; // Negative comments
}get_price_calendar)interface PriceCalendarResult {
hotelName: string; // Hotel name
startDate: string; // Calendar start (YYYY-MM-DD)
endDate: string; // Calendar end (YYYY-MM-DD)
nights: number; // Number of nights checked
currency: string; // Currency code
prices: DatePrice[]; // Price for each date
lowestPrice: number | null; // Lowest price in range
lowestPriceDate: string | null; // Date with lowest price
highestPrice: number | null; // Highest price in range
highestPriceDate: string | null; // Date with highest price
averagePrice: number | null; // Average price
url: string; // Hotel URL
}
interface DatePrice {
date: string; // Date (YYYY-MM-DD)
price: number | null; // Price as number
priceDisplay: string; // Formatted price
available: boolean; // Whether available
currency: string; // Currency code
}When an error occurs, the response includes:
interface ErrorResponse {
content: [{
type: "text";
text: string; // Error message with code and help text
}];
isError: true;
}Error codes:
BROWSER_NOT_INITIALIZED - Call init() firstNAVIGATION_FAILED - Page load failedRATE_LIMITED - Too many requestsCAPTCHA_DETECTED - CAPTCHA challenge encounteredNO_RESULTS - Search returned no resultsDESTINATION_NOT_FOUND - Invalid destinationNETWORK_ERROR - Connection issueTIMEOUT - Request timed outBLOCKED - Access denied by Booking.comMIT
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.