The Host Tools MCP server gives AI assistants access to your account over the Model Context Protocol: Claude, Cursor, and anything else that supports MCP with OAuth 2.0. It covers much of what the REST API documented here does, as tools an assistant calls during a conversation instead of endpoints your code calls. The two don't match exactly. Analytics is only available over MCP, and webhooks, owner import, and creating or deleting listing groups are only available over the REST API.
The server URL is:
https://app.hosttools.com/mcp
That is the only value a client needs. It discovers the authorization server, the registration endpoint, and the token endpoint from there.
Which one should I use?
| REST API | MCP server | |
|---|---|---|
| You are building | an integration, a sync job, a partner product | an assistant workflow, an internal chat tool |
| Auth | authToken, apiKey, or OAuth Bearer | OAuth Bearer only |
| Shape | one endpoint per operation | 56 tools, 2 resources, 3 prompts |
| Called by | your code | an MCP client, on a user's behalf |
Both use the same account model and the same OAuth provider, so a partner can ship both against one integration.
Authorization
MCP clients authorize with the same OAuth 2.0 endpoints documented in this reference. A compliant client runs this flow on its own:
GET /.well-known/oauth-protected-resource/mcpfinds which authorization server secures/mcp(RFC 9728).GET /.well-known/oauth-authorization-serverdiscovers the authorize, token, registration, and revocation endpoints (RFC 8414).POST /oauth/registerregisters the client dynamically (RFC 7591). Public clients get noclient_secret. Self-registration is open to clients that redirect to a trusted assistant's own domain (claude.ai, claude.com, chatgpt.com, openai.com, cursor.com) or to the user's machine (localhost). An app that redirects to its own domain is registered by Host Tools as an official partner first: email [email protected].GET /oauth/authorize, the user consents, thenPOST /oauth/tokencompletes the authorization code flow with PKCE (S256).
Access tokens last 1 hour and refresh tokens 30 days, and clients refresh in the background. Revoke with POST /oauth/token/revoke.
/mcp accepts bearer tokens only. The legacy authToken and apiKey headers do not work there.
Two account conditions are checked on every request, not only at authorization: the subscription must be in good standing, and the token must belong to the account owner. A sub-user's token gets 401 invalid_token, so team members connect an assistant to their own account rather than to the account they were invited to.
Access
An assistant you connect to your own account registers with every scope unless it asks for fewer, so it can use every tool on this page.
Scopes only limit partner apps registered with a narrower set. Calling a tool outside that set returns an insufficient_scope error that names the scope it needs, and the tool stays in the assistant's list. The REST API checks the same scopes.
Tools
Read (22): list_listings, get_listing, get_listing_content_options, get_calendar, get_reservations, get_reservation, get_cancellation_options, get_quote, quote_alteration, get_message_thread, list_support_threads, get_support_thread, get_message_rules, get_calendar_rules, get_reviews, list_accounts, get_account, get_user, list_help_articles, get_help_article, collect_date_range, list_errors
get_reservations takes an optional updatedSince (an ISO 8601 date-time) to return only the reservations that changed at or after that time, across all listings or one listingId. Pair it with sortBy: "updatedAt" to see the oldest or newest changes first. It returns at most 200 reservations and has no paging, so if you get 200 back, narrow the time window. To catch up on every change reliably, use GET /api/getAllReservations, which pages through all of them.
list_errors returns the problems Host Tools is reporting for the user right now (a disconnected account, a refused price or minimum-nights change, a failed scheduled message, and so on), the same list as GET /api/getErrors and the type: "error" webhook. Each error is only returned when the granted scopes cover its data, for example accounts:read for account.disconnected.
Analytics (23): get_headline_kpis, get_occupancy_stats, get_revenue_stats, get_adr_stats, get_revpar_stats, get_timeseries_stats, get_pace_stats, get_listing_breakdown_stats, get_channel_performance, get_booking_pattern_stats, get_cancellation_stats, get_reservation_status_stats, get_gap_analysis, get_turnover_stats, get_check_ins_check_outs, get_upcoming_reservations, get_pricing_stats, get_review_stats, get_review_analytics, get_response_time_stats, get_response_time_breakdown, list_listing_groups, get_metric_definitions
Write (26): send_message, send_support_message, set_prices, set_availability, create_reservation, update_reservation, cancel_reservation, accept_booking_request, decline_booking_request, preapprove_inquiry, send_special_offer, request_alteration, respond_to_alteration_request, leave_review, reply_to_review, update_listing, manage_listing_photos, update_user, create_message_rule, pause_message_rule, create_calendar_rule, update_calendar_rule, pause_calendar_rule, move_calendar_rule, delete_calendar_rule, publish_listing
list_support_threads, get_support_thread and send_support_message read and answer the user's Airbnb customer support threads: the conversations with Airbnb support about the account, which the Host Tools inbox shows as Airbnb Support. They are not about one reservation, so they aren't in get_message_thread. A message's role is support for Airbnb support and Airbnb's automated messages, and host for the host's own replies. Only Airbnb support threads are imported. Images in these threads aren't returned yet.
The calendar rule tools read and manage a listing's calendar rules, like the Calendar Rules endpoints. get_pricing_rules and create_pricing_rule, their old names, still work. Rules apply from the top of the listing's list down (position 1 first), and a later rule overwrites an earlier one on the same day, minimum nights included, so a fixedPrice rule should sit above a channel markup such as "Airbnb +15%". create_calendar_rule adds a rule at the bottom unless given a position, and move_calendar_rule moves one. A rule applies on every weekday unless limitDays names some. Dates are YYYY-MM-DD on the listing's calendar; a specificDates end date is not included (like a check-out day), while a yearlyDates end date is. A rule from a calendar rule group (calendarRuleGroupName set) is shared with every listing in the group and can't be changed with these tools.
set_prices writes the listing's API price, the same per-date price a pricing partner such as PriceLabs sends, and the partner's next sync replaces it. It only applies to listings whose price source is API. To adjust prices on dates for a listing priced by a partner, or on any other listing, use create_calendar_rule, which applies on top of the partner's price.
update_user changes account-level settings, the same ones get_user returns: today channelPriceAdjustments, the percentage by which the price sent to each channel is raised or lowered. Only the channels sent change; null clears one. It applies to every listing on the account and re-sends their prices, so the assistant confirms with the user first.
cancel_reservation works on internal, direct, Airbnb and VRBO reservations whose stay hasn't ended. For Airbnb and VRBO, call get_cancellation_options first. On Airbnb it returns the reasons Airbnb accepts and the penalty it would charge the host: pass one of its reason/subReason pairs, plus a messageToGuest when the reason needs one. On VRBO it returns the reasons VRBO offers, the refunds each allows and VRBO's guidance for it, a breakdown of each refund (booking amount, commission, guest service fee, lodging taxes), and VRBO's warnings: pass a reason as reason with a customReason of the length VRBO requires, and one of that reason's refund options as refundPercentType. The guest is refunded as chosen. VRBO counts this as a host cancellation whoever asked for it. When a VRBO reservation has cancellationRequestedDate, the guest asked to cancel; VRBO's own advice is to have the guest cancel from their account, which avoids host penalties, so the assistant says that first and cancels with the reason GUEST_NEEDS_TO_CANCEL only as the fallback. VRBO has no call to approve or decline a request. Booking.com reservations must be cancelled on the channel.
accept_booking_request works on Airbnb requests to book (status pending) only for now. decline_booking_request works on Airbnb requests to book (status pending) and on Booking.com requests to book (status inquiry, with one of Booking.com's upper-case reasons).
preapprove_inquiry works on Airbnb, Booking.com and VRBO inquiries (status inquiry). On Booking.com it approves the guest's request to book. On VRBO it needs a message to the guest, which goes with the pre-approval; Airbnb and Booking.com take no message. VRBO support is new and not yet tried on a live account.
send_special_offer works on Airbnb and VRBO inquiries. Booking.com has no special offers. A message can only go with a VRBO offer.
quote_alteration prices a change to a confirmed Airbnb reservation before it is sent, with nothing going to the guest: the stay as it is and as proposed, each with the host's payout, the guest's total and itemized rates, plus Airbnb's own price next to a total of the host's and any nights that run into another booking. request_alteration asks the guest to accept new dates, guest counts or a new total price on a confirmed Airbnb reservation; only the values given change. respond_to_alteration_request answers the open request shown as alterationRequest on get_reservation: accept or decline the guest's, or cancel the host's own. Airbnb only for now.
leave_review reviews a guest after a booked stay on Airbnb or VRBO, from check-out until the channel closes reviews 14 days later. Airbnb needs comments (the public review) and has no overall star; VRBO takes star ratings only, no text. Booking.com doesn't let hosts review guests.
reply_to_review posts the host's public reply to a guest's review on Airbnb, Booking.com or VRBO. Each review takes one reply. Airbnb replies must be under 1,000 characters; Booking.com only takes replies to reviews with written comments; VRBO only while it offers a reply on the review. Booking.com and VRBO check replies before guests see them. VRBO support is new and not yet tried on a live account.
update_listing takes a listing's amenities as amenities, a list of {id, quantity} with the ids get_listing returns. attributesWithQuantity, the older name, still works but is deprecated.
update_listing refuses an amenity or bed type it adds that none of the listing's Airbnb, VRBO and Booking.com channels supports, and a property type that its Airbnb or VRBO channel doesn't support, with an error naming each value and the channels that don't support it (for example Amenity "HAC6043" is not supported on Airbnb or VRBO.). An amenity or bed type one of the listing's channels supports is accepted, and each channel is only sent the ones it supports. A value the listing already has is still accepted. get_listing_content_options lists each option's channels: the channels Host Tools sends it to and reads it from, so for a listing pick amenities and bed types whose channels include at least one channel the listing is on, and a property type whose channels include each of its Airbnb and VRBO channels. Booking.com isn't sent a property type, so it isn't checked for one.
update_listing takes the listing's other rooms (a living room without beds, bathrooms, kitchen, patio and so on) as rooms, a list of {id, typeId} with the room types get_listing_content_options lists in roomTypes. Send each bedroom's and room's id back, as get_listing returns it, to keep the photos in it. When rooms has any bathrooms, the bathroom count is set from them. manage_listing_photos puts a photo in a bedroom or room with roomId, on upload and update, and removeFromRoom: true on update takes it out.
update_listing saves a change even when a channel won't be sent part of it, and lists each such change in data.skipped as {channel, label, reason}, for example a name Booking.com would refuse (Booking.com property names can't have emoji, so "Casamare 🌴" isn't sent. Rename the listing to send it.). Show the user the reason.
update_listing takes a last-minute discount as lastMinuteDiscount (percent off, 0 to 99; 0 or null turns it off) and lastMinuteDiscountDays (1 to 28 days before check-in). A discount needs days, sent with it or already on the listing. It goes to Airbnb as a last-minute pricing rule, which replaces the listing's other last-minute rules there; VRBO, Booking.com and Houfy aren't sent it, and direct booking quotes don't apply it.
publish_listing publishes a listing that isn't on the channel yet, like POST /api/publishListing/{listingID}: as a new Airbnb listing, as a new VRBO property, as a new Houfy listing, or as a new room on one of the user's Booking.com properties (each Booking.com account in list_accounts is one property). A Booking.com room can only be added at the property's address, so a listing elsewhere goes on the user's other property at its street address when there is one (the result has its accountId), else on a new Booking.com property of its own, created under the same Booking.com partner account as the property given (the result has newProperty: true); a Booking.com property can't be deleted, which the assistant tells the user first. VRBO asks whether the user is a private or professional host (hostType) and, where the place requires one, for the property's registration number, so the assistant asks the user; VRBO can't delete a property, so one it refuses stays on the user's VRBO account for the next publish to carry on with. Houfy asks who the listing is listed by, the owner or a manager (listedBy), so the assistant asks the user; Houfy shows the new listing in its search only once it's verified, which the user asks for by uploading their ID and a recent utility bill, insurance statement or deed for the property on the listing's Verifications page on Houfy (and emailing [email protected] with the listing number only if Houfy doesn't verify it), so the assistant tells them, and get_listing's channels.Houfy.awaitingVerification is true until it is (read from Houfy once a day); and Houfy can't delete a listing either, so one it refuses stays for the next publish to carry on with. It's queued: get_listing shows publishing until the listing is on the channel, and if the channel refuses it, list_errors has a listing.publishFailed error with the channel's reason. On Booking.com, get_listing's channels.Booking.opening then says what the room waits for before guests can book it: calendar sync (calendarSync), Booking.com still checking a new property itself (review), which Host Tools opens after, or Booking.com's checks that fail (issues), whose reason list_errors has as a listing.openFailed error for the user to fix. It turns the listing's content sync on, which also sends the listing's content to its other channels when it was off, so the assistant confirms with the user first.
Each tool documents its own parameters over the protocol, so an assistant discovers them with tools/list. There is no separate parameter reference to keep in sync.
Resources and prompts
resources/list returns exactly two entries, hosttools://user and hosttools://listings. Three more are templates the assistant fills in on demand (a single listing, a listing's calendar for a date range, and a single reservation), so they are not enumerable. Two entries is the correct result and does not indicate a partial connection.
Three prompts ship with the server: daily_briefing, guest_response, and pricing_review.
Transport and limits
POST /mcp carries JSON-RPC 2.0 and returns a JSON body. Every request is served on its own, with no session held between requests, so any instance can serve any request and an mcp-session-id header is ignored rather than rejected.
GET /mcp currently returns 405. The server sends nothing on its own initiative today, so there is no stream for a client to attach to, and compliant clients fall back to request/response. DELETE /mcp returns 204 so a client's teardown succeeds.
Requests are limited to 300 per minute, keyed on the access token. Going over returns 429 with a JSON-RPC error.
Connecting as a user
Hosts who want to connect their own assistant should follow How do I use the Host Tools MCP server?. It gives the same server URL without the protocol detail.