Documentation

MCP · Streamable HTTP · protocol 2025-06-18 · v0.1.0

Endpoint

POST https://bookhotelsmcp.com/mcp
Content-Type: application/json
Authorization: Bearer <platform key>   # only if one was issued to your platform
Manifest/.well-known/mcp.json Capabilities/agent.json For crawlers/llms.txt Health/health

Flow

search_hotels → get_hotel → hold_offerbook_hotel → get_booking | modify_booking | cancel_booking
                 ↳ get_offer   (re-price without holding)

REST equivalents for Stripe agentic commerce: GET /availability, POST /bookings, GET|PATCH|DELETE /bookings/{id}. Pass payment_data: { token, provider: "stripe" } on book.

Every tool returns { ok: true, … } or a structured error { ok: false, code, message, retryable, alternates? }. The MCP result sets isError and carries the same object in structuredContent.

Tools

search_hotels

Find bookable hotel rooms with live prices, photos, star rating, and cancellation terms. Call first for any stay request. Returns offer_id, totals, photoUrl, amenities, and display_markdown for Muse. Next: get_hotel, hold_offer, or book_hotel.

Input schema
{
  "type": "object",
  "properties": {
    "location": {
      "type": "string",
      "description": "City, neighborhood, landmark, or IATA code. e.g. 'Portland, Maine', 'near Fenway Park', 'BOS'."
    },
    "check_in": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "description": "YYYY-MM-DD"
    },
    "check_out": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "description": "YYYY-MM-DD"
    },
    "adults": {
      "type": "integer",
      "minimum": 1,
      "maximum": 8,
      "default": 2
    },
    "rooms": {
      "type": "integer",
      "minimum": 1,
      "maximum": 4,
      "default": 1
    },
    "max_per_night": {
      "type": "number",
      "description": "Budget cap per night."
    },
    "refundable_only": {
      "type": "boolean",
      "default": false,
      "description": "Only rates with free cancellation."
    },
    "currency": {
      "type": "string",
      "default": "USD"
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 12,
      "default": 6
    }
  },
  "required": [
    "location",
    "check_in",
    "check_out"
  ]
}

get_hotel

Load photos, amenities, description, and check-in times for one hotel_id from search_hotels. Call before quoting a stay so the user can see the property. Returns display_markdown Muse can render.

Input schema
{
  "type": "object",
  "properties": {
    "hotel_id": {
      "type": "string"
    }
  },
  "required": [
    "hotel_id"
  ]
}

get_offer

Re-check the current price and cancellation policy for one offer_id before quoting it to the user. Returns PRICE_CHANGED or OFFER_EXPIRED with alternates if anything moved.

Input schema
{
  "type": "object",
  "properties": {
    "offer_id": {
      "type": "string"
    }
  },
  "required": [
    "offer_id"
  ]
}

hold_offer

Lock an offer's price for 15 minutes and get a hold_id. Call this as soon as the user picks a room, before collecting guest details, so the price can't move while they decide. Returns hold_id and expires_at. Next step: book_hotel with hold_id.

Input schema
{
  "type": "object",
  "properties": {
    "offer_id": {
      "type": "string"
    }
  },
  "required": [
    "offer_id"
  ]
}

book_hotel

Confirm the reservation. Pass hold_id (preferred) or offer_id, guest name/email, and a unique idempotency_key. Pay with payment_data {token: spt_…, provider: stripe} from the Link agent wallet. Some suppliers also need a guarantee card. Retries with the same key return the same booking.

Input schema
{
  "type": "object",
  "properties": {
    "hold_id": {
      "type": "string"
    },
    "offer_id": {
      "type": "string"
    },
    "guest": {
      "type": "object",
      "properties": {
        "first_name": {
          "type": "string"
        },
        "last_name": {
          "type": "string"
        },
        "email": {
          "type": "string",
          "format": "email"
        },
        "phone": {
          "type": "string"
        }
      },
      "required": [
        "first_name",
        "last_name",
        "email"
      ]
    },
    "card": {
      "type": "object",
      "properties": {
        "vendor": {
          "type": "string",
          "enum": [
            "VI",
            "MC",
            "AX",
            "DC",
            "JC"
          ]
        },
        "number": {
          "type": "string"
        },
        "expiry": {
          "type": "string",
          "pattern": "^\\d{4}$",
          "description": "MMYY"
        },
        "holder_name": {
          "type": "string"
        }
      },
      "required": [
        "vendor",
        "number",
        "expiry",
        "holder_name"
      ]
    },
    "payment_data": {
      "type": "object",
      "description": "Stripe Shared Payment Token from the Link agent wallet.",
      "properties": {
        "token": {
          "type": "string",
          "description": "spt_…"
        },
        "provider": {
          "type": "string",
          "enum": [
            "stripe"
          ]
        }
      },
      "required": [
        "token",
        "provider"
      ]
    },
    "idempotency_key": {
      "type": "string",
      "minLength": 8,
      "maxLength": 128
    },
    "special_requests": {
      "type": "string",
      "maxLength": 500
    }
  },
  "required": [
    "guest",
    "idempotency_key"
  ]
}

get_booking

Look up a reservation by booking_id: status, confirmation number, dates, total, and cancellation terms.

Input schema
{
  "type": "object",
  "properties": {
    "booking_id": {
      "type": "string"
    }
  },
  "required": [
    "booking_id"
  ]
}

modify_booking

Change a booking's guest name/email or stay dates. Date changes re-price at the same hotel; if the total moves, confirm with the user and call again with confirm_new_total. Returns the updated booking or PRICE_CHANGED / NOT_MODIFIABLE.

Input schema
{
  "type": "object",
  "properties": {
    "booking_id": {
      "type": "string"
    },
    "guest": {
      "type": "object",
      "properties": {
        "first_name": {
          "type": "string"
        },
        "last_name": {
          "type": "string"
        },
        "email": {
          "type": "string",
          "format": "email"
        },
        "phone": {
          "type": "string"
        }
      },
      "required": [
        "first_name",
        "last_name",
        "email"
      ]
    },
    "check_in": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
    },
    "check_out": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
    },
    "adults": {
      "type": "integer",
      "minimum": 1,
      "maximum": 8
    },
    "confirm_new_total": {
      "type": "number",
      "description": "Accepted new stay total after PRICE_CHANGED."
    }
  },
  "required": [
    "booking_id"
  ]
}

cancel_booking

Cancel a reservation made through this connector. Returns the updated booking, or NOT_CANCELLABLE with exact instructions when the rate is non-refundable or the property must be contacted directly. Refunds a charged Shared Payment Token when the cancel succeeds.

Input schema
{
  "type": "object",
  "properties": {
    "booking_id": {
      "type": "string"
    }
  },
  "required": [
    "booking_id"
  ]
}

Errors

CodeMeaningNext call
NO_AVAILABILITYNo rooms for those dates or locationsearch_hotels with other dates or a wider area
LOCATION_NOT_FOUNDCouldn't resolve the placesearch_hotels with a city name or IATA code
INVALID_DATESPast date, or check_out ≤ check_insearch_hotels; alternates.nextAvailableCheckIn is set
OFFER_EXPIREDoffer_id unknown or withdrawnsearch_hotels
PRICE_CHANGEDRate moved since it was quotedconfirm alternates.newTotal with the user, then hold_offer
HOLD_EXPIREDhold_id past its 15-minute windowhold_offer again
PAYMENT_REQUIREDSupplier needs a guarantee card, or SPT missingbook_hotel with card and/or payment_data
PAYMENT_DECLINEDCard, wallet, or Shared Payment Token rejectedretry with a new spt_ or another card
NOT_CANCELLABLENon-refundable, or property must be contactedrelay message to the user verbatim
NOT_MODIFIABLESupplier cannot change this bookingcancel_booking and search_hotels again
NOT_FOUNDUnknown booking_id
SUPPLIER_ERRORUpstream failureretry once if retryable is true
VALIDATIONBad inputfix the field named in message

Guarantees

Limits

Prompts that route here