Search Hotels With Details
search_hotels_with_detailsSearch for hotels and retrieve detailed rates, availability, and cancellation policies for multiple properties in one call, enabling easy comparison.
Instructions
Search + parallel detail fetch for the top N hotels in one call.
Use when the user wants to COMPARE rooms, rates, or cancellation policies across multiple hotels. Costs 1 + N RPCs. max_hotels is HARD-CAPPED at 15.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| check_in | Yes | ||
| check_out | Yes | ||
| max_hotels | No | Top-N hotels to enrich with detail. Hard cap = 15. Default 5. | |
| adults | No | ||
| children | No | ||
| child_ages | No | ||
| currency | No | USD | |
| sort_by | No | RELEVANCE | |
| hotel_class | No | ||
| amenities | No | ||
| brands | No | ||
| min_guest_rating | No | ||
| free_cancellation | No | ||
| eco_certified | No | ||
| special_offers | No | ||
| price_min | No | ||
| price_max | No | ||
| property_type | No | HOTELS |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- stays/mcp/server.py:244-294 (handler)The actual handler function for search_hotels_with_details tool. It collects arguments, builds a SearchHotelsWithDetailsParams object, and delegates to _execute_search_hotels_with_details_from_params.
def _search_hotels_with_details_impl( query: Annotated[str, Field()], check_in: Annotated[str, Field()], check_out: Annotated[str, Field()], max_hotels: Annotated[ int, Field( ge=1, le=HARD_MAX_HOTELS_WITH_DETAILS, description=(f"Top-N hotels to enrich with detail. Hard cap = {HARD_MAX_HOTELS_WITH_DETAILS}. Default 5."), ), ] = CONFIG.default_max_hotels_with_details, adults: Annotated[int, Field(ge=1)] = CONFIG.default_adults, children: Annotated[int, Field(ge=0, le=8)] = CONFIG.default_children, child_ages: Annotated[list[int] | None, Field()] = None, currency: Annotated[str, Field(min_length=3, max_length=3)] = CONFIG.default_currency, sort_by: Annotated[SortByLiteral, Field()] = CONFIG.default_sort_by, hotel_class: Annotated[list[int] | None, Field()] = None, amenities: Annotated[list[str] | None, Field()] = None, brands: Annotated[list[str] | None, Field()] = None, min_guest_rating: Annotated[float | None, Field(ge=3.5, le=4.5)] = None, free_cancellation: bool = False, eco_certified: bool = False, special_offers: bool = False, price_min: Annotated[int | None, Field(ge=0)] = None, price_max: Annotated[int | None, Field(ge=0)] = None, property_type: Annotated[PropertyTypeLiteral, Field()] = "HOTELS", ) -> dict[str, Any]: """placeholder — overwritten via __doc__ assignment below.""" params = SearchHotelsWithDetailsParams( query=query, check_in=check_in, check_out=check_out, max_hotels=max_hotels, adults=adults, children=children, child_ages=child_ages, currency=currency, sort_by=sort_by, hotel_class=hotel_class, amenities=amenities, brands=brands, min_guest_rating=min_guest_rating, free_cancellation=free_cancellation, eco_certified=eco_certified, special_offers=special_offers, price_min=price_min, price_max=price_max, property_type=property_type, ) return _execute_search_hotels_with_details_from_params(params) - stays/mcp/server.py:303-319 (registration)Registration of search_hotels_with_details as an MCP tool via @mcp.tool decorator. Docstring is assigned programmatically to allow f-string expansion with the HARD_MAX constant.
_search_hotels_with_details_impl.__doc__ = f"""Search + parallel detail fetch for the top N hotels in one call. Use when the user wants to COMPARE rooms, rates, or cancellation policies across multiple hotels. Costs 1 + N RPCs. max_hotels is HARD-CAPPED at {HARD_MAX_HOTELS_WITH_DETAILS}. """ _search_hotels_with_details_impl.__name__ = "search_hotels_with_details" _search_hotels_with_details_impl.__qualname__ = "search_hotels_with_details" search_hotels_with_details = mcp.tool( name="search_hotels_with_details", annotations={ "title": "Search Hotels With Details", "readOnlyHint": True, "idempotentHint": True, }, )(_search_hotels_with_details_impl) - stays/mcp/_executors.py:227-248 (handler)Core executor: converts params to filters, calls search_with_details on the SearchHotels client, and serializes result+detail for each enriched hotel.
def _execute_search_hotels_with_details_from_params( params: SearchHotelsWithDetailsParams, ) -> dict[str, Any]: try: shp = SearchHotelsParams(**params.model_dump(exclude={"max_hotels"})) filters = _build_filters_from_search_params(shp) enriched = _get_search_hotels_cls()().search_with_details(filters, max_hotels=params.max_hotels) items = [] for er in enriched: items.append( { "ok": er.ok, "result": _serialize_hotel_result(er.result), "detail": _serialize_hotel_detail(er.detail) if er.detail else None, "error": er.error, "error_kind": er.error_kind, "is_retryable": er.is_retryable, } ) return {"success": True, "count": len(items), "items": items} except (BatchExecuteError, TransientBatchExecuteError) as e: return {"success": False, "error": f"{type(e).__name__}: {e}", "items": []} - stays/mcp/_params.py:75-104 (schema)Pydantic model defining all input parameters for search_hotels_with_details, including validation for child_ages matching children count.
class SearchHotelsWithDetailsParams(BaseModel): query: str = Field(description="City or property query.") check_in: str = Field(description="YYYY-MM-DD — REQUIRED.") check_out: str = Field(description="YYYY-MM-DD after check_in — REQUIRED.") max_hotels: int = Field( default=CONFIG.default_max_hotels_with_details, ge=1, le=HARD_MAX_HOTELS_WITH_DETAILS, description=f"Top-N to enrich. HARD CAP = {HARD_MAX_HOTELS_WITH_DETAILS}.", ) adults: int = Field(default=CONFIG.default_adults, ge=1) children: int = Field(default=CONFIG.default_children, ge=0, le=8) child_ages: list[int] | None = Field(default=None) currency: str = Field(default=CONFIG.default_currency, min_length=3, max_length=3) sort_by: SortByLiteral = CONFIG.default_sort_by hotel_class: list[int] | None = None amenities: list[str] | None = None brands: list[str] | None = None min_guest_rating: float | None = Field(default=None, ge=3.5, le=4.5) free_cancellation: bool = False eco_certified: bool = False special_offers: bool = False price_min: int | None = Field(default=None, ge=0) price_max: int | None = Field(default=None, ge=0) property_type: PropertyTypeLiteral = "HOTELS" @model_validator(mode="after") def _child_ages_matches_children(self): _validate_child_ages(self.children, self.child_ages) return self - stays/mcp/_config.py:23-23 (helper)Canonical hard cap constant (15) for max_hotels parameter used across validation and documentation.
HARD_MAX_HOTELS_WITH_DETAILS = 15