# Ozvermont Stays MCP tools

Every tool of this MCP server: its class, whether it needs sign-in, its side effects, inputs, output, errors and confirmation. The server builds this page from its live tool list and each tool's route, so it matches what `tools/list` shows.

## Addresses

- `https://api.deerfieldvalleyinn.com/mcp`: Streamable HTTP. Browse without sign-in. A tool that acts for a guest answers HTTP 401 when it is called, and the app opens sign-in then.
- `https://api.deerfieldvalleyinn.com/mcp/signed-in`: the same tools. Every request needs an access token, so an app that signs in only when it connects uses this address.
- Server card: https://api.deerfieldvalleyinn.com/.well-known/mcp/server-card.json. Sign-in and agent registration: https://api.deerfieldvalleyinn.com/auth.md.

## Sign-in

An app signs the guest in with OAuth 2.1 and PKCE (S256). On this server's sign-in page, the guest types a code sent to their email and allows the app. The scopes:

- `browse`: See the business's offer, open dates and quotes.
- `client`: Act for the signed-in guest: their record, bookings and payments.

Tools that need the `client` scope: `who_am_i`, `start_booking`, `list_my_bookings`, `get_booking`, `cancel_booking`, `open_card_payment`, `get_bank_transfer_details`, `report_bank_transfer_sent`, `send_request`, `get_request`. Every other tool works without sign-in at `https://api.deerfieldvalleyinn.com/mcp`.

| Sign-in setting | Value |
|---|---|
| Access token lifetime | 1 hour |
| Sign-in lifetime: then refresh stops, and the guest signs in again | 24 hours |
| Code emails the sign-in page sends, for the whole server | 60 a day |

Over the code email limit, the sign-in page shows a message. It is not an HTTP 429.

## Limits

| Requests to `/mcp` and `/mcp/signed-in` | Limit |
|---|---|
| Under one sign-in, across its tokens | 60 a minute |
| Without sign-in, per MCP session (only when the client sends `Mcp-Session-Id`) | 30 a minute |
| Without sign-in, for the whole server | 300 a minute |

The server counts every HTTP request: `initialize`, `tools/list`, tool calls, notifications and GET streams. A JSON-RPC batch counts once. Requests to the A2A agent count in the same limits. A request over a limit gets HTTP 429 `rate_limited` and a `Retry-After` header with the seconds to wait.

## Tool classes

- Read (`x-tool-class: read`): It only retrieves information. It changes nothing, takes no payment and sends nothing.
- Write (`x-tool-class: write`): It creates or changes data, or acts for the guest, as its side effects say.
- Sensitive write (`x-tool-class: sensitive_write`): A consequential action, such as a payment or a cancellation; its side effects say what it does. Call it only once the guest has clearly approved it, every time.

## Calling a tool

- The server calls the tool's route itself and acts for the signed-in guest. It sends the REST headers, such as `Idempotency-Key`. REST steps quoted from a route below (headers, sessions, partner keys) do not apply to an MCP caller.
- A change sent again by the same caller, with the same arguments, JSON-RPC request id and MCP session (if any), gets the first answer again. It does not run twice.

## Errors

- MCP errors are HTTP answers from the server before the tool runs. Their body is `{"error": "<code>", "error_description": "..."}`. A 401 or 403 answer has a `WWW-Authenticate` header that names the resource metadata and the scope.
- Route errors come back as a tool result with `isError: true`. Its text is the route's error message and next step. Only when the route's error has neither does the text name the HTTP status: `The call failed (<status>).` It never carries the REST code: each tool's table gives the status and code for reference.
- A call to an unknown tool, with an unknown or missing argument, or with `/`, `?` or `#` in a path value gets JSON-RPC error -32602 (invalid params).
- A request body over 1 MiB gets HTTP 413 `too_large`. HTTP 503 `temporarily_unavailable` means the server can't run now: try again later.

## Tools

| Tool | Title | Class | Needs sign-in |
|---|---|---|---|
| `list_properties` | The properties | Read | No |
| `get_property` | A property | Read | No |
| `get_location` | Where a property is | Read | No |
| `get_accommodations` | Rooms and beds | Read | No |
| `get_stay_rules` | Stay rules | Read | No |
| `get_policies` | Policies | Read | No |
| `get_breakfast` | Breakfast | Read | No |
| `get_common_questions` | Common questions | Read | No |
| `check_availability` | Check dates | Read | No |
| `find_nearest_dates` | Nearest open dates | Read | No |
| `list_open_dates` | Open dates and prices | Read | No |
| `get_quote` | Get a quote | Read | No |
| `who_am_i` | The signed-in guest | Read | Yes, scope `client` |
| `start_booking` | Start a booking | Sensitive write | Yes, scope `client` |
| `list_my_bookings` | My bookings | Read | Yes, scope `client` |
| `get_booking` | Where a booking stands | Read | Yes, scope `client` |
| `cancel_booking` | Cancel a booking | Sensitive write | Yes, scope `client` |
| `open_card_payment` | Card payment page | Sensitive write | Yes, scope `client` |
| `get_bank_transfer_details` | Bank transfer details | Read | Yes, scope `client` |
| `report_bank_transfer_sent` | Bank transfer sent | Sensitive write | Yes, scope `client` |
| `send_request` | Send a request | Sensitive write | Yes, scope `client` |
| `get_request` | A request | Read | Yes, scope `client` |

### `list_properties`: The properties

- Class: Read (`x-tool-class: read`)
- Needs sign-in: No at `/mcp`. At `/mcp/signed-in`, every request needs an access token.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server.
- Route: `GET /v1/discover/properties`

#### What it does

> The properties a guest can book: Deerfield Valley Inn and the Paradise Vermont chalet.

The route's own words (the server does the REST steps in them for you):

> List Properties
>
> The properties a guest can book.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

None.

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

| Name | Type | Always present | Description |
|---|---|---|---|
| `properties` | array of PropertySummary | yes | - |

`PropertySummary` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `id` | string | yes | - |
| `name` | string | yes | - |
| `town` | string | yes | - |
| `region` | string | yes | - |
| `description` | string | yes | - |

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 400 | Invalid request: the error names the parameter and how to fix it. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | Only at `/mcp/signed-in`, without an access token. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server. Wait the seconds in `Retry-After`. |

### `get_property`: A property

- Class: Read (`x-tool-class: read`)
- Needs sign-in: No at `/mcp`. At `/mcp/signed-in`, every request needs an access token.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server.
- Route: `GET /v1/discover/properties/{property_id}`

#### What it does

> One property: its name, what a stay includes, photos, and who the guest would pay.

The route's own words (the server does the REST steps in them for you):

> Get Property
>
> One property: name, what a stay includes, photos, and who the guest would pay.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `property_id` | string | yes | - |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

| Name | Type | Always present | Description |
|---|---|---|---|
| `property_id` | string | yes | - |
| `name` | string | yes | - |
| `description` | string | yes | - |
| `amenities` | array of string | yes | - |
| `included` | array of string | yes | - |
| `not_included` | array of string | yes | - |
| `photos` | array of Photo | yes | - |
| `seller` | string | yes | - |
| `contact_email` | string | yes | - |

`Photo` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `url` | string | yes | - |
| `caption` | string | yes | - |

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 400 | Invalid request: the error names the parameter and how to fix it. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | Only at `/mcp/signed-in`, without an access token. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server. Wait the seconds in `Retry-After`. |

### `get_location`: Where a property is

- Class: Read (`x-tool-class: read`)
- Needs sign-in: No at `/mcp`. At `/mcp/signed-in`, every request needs an access token.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server.
- Route: `GET /v1/discover/properties/{property_id}/location`

#### What it does

> Where the property is, and its local time offset.

The route's own words (the server does the REST steps in them for you):

> Get Location
>
> Where the property is, and its local time offset.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `property_id` | string | yes | - |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

| Name | Type | Always present | Description |
|---|---|---|---|
| `address` | string | yes | - |
| `locality` | string | yes | - |
| `region` | string | yes | - |
| `country` | string | yes | - |
| `utc_offset` | string | yes | - |
| `description` | string | yes | - |

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 400 | Invalid request: the error names the parameter and how to fix it. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | Only at `/mcp/signed-in`, without an access token. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server. Wait the seconds in `Retry-After`. |

### `get_accommodations`: Rooms and beds

- Class: Read (`x-tool-class: read`)
- Needs sign-in: No at `/mcp`. At `/mcp/signed-in`, every request needs an access token.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server.
- Route: `GET /v1/discover/properties/{property_id}/accommodations`

#### What it does

> The room types a guest can book, and the rooms of each type.

The route's own words (the server does the REST steps in them for you):

> Get Accommodations
>
> Room types a guest can book, and the rooms of each type.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `property_id` | string | yes | - |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

| Name | Type | Always present | Description |
|---|---|---|---|
| `accommodations` | array of AccommodationResponse | yes | - |

`AccommodationResponse` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `id` | string | yes | - |
| `property_id` | string | yes | - |
| `kind` | string | yes | One of: `hotel_room`, `residence`. |
| `name` | string | yes | - |
| `description` | string | yes | - |
| `max_guests` | integer or null | yes | - |
| `rooms` | array of string | yes | - |
| `amenities` | array of string | yes | - |
| `photos` | array of Photo | yes | - |

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 400 | Invalid request: the error names the parameter and how to fix it. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | Only at `/mcp/signed-in`, without an access token. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server. Wait the seconds in `Retry-After`. |

### `get_stay_rules`: Stay rules

- Class: Read (`x-tool-class: read`)
- Needs sign-in: No at `/mcp`. At `/mcp/signed-in`, every request needs an access token.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server.
- Route: `GET /v1/discover/properties/{property_id}/stay-rules`

#### What it does

> How long a stay can be, and check-in and check-out.

The route's own words (the server does the REST steps in them for you):

> Get Stay Rules
>
> How long a stay can be, and check-in and check-out.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `property_id` | string | yes | - |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

| Name | Type | Always present | Description |
|---|---|---|---|
| `min_nights` | integer or null | yes | - |
| `max_nights` | integer or null | yes | - |
| `check_in_time` | string or null | yes | - |
| `check_out_time` | string or null | yes | - |
| `utc_offset` | string or null | yes | - |
| `summary` | array of string | yes | - |

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 400 | Invalid request: the error names the parameter and how to fix it. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | Only at `/mcp/signed-in`, without an access token. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server. Wait the seconds in `Retry-After`. |

### `get_policies`: Policies

- Class: Read (`x-tool-class: read`)
- Needs sign-in: No at `/mcp`. At `/mcp/signed-in`, every request needs an access token.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server.
- Route: `GET /v1/discover/properties/{property_id}/policies`

#### What it does

> The payment, cancellation and fee rules.

The route's own words (the server does the REST steps in them for you):

> Get Policies
>
> Payment, cancellation, and fee rules taken from the property file.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `property_id` | string | yes | - |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

| Name | Type | Always present | Description |
|---|---|---|---|
| `policies` | array of string | yes | - |

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 400 | Invalid request: the error names the parameter and how to fix it. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | Only at `/mcp/signed-in`, without an access token. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server. Wait the seconds in `Retry-After`. |

### `get_breakfast`: Breakfast

- Class: Read (`x-tool-class: read`)
- Needs sign-in: No at `/mcp`. At `/mcp/signed-in`, every request needs an access token.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server.
- Route: `GET /v1/discover/properties/{property_id}/breakfast`

#### What it does

> The inn's breakfast menu. The chalet has none.

The route's own words (the server does the REST steps in them for you):

> Get Breakfast
>
> The inn breakfast menu. The chalet returns an empty list.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `property_id` | string | yes | - |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

| Name | Type | Always present | Description |
|---|---|---|---|
| `serving_times` | array of string | yes | - |
| `dishes` | array of BreakfastDishResponse | yes | - |

`BreakfastDishResponse` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `id` | string | yes | - |
| `name` | string | yes | - |
| `contains` | string | yes | - |
| `calories` | string | yes | - |
| `at_inn_cents` | integer | yes | Bank-transfer price in cents. The quote gives the card price. |
| `preorder_cents` | integer | yes | Bank-transfer price in cents. The quote gives the card price. |
| `addons` | array of BreakfastAddonResponse | yes | - |

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 400 | Invalid request: the error names the parameter and how to fix it. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | Only at `/mcp/signed-in`, without an access token. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server. Wait the seconds in `Retry-After`. |

### `get_common_questions`: Common questions

- Class: Read (`x-tool-class: read`)
- Needs sign-in: No at `/mcp`. At `/mcp/signed-in`, every request needs an access token.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server.
- Route: `GET /v1/discover/properties/{property_id}/questions`

#### What it does

> Answers to the questions guests ask most.

The route's own words (the server does the REST steps in them for you):

> Get Questions
>
> Answers to common questions. Empty until the property file lists them.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `property_id` | string | yes | - |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

| Name | Type | Always present | Description |
|---|---|---|---|
| `questions` | array of string | yes | - |

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 400 | Invalid request: the error names the parameter and how to fix it. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | Only at `/mcp/signed-in`, without an access token. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server. Wait the seconds in `Retry-After`. |

### `check_availability`: Check dates

- Class: Read (`x-tool-class: read`)
- Needs sign-in: No at `/mcp`. At `/mcp/signed-in`, every request needs an access token.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server.
- Route: `GET /v1/availability`

#### What it does

> Whether a room or the chalet is free for a start date and a number of nights.

The route's own words (the server does the REST steps in them for you):

> Get Availability
>
> Whether this accommodation can be reserved for these dates at this rate. No price is returned.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `accommodation_id` | string | yes | Id from get_accommodations. |
| `start_date` | string (date) | yes | Check-in day, YYYY-MM-DD. |
| `nights` | integer | yes | Number of nights, from 1 to 366. |
| `rate` | string or null | no | Optional. "non-refundable" (the default) or "refundable". The quote lists the rates sold. |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

| Name | Type | Always present | Description |
|---|---|---|---|
| `accommodation_id` | string | yes | - |
| `start_date` | string | yes | - |
| `nights` | integer | yes | - |
| `check_out_date` | string | yes | - |
| `status` | string | yes | One of: `available`, `unavailable`, `on_request`. |
| `reason` | string | yes | - |
| `next_step` | string | yes | - |
| `nearest_open_dates` | NearestDates or null | yes | - |

Types used here: [`NearestDates`](#type-nearestdates).

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 400 | Invalid request: the error names the parameter and how to fix it. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | Only at `/mcp/signed-in`, without an access token. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server. Wait the seconds in `Retry-After`. |

### `find_nearest_dates`: Nearest open dates

- Class: Read (`x-tool-class: read`)
- Needs sign-in: No at `/mcp`. At `/mcp/signed-in`, every request needs an access token.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server.
- Route: `GET /v1/nearest-dates`

#### What it does

> The open start dates nearest to the dates the guest asked for.

The route's own words (the server does the REST steps in them for you):

> Get Nearest Dates
>
> The nearest open check-in dates for the same room and number of nights, at this rate.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `accommodation_id` | string | yes | Id from get_accommodations. |
| `start_date` | string (date) | yes | Check-in day, YYYY-MM-DD. |
| `nights` | integer | yes | Number of nights, from 1 to 366. |
| `guests` | integer or null | no | Number of guests, 1 or greater when sent. |
| `rate` | string or null | no | Optional. "non-refundable" (the default) or "refundable". The quote lists the rates sold. |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

| Name | Type | Always present | Description |
|---|---|---|---|
| `accommodation_id` | string | yes | - |
| `start_date` | string | yes | - |
| `nights` | integer | yes | - |
| `nearest_open_dates` | NearestDates | yes | - |

Types used here: [`NearestDates`](#type-nearestdates).

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 400 | Invalid request: the error names the parameter and how to fix it. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | Only at `/mcp/signed-in`, without an access token. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server. Wait the seconds in `Retry-After`. |

### `list_open_dates`: Open dates and prices

- Class: Read (`x-tool-class: read`)
- Needs sign-in: No at `/mcp`. At `/mcp/signed-in`, every request needs an access token.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server.
- Route: `GET /v1/open-dates`

#### What it does

> Every open start day in a range, with its total for the payment method.

The route's own words (the server does the REST steps in them for you):

> Get Open Dates
>
> Each check-in in the range that the stay rules allow and the rate is sold for, with its quote total.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `accommodation_id` | string | yes | Id from get_accommodations. |
| `from` | string (date) | yes | First check-in day to look at, YYYY-MM-DD. |
| `to` | string (date) | yes | Last check-in day to look at, YYYY-MM-DD, on or after `from`. |
| `nights` | integer | yes | Number of nights, from 1 to 366. |
| `guests` | integer or null | no | Number of guests, 1 or greater when sent. |
| `payment_method` | string | yes | Required. "credit card" or "bank". |
| `rate` | string or null | no | Optional. "non-refundable" (the default) or "refundable". The quote lists the rates sold. |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

| Name | Type | Always present | Description |
|---|---|---|---|
| `accommodation_id` | string | yes | - |
| `from` | string | yes | - |
| `to` | string | yes | - |
| `nights` | integer | yes | - |
| `guests` | integer or null | yes | - |
| `payment_method` | string or null | yes | - |
| `currency` | string | yes | - |
| `open_dates` | array of OpenDate | yes | - |
| `notes` | array of string | yes | - |
| `next_step` | string | yes | - |

`OpenDate` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `start_date` | string | yes | - |
| `check_out_date` | string | yes | - |
| `status` | string | yes | One of: `available`, `on_request`. |
| `total_cents` | integer or null | yes | - |

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 400 | Invalid request: the error names the parameter and how to fix it. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | Only at `/mcp/signed-in`, without an access token. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server. Wait the seconds in `Retry-After`. |

### `get_quote`: Get a quote

- Class: Read (`x-tool-class: read`)
- Needs sign-in: No at `/mcp`. At `/mcp/signed-in`, every request needs an access token.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server.
- Route: `GET /v1/quote`

#### What it does

> An itemized price for a stay: dates, guests and payment method, with the terms. A booking needs the quote's total, which the guest approved.

The route's own words (the server does the REST steps in them for you):

> Get Quote
>
> An itemized price at the chosen rate, or a refusal with no total.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `accommodation_id` | string | yes | Id from get_accommodations. |
| `start_date` | string (date) | yes | Check-in day, YYYY-MM-DD. |
| `nights` | integer | yes | Number of nights, from 1 to 366. |
| `guests` | integer or null | no | Number of guests, 1 or greater when sent. |
| `payment_method` | string | yes | Required. "credit card" or "bank". |
| `pets` | integer | no | Number of pets. More than the property allows is on request. Default: `0`. |
| `breakfast` | array of string | no | Breakfast entries, one per dish: <morning>@<time>:<dish>[+<add-on>]. Repeat the parameter. Send each + as %2B. Only where the quote has a breakfast_offer. Default: `[]`. |
| `extra` | array of string | no | Optional extras: early-check-in, late-check-out, ev-charging. Default: `[]`. |
| `rate` | string or null | no | Optional. "non-refundable" (the default) or "refundable". The quote lists the rates sold. |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

This route leaves out every field whose value is null.

| Name | Type | Always present | Description |
|---|---|---|---|
| `accommodation_id` | string | yes | - |
| `start_date` | string | yes | - |
| `nights` | integer | yes | - |
| `check_out_date` | string | yes | - |
| `guests` | integer or null | when not null | - |
| `payment_method` | string or null | when not null | - |
| `rate` | string | yes | - |
| `rates` | array of string | yes | - |
| `currency` | string | yes | - |
| `lines` | array of QuoteLine | yes | - |
| `total_cents` | integer or null | when not null | - |
| `deposit_cents` | integer or null | when not null | - |
| `payment_schedule` | array of string | yes | - |
| `availability` | QuoteAvailability | yes | - |
| `nearest_open_dates` | NearestDates or null | when not null | - |
| `next_step` | string | yes | - |
| `terms` | string | yes | - |
| `seller` | string | yes | - |
| `key_terms` | array of string | yes | - |
| `questions_for_guest` | array of string | yes | Ask the guest all of these in one message. |
| `breakfast_offer` | BreakfastOffer or null | when not null | - |

Types used here: [`NearestDates`](#type-nearestdates).

`QuoteLine` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `code` | string | yes | One of: `room`, `cleaning`, `pet`, `breakfast`, `extra`, `resort_fee`, `tax`. |
| `label` | string | yes | - |
| `cents` | integer | yes | - |

`QuoteAvailability` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `status` | string | yes | One of: `available`, `unavailable`, `on_request`. |
| `reason` | string | yes | - |

`BreakfastOffer` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `mornings` | array of string | yes | - |
| `serving_times` | array of string | yes | - |
| `entry_form` | string | yes | One breakfast entry per dish. In a query string, send each + as %2B. |
| `note` | string | yes | - |
| `dishes` | array of BreakfastOfferDish | yes | - |

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 400 | Invalid request: the error names the parameter and how to fix it. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | Only at `/mcp/signed-in`, without an access token. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in; without sign-in at `/mcp`, 30 a minute per MCP session (when the client sends `Mcp-Session-Id`) and 300 a minute for the whole server. Wait the seconds in `Retry-After`. |

### `who_am_i`: The signed-in guest

- Class: Read (`x-tool-class: read`)
- Needs sign-in: Yes. It acts for the signed-in guest, so it needs an access token with the `client` scope at either address.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in.
- Route: `GET /v1/clients/me`

#### What it does

> The signed-in guest's name, email and phone.

The route's own words (the server does the REST steps in them for you):

> Get Me
>
> The guest behind a session, and when the session expires. An MCP sign-in's access token
> works here too: then the time is when the token expires.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

None.

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

The guest behind the session.

| Name | Type | Always present | Description |
|---|---|---|---|
| `client` | ClientDetails | yes | - |
| `session_expires_at` | string | yes | When the session stops working: ISO 8601, UTC. |

`ClientDetails` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `client_id` | string | yes | - |
| `first_name` | string | yes | - |
| `last_name` | string | yes | - |
| `email` | string | yes | - |
| `phone` | string | yes | "+" and digits. |

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 400 | Invalid request: the error names the parameter and how to fix it. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the guest must sign in. The app opens sign-in. |
| 403 | `insufficient_scope` | The access token has no `client` scope. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in. Wait the seconds in `Retry-After`. |

### `start_booking`: Start a booking

- Class: Sensitive write (`x-tool-class: sensitive_write`)
- Needs sign-in: Yes. It acts for the signed-in guest, so it needs an access token with the `client` scope at either address.
- Side effects: stores an unpaid booking. It does not hold dates or take payment. With bank transfer on, a bank booking queues one email with the bank details.
- Confirms before it runs: Yes. Before the call, the server asks the guest to confirm (MCP elicitation), where the app supports it. If the guest does not confirm, nothing changes. An app without elicitation relies on the hints.
- Hints: `readOnlyHint: false`, `destructiveHint: true`, `idempotentHint: false`, `openWorldHint: true`
- Rate limit: 60 requests a minute per sign-in.
- Route: `POST /v1/bookings`

#### What it does

> Book the stay of a quote the guest approved, at that quote's total. The room is held only once the payment arrives. Ask the guest first.

The route's own words (the server does the REST steps in them for you):

> Start Booking
>
> Turn the quote the guest approved, at the rate it priced, into an unpaid booking.
>
> Tool class: Sensitive write. Call it only once the guest has clearly approved it, every time. Side effects: stores an unpaid booking. It does not hold dates or take payment. With bank transfer on, a bank booking queues one email with the bank details.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `accommodation_id` | string | yes | - |
| `start_date` | string (date) | yes | - |
| `nights` | integer | yes | - |
| `guests` | integer | yes | - |
| `payment_method` | string | yes | One of: `credit card`, `bank`. |
| `pets` | integer | no | Default: `0`. |
| `breakfast` | array of string or null | no | Breakfast entries from the approved quote, <morning>@<time>:<dish>[+<add-on>]. Required where the quote has a breakfast_offer: the guest's entries, or an empty list for none. |
| `extra` | array of string | no | - |
| `approved_total_cents` | integer | yes | - |
| `rate` | string or null | no | Optional. "non-refundable" (the default) or "refundable": the rate the approved quote priced. |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

This route leaves out every field whose value is null.

Where the booking stands. Dates stay free until a payment is recorded.

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |
| `status` | string | yes | One of: `payment_pending`, `confirmed`, `completed`, `closed_unpaid`, `dates_taken`, `cancelled_by_guest`, `cancelled_by_owner`. |
| `status_text` | string | yes | - |
| `stage` | string | yes | One of: `pending`, `confirmed`, `completed`, `failed`, `cancelled`. |
| `who_acts_next` | string | yes | One of: `guest`, `operator`, `nobody`. |
| `next_step` | string | yes | - |
| `deadline` | string or null | when not null | - |
| `amount_due_cents` | integer or null | when not null | - |
| `payment_page` | PaymentPage or null | when not null | - |
| `allowed_actions` | array of string | yes | - |
| `check_back_at` | string or null | when not null | - |
| `flags` | array of string | yes | - |
| `summary` | BookingSummary | yes | - |
| `payments` | array of BookingPayment | yes | - |
| `requests` | array of RequestView | yes | - |
| `started_at` | string | yes | - |
| `rate` | string | yes | The rate booked. Its cancellation rule is in key_terms. One of: `non-refundable`, `refundable`. |
| `seller` | string | yes | - |
| `key_terms` | array of string | yes | - |
| `contact_email` | string | yes | - |
| `breakfast` | array of BreakfastMorning | yes | Each morning's serving time and dishes. Empty when none was ordered. |

Types used here: [`PaymentPage`](#type-paymentpage), [`BookingSummary`](#type-bookingsummary), [`BookingPayment`](#type-bookingpayment), [`RequestView`](#type-requestview), [`BreakfastMorning`](#type-breakfastmorning).

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 409 | The quote changed, the dates are refused, or the guest already has an open booking on these nights. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the guest must sign in. The app opens sign-in. |
| 403 | `insufficient_scope` | The access token has no `client` scope. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in. Wait the seconds in `Retry-After`. |

### `list_my_bookings`: My bookings

- Class: Read (`x-tool-class: read`)
- Needs sign-in: Yes. It acts for the signed-in guest, so it needs an access token with the `client` scope at either address.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in.
- Route: `GET /v1/bookings`

#### What it does

> The signed-in guest's bookings.

The route's own words (the server does the REST steps in them for you):

> List Bookings
>
> This guest's bookings, the latest first.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

None.

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

This route leaves out every field whose value is null.

The guest's bookings, latest first.

| Name | Type | Always present | Description |
|---|---|---|---|
| `bookings` | array of BookingResponse | yes | - |

`BookingResponse` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |
| `status` | string | yes | One of: `payment_pending`, `confirmed`, `completed`, `closed_unpaid`, `dates_taken`, `cancelled_by_guest`, `cancelled_by_owner`. |
| `status_text` | string | yes | - |
| `stage` | string | yes | One of: `pending`, `confirmed`, `completed`, `failed`, `cancelled`. |
| `who_acts_next` | string | yes | One of: `guest`, `operator`, `nobody`. |
| `next_step` | string | yes | - |
| `deadline` | string or null | when not null | - |
| `amount_due_cents` | integer or null | when not null | - |
| `payment_page` | PaymentPage or null | when not null | - |
| `allowed_actions` | array of string | yes | - |
| `check_back_at` | string or null | when not null | - |
| `flags` | array of string | yes | - |
| `summary` | BookingSummary | yes | - |
| `payments` | array of BookingPayment | yes | - |
| `requests` | array of RequestView | yes | - |
| `started_at` | string | yes | - |
| `rate` | string | yes | The rate booked. Its cancellation rule is in key_terms. One of: `non-refundable`, `refundable`. |
| `seller` | string | yes | - |
| `key_terms` | array of string | yes | - |
| `contact_email` | string | yes | - |
| `breakfast` | array of BreakfastMorning | yes | Each morning's serving time and dishes. Empty when none was ordered. |

Other types used here: [`PaymentPage`](#type-paymentpage), [`BookingSummary`](#type-bookingsummary), [`BookingPayment`](#type-bookingpayment), [`RequestView`](#type-requestview), [`BreakfastMorning`](#type-breakfastmorning).

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

The route documents none.

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the guest must sign in. The app opens sign-in. |
| 403 | `insufficient_scope` | The access token has no `client` scope. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in. Wait the seconds in `Retry-After`. |

### `get_booking`: Where a booking stands

- Class: Read (`x-tool-class: read`)
- Needs sign-in: Yes. It acts for the signed-in guest, so it needs an access token with the `client` scope at either address.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in.
- Route: `GET /v1/bookings/{booking_id}`

#### What it does

> A booking's status, the amount due, the deadline, and what the guest may do next.

The route's own words (the server does the REST steps in them for you):

> Get Booking
>
> One booking for this guest.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

This route leaves out every field whose value is null.

Where the booking stands. Dates stay free until a payment is recorded.

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |
| `status` | string | yes | One of: `payment_pending`, `confirmed`, `completed`, `closed_unpaid`, `dates_taken`, `cancelled_by_guest`, `cancelled_by_owner`. |
| `status_text` | string | yes | - |
| `stage` | string | yes | One of: `pending`, `confirmed`, `completed`, `failed`, `cancelled`. |
| `who_acts_next` | string | yes | One of: `guest`, `operator`, `nobody`. |
| `next_step` | string | yes | - |
| `deadline` | string or null | when not null | - |
| `amount_due_cents` | integer or null | when not null | - |
| `payment_page` | PaymentPage or null | when not null | - |
| `allowed_actions` | array of string | yes | - |
| `check_back_at` | string or null | when not null | - |
| `flags` | array of string | yes | - |
| `summary` | BookingSummary | yes | - |
| `payments` | array of BookingPayment | yes | - |
| `requests` | array of RequestView | yes | - |
| `started_at` | string | yes | - |
| `rate` | string | yes | The rate booked. Its cancellation rule is in key_terms. One of: `non-refundable`, `refundable`. |
| `seller` | string | yes | - |
| `key_terms` | array of string | yes | - |
| `contact_email` | string | yes | - |
| `breakfast` | array of BreakfastMorning | yes | Each morning's serving time and dishes. Empty when none was ordered. |

Types used here: [`PaymentPage`](#type-paymentpage), [`BookingSummary`](#type-bookingsummary), [`BookingPayment`](#type-bookingpayment), [`RequestView`](#type-requestview), [`BreakfastMorning`](#type-breakfastmorning).

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 404 | No booking with this id belongs to this guest. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the guest must sign in. The app opens sign-in. |
| 403 | `insufficient_scope` | The access token has no `client` scope. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in. Wait the seconds in `Retry-After`. |

### `cancel_booking`: Cancel a booking

- Class: Sensitive write (`x-tool-class: sensitive_write`)
- Needs sign-in: Yes. It acts for the signed-in guest, so it needs an access token with the `client` scope at either address.
- Side effects: cancels the booking and frees the room, or, at a refundable rate between its two refund days, records a cancellation request and keeps the booking. It queues one email and one notice. The booking's rate decides what is refunded. A cancelled booking can't be restored.
- Confirms before it runs: Yes. Before the call, the server asks the guest to confirm (MCP elicitation), where the app supports it. If the guest does not confirm, nothing changes. An app without elicitation relies on the hints.
- Hints: `readOnlyHint: false`, `destructiveHint: true`, `idempotentHint: false`, `openWorldHint: true`
- Rate limit: 60 requests a minute per sign-in.
- Route: `POST /v1/bookings/{booking_id}/cancel`

#### What it does

> Cancel a booking before check-in. The rate and the days left decide: a full refund, no refund (a non-refundable or late cancel), or, between the refund days, a cancellation request the owner answers while the booking stays as it is. A cancelled booking can't be restored. Ask the guest first, every time.

The route's own words (the server does the REST steps in them for you):

> Cancel Booking
>
> Cancel this booking before check-in. A non-refundable stay stays paid. A refundable stay follows its
> refund days: all back, a cancellation request the owner decides, or the deposit only. While that request
> is open, a cancel answers the booking as it stands and sends nothing, at any date.
>
> Tool class: Sensitive write. Call it only once the guest has clearly approved it, every time. Side effects: cancels the booking and frees the room, or, at a refundable rate between its two refund days, records a cancellation request and keeps the booking. It queues one email and one notice. The booking's rate decides what is refunded. A cancelled booking can't be restored.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

This route leaves out every field whose value is null.

Where the booking stands. Dates stay free until a payment is recorded.

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |
| `status` | string | yes | One of: `payment_pending`, `confirmed`, `completed`, `closed_unpaid`, `dates_taken`, `cancelled_by_guest`, `cancelled_by_owner`. |
| `status_text` | string | yes | - |
| `stage` | string | yes | One of: `pending`, `confirmed`, `completed`, `failed`, `cancelled`. |
| `who_acts_next` | string | yes | One of: `guest`, `operator`, `nobody`. |
| `next_step` | string | yes | - |
| `deadline` | string or null | when not null | - |
| `amount_due_cents` | integer or null | when not null | - |
| `payment_page` | PaymentPage or null | when not null | - |
| `allowed_actions` | array of string | yes | - |
| `check_back_at` | string or null | when not null | - |
| `flags` | array of string | yes | - |
| `summary` | BookingSummary | yes | - |
| `payments` | array of BookingPayment | yes | - |
| `requests` | array of RequestView | yes | - |
| `started_at` | string | yes | - |
| `rate` | string | yes | The rate booked. Its cancellation rule is in key_terms. One of: `non-refundable`, `refundable`. |
| `seller` | string | yes | - |
| `key_terms` | array of string | yes | - |
| `contact_email` | string | yes | - |
| `breakfast` | array of BreakfastMorning | yes | Each morning's serving time and dishes. Empty when none was ordered. |

Types used here: [`PaymentPage`](#type-paymentpage), [`BookingSummary`](#type-bookingsummary), [`BookingPayment`](#type-bookingpayment), [`RequestView`](#type-requestview), [`BreakfastMorning`](#type-breakfastmorning).

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 404 | No booking with this id belongs to this guest. | - |
| 409 | not_cancellable: this booking can no longer be cancelled. payment_processing: a payment waits for Stripe; cancel once it settles. | `not_cancellable`, `payment_processing` |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the guest must sign in. The app opens sign-in. |
| 403 | `insufficient_scope` | The access token has no `client` scope. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in. Wait the seconds in `Retry-After`. |

### `open_card_payment`: Card payment page

- Class: Sensitive write (`x-tool-class: sensitive_write`)
- Needs sign-in: Yes. It acts for the signed-in guest, so it needs an access token with the `client` scope at either address.
- Side effects: opens a card payment page for the booking and closes its earlier open page. It takes no payment by itself.
- Confirms before it runs: Yes. Before the call, the server asks the guest to confirm (MCP elicitation), where the app supports it. If the guest does not confirm, nothing changes. An app without elicitation relies on the hints.
- Hints: `readOnlyHint: false`, `destructiveHint: true`, `idempotentHint: false`, `openWorldHint: true`
- Rate limit: 60 requests a minute per sign-in.
- Route: `POST /v1/bookings/{booking_id}/card-payment`

#### What it does

> A secure card payment page for the booking. Give the guest the link; nothing is charged until they pay there. Ask the guest first.

The route's own words (the server does the REST steps in them for you):

> Open Card Payment
>
> Open the guest's card page, or refuse with one of contract section 3's answers.
>
> Tool class: Sensitive write. Call it only once the guest has clearly approved it, every time. Side effects: opens a card payment page for the booking and closes its earlier open page. It takes no payment by itself.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

This route leaves out every field whose value is null.

The page the guest pays. The route does not take the payment.

| Name | Type | Always present | Description |
|---|---|---|---|
| `payment_page` | PaymentPage | yes | The open card page. Absent unless the latest page is open and the booking is unpaid. |
| `amount_cents` | integer | yes | - |
| `lines` | array of CardPaymentLine | yes | - |

Types used here: [`PaymentPage`](#type-paymentpage).

`CardPaymentLine` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `name` | string | yes | - |
| `amount_cents` | integer | yes | - |

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 404 | Not Found | - |
| 409 | Conflict | - |
| 503 | Service Unavailable | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the guest must sign in. The app opens sign-in. |
| 403 | `insufficient_scope` | The access token has no `client` scope. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in. Wait the seconds in `Retry-After`. |

### `get_bank_transfer_details`: Bank transfer details

- Class: Read (`x-tool-class: read`)
- Needs sign-in: Yes. It acts for the signed-in guest, so it needs an access token with the `client` scope at either address.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in.
- Route: `GET /v1/bookings/{booking_id}/bank-transfer`

#### What it does

> The bank details and the payment reference for the booking, at the bank price.

The route's own words (the server does the REST steps in them for you):

> Bank Transfer
>
> The amount, reference and bank lines for this guest's bank booking.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

This route leaves out every field whose value is null.

What the guest needs to send a domestic transfer. The route holds nothing.

| Name | Type | Always present | Description |
|---|---|---|---|
| `amount_cents` | integer | yes | - |
| `currency` | string | yes | - |
| `reference` | string | yes | - |
| `deadline` | string or null | when not null | - |
| `details` | array of BankLine | yes | - |

`BankLine` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `label` | string | yes | - |
| `value` | string | yes | - |

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 404 | Not Found | - |
| 409 | Conflict | - |
| 503 | Service Unavailable | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the guest must sign in. The app opens sign-in. |
| 403 | `insufficient_scope` | The access token has no `client` scope. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in. Wait the seconds in `Retry-After`. |

### `report_bank_transfer_sent`: Bank transfer sent

- Class: Sensitive write (`x-tool-class: sensitive_write`)
- Needs sign-in: Yes. It acts for the signed-in guest, so it needs an access token with the `client` scope at either address.
- Side effects: records that the guest says the transfer was sent. It holds no room and queues one owner notice.
- Confirms before it runs: Yes. Before the call, the server asks the guest to confirm (MCP elicitation), where the app supports it. If the guest does not confirm, nothing changes. An app without elicitation relies on the hints.
- Hints: `readOnlyHint: false`, `destructiveHint: true`, `idempotentHint: false`, `openWorldHint: true`
- Rate limit: 60 requests a minute per sign-in.
- Route: `POST /v1/bookings/{booking_id}/bank-transfer-sent`

#### What it does

> Tell the owner the guest sent the bank transfer. Nothing moves on until the owner confirms it arrived. Ask the guest first.

The route's own words (the server does the REST steps in them for you):

> Report Bank Transfer
>
> Record the guest's report. The rows stay due, and a repeat queues nothing.
>
> Tool class: Sensitive write. Call it only once the guest has clearly approved it, every time. Side effects: records that the guest says the transfer was sent. It holds no room and queues one owner notice.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

This route leaves out every field whose value is null.

Where the booking stands. Dates stay free until a payment is recorded.

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |
| `status` | string | yes | One of: `payment_pending`, `confirmed`, `completed`, `closed_unpaid`, `dates_taken`, `cancelled_by_guest`, `cancelled_by_owner`. |
| `status_text` | string | yes | - |
| `stage` | string | yes | One of: `pending`, `confirmed`, `completed`, `failed`, `cancelled`. |
| `who_acts_next` | string | yes | One of: `guest`, `operator`, `nobody`. |
| `next_step` | string | yes | - |
| `deadline` | string or null | when not null | - |
| `amount_due_cents` | integer or null | when not null | - |
| `payment_page` | PaymentPage or null | when not null | - |
| `allowed_actions` | array of string | yes | - |
| `check_back_at` | string or null | when not null | - |
| `flags` | array of string | yes | - |
| `summary` | BookingSummary | yes | - |
| `payments` | array of BookingPayment | yes | - |
| `requests` | array of RequestView | yes | - |
| `started_at` | string | yes | - |
| `rate` | string | yes | The rate booked. Its cancellation rule is in key_terms. One of: `non-refundable`, `refundable`. |
| `seller` | string | yes | - |
| `key_terms` | array of string | yes | - |
| `contact_email` | string | yes | - |
| `breakfast` | array of BreakfastMorning | yes | Each morning's serving time and dishes. Empty when none was ordered. |

Types used here: [`PaymentPage`](#type-paymentpage), [`BookingSummary`](#type-bookingsummary), [`BookingPayment`](#type-bookingpayment), [`RequestView`](#type-requestview), [`BreakfastMorning`](#type-breakfastmorning).

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 404 | Not Found | - |
| 409 | Conflict | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the guest must sign in. The app opens sign-in. |
| 403 | `insufficient_scope` | The access token has no `client` scope. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in. Wait the seconds in `Retry-After`. |

### `send_request`: Send a request

- Class: Sensitive write (`x-tool-class: sensitive_write`)
- Needs sign-in: Yes. It acts for the signed-in guest, so it needs an access token with the `client` scope at either address.
- Side effects: records the guest's request. It queues one email and one notice. The booking stays as it is.
- Confirms before it runs: Yes. Before the call, the server asks the guest to confirm (MCP elicitation), where the app supports it. If the guest does not confirm, nothing changes. An app without elicitation relies on the hints.
- Hints: `readOnlyHint: false`, `destructiveHint: true`, `idempotentHint: false`, `openWorldHint: true`
- Rate limit: 60 requests a minute per sign-in.
- Route: `POST /v1/bookings/{booking_id}/requests`

#### What it does

> Send the guest's change or other request to the owner, who answers it. The booking stays as it is. Ask the guest first.

The route's own words (the server does the REST steps in them for you):

> Create Request
>
> Record a change or other request. The booking's room, dates and payments stay as they are.
>
> Tool class: Sensitive write. Call it only once the guest has clearly approved it, every time. Side effects: records the guest's request. It queues one email and one notice. The booking stays as it is.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |
| `kind` | string | yes | "change" or "other". To cancel, use cancel_booking. One of: `change`, `other`. |
| `text` | string | yes | - |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

This route leaves out every field whose value is null.

Where the booking stands. Dates stay free until a payment is recorded.

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |
| `status` | string | yes | One of: `payment_pending`, `confirmed`, `completed`, `closed_unpaid`, `dates_taken`, `cancelled_by_guest`, `cancelled_by_owner`. |
| `status_text` | string | yes | - |
| `stage` | string | yes | One of: `pending`, `confirmed`, `completed`, `failed`, `cancelled`. |
| `who_acts_next` | string | yes | One of: `guest`, `operator`, `nobody`. |
| `next_step` | string | yes | - |
| `deadline` | string or null | when not null | - |
| `amount_due_cents` | integer or null | when not null | - |
| `payment_page` | PaymentPage or null | when not null | - |
| `allowed_actions` | array of string | yes | - |
| `check_back_at` | string or null | when not null | - |
| `flags` | array of string | yes | - |
| `summary` | BookingSummary | yes | - |
| `payments` | array of BookingPayment | yes | - |
| `requests` | array of RequestView | yes | - |
| `started_at` | string | yes | - |
| `rate` | string | yes | The rate booked. Its cancellation rule is in key_terms. One of: `non-refundable`, `refundable`. |
| `seller` | string | yes | - |
| `key_terms` | array of string | yes | - |
| `contact_email` | string | yes | - |
| `breakfast` | array of BreakfastMorning | yes | Each morning's serving time and dishes. Empty when none was ordered. |

Types used here: [`PaymentPage`](#type-paymentpage), [`BookingSummary`](#type-bookingsummary), [`BookingPayment`](#type-bookingpayment), [`RequestView`](#type-requestview), [`BreakfastMorning`](#type-breakfastmorning).

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 400 | The kind is not change or other, or the text is blank. | - |
| 404 | No booking with this id belongs to this guest. | - |
| 409 | This booking is not open for a request. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the guest must sign in. The app opens sign-in. |
| 403 | `insufficient_scope` | The access token has no `client` scope. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in. Wait the seconds in `Retry-After`. |

### `get_request`: A request

- Class: Read (`x-tool-class: read`)
- Needs sign-in: Yes. It acts for the signed-in guest, so it needs an access token with the `client` scope at either address.
- Side effects: None
- Confirms before it runs: No. The server runs the call at once. The app may still ask the guest, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in.
- Route: `GET /v1/bookings/{booking_id}/requests/{request_id}`

#### What it does

> One request of a booking: its text, its state and the owner's answer.

The route's own words (the server does the REST steps in them for you):

> Get Request
>
> One request on this guest's booking. It changes nothing.
>
> Tool class: Read. Side effects: none. It only retrieves information: it books nothing, holds no dates, takes no payment and sends nothing.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |
| `request_id` | string | yes | - |

#### Output

The tool result's text is this JSON object, and `structuredContent` holds the same object.

This route leaves out every field whose value is null.

One request, open until the operator answers.

| Name | Type | Always present | Description |
|---|---|---|---|
| `request_id` | string | yes | - |
| `booking_id` | string | yes | - |
| `kind` | string | yes | One of: `change`, `other`, `cancellation`. |
| `text` | string | yes | - |
| `state` | string | yes | One of: `open`, `accepted`, `declined`. |
| `answer` | string or null | when not null | - |
| `answered_at` | string or null | when not null | - |

#### Errors

Route errors: a tool result with `isError: true`, whose text is the route's message and next step (or `The call failed (<status>).` when the error has neither).

| REST status | Meaning | REST code, for reference |
|---|---|---|
| 404 | No request with this id belongs to this booking. | - |

MCP errors: HTTP answers from the server, before the tool runs.

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the guest must sign in. The app opens sign-in. |
| 403 | `insufficient_scope` | The access token has no `client` scope. |
| 401 | `invalid_token` | The access token is not valid here: it ended, was revoked, or is for another server. |
| 429 | `rate_limited` | Over the limit: 60 requests a minute per sign-in. Wait the seconds in `Retry-After`. |

## Types

The objects that more than one tool uses. Each tool links here instead of repeating them.

<a id="type-nearestdates"></a>

### `NearestDates`

Used by: `check_availability`, `find_nearest_dates`, `get_quote`.

| Name | Type | Always present | Description |
|---|---|---|---|
| `earlier` | array of string | yes | - |
| `later` | array of string | yes | - |
| `earlier_on_request` | array of string | depends on the tool | - |
| `later_on_request` | array of string | depends on the tool | - |

<a id="type-paymentpage"></a>

### `PaymentPage`

Used by: `start_booking`, `get_booking`, `cancel_booking`, `open_card_payment`, `report_bank_transfer_sent`, `send_request`.

| Name | Type | Always present | Description |
|---|---|---|---|
| `url` | string | yes | - |
| `expires_at` | string | yes | - |

<a id="type-bookingsummary"></a>

### `BookingSummary`

Used by: `start_booking`, `get_booking`, `cancel_booking`, `report_bank_transfer_sent`, `send_request`.

| Name | Type | Always present | Description |
|---|---|---|---|
| `property_id` | string | yes | - |
| `accommodation_id` | string | yes | - |
| `room_id` | string or null | when not null | - |
| `start_date` | string | yes | - |
| `check_out_date` | string | yes | - |
| `nights` | integer | yes | - |
| `guests` | integer | yes | - |
| `pets` | integer | yes | - |
| `payment_method` | string | yes | One of: `credit card`, `bank`. |
| `currency` | string | yes | - |
| `lines` | array of QuoteLine | yes | - |
| `total_cents` | integer | yes | - |
| `deposit_cents` | integer | yes | - |

<a id="type-bookingpayment"></a>

### `BookingPayment`

Used by: `start_booking`, `get_booking`, `cancel_booking`, `report_bank_transfer_sent`, `send_request`.

| Name | Type | Always present | Description |
|---|---|---|---|
| `payment_id` | string | yes | - |
| `label` | string | yes | - |
| `amount_cents` | integer | yes | - |
| `status` | string | yes | One of: `due`, `paid`, `refund_due`, `refunded`. |
| `paid_at` | string or null | when not null | - |

<a id="type-requestview"></a>

### `RequestView`

Used by: `start_booking`, `get_booking`, `cancel_booking`, `report_bank_transfer_sent`, `send_request`.

| Name | Type | Always present | Description |
|---|---|---|---|
| `request_id` | string | yes | - |
| `booking_id` | string | yes | - |
| `kind` | string | yes | One of: `change`, `other`, `cancellation`. |
| `text` | string | yes | - |
| `state` | string | yes | One of: `open`, `accepted`, `declined`. |
| `answer` | string or null | when not null | - |
| `answered_at` | string or null | when not null | - |

<a id="type-breakfastmorning"></a>

### `BreakfastMorning`

Used by: `start_booking`, `get_booking`, `cancel_booking`, `report_bank_transfer_sent`, `send_request`.

| Name | Type | Always present | Description |
|---|---|---|---|
| `morning` | string | yes | - |
| `serving_time` | string | yes | - |
| `dishes` | array of BreakfastDishOrdered | yes | - |
