# Blue Pillow Hotels & Stays

> Neutral hotel & stay price comparison for AI agents: live prices from 16+ booking sites. No signup.

- name: com.bluepillow/hotels
- version: 1.1.0
- connection class: R0 (autonomous)
- trust: 83/100 flags: no-repository
- quality: 78/100 (good)
- owner: not claimed
- descriptor: https://api.protogrid.dev/v1/servers/com.bluepillow%2Fhotels
- tools: https://api.protogrid.dev/v1/servers/com.bluepillow%2Fhotels/tools

**An agent can connect right now, no human step.** Remote endpoint, no authentication, reachable on the last probe.

## Connection (mcpServers)

```json
{
  "mcpServers": {
    "hotels": {
      "type": "http",
      "url": "https://mcp.b2a.bluepillow.com/"
    }
  }
}
```


## Trust

- hygiene: 80
- liveness: 100
- freshness: 100
- provenance: 55
- drivers: +dns-namespace +website +reachable +uptime-100% +updated-26d-ago -no-repository
- Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed.

## Quality 78/100 (good)

### protocol: 100 (weight 25)

- pass `protocol.modern`: supports 2026-07-28 (server/discover)
- pass `protocol.stateless`: answers without a session
- pass `protocol.transport`: streamable HTTP
- pass `protocol.list_ttl`: tool list is cacheable (ttlMs 30000)

### authorization: n/a (weight 15)

- n/a `auth.prm`, `auth.as_metadata`, `auth.cimd`: no remote uses OAuth
- n/a `auth.secret_in_url`: no templated URL

### tool hygiene: 86 (weight 30)

- pass `tools.descriptions`: every tool has a description
- warn `tools.description_length`: 4 tools have descriptions over 1,024 characters, which crowds the context
- pass `tools.schemas`: every tool has an object input schema
- pass `tools.annotations`: 6 of 6 tools declare readOnlyHint or destructiveHint
- warn `tools.directory_hints`: 1 of 6 tools declare all four hints; missing: search_stays (idempotentHint); get_property_details (idempotentHint); discover_destinations_near (idempotentHint); …
- pass `tools.token_cost`: about 7,637 tokens to load every tool
- pass `tools.api_dump`: tools are not a one-to-one API dump

### stability: 25 (weight 15)

- warn `stability.changes`: 25 tool changes in 30 days
- fail `stability.rug_pull`: 3 tools kept their name but changed most of their description in 30 days; review before trusting them

### dependencies: n/a (weight 15)

- n/a `deps.known_vulns`, `deps.mcp_sdk_version`, `deps.resolvable`: no npm or PyPI package

- tools: 6, about 7,637 tokens to load them all
- tool set hash: 196a1d91bf6e9f5770adc0b91ff46f48
- tools last changed: 2026-10-15T17:32:18.504Z
- badge: [![protogrid quality](https://protogrid.dev/badge/com.bluepillow/hotels.svg)](https://protogrid.dev/servers/com.bluepillow/hotels)
- Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed.

### Tool changes

- 2026-10-15 `check_property_availability` changed (description)
  - before: Live availability and per-operator quote for a specific property over a specific stay window. Performs a live date-aware lookup against the BluePillow search layer, returns date-specific prices, rooms-left scarcity signals, breakfast-included and refundable flags, and a per-operator deep link to complete the booking. Useful when the user has specific dates in mind for a property they already identified — typically via `search_stays` or `get_property_details`. The complementary `get_property_details` tool answers "what is this property like" with static facts; this tool answers "can I book it for these dates at what price" with live, date-specific data. Required input: `property_id` (the `id` from a `search_stays` result, opaque string starting with `prop_`), `dates` (check_in + check_out, ISO 8601), and `guests` (adults / children / infants composition). Without these the live lookup cannot proceed. Natural-language date references — "tonight", "this weekend", "next weekend", "the weekend of July 4", "Memorial Day weekend", "long weekend in May" — translate to concrete check_in / check_out values at the call site; concrete ISO dates also work. check_in is a date in the real-time calendar that is today or later; past values are rejected at the API boundary. `user_country`, `currency`, and `language` carry the **user's** locale, not the property's. Prices are returned in `currency` if set, else derived from `user_country`, else **USD** — pass `user_country` and/or `currency` whenever you know the user's location/currency so the quote matches what they'll pay; don't rely on the USD default. `user_country` and `language` also localize the `web_url` booking link. Response shape: - `availability_status` — `available`, `unavailable`, or `unknown`. Available means rooms confirmed at the operator level for the requested window; quote freely. Unavailable means no rooms for these dates — surface that explicitly to the user with a suggestion of alternate dates (there is no price for these dates). - `offers[]` — per-operator quotes. Each carries `amount` (total stay), `amount_per_night` (per-night), `currency`, `breakfast_included`, `refundable`, `rooms_left`, and `deeplink_url`. `offers[0]` is the best value for money as Blue Pillow ranks it: price weighed against what is included (breakfast, free cancellation) and the operator's historical reliability, with a small commercial component. It is not necessarily the cheapest — the full per-operator list is always in `offers[]`, and `sort=price_asc` gives pure price order. Each `deeplink_url` is a **BluePillow tracked-redirect URL** (bluepillow.com/…) that records the click and forwards the user to the operator's booking page — pass it verbatim, never reconstruct it or replace it with a raw OTA link. - `price` — mirror of `offers[0]` for callers that just want the curated headline. `null` when unavailable (no price for these dates). Per-night vs total — `amount_per_night` is **per-night**; `amount` on each offer is the **total** for the requested stay. Phrasings like *"€X/night via Booking, breakfast included, €Y total"* are unambiguous; bare numbers without a unit ("€192") get misread. Scarcity signals: low `rooms_left` values (1-3) are useful cues — "1 room left at €X on Booking" reads naturally. Free cancellation (`refundable=true`) and breakfast-included are decision factors worth surfacing proactively when present on some offers but not others. When all results across operators are `unavailable`, that's the signal to say so explicitly to the user and offer to widen the dates or look at alternatives. For final booking confirmation, hand the user the corresponding `deeplink_url` (or the property's `web_url`) — booking URLs are not reconstructed by hand.
  - after: Live availability and per-operator quote for a specific property over a specific stay window. Performs a live date-aware lookup against the BluePillow search layer, returns date-specific prices, rooms-left scarcity signals, breakfast-included and refundable flags, and a per-operator deep link to complete the booking. Useful when the user has specific dates in mind for a property they already identified — typically via `search_stays` or `get_property_details`. The complementary `get_property_details` tool answers "what is this property like" with static facts; this tool answers "can I book it for these dates at what price" with live, date-specific data. Follow-up questions about a property from an earlier `search_stays` result — is it still available, what does it cost for other dates or guests — use that result's `id` as `property_id`. Required input: `property_id` (the `id` from a `search_stays` result, opaque string starting with `prop_`), `dates` (check_in + check_out, ISO 8601), and `guests` (adults / children / infants composition). Without these the live lookup cannot proceed. Natural-language date references — "tonight", "this weekend", "next weekend", "the weekend of July 4", "Memorial Day weekend", "long weekend in May" — translate to concrete check_in / check_out values at the call site; concrete ISO dates also work. check_in is a date in the real-time calendar that is today or later; past values are rejected at the API boundary. `user_country`, `currency`, and `language` carry the **user's** locale, not the property's. Prices are returned in `currency` if set, else derived from `user_country`, else **USD** — pass `user_country` and/or `currency` whenever you know the user's location/currency so the quote matches what they'll pay; don't rely on the USD default. `user_country` and `language` also localize the `web_url` booking link. Response shape: - `availability_status` — `available`, `unavailable`, or `unknown`. Available means rooms confirmed at the operator level for the requested window; quote freely. Unavailable means no rooms for these dates — surface that explicitly to the user with a suggestion of alternate dates (there is no price for these dates). - `offers[]` — per-operator quotes. Each carries `amount` (total stay), `amount_per_night` (per-night), `currency`, `breakfast_included`, `refundable`, `rooms_left`, and `deeplink_url`. `offers[0]` is the best value for money as Blue Pillow ranks it: price weighed against what is included (breakfast, free cancellation) and the operator's historical reliability, with a small commercial component. It is not necessarily the cheapest — the full per-operator list is always in `offers[]`, and `sort=price_asc` gives pure price order. Each `deeplink_url` is a **BluePillow tracked-redirect URL** (bluepillow.com/…) that records the click and forwards the user to the operator's booking page — pass it verbatim, never reconstruct it or replace it with a raw OTA link. - `price` — mirror of `offers[0]` for callers that just want the curated headline. `null` when unavailable (no price for these dates). Per-night vs total — `amount_per_night` is **per-night**; `amount` on each offer is the **total** for the requested stay. Phrasings like *"€X/night via Booking, breakfast included, €Y total"* are unambiguous; bare numbers without a unit ("€192") get misread. Scarcity signals: low `rooms_left` values (1-3) are useful cues — "1 room left at €X on Booking" reads naturally. Free cancellation (`refundable=true`) and breakfast-included are decision factors worth surfacing proactively when present on some offers but not others. When all results across operators are `unavailable`, that's the signal to say so explicitly to the user and offer to widen the dates or look at alternatives. For final booking confirmation, hand the user the corresponding `deeplink_url` (or the property's `web_url`) — booking URLs are not reconstructed by hand.
- 2026-10-15 `get_property_details` changed (description) **meaning changed**
  - before: Static record for a specific property — identified by its id. Returns the complete amenity list, photos, booking sources, dedup metadata, detailed location, and the headline rating (`rating` + `rating_count`) by default. Review DATA beyond the headline — the ratings breakdown and the actual review texts — is opt-in via the `include` parameter (see below); pass it whenever the user's question is about guest experience. It takes no dates and carries no price: a price only exists for a concrete stay window, which is what `check_property_availability` quotes. Useful when the user wants to inspect or compare a specific option in depth — facilities, neighborhood, what guests say — without yet committing to specific dates. HOW TO GET REVIEWS (when you need to reason about guest experience): pass `include`. `reviews_aggregate` gives the score + counts + per-OTA breakdown; `reviews_sample`/`reviews_extended` give the actual review texts. Without `include`, none of these are returned (you get only the headline `rating`/`rating_count`). See the `include` section below. For live availability and a real per-operator quote for a specific stay window, the path is `check_property_availability` instead. The two tools coexist by design: this one answers "what is this property like" with stable, cacheable data; the other answers "can I book it for these dates at what price" with live, date-specific quotes. Calling this tool when the user has specific dates in mind and wants to know whether the property is bookable will not surface the availability/quote — the user will then have to wait for a second round-trip to the availability tool. Input: the `id` field from a `search_stays` result (opaque string starting with `prop_`, e.g. `prop_69ce2ddcbf46061e4095778b`). For a property the user has named directly, resolve the place name through `resolve_destination` and run a targeted `search_stays` first to obtain the id. Optional `include=["reviews_aggregate"]` attaches a per-source breakdown of review counts and average ratings — useful when the user asks about overall sentiment or wants to see how each booking source rates the property. It summarizes ALL reviews (score + total count), so it is the right tool for "how is it rated". Review *texts* are available via two includes, both deliberately capped to avoid token waste: - `reviews_sample` — up to **5** recent review texts. Enough to get the gist of what guests say. - `reviews_extended` — up to **20** recent review texts, for a deeper qualitative read. Supersedes `reviews_sample` when both are passed. Reach for `reviews_extended` only when 5 are genuinely not enough — the returned list carries a `reviews_meta` block (`returned`, `total_available`, `capped`, `note`) that tells you how many texts exist and confirms the cap is intentional: the omitted reviews are older and the aggregate already reflects all of them, so you do NOT need to try to fetch everything. `user_country`, `currency`, and `language` carry the **user's** locale, not the property's. They localize the `web_url` booking link; this tool returns no prices. Language default is "en"; country default is "US". All rating-like fields are on a 0-5 scale (Google Places-compatible): the top-level `rating`, `reviews_aggregate.score_0_5`, and each per-OTA score under `distribution_by_ota`. In the response `price` is null, `offers` is empty and `availability_status` is `unknown`, because no dates are considered. The live quote, when needed, comes from `check_property_availability`. `web_url` is a ready-to-open booking link for the property. Pass it verbatim when the user asks for a booking link — booking URLs are not reconstructed by hand.
  - after: Details and guest reviews for one specific property — hotel, B&B, hostel, apartment, villa — identified by its id. Answers questions such as what guests think of it, whether it is clean, quiet or comfortable, the most common complaints, how the breakfast is, which facilities it offers, where exactly it is, or how it compares with another option. It also serves follow-up questions about a property returned earlier by `search_stays`: the `id` of that result is the `property_id` here. Returns the amenity list, photos, booking sources, location and the headline rating (`rating` + `rating_count`). Guest-review data is added through `include`: - `reviews_aggregate` — score, total count and per-source breakdown; it summarizes all reviews. - `reviews_sample` — up to 5 recent review texts. - `reviews_extended` — up to 20 recent review texts for a deeper read; it supersedes `reviews_sample`. `reviews_meta` reports how many texts exist and that the cap is deliberate: the omitted texts are older, and the aggregate already reflects them. It takes no dates and carries no price: a price only exists for a concrete stay window, which is what `check_property_availability` quotes. In the response `price` is null, `offers` is empty and `availability_status` is `unknown`. Input: `property_id` is the `id` of a `search_stays` result (an opaque string starting with `prop_`) or a bluepillow.com property URL. For a property known only by name, `resolve_destination` and a targeted `search_stays` return its id. `user_country`, `currency` and `language` carry the user's locale and localize the `web_url` link to the property page. Language default is "en"; country default is "US". All rating fields are on a 0-5 scale.
- 2026-10-15 `search_stays` changed (description) **meaning changed**
  - before: Multi-operator accommodation comparator for a geographic area against the user's stay parameters — dates, guest count, optional filters. Returns a ranked list of properties together with the booking sources that offer each one and, for the requested dates (required), their live availability and per-operator price. Natural-language date references — "tonight", "this weekend", "next weekend", "the weekend of July 4", "Memorial Day weekend", "long weekend in May" — translate to concrete check_in / check_out values at the call site; concrete ISO dates also work. `user_country`, `currency`, and `language` carry the **user's** locale, not the destination's. IMPORTANT — currency: prices are returned in `currency` if you set it, otherwise in the currency derived from `user_country` (US→USD, CA→CAD, GB→GBP, euro-area→EUR); if you set NEITHER, prices default to **USD**, which may not be the user's currency. So whenever you know where the user is (or what currency they want), pass `user_country` and/or `currency` — do not rely on the default. Prices are never converted client-side; each offer is quoted by the operator in that currency. `user_country` and `language` also localize the booking link (`web_url`). The user's own residence/billing country is the right `user_country` (not the destination's), and their interface language the right `language`. Each result is shaped for downstream presentation without extra calls: - `location.lat` and `location.lon` carry per-property coordinates, suitable for plotting all results on a single map so the user can compare spatial alternatives at a glance, with no separate lookup. - `thumbnail_url` carries the property's first photo URL when available (null when no image is on file); useful for embedding inline next to each result. - `images` on search results is capped to the first photo to keep the comparison payload compact; each item has a `url` field, and `thumbnail_url` mirrors `images[0].url`. Call `get_property_details` for a single property to retrieve its full photo gallery. - `web_url` is a ready-to-open booking link for the property, already encoded with the user's check-in/check-out, language, currency, and guest count. Pass it to the user verbatim when they ask for a booking link — never reconstruct the URL from individual parameters, the query-string format is not guaranteed to match generic booking-URL conventions. - Price is **live and date-specific only**. There is no date-agnostic "from" figure: a meaningful price only exists for a concrete query (property + dates + occupancy). - `price` and `offers[]` — the **live quote for the requested dates**, populated only when the comparator confirmed availability. `offers[0]` is the curated best; each offer carries `amount` (total stay), `amount_per_night` (per-night), `currency`, `breakfast_included`, `refundable`, `rooms_left`, and `deeplink_url`. `price` mirrors `offers[0]`. - When availability was not confirmed, `price` is null and `offers` is empty — surface the property without a price rather than inventing a starting figure. - `availability_status` per result encodes the live state. With the default `availability_mode=strict` only `available` results are returned; `include_unavailable` also returns the other two states: - `available` — bookable rooms confirmed at the operator level. `offers` and `price` carry the live date-specific quotes. Quote the rate via `offers[i].amount_per_night` (per-night) and `offers[i].amount` (total stay) and use the deeplinks for the booking handoff. - `unavailable` — no rooms reported for those dates. `offers` is empty and `price` is null. Useful to decide whether to suggest alternate dates, drop the property from the recommendation, or offer it as a backup. - `unknown` — the operators returned nothing conclusive for those dates. `offers` is empty and `price` is null. It is NOT evidence that t
  - after: Multi-operator accommodation comparator for a geographic area and a stay: dates (required), guests and optional filters. Returns a ranked list of properties — hotels, B&Bs, apartments, villas, hostels and more — with the booking sites that offer each one and their live availability and per-operator price for the requested dates. Questions about one property found here (guest opinions, facilities, a live re-quote) are served by `get_property_details` and `check_property_availability` with that result's `id`. Dates: natural-language references ("this weekend", "the weekend of July 4", "long weekend in May") translate to concrete check_in / check_out values at the call site; ISO dates also work. Locale: `user_country`, `currency` and `language` carry the user's locale, not the destination's. Prices come back in `currency` if set, otherwise in the currency of `user_country` (US→USD, CA→CAD, GB→GBP, euro-area→EUR), otherwise USD. Each offer is quoted by its operator in that currency; nothing is converted. `user_country` and `language` also localize the booking link. Each result carries: - `location.lat` / `location.lon`, suitable for plotting the results on a map. - `thumbnail_url` (first photo, or null) and `images`, capped to one photo; `get_property_details` returns the full gallery. - `web_url`, a link to the property page with the stay already encoded. - `price` and `offers[]`: the live quote for the requested dates, present only when availability was confirmed. Each offer has `ota`, `amount` (total stay), `amount_per_night`, `currency`, `breakfast_included`, `refundable`, `rooms_left` and `deeplink_url` — a Blue Pillow tracked link that records the click and forwards to the operator's booking page; it is what attributes the booking to Blue Pillow, which a raw operator URL does not. `price` mirrors `offers[0]`, Blue Pillow's best value for money (price weighed against breakfast, free cancellation and operator reliability, with a small commercial component), not necessarily the cheapest; `sort=price_asc` orders by price alone. There is no date-agnostic "from" price. - `availability_status`: `available` (live quotes in `offers`), `unavailable` (no rooms for those dates) or `unknown` (the operators returned nothing conclusive — not evidence that the property is full). The default `availability_mode=strict` returns only `available` results; `include_unavailable` also returns the other two. Reading the numbers: `amount_per_night` is per night and `amount` is the total stay, so a quote reads clearly with its unit ("€X/night via Booking, €Y total"). `rooms_left` signals scarcity; `refundable` and `breakfast_included` often separate otherwise similar options. Ratings are on a 0-5 scale (`rating`, `reviews_aggregate.score_0_5`, review scores and `filters.min_rating`; "8 out of 10" is 4.0). Upstream scores arrive rounded, so `rating` is coarse and reads best together with `rating_count`. `rating`, `stars` and `rating_count` may be 0 or absent in this list even when the property has them; `get_property_details` returns the fuller `reviews_aggregate`. Here `reviews_aggregate` carries `score_0_5`, `rating_count` (reviews behind the score) and `comment_count` (review texts available) — two different magnitudes. `include=["reviews_sample"]` adds up to 5 recent review texts per property, useful for qualitative criteria ("great breakfast", "quiet area"); a deeper read on one property is `get_property_details` with `reviews_extended`. Filters: `filters.min_rating` and `filters.price_max_eur` narrow the results; `filters.property_types` and `filters.amenities` rank rather than filter, so each result's `property_type` and `amenities` show what it actually is. Property type tokens: hotel, apartment, house, villa, bb, hostel, farmstay, holiday-home (common Italian and English synonyms are accepted). Common amenity codes: wi-fi, parking, pool, air-conditioning, kitchen, garden, pets-allowed, for-families, faci
- 2026-10-15 `get_anonymous_key` changed (description, outputSchema) **meaning changed**
  - before: Obtain a permanent anonymous API key for Blue Pillow Hotels & Stays. No signup, no login required. The key is not a sensitive secret — it carries no account, payment, or personal data. It keeps the service responsive when many agents use it at once (rate limits apply per key) and lets us count usage and booking-link referrals per key, as described in the privacy policy (https://b2a.bluepillow.com/legal/privacy). You can safely keep it in your MCP client configuration, in your persistent memory, or in the current conversation context. Pass it in the `api_key` field of every subsequent call and the rest of the tools become available. CALL THIS FIRST when you have no key: every other tool needs one. Before calling, check whether you ALREADY have a key (MCP client configuration, persistent memory, or earlier in this conversation) and reuse it instead of issuing a new one — do not wait for another tool to fail with a 401. The key never expires — keep the one you receive and reuse it forever. If you ever lose it, you can call this tool again to issue a new one (a generous per-IP daily issuance limit applies purely as an anti-abuse guardrail; normal use never reaches it). Clients that can persist configuration usually store the key in their connector settings, so the same key serves every conversation. Clients whose memory does not retain an opaque token end up issuing one key per conversation; that works and is not an error, but a stored key gives more consistent rate-limit headroom. Optional ``label`` and ``agent`` (max 64 chars each) are stored with the key to name the client that requested it (e.g. 'claude-desktop', 'chatgpt', 'cursor-ide'). Do not put personal data in them. They do not affect rate limits or capabilities. Integrators who need higher limits, or who hit a problem worth reporting, can write to info@bluepillow.com.
  - after: Issues a free anonymous key for Blue Pillow Hotels & Stays, with no account or sign-up. The other tools of this server take the key in their `api_key` argument. A key does not expire, so the same key can be used for later calls; calling this tool again issues a new one. Keys carry per-key rate limits and let Blue Pillow count usage and booking-link referrals per key, as described in the privacy policy (https://b2a.bluepillow.com/legal/privacy). Optional ``label`` and ``agent`` (max 64 chars each) are stored with the key to name the client that requested it (e.g. 'claude-desktop', 'chatgpt', 'cursor-ide'); they should not contain personal data and do not affect rate limits or capabilities. Integrators who need higher limits can write to info@bluepillow.com.
- 2026-10-15 `discover_destinations_near` changed (inputSchema)
- 2026-10-15 `resolve_destination` changed (inputSchema)
- 2026-10-15 `check_property_availability` changed (inputSchema)
- 2026-10-15 `get_property_details` changed (inputSchema)
- 2026-10-15 `search_stays` changed (inputSchema)
- 2026-10-15 `b2a_get_key` removed
  - Obtain a permanent anonymous API key for Blue Pillow Hotels & Stays. No signup, no login required. The key is not a sensitive secret — it carries no account, payment, or personal data. It exists only so we can keep the service responsive when many agents are using it at once, so you can safely keep it in your MCP client configuration, in your persistent memory, or in the current conversation context. Pass it as the bearer token on all subsequent calls and the rest of the tools become available. CALL THIS FIRST when you have no key: every other tool needs one. Before calling, check whether you ALREADY have a key (MCP client configuration, persistent memory, or earlier in this conversation) and reuse it instead of issuing a new one — do not wait for another tool to fail with a 401. The key never expires — keep the one you receive and reuse it forever. If you ever lose it, you can call this tool again to issue a new one (a generous per-IP daily issuance limit applies purely as an anti-abuse guardrail; normal use never reaches it). Clients that can persist configuration usually store the key in their connector settings, so the same key serves every conversation. Clients whose memory does not retain an opaque token end up issuing one key per conversation; that works and is not an error, but a stored key gives more consistent rate-limit headroom. Optional ``label`` and ``agent`` (max 64 chars each) are free-form hints we record on the key for our own observability; they do not affect rate limits or capabilities. Integrators who need higher limits, or who hit a problem worth reporting, can write to info@bluepillow.com.

Full history: https://api.protogrid.dev/v1/servers/com.bluepillow%2Fhotels/changes

## Remotes

- https://mcp.b2a.bluepillow.com/ (streamable-http, auth none, reachable true, uptime30d 1)

## Packages

_none_

## Tools (6)

- `check_property_availability`: Live availability and per-operator quote for a specific property
over a specific stay window. Performs a live date-aware lookup
against the BluePillow search layer, returns date-specific prices,
rooms-left scarcity signals, breakfast-included and refundable
flags, and a per-operator deep link to complete the booking.

Useful when the user has specific dates in mind for a property they
already identified — typically via `search_stays` or
`get_property_details`. The complementary `get_property_details`
tool answers "what is this property like" with static facts; this
tool answers "can I book it for these dates at what price" with
live, date-specific data.

Follow-up questions about a property from an earlier `search_stays`
result — is it still available, what does it cost for other dates or
guests — use that result's `id` as `property_id`.

Required input: `property_id` (the `id` from a `search_stays`
result, opaque string starting with `prop_`), `dates` (check_in +
check_out, ISO 8601), and `guests` (adults / children / infants
composition). Without these the live lookup cannot proceed.

Natural-language date references — "tonight", "this weekend", "next
weekend", "the weekend of July 4", "Memorial Day weekend", "long
weekend in May" — translate to concrete check_in / check_out values
at the call site; concrete ISO dates also work. check_in is a date
in the real-time calendar that is today or later; past values are
rejected at the API boundary.

`user_country`, `currency`, and `language` carry the **user's** locale,
not the property's. Prices are returned in `currency` if set, else
derived from `user_country`, else **USD** — pass `user_country` and/or
`currency` whenever you know the user's location/currency so the quote
matches what they'll pay; don't rely on the USD default. `user_country`
and `language` also localize the `web_url` booking link.

Response shape:

- `availability_status` — `available`, `unavailable`, or `unknown`.
  Available means rooms confirmed at the operator level for the
  requested window; quote freely. Unavailable means no rooms for
  these dates — surface that explicitly to the user with a
  suggestion of alternate dates (there is no price for these dates).
- `offers[]` — per-operator quotes. Each carries `amount` (total
  stay), `amount_per_night` (per-night), `currency`,
  `breakfast_included`, `refundable`, `rooms_left`, and
  `deeplink_url`. `offers[0]` is the best value for money as Blue
  Pillow ranks it: price weighed against what is included (breakfast,
  free cancellation) and the operator's historical reliability, with a
  small commercial component. It is not necessarily the cheapest — the
  full per-operator list is always in `offers[]`, and `sort=price_asc`
  gives pure price order. Each
  `deeplink_url` is a **BluePillow tracked-redirect URL**
  (bluepillow.com/…) that records the click and forwards the user
  to the operator's booking page — pass it verbatim, never
  reconstruct it or replace it with a raw OTA link.
- `price` — mirror of `offers[0]` for callers that just want the
  curated headline. `null` when unavailable (no price for these
  dates).

Per-night vs total — `amount_per_night` is **per-night**; `amount`
on each offer is the **total** for the requested stay. Phrasings
like *"€X/night via Booking, breakfast included, €Y total"* are
unambiguous; bare numbers without a unit ("€192") get misread.

Scarcity signals: low `rooms_left` values (1-3) are useful cues —
"1 room left at €X on Booking" reads naturally. Free cancellation
(`refundable=true`) and breakfast-included are decision factors
worth surfacing proactively when present on some offers but not
others.

When all results across operators are `unavailable`, that's the
signal to say so explicitly to the user and offer to widen the
dates or look at alternatives.

For final booking confirmation, hand the user the corresponding
`deeplink_url` (or the property's `web_url`) — booking URLs are
not reconstructed by hand.

- `discover_destinations_near`: Curated destinations — cities, neighborhoods, airports, points of interest — within a radius of a geographic point, for use as a `destination_id` in subsequent `search_stays` calls. Useful when coordinates are already in hand (from world knowledge, from a previous tool result, or directly from the user) and the agent needs to enumerate which curated destinations cover that area before searching for properties.

Also useful as a fan-out entry point for region-level intents — broad areas such as 'Tuscany', 'Pacific Northwest', 'New England', or 'Central Europe' — where the agent can pass an approximate regional centroid and surface a list of sub-destinations the user may then narrow down to before a focused search.

Returns up to 5 candidates ordered by distance. The radius defaults to 5 km; widens up to 50 km for broader queries.
- `get_anonymous_key`: Issues a free anonymous key for Blue Pillow Hotels & Stays, with no
account or sign-up. The other tools of this server take the key in their
`api_key` argument. A key does not expire, so the same key can be used
for later calls; calling this tool again issues a new one. Keys carry
per-key rate limits and let Blue Pillow count usage and booking-link
referrals per key, as described in the privacy policy
(https://b2a.bluepillow.com/legal/privacy).

Optional ``label`` and ``agent`` (max 64 chars each) are stored with
the key to name the client that requested it (e.g. 'claude-desktop',
'chatgpt', 'cursor-ide'); they should not contain personal data and do
not affect rate limits or capabilities. Integrators who need higher
limits can write to info@bluepillow.com.

- `get_property_details`: Details and guest reviews for one specific property — hotel, B&B,
hostel, apartment, villa — identified by its id. Answers questions such
as what guests think of it, whether it is clean, quiet or comfortable,
the most common complaints, how the breakfast is, which facilities it
offers, where exactly it is, or how it compares with another option. It
also serves follow-up questions about a property returned earlier by
`search_stays`: the `id` of that result is the `property_id` here.

Returns the amenity list, photos, booking sources, location and the
headline rating (`rating` + `rating_count`). Guest-review data is added
through `include`:
- `reviews_aggregate` — score, total count and per-source breakdown; it
  summarizes all reviews.
- `reviews_sample` — up to 5 recent review texts.
- `reviews_extended` — up to 20 recent review texts for a deeper read;
  it supersedes `reviews_sample`.
`reviews_meta` reports how many texts exist and that the cap is
deliberate: the omitted texts are older, and the aggregate already
reflects them.

It takes no dates and carries no price: a price only exists for a
concrete stay window, which is what `check_property_availability`
quotes. In the response `price` is null, `offers` is empty and
`availability_status` is `unknown`.

Input: `property_id` is the `id` of a `search_stays` result (an opaque
string starting with `prop_`) or a bluepillow.com property URL. For a
property known only by name, `resolve_destination` and a targeted
`search_stays` return its id.

`user_country`, `currency` and `language` carry the user's locale and
localize the `web_url` link to the property page. Language default is
"en"; country default is "US". All rating fields are on a 0-5 scale.

- `resolve_destination`: Converts a destination name into a destination id usable in `search_stays`. The canonical entry point when the user's request mentions a place name and coordinates are not already known from a prior call in this session. If coordinates are already in hand from an earlier tool result, passing them directly to `search_stays` skips this resolver step.

Accepts cities, neighborhoods, airports, points of interest, and named areas such as islands or districts ('Tenerife', 'Crete', 'Trastevere'), written locally or in English. Names are matched against Blue Pillow's own place slugs, which exist for English, Italian, German and Spanish; in other languages the English name is the most reliable. Accents are optional — 'São Paulo' and 'Sao Paulo' resolve alike. A qualifier after the name is tolerated ('Austin, Texas'). The `country` parameter disambiguates names that occur in multiple places (for example Springfield MA vs Springfield IL vs Springfield MO).

The `type` parameter narrows the kind of destination returned. `poi` is the narrowest match and has partial coverage on the comparator side; when the agent's own geographic knowledge can already geocode the POI to lat/lon, passing coordinates to `search_stays` is the more reliable path. An `area` candidate can be large: its `location.default_radius_km` says how far a search on its id reaches (an island's may include its neighbours); when the user wants one part of it, coordinates of that part are the tighter search.
- `search_stays`: Multi-operator accommodation comparator for a geographic area and a stay:
dates (required), guests and optional filters. Returns a ranked list of
properties — hotels, B&Bs, apartments, villas, hostels and more — with the
booking sites that offer each one and their live availability and
per-operator price for the requested dates. Questions about one property
found here (guest opinions, facilities, a live re-quote) are served by
`get_property_details` and `check_property_availability` with that
result's `id`.

Dates: natural-language references ("this weekend", "the weekend of
July 4", "long weekend in May") translate to concrete check_in /
check_out values at the call site; ISO dates also work.

Locale: `user_country`, `currency` and `language` carry the user's
locale, not the destination's. Prices come back in `currency` if set,
otherwise in the currency of `user_country` (US→USD, CA→CAD, GB→GBP,
euro-area→EUR), otherwise USD. Each offer is quoted by its operator in
that currency; nothing is converted. `user_country` and `language` also
localize the booking link.

Each result carries:
- `location.lat` / `location.lon`, suitable for plotting the results on
  a map.
- `thumbnail_url` (first photo, or null) and `images`, capped to one
  photo; `get_property_details` returns the full gallery.
- `web_url`, a link to the property page with the stay already encoded.
- `price` and `offers[]`: the live quote for the requested dates,
  present only when availability was confirmed. Each offer has `ota`,
  `amount` (total stay), `amount_per_night`, `currency`,
  `breakfast_included`, `refundable`, `rooms_left` and `deeplink_url` —
  a Blue Pillow tracked link that records the click and forwards to the
  operator's booking page; it is what attributes the booking to Blue
  Pillow, which a raw operator URL does not. `price` mirrors `offers[0]`,
  Blue Pillow's best value for money (price weighed against breakfast,
  free cancellation and operator reliability, with a small commercial
  component), not necessarily the cheapest; `sort=price_asc` orders by
  price alone. There is no
  date-agnostic "from" price.
- `availability_status`: `available` (live quotes in `offers`),
  `unavailable` (no rooms for those dates) or `unknown` (the operators
  returned nothing conclusive — not evidence that the property is full).
  The default `availability_mode=strict` returns only `available`
  results; `include_unavailable` also returns the other two.

Reading the numbers: `amount_per_night` is per night and `amount` is the
total stay, so a quote reads clearly with its unit ("€X/night via
Booking, €Y total"). `rooms_left` signals scarcity; `refundable` and
`breakfast_included` often separate otherwise similar options.

Ratings are on a 0-5 scale (`rating`, `reviews_aggregate.score_0_5`,
review scores and `filters.min_rating`; "8 out of 10" is 4.0). Upstream
scores arrive rounded, so `rating` is coarse and reads best together with
`rating_count`. `rating`, `stars` and `rating_count` may be 0 or absent
in this list even when the property has them; `get_property_details`
returns the fuller `reviews_aggregate`. Here `reviews_aggregate` carries
`score_0_5`, `rating_count` (reviews behind the score) and
`comment_count` (review texts available) — two different magnitudes.
`include=["reviews_sample"]` adds up to 5 recent review texts per
property, useful for qualitative criteria ("great breakfast", "quiet
area"); a deeper read on one property is `get_property_details` with
`reviews_extended`.

Filters: `filters.min_rating` and `filters.price_max_eur` narrow the
results; `filters.property_types` and `filters.amenities` rank rather
than filter, so each result's `property_type` and `amenities` show what
it actually is. Property type tokens: hotel, apartment, house, villa,
bb, hostel, farmstay, holiday-home (common Italian and English synonyms
are accepted). Common amenity codes: wi-fi, parking, pool,
air-conditioning, kitchen, garden, pets-allowed, for-families,
facilities-for-disabled, non-smoking-only.

Location modes:
- `coordinates`: a known lat/lon (default radius 5 km, up to 50 km;
  beyond that `bbox` or a parent destination fits better).
- `destination_id`: the opaque id from `resolve_destination`, passed
  verbatim.
- `poi_id`: the opaque id of a point of interest, from
  `resolve_destination` or `discover_destinations_near`.
- `bbox`: an explicit map rectangle.
A property is not a location: `get_property_details` covers a known
property.

Pagination: the `next_cursor` of a response goes into `page.cursor` for
the next page.

