# Allegra Yacht Charters 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.allegra-yacht.com/mcp`: Streamable HTTP. Browse without sign-in. A tool that acts for a client answers HTTP 401 when it is called, and the app opens sign-in then.
- `https://api.allegra-yacht.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.allegra-yacht.com/.well-known/mcp/server-card.json. Sign-in and agent registration: https://api.allegra-yacht.com/auth.md.

## Sign-in

An app signs the client in with OAuth 2.1 and PKCE (S256). On this server's sign-in page, the client 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 client: their record, bookings and payments.

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

| Sign-in setting | Value |
|---|---|
| Access token lifetime | 1 hour |
| Sign-in lifetime: then refresh stops, and the client 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 client, 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 client has clearly approved it, every time.

## Calling a tool

- The server calls the tool's route itself and acts for the signed-in client. 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 |
|---|---|---|---|
| `get_boat` | The boat | Read | No |
| `get_itinerary` | Home base, route and seasons | Read | No |
| `get_destinations` | Other destinations | Read | No |
| `get_charter_rules` | Charter rules | Read | No |
| `get_policies` | Policies | 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 client | 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` |
| `get_payment` | A payment | Read | 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` |
| `cancel_booking` | Cancel a booking | Sensitive write | Yes, scope `client` |
| `request_change` | Ask for a change | Sensitive write | Yes, scope `client` |
| `request_cancellation` | Ask to cancel | Sensitive write | Yes, scope `client` |

### `get_boat`: The boat

- 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 client, 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/boat`

#### What it does

> The yacht: cabins, crew, what is included, amenities and photos.

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

> Get Boat Info
>
> The yacht: specifications, cabins, crew, amenities, included items, water toys and photos.
>
> 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 yacht: specifications, cabins, crew, amenities, what is included, photos.

| Name | Type | Always present | Description |
|---|---|---|---|
| `boat_id` | string | yes | Identifier of this yacht in the API. |
| `name` | string | yes | - |
| `model` | string | yes | - |
| `builder` | string | yes | - |
| `year` | integer | yes | Year the yacht is marketed as. |
| `length` | string | yes | - |
| `beam` | string | yes | - |
| `draft` | string | yes | - |
| `description` | string | yes | A short description to read to the client. |
| `cabins` | string | yes | - |
| `crew` | string | yes | - |
| `max_guests` | integer | yes | Most guests aboard a charter. |
| `amenities` | array of string | yes | - |
| `included` | array of string | yes | What the charter price includes. |
| `not_included` | array of string | yes | What the charter price does not include. |
| `water_toys` | array of string | yes | - |
| `photos` | array of Photo | yes | - |
| `seller` | string | yes | The company the client books with and pays: the yacht's owner company. |
| `contact_email` | string | yes | Where the client can write to the owner's team. |

`Photo` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `url` | string | yes | Absolute https link to the photo. |
| `caption` | string | yes | What the photo shows. |

#### 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` | 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_itinerary`: Home base, route and seasons

- 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 client, 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/itinerary`

#### What it does

> Where charters start, the usual route, and the season dates.

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

> Get Itinerary
>
> Home base, standard route, seasons and the off-season.
>
> 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.

Where the yacht is based and sails, and its seasons.

| Name | Type | Always present | Description |
|---|---|---|---|
| `home_base` | string | yes | Where every charter starts and ends, unless relocated. |
| `standard_route` | string | yes | - |
| `seasons` | array of Season | yes | - |
| `off_season` | OffSeason | yes | - |
| `utc_offset` | string | yes | Local time of the home base as an offset from UTC, e.g. "-04:00". |

Types used here: [`OffSeason`](#type-offseason).

`Season` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `name` | string | yes | - |
| `start` | string | yes | First day of the season every year, as "MM-DD". |
| `end` | string | yes | Last day of the season every year, as "MM-DD". |
| `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).

The route documents none.

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_destinations`: Other destinations

- 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 client, 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/destinations`

#### What it does

> Places a charter can go besides the home waters, with the relocation charge for each.

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

> Get Destinations
>
> Cruising areas, each with its relocation charge (bank-transfer and card price) and restrictions.
>
> 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.

Every cruising area, with its relocation charge and restrictions.

| Name | Type | Always present | Description |
|---|---|---|---|
| `destinations` | array of DestinationResponse | yes | - |

`DestinationResponse` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `id` | string | yes | Use this value as `destination` when asking for a quote. |
| `name` | string | yes | - |
| `home` | boolean | yes | True for the home cruising area, which has no relocation charge. |
| `relocation_charge_bank_cents` | integer | yes | Relocation charge when paying by bank transfer, in US cents. |
| `relocation_charge_card_cents` | integer | yes | Relocation charge when paying by credit card, in US cents. |
| `restrictions` | array of string | yes | Rules that apply to this destination, in plain English. |

#### 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` | 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_charter_rules`: Charter 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 client, 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/charter-rules`

#### What it does

> How many nights a charter lasts, the start days, and the gap between charters.

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

> Get Charter Rules
>
> Charter length, start days, check-in and check-out times, the gap between charters, how far ahead.
>
> 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.

Charter length, start days, check-in and check-out, the gap between charters, how far ahead.

| Name | Type | Always present | Description |
|---|---|---|---|
| `min_nights` | integer | yes | - |
| `max_nights` | integer | yes | - |
| `typical_nights` | integer | yes | - |
| `start_days` | string | yes | - |
| `check_in_time` | string | yes | Local time, "HH:MM". |
| `check_out_time` | string | yes | Local time, "HH:MM". |
| `utc_offset` | string | yes | Local time as an offset from UTC. |
| `preferred_gap_hours` | integer | yes | Preferred free time between charters; dates closer to another charter are "available on request". |
| `booking_window_years` | integer | yes | How far ahead a charter can start. |
| `max_guests` | integer | yes | - |
| `off_season` | OffSeason | yes | - |
| `summary` | array of string | yes | The same rules in plain English, ready to read to a client. |

Types used here: [`OffSeason`](#type-offseason).

#### 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` | 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 client, 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/policies`

#### What it does

> The payment schedule, the deadlines, and the cancellation and refund terms.

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

> Get Policies
>
> Prices by payment method, payment schedule, contract, cancellation and refunds, and deadlines.
>
> 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.

Prices by payment method, payment schedule, contract, cancellation and refunds, deadlines.

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

Types used here: [`Policy`](#type-policy).

#### 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` | 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 client, 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/questions`

#### What it does

> Answers to the questions clients ask most.

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

> Get Questions
>
> Answers to common questions, written and approved by the owner.
>
> 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.

Answers to common questions, written and approved by the owner.

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

`Question` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `question` | string | yes | - |
| `answer` | 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).

The route documents none.

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 client, 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 start date and a number of nights are free, on request, or taken.

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

> Get Availability
>
> Whether the yacht is free for these dates: "available", "available on request" or "unavailable".
>
> Unavailable answers include the nearest open dates. Every answer says what to do next.
>
> 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 |
|---|---|---|---|
| `start_date` | string (date) | yes | Check-in day, YYYY-MM-DD. Today or later, within the booking window (see get_charter_rules). |
| `nights` | integer | yes | Number of nights; see get_charter_rules for the allowed range. |

#### Output

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

Whether the yacht is free for a charter, why, and what to do next.

| Name | Type | Always present | Description |
|---|---|---|---|
| `start_date` | string | yes | Check-in day, YYYY-MM-DD. |
| `nights` | integer | yes | - |
| `check_out_date` | string | yes | Check-out day, YYYY-MM-DD. |
| `status` | string | yes | "available"; "available on request" (free, but close to another charter, so the owner must confirm); or "unavailable". |
| `reason` | string | yes | Why, in plain English. Never says who or what holds the dates. |
| `next_step` | string | yes | What the client can do next, in plain English. |
| `nearest_open_dates` | NearestDates or null | yes | Only when the dates are unavailable. |

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 client, 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 client asked for.

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

> Get Nearest Dates
>
> The nearest open start dates for the same number of nights, before and after the requested one.
>
> 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 |
|---|---|---|---|
| `start_date` | string (date) | yes | Check-in day, YYYY-MM-DD. Today or later, within the booking window (see get_charter_rules). |
| `nights` | integer | yes | Number of nights; see get_charter_rules for the allowed range. |

#### Output

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

The nearest open start dates around a requested one.

| Name | Type | Always present | Description |
|---|---|---|---|
| `start_date` | string | yes | - |
| `nights` | integer | yes | - |
| `nearest_open_dates` | NearestDates | yes | Other start dates for the same number of nights, nearest first, all inside the booking window. |

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 client, 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 price for the payment method.

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

> Get Open Dates
>
> Every check-in day in a range at which the yacht is free for these nights, each with its total price
> in US cents for the chosen payment method.
>
> For questions like "what's open in January?": one call instead of a check and a quote per day. Days
> that are "available on request" are included and marked. Free days the price rules refuse for the
> chosen dining plan or destination (holiday charters) are left out, and `notes` says why. Then get
> the itemized quote for the day the client picks.
>
> 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 |
|---|---|---|---|
| `from` | string (date) | yes | First check-in day to look at, YYYY-MM-DD. Today or later. |
| `to` | string (date) | yes | Last check-in day to look at, YYYY-MM-DD: on or after `from`, at most 92 days after it, and within the booking window (see get_charter_rules). |
| `nights` | integer | yes | Number of nights; see get_charter_rules for the allowed range. |
| `guests` | integer | yes | Number of guests; see get_boat for the most allowed. |
| `payment_method` | string | yes | How the client will pay: "credit card" or "bank" (bank transfer). Prices differ; the method applies to every payment of a booking. One of: `credit card`, `bank`. |
| `dining_plan` | string or null | no | Dining plan id or name (see get_boat); default: the yacht's standard plan. |
| `destination` | string or null | no | Destination id or name (see get_destinations); default: the home waters. |

#### Output

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

Every open start date in a range, each with its total price for these inputs.

| Name | Type | Always present | Description |
|---|---|---|---|
| `from` | string | yes | First start date searched, YYYY-MM-DD. |
| `to` | string | yes | Last start date searched, YYYY-MM-DD. |
| `nights` | integer | yes | - |
| `guests` | integer | yes | - |
| `payment_method` | string | yes | "credit card" or "bank" (bank transfer). |
| `dining_plan` | string | yes | Dining plan id used for the prices. |
| `destination` | string | yes | Destination id used for the prices. |
| `currency` | string | yes | Always USD. |
| `open_dates` | array of OpenDate | yes | The open start dates, earliest first; empty if there are none. |
| `notes` | array of string | yes | Why free dates were left out (holiday rules), in plain English. |
| `next_step` | string | yes | What to do next, in plain English. |

`OpenDate` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `start_date` | string | yes | Check-in day, YYYY-MM-DD. |
| `check_out_date` | string | yes | Check-out day, YYYY-MM-DD. |
| `status` | string | yes | "available", or "available on request" (free, but close to another charter, so the owner must confirm). |
| `total_cents` | integer | yes | Total price in US cents for the chosen payment method, as a quote gives it. |
| `holiday` | string or null | yes | Name of the holiday price applied, if any. |

#### 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 client, 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 dates, guests and a payment method, with the payment schedule and the key terms. A booking needs the quote's total, which the client approved.

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

> Get Quote
>
> An itemized price in US cents for the chosen payment method, with the payment schedule if booked today.
>
> Dates that are not free still get a quote, flagged, with the nearest open dates. A quote is not a
> reservation and does not hold the dates. Every quote names the seller, the company the client would
> book with and pay, and repeats the key terms of a booking, such as cancellation and refunds.
>
> 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 |
|---|---|---|---|
| `start_date` | string (date) | yes | Check-in day, YYYY-MM-DD. Today or later, within the booking window (see get_charter_rules). |
| `nights` | integer | yes | Number of nights; see get_charter_rules for the allowed range. |
| `guests` | integer | yes | Number of guests; see get_boat for the most allowed. |
| `payment_method` | string | yes | How the client will pay: "credit card" or "bank" (bank transfer). Prices differ; the method applies to every payment of a booking. One of: `credit card`, `bank`. |
| `dining_plan` | string or null | no | Dining plan id or name (see get_boat); default: the yacht's standard plan. |
| `destination` | string or null | no | Destination id or name (see get_destinations); default: the home waters. |

#### Output

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

An itemized price in US cents for the chosen payment method, with its payment schedule.

| Name | Type | Always present | Description |
|---|---|---|---|
| `start_date` | string | yes | Check-in day, YYYY-MM-DD. |
| `nights` | integer | yes | - |
| `check_out_date` | string | yes | Check-out day, YYYY-MM-DD. |
| `guests` | integer | yes | - |
| `dining_plan` | string | yes | Dining plan id used for the price. |
| `destination` | string | yes | Destination id used for the price. |
| `payment_method` | string | yes | "credit card" or "bank" (bank transfer). |
| `currency` | string | yes | Always USD. |
| `holiday` | string or null | yes | Name of the holiday price applied, if any. |
| `lines` | array of PriceLine | yes | The price, line by line; the `amount_cents` add up to `total_cents`. |
| `total_cents` | integer | yes | Total price in US cents for the chosen payment method. |
| `discount_note` | string or null | yes | For bank transfer: the bank transfer discount against the card price. |
| `payment_schedule` | array of Installment | yes | When each payment is due, if booked today. |
| `availability` | QuoteAvailability | yes | - |
| `nearest_open_dates` | NearestDates or null | yes | Only when the dates are unavailable. |
| `next_step` | string | yes | What the client can do next, in plain English. |
| `terms` | string | yes | What this quote is and is not. |
| `seller` | string | yes | The company the client would book with and pay: the yacht's owner company. |
| `key_terms` | array of Policy | yes | The terms that come with a booking (for example the payment schedule, the contract, and cancellation and refunds), each as get_policies gives it, so the client sees them with the price before deciding. |

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

`PriceLine` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `kind` | string | yes | "base", "holiday", "dining" or "relocation". |
| `label` | string | yes | What the line is, in plain English. |
| `amount_cents` | integer | yes | US cents at the chosen payment method's price; negative for a discount. |

`Installment` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `label` | string | yes | e.g. "Deposit (25%)". |
| `amount_cents` | integer | yes | US cents. |
| `due` | string | yes | When it is due, in plain English, e.g. "at booking". |
| `due_date` | string or null | yes | YYYY-MM-DD, when the payment has a fixed date. |

`QuoteAvailability` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `status` | string | yes | "available"; "available on request" (free, but close to another charter, so the owner must confirm); or "unavailable". |
| `reason` | 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`. |

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

- Class: Read (`x-tool-class: read`)
- Needs sign-in: Yes. It acts for the signed-in client, 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 client, 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 client's name, email and phone.

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

> Get Me
>
> The client 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 client 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 client 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 client, so it needs an access token with the `client` scope at either address.
- Side effects: stores a booking for the client from the quote they approved, unpaid: its dates are not held until the first payment arrives, and it closes by itself if no payment arrives in time. The client and the owner are emailed.
- Confirms before it runs: Yes. Before the call, the server asks the client to confirm (MCP elicitation), where the app supports it. If the client 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 dates of a quote the client approved, at that quote's total. The dates are held only once the first payment arrives. Ask the client first.

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

> Start Booking
>
> Turn the quote the client approved into a booking.
>
> Send the quote's own inputs and its `total_cents` as `approved_total_cents`, once the
> client has seen the price, the payment schedule, the seller and the key terms, and agreed.
> The booking starts unpaid: the dates are not held until the first payment arrives (the
> first payment for the dates wins). Needs an `Idempotency-Key` header.
>
> Tool class: Sensitive write. Call it only once the client has clearly approved it, every time. Side effects: stores a booking for the client from the quote they approved, unpaid: its dates are not held until the first payment arrives, and it closes by itself if no payment arrives in time. The client and the owner are emailed.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `start_date` | string (date) | yes | Check-in day, YYYY-MM-DD, as quoted. |
| `nights` | integer | yes | As quoted. |
| `guests` | integer | yes | As quoted. |
| `payment_method` | string | yes | "credit card" or "bank" (bank transfer), as quoted. It applies to every payment of the booking. One of: `credit card`, `bank`. |
| `dining_plan` | string or null | no | As quoted; leave out for the default plan. |
| `destination` | string or null | no | As quoted; leave out for the home cruising area. |
| `approved_total_cents` | integer | yes | The quote's `total_cents`, which the client saw and approved. If the price has changed since, the booking is refused with the new price. |

#### Output

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

A booking: where it stands, what happens next, who acts and by when.

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | Starts with `bk_`. |
| `status` | string | yes | `deposit_pending`, `full_payment_pending`, `contract_being_prepared`, `contract_sent`, `second_payment_pending`, `final_payment_pending`, `fully_paid`, `completed`; or it ended: `cancelled_by_client`, `cancelled_by_owner`, `client_unreachable`, `dates_taken`, `expired`. |
| `status_text` | string | yes | The status in plain English. |
| `stage` | string | yes | "pending" (not paid: the dates are not held), "reserved" (paid, dates held, contract not yet signed), "confirmed" (contract signed by both sides), "completed", "cancelled" or "failed". |
| `who_acts_next` | string | yes | "client", "owner" or "nobody". |
| `next_step` | string | yes | What happens next, in plain English, to pass on to the client. |
| `deadline` | string or null | yes | When the current step is due: ISO 8601, UTC. |
| `amount_due_cents` | integer or null | yes | The payment due now, in US cents, if any. |
| `allowed_actions` | array of string | yes | What can be called for this booking now, as "METHOD path". |
| `check_back_at` | string or null | yes | When to look at the booking again: ISO 8601, UTC. None once nothing more happens. |
| `flags` | array of string | yes | `change_request_open`, `cancellation_request_open`, `deadline_missed` (the owner decides what happens), `refund_due`. |
| `summary` | BookingSummary | yes | - |
| `payments` | array of BookingPayment | yes | The payment schedule, with each payment's status. |
| `requests` | array of BookingRequest | yes | The client's change and cancellation requests, oldest first, with the owner's answers. |
| `started_at` | string | yes | When the booking started: ISO 8601, UTC. |
| `seller` | string | yes | The company the client books with and pays: the yacht's owner company. |
| `key_terms` | array of Policy | yes | The terms that come with the booking, as quoted. |
| `contact_email` | string | yes | Where the client can write to the owner's team. |

Types used here: [`BookingSummary`](#type-bookingsummary), [`BookingPayment`](#type-bookingpayment), [`BookingRequest`](#type-bookingrequest), [`Policy`](#type-policy).

#### 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. | - |
| 409 | The booking can't start: the price changed (`price_changed`), the dates need the owner (`dates_on_request`) or are taken (`dates_unavailable`), or the client already has a booking for those dates (`booking_exists`); or the `Idempotency-Key` was reused or is still running. | `price_changed`, `dates_on_request`, `dates_unavailable`, `booking_exists` |

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

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the client 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 client, 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 client, 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 client's bookings, newest first.

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

> List Bookings
>
> The client's bookings, the latest first, each as `GET /v1/bookings/{booking_id}` gives it.
>
> 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 client's bookings, the latest first.

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

`BookingResponse` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | Starts with `bk_`. |
| `status` | string | yes | `deposit_pending`, `full_payment_pending`, `contract_being_prepared`, `contract_sent`, `second_payment_pending`, `final_payment_pending`, `fully_paid`, `completed`; or it ended: `cancelled_by_client`, `cancelled_by_owner`, `client_unreachable`, `dates_taken`, `expired`. |
| `status_text` | string | yes | The status in plain English. |
| `stage` | string | yes | "pending" (not paid: the dates are not held), "reserved" (paid, dates held, contract not yet signed), "confirmed" (contract signed by both sides), "completed", "cancelled" or "failed". |
| `who_acts_next` | string | yes | "client", "owner" or "nobody". |
| `next_step` | string | yes | What happens next, in plain English, to pass on to the client. |
| `deadline` | string or null | yes | When the current step is due: ISO 8601, UTC. |
| `amount_due_cents` | integer or null | yes | The payment due now, in US cents, if any. |
| `allowed_actions` | array of string | yes | What can be called for this booking now, as "METHOD path". |
| `check_back_at` | string or null | yes | When to look at the booking again: ISO 8601, UTC. None once nothing more happens. |
| `flags` | array of string | yes | `change_request_open`, `cancellation_request_open`, `deadline_missed` (the owner decides what happens), `refund_due`. |
| `summary` | BookingSummary | yes | - |
| `payments` | array of BookingPayment | yes | The payment schedule, with each payment's status. |
| `requests` | array of BookingRequest | yes | The client's change and cancellation requests, oldest first, with the owner's answers. |
| `started_at` | string | yes | When the booking started: ISO 8601, UTC. |
| `seller` | string | yes | The company the client books with and pays: the yacht's owner company. |
| `key_terms` | array of Policy | yes | The terms that come with the booking, as quoted. |
| `contact_email` | string | yes | Where the client can write to the owner's team. |

Other types used here: [`BookingSummary`](#type-bookingsummary), [`BookingPayment`](#type-bookingpayment), [`BookingRequest`](#type-bookingrequest), [`Policy`](#type-policy).

#### 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 client 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 client, 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 client, 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, who acts next, the deadline, the amount due, and what the client may do.

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

> Get Booking
>
> Where the booking stands: its status, who acts next and by when, what is due, what can be
> done now (`allowed_actions`), and when to look again (`check_back_at`).
>
> Ask again at `check_back_at`, or sooner after the client does something. The client is also
> emailed at every change of status.
>
> 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 | The booking's id, from starting it or from list_my_bookings. |

#### Output

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

A booking: where it stands, what happens next, who acts and by when.

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | Starts with `bk_`. |
| `status` | string | yes | `deposit_pending`, `full_payment_pending`, `contract_being_prepared`, `contract_sent`, `second_payment_pending`, `final_payment_pending`, `fully_paid`, `completed`; or it ended: `cancelled_by_client`, `cancelled_by_owner`, `client_unreachable`, `dates_taken`, `expired`. |
| `status_text` | string | yes | The status in plain English. |
| `stage` | string | yes | "pending" (not paid: the dates are not held), "reserved" (paid, dates held, contract not yet signed), "confirmed" (contract signed by both sides), "completed", "cancelled" or "failed". |
| `who_acts_next` | string | yes | "client", "owner" or "nobody". |
| `next_step` | string | yes | What happens next, in plain English, to pass on to the client. |
| `deadline` | string or null | yes | When the current step is due: ISO 8601, UTC. |
| `amount_due_cents` | integer or null | yes | The payment due now, in US cents, if any. |
| `allowed_actions` | array of string | yes | What can be called for this booking now, as "METHOD path". |
| `check_back_at` | string or null | yes | When to look at the booking again: ISO 8601, UTC. None once nothing more happens. |
| `flags` | array of string | yes | `change_request_open`, `cancellation_request_open`, `deadline_missed` (the owner decides what happens), `refund_due`. |
| `summary` | BookingSummary | yes | - |
| `payments` | array of BookingPayment | yes | The payment schedule, with each payment's status. |
| `requests` | array of BookingRequest | yes | The client's change and cancellation requests, oldest first, with the owner's answers. |
| `started_at` | string | yes | When the booking started: ISO 8601, UTC. |
| `seller` | string | yes | The company the client books with and pays: the yacht's owner company. |
| `key_terms` | array of Policy | yes | The terms that come with the booking, as quoted. |
| `contact_email` | string | yes | Where the client can write to the owner's team. |

Types used here: [`BookingSummary`](#type-bookingsummary), [`BookingPayment`](#type-bookingpayment), [`BookingRequest`](#type-bookingrequest), [`Policy`](#type-policy).

#### 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. | - |
| 404 | The client has no such booking (`booking_not_found`). | `booking_not_found` |

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

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the client 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_payment`: A payment

- Class: Read (`x-tool-class: read`)
- Needs sign-in: Yes. It acts for the signed-in client, 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 client, from the hints.
- Hints: `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`
- Rate limit: 60 requests a minute per sign-in.
- Route: `GET /v1/payments/{payment_id}`

#### What it does

> One payment of a booking: its amount, method, state, when it was paid, and any refund.

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

> Get Payment
>
> One payment of the client's bookings: its amount, method and status (`due`, `processing`,
> `paid`, `refund_due`, `refunded` or `cancelled`), and when it was paid.
>
> 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 |
|---|---|---|---|
| `payment_id` | string | yes | The payment's id, from its booking. |

#### Output

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

One payment of a booking.

| Name | Type | Always present | Description |
|---|---|---|---|
| `payment_id` | string | yes | Starts with `pay_`. |
| `booking_id` | string | yes | - |
| `label` | string | yes | e.g. "Deposit (25%)". |
| `amount_cents` | integer | yes | US cents. |
| `currency` | string | yes | Always USD. |
| `payment_method` | string | yes | "credit card" or "bank" (bank transfer): the booking's method. |
| `status` | string | yes | "due", "processing" (the bank is still confirming a card payment), "paid", "refund_due", "refunded" or "cancelled". |
| `paid_at` | string or null | yes | When it was received: ISO 8601, UTC. |
| `refund_cents` | integer or null | yes | What is due back, or was refunded, in US cents. |

#### 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. | - |
| 404 | The client has no such payment (`payment_not_found`). | `payment_not_found` |

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

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the client 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 client, so it needs an access token with the `client` scope at either address.
- Side effects: makes a Stripe payment page for the payment due now, open for 1 hour, and closes the booking's previous page, if one is open. Nothing is charged until the client pays on the page.
- Confirms before it runs: Yes. Before the call, the server asks the client to confirm (MCP elicitation), where the app supports it. If the client 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 payment due now, open for an hour. Give the client the link; nothing is charged until they pay there. Ask the client first.

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

> Card Payment
>
> A Stripe payment page for the payment due now, for a booking paid by card.
>
> Give the client the page's link: they pay on Stripe's page (the card details never pass
> through this API), then return to you. The page is open for 1 hour; asking again closes it
> and makes a new one. Once paid, the booking moves on by itself: look at it again a few
> minutes later. Needs an `Idempotency-Key` header.
>
> Tool class: Sensitive write. Call it only once the client has clearly approved it, every time. Side effects: makes a Stripe payment page for the payment due now, open for 1 hour, and closes the booking's previous page, if one is open. Nothing is charged until the client pays on the page.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `booking_id` | string | yes | The booking's id, from starting it or from list_my_bookings. |

#### Output

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

A Stripe payment page for the payment due: give the client its link.

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |
| `payment_id` | string | yes | Starts with `pay_`. |
| `label` | string | yes | e.g. "Deposit (25%)". |
| `amount_cents` | integer | yes | US cents, at the card price. |
| `currency` | string | yes | Always USD. |
| `payment_url` | string | yes | Stripe's payment page, for the client to open and pay on. |
| `expires_at` | string | yes | When the page closes: ISO 8601, UTC. |
| `next_step` | string | yes | What to do now, in plain English. |
| `seller` | string | yes | The company the client pays: the yacht's owner company. |
| `key_terms` | array of Policy | yes | The terms that come with the booking, as quoted. |

Types used here: [`Policy`](#type-policy).

#### 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. | - |
| 404 | The client has no such booking (`booking_not_found`). | `booking_not_found` |
| 409 | No card payment now: the booking is paid by bank transfer (`wrong_payment_method`), nothing is due (`no_payment_due`), the last payment is still being processed (`payment_processing`), or the open page was just paid (`payment_received`); or the `Idempotency-Key` was reused or is still running. | `wrong_payment_method`, `no_payment_due`, `payment_processing`, `payment_received` |
| 503 | Card payments are unavailable right now (`payment_unavailable`, `service_unavailable`): try again in a few minutes. | `payment_unavailable`, `service_unavailable` |

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

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the client 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 client, 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 client, 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 payment due now, at the bank price.

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

> Bank Transfer
>
> The bank details for the payment due, for a booking paid by bank transfer: the amount,
> the reference to quote, and the details of each account. Once the client has sent it,
> say so with `POST /v1/bookings/{booking_id}/bank-transfer-sent`. The dates are held once
> the owner confirms the money arrived.
>
> 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 | The booking's id, from starting it or from list_my_bookings. |

#### Output

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

What the client needs to pay the payment due by bank transfer.

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | - |
| `payment_id` | string | yes | Starts with `pay_`. |
| `label` | string | yes | e.g. "Deposit (25%)". |
| `amount_cents` | integer | yes | US cents, at the bank-transfer price. |
| `currency` | string | yes | Always USD. |
| `reference` | string | yes | What the client quotes with the transfer, so the owner can match it. |
| `deadline` | string or null | yes | When it is due: ISO 8601, UTC. |
| `details` | array of BankDetails | yes | Each account set the client can pay into: send to either one. |
| `next_step` | string | yes | What to do now, in plain English. |

`BankDetails` fields:

| Name | Type | Always present | Description |
|---|---|---|---|
| `id` | string | yes | - |
| `title` | string | yes | Which account set this is, e.g. "From a bank in the United States". |
| `lines` | array of BankLine | 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. | - |
| 404 | The client has no such booking (`booking_not_found`). | `booking_not_found` |
| 409 | No bank transfer now: the booking is paid by card (`wrong_payment_method`), or nothing is due (`no_payment_due`). | `wrong_payment_method`, `no_payment_due` |
| 503 | Card payments are unavailable right now (`payment_unavailable`, `service_unavailable`): try again in a few minutes. | `payment_unavailable`, `service_unavailable` |

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

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the client 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 client, so it needs an access token with the `client` scope at either address.
- Side effects: records that the client sent the payment due by bank transfer, and emails the owner, who confirms when it arrives. Nothing is held or moves on until then.
- Confirms before it runs: Yes. Before the call, the server asks the client to confirm (MCP elicitation), where the app supports it. If the client 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 client sent the payment due by bank transfer. Nothing moves on until the owner confirms it arrived. Ask the client first.

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

> Bank Transfer Sent
>
> Say that the client sent the payment due by bank transfer. The owner is emailed and
> confirms when it arrives; until then nothing is held or moves on. Needs an
> `Idempotency-Key` header.
>
> Tool class: Sensitive write. Call it only once the client has clearly approved it, every time. Side effects: records that the client sent the payment due by bank transfer, and emails the owner, who confirms when it arrives. Nothing is held or moves on until then.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `booking_id` | string | yes | The booking's id, from starting it or from list_my_bookings. |

#### Output

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

A booking: where it stands, what happens next, who acts and by when.

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | Starts with `bk_`. |
| `status` | string | yes | `deposit_pending`, `full_payment_pending`, `contract_being_prepared`, `contract_sent`, `second_payment_pending`, `final_payment_pending`, `fully_paid`, `completed`; or it ended: `cancelled_by_client`, `cancelled_by_owner`, `client_unreachable`, `dates_taken`, `expired`. |
| `status_text` | string | yes | The status in plain English. |
| `stage` | string | yes | "pending" (not paid: the dates are not held), "reserved" (paid, dates held, contract not yet signed), "confirmed" (contract signed by both sides), "completed", "cancelled" or "failed". |
| `who_acts_next` | string | yes | "client", "owner" or "nobody". |
| `next_step` | string | yes | What happens next, in plain English, to pass on to the client. |
| `deadline` | string or null | yes | When the current step is due: ISO 8601, UTC. |
| `amount_due_cents` | integer or null | yes | The payment due now, in US cents, if any. |
| `allowed_actions` | array of string | yes | What can be called for this booking now, as "METHOD path". |
| `check_back_at` | string or null | yes | When to look at the booking again: ISO 8601, UTC. None once nothing more happens. |
| `flags` | array of string | yes | `change_request_open`, `cancellation_request_open`, `deadline_missed` (the owner decides what happens), `refund_due`. |
| `summary` | BookingSummary | yes | - |
| `payments` | array of BookingPayment | yes | The payment schedule, with each payment's status. |
| `requests` | array of BookingRequest | yes | The client's change and cancellation requests, oldest first, with the owner's answers. |
| `started_at` | string | yes | When the booking started: ISO 8601, UTC. |
| `seller` | string | yes | The company the client books with and pays: the yacht's owner company. |
| `key_terms` | array of Policy | yes | The terms that come with the booking, as quoted. |
| `contact_email` | string | yes | Where the client can write to the owner's team. |

Types used here: [`BookingSummary`](#type-bookingsummary), [`BookingPayment`](#type-bookingpayment), [`BookingRequest`](#type-bookingrequest), [`Policy`](#type-policy).

#### 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. | - |
| 404 | The client has no such booking (`booking_not_found`). | `booking_not_found` |
| 409 | No bank transfer now: the booking is paid by card (`wrong_payment_method`), or nothing is due (`no_payment_due`). | `wrong_payment_method`, `no_payment_due` |

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

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the client 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 client, so it needs an access token with the `client` scope at either address.
- Side effects: cancels the booking for good: the dates go back on sale, and everything paid is refunded by hand, the way it was paid. A card payment goes back less the payment processor's fees, a bank transfer in full. The client and the owner are emailed.
- Confirms before it runs: Yes. Before the call, the server asks the client to confirm (MCP elicitation), where the app supports it. If the client 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 the contract is signed, for good. The owner refunds by hand: a card payment less the card processor's fees, a bank transfer in full. Ask the client first, every time.

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

> Cancel Booking
>
> Cancel the booking, before its contract is signed by both sides. Everything paid is
> refunded: a card payment less the payment processor's fees. The dates go back on sale. It
> can't be undone, so only once the client has clearly approved it. Once the contract is
> signed, send a cancellation request instead. Needs an `Idempotency-Key` header.
>
> Tool class: Sensitive write. Call it only once the client has clearly approved it, every time. Side effects: cancels the booking for good: the dates go back on sale, and everything paid is refunded by hand, the way it was paid. A card payment goes back less the payment processor's fees, a bank transfer in full. The client and the owner are emailed.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `booking_id` | string | yes | The booking's id, from starting it or from list_my_bookings. |

#### Output

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

A booking: where it stands, what happens next, who acts and by when.

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | Starts with `bk_`. |
| `status` | string | yes | `deposit_pending`, `full_payment_pending`, `contract_being_prepared`, `contract_sent`, `second_payment_pending`, `final_payment_pending`, `fully_paid`, `completed`; or it ended: `cancelled_by_client`, `cancelled_by_owner`, `client_unreachable`, `dates_taken`, `expired`. |
| `status_text` | string | yes | The status in plain English. |
| `stage` | string | yes | "pending" (not paid: the dates are not held), "reserved" (paid, dates held, contract not yet signed), "confirmed" (contract signed by both sides), "completed", "cancelled" or "failed". |
| `who_acts_next` | string | yes | "client", "owner" or "nobody". |
| `next_step` | string | yes | What happens next, in plain English, to pass on to the client. |
| `deadline` | string or null | yes | When the current step is due: ISO 8601, UTC. |
| `amount_due_cents` | integer or null | yes | The payment due now, in US cents, if any. |
| `allowed_actions` | array of string | yes | What can be called for this booking now, as "METHOD path". |
| `check_back_at` | string or null | yes | When to look at the booking again: ISO 8601, UTC. None once nothing more happens. |
| `flags` | array of string | yes | `change_request_open`, `cancellation_request_open`, `deadline_missed` (the owner decides what happens), `refund_due`. |
| `summary` | BookingSummary | yes | - |
| `payments` | array of BookingPayment | yes | The payment schedule, with each payment's status. |
| `requests` | array of BookingRequest | yes | The client's change and cancellation requests, oldest first, with the owner's answers. |
| `started_at` | string | yes | When the booking started: ISO 8601, UTC. |
| `seller` | string | yes | The company the client books with and pays: the yacht's owner company. |
| `key_terms` | array of Policy | yes | The terms that come with the booking, as quoted. |
| `contact_email` | string | yes | Where the client can write to the owner's team. |

Types used here: [`BookingSummary`](#type-bookingsummary), [`BookingPayment`](#type-bookingpayment), [`BookingRequest`](#type-bookingrequest), [`Policy`](#type-policy).

#### 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. | - |
| 404 | The client has no such booking (`booking_not_found`). | `booking_not_found` |
| 409 | Not now: the contract is signed (`contract_signed`: send a cancellation request instead), or not yet (`not_signed_yet`: the client can cancel instead), the booking has ended (`booking_ended`), or a request of that kind is waiting for the owner (`request_open`); or the `Idempotency-Key` was reused or is still running. | `contract_signed`, `not_signed_yet`, `booking_ended`, `request_open` |

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

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the client 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`. |

### `request_change`: Ask for a change

- Class: Sensitive write (`x-tool-class: sensitive_write`)
- Needs sign-in: Yes. It acts for the signed-in client, so it needs an access token with the `client` scope at either address.
- Side effects: sends the client's request to the owner, who answers it: the answer shows on the booking and is emailed to the client.
- Confirms before it runs: Yes. Before the call, the server asks the client to confirm (MCP elicitation), where the app supports it. If the client 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}/change-requests`

#### What it does

> Send the client's change request to the owner, who answers it. Ask the client first.

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

> Change Request
>
> Ask the owner for a change: other dates, guests, dining plan or payment method. The
> owner answers on the booking (`requests`) and by email; an accepted change is made by the
> owner's team. Needs an `Idempotency-Key` header.
>
> Tool class: Sensitive write. Call it only once the client has clearly approved it, every time. Side effects: sends the client's request to the owner, who answers it: the answer shows on the booking and is emailed to the client.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `booking_id` | string | yes | The booking's id, from starting it or from list_my_bookings. |
| `text` | string | yes | What the client asks, in their words: 1 to 2000 characters. |

#### Output

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

A booking: where it stands, what happens next, who acts and by when.

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | Starts with `bk_`. |
| `status` | string | yes | `deposit_pending`, `full_payment_pending`, `contract_being_prepared`, `contract_sent`, `second_payment_pending`, `final_payment_pending`, `fully_paid`, `completed`; or it ended: `cancelled_by_client`, `cancelled_by_owner`, `client_unreachable`, `dates_taken`, `expired`. |
| `status_text` | string | yes | The status in plain English. |
| `stage` | string | yes | "pending" (not paid: the dates are not held), "reserved" (paid, dates held, contract not yet signed), "confirmed" (contract signed by both sides), "completed", "cancelled" or "failed". |
| `who_acts_next` | string | yes | "client", "owner" or "nobody". |
| `next_step` | string | yes | What happens next, in plain English, to pass on to the client. |
| `deadline` | string or null | yes | When the current step is due: ISO 8601, UTC. |
| `amount_due_cents` | integer or null | yes | The payment due now, in US cents, if any. |
| `allowed_actions` | array of string | yes | What can be called for this booking now, as "METHOD path". |
| `check_back_at` | string or null | yes | When to look at the booking again: ISO 8601, UTC. None once nothing more happens. |
| `flags` | array of string | yes | `change_request_open`, `cancellation_request_open`, `deadline_missed` (the owner decides what happens), `refund_due`. |
| `summary` | BookingSummary | yes | - |
| `payments` | array of BookingPayment | yes | The payment schedule, with each payment's status. |
| `requests` | array of BookingRequest | yes | The client's change and cancellation requests, oldest first, with the owner's answers. |
| `started_at` | string | yes | When the booking started: ISO 8601, UTC. |
| `seller` | string | yes | The company the client books with and pays: the yacht's owner company. |
| `key_terms` | array of Policy | yes | The terms that come with the booking, as quoted. |
| `contact_email` | string | yes | Where the client can write to the owner's team. |

Types used here: [`BookingSummary`](#type-bookingsummary), [`BookingPayment`](#type-bookingpayment), [`BookingRequest`](#type-bookingrequest), [`Policy`](#type-policy).

#### 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. | `invalid_text` |
| 404 | The client has no such booking (`booking_not_found`). | `booking_not_found` |
| 409 | Not now: the contract is signed (`contract_signed`: send a cancellation request instead), or not yet (`not_signed_yet`: the client can cancel instead), the booking has ended (`booking_ended`), or a request of that kind is waiting for the owner (`request_open`); or the `Idempotency-Key` was reused or is still running. | `contract_signed`, `not_signed_yet`, `booking_ended`, `request_open` |

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

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the client 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`. |

### `request_cancellation`: Ask to cancel

- Class: Sensitive write (`x-tool-class: sensitive_write`)
- Needs sign-in: Yes. It acts for the signed-in client, so it needs an access token with the `client` scope at either address.
- Side effects: sends the client's request to the owner, who answers it: the answer shows on the booking and is emailed to the client.
- Confirms before it runs: Yes. Before the call, the server asks the client to confirm (MCP elicitation), where the app supports it. If the client 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}/cancellation-requests`

#### What it does

> After the contract is signed: ask the owner to cancel. The owner decides. Ask the client first.

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

> Cancellation Request
>
> Ask the owner to cancel, once the contract is signed: the owner decides, and any refund
> follows the contract. The answer shows on the booking (`requests`) and comes by email.
> Before signing, cancel instead. Needs an `Idempotency-Key` header.
>
> Tool class: Sensitive write. Call it only once the client has clearly approved it, every time. Side effects: sends the client's request to the owner, who answers it: the answer shows on the booking and is emailed to the client.

#### Inputs

| Name | Type | Required | Description |
|---|---|---|---|
| `booking_id` | string | yes | The booking's id, from starting it or from list_my_bookings. |
| `text` | string | yes | What the client asks, in their words: 1 to 2000 characters. |

#### Output

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

A booking: where it stands, what happens next, who acts and by when.

| Name | Type | Always present | Description |
|---|---|---|---|
| `booking_id` | string | yes | Starts with `bk_`. |
| `status` | string | yes | `deposit_pending`, `full_payment_pending`, `contract_being_prepared`, `contract_sent`, `second_payment_pending`, `final_payment_pending`, `fully_paid`, `completed`; or it ended: `cancelled_by_client`, `cancelled_by_owner`, `client_unreachable`, `dates_taken`, `expired`. |
| `status_text` | string | yes | The status in plain English. |
| `stage` | string | yes | "pending" (not paid: the dates are not held), "reserved" (paid, dates held, contract not yet signed), "confirmed" (contract signed by both sides), "completed", "cancelled" or "failed". |
| `who_acts_next` | string | yes | "client", "owner" or "nobody". |
| `next_step` | string | yes | What happens next, in plain English, to pass on to the client. |
| `deadline` | string or null | yes | When the current step is due: ISO 8601, UTC. |
| `amount_due_cents` | integer or null | yes | The payment due now, in US cents, if any. |
| `allowed_actions` | array of string | yes | What can be called for this booking now, as "METHOD path". |
| `check_back_at` | string or null | yes | When to look at the booking again: ISO 8601, UTC. None once nothing more happens. |
| `flags` | array of string | yes | `change_request_open`, `cancellation_request_open`, `deadline_missed` (the owner decides what happens), `refund_due`. |
| `summary` | BookingSummary | yes | - |
| `payments` | array of BookingPayment | yes | The payment schedule, with each payment's status. |
| `requests` | array of BookingRequest | yes | The client's change and cancellation requests, oldest first, with the owner's answers. |
| `started_at` | string | yes | When the booking started: ISO 8601, UTC. |
| `seller` | string | yes | The company the client books with and pays: the yacht's owner company. |
| `key_terms` | array of Policy | yes | The terms that come with the booking, as quoted. |
| `contact_email` | string | yes | Where the client can write to the owner's team. |

Types used here: [`BookingSummary`](#type-bookingsummary), [`BookingPayment`](#type-bookingpayment), [`BookingRequest`](#type-bookingrequest), [`Policy`](#type-policy).

#### 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. | `invalid_text` |
| 404 | The client has no such booking (`booking_not_found`). | `booking_not_found` |
| 409 | Not now: the contract is signed (`contract_signed`: send a cancellation request instead), or not yet (`not_signed_yet`: the client can cancel instead), the booking has ended (`booking_ended`), or a request of that kind is waiting for the owner (`request_open`); or the `Idempotency-Key` was reused or is still running. | `contract_signed`, `not_signed_yet`, `booking_ended`, `request_open` |

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

| HTTP status | Code | Meaning |
|---|---|---|
| 401 | `unauthorized` | No access token: the client 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-offseason"></a>

### `OffSeason`

Used by: `get_itinerary`, `get_charter_rules`.

| Name | Type | Always present | Description |
|---|---|---|---|
| `start` | string | yes | First day with no charters every year, as "MM-DD". |
| `end` | string | yes | Last day with no charters every year, as "MM-DD". |
| `description` | string | yes | - |

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

### `Policy`

Used by: `get_policies`, `get_quote`, `start_booking`, `get_booking`, `open_card_payment`, `report_bank_transfer_sent`, `cancel_booking`, `request_change`, `request_cancellation`.

| Name | Type | Always present | Description |
|---|---|---|---|
| `id` | string | yes | - |
| `title` | string | yes | - |
| `text` | string | yes | - |

<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 | Up to 3 fully available start dates before the requested one. |
| `later` | array of string | yes | Up to 3 fully available start dates after the requested one. |
| `earlier_on_request` | array of string | yes | "Available on request" start dates nearer than the first earlier available one. |
| `later_on_request` | array of string | yes | "Available on request" start dates nearer than the first later available one. |

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

### `BookingSummary`

Used by: `start_booking`, `get_booking`, `report_bank_transfer_sent`, `cancel_booking`, `request_change`, `request_cancellation`.

| Name | Type | Always present | Description |
|---|---|---|---|
| `start_date` | string | yes | Check-in day, YYYY-MM-DD. |
| `check_out_date` | string | yes | Check-out day, YYYY-MM-DD. |
| `nights` | integer | yes | - |
| `guests` | integer | yes | - |
| `dining_plan` | string | yes | - |
| `destination` | string | yes | - |
| `payment_method` | string | yes | "credit card" or "bank" (bank transfer), for every payment. |
| `currency` | string | yes | Always USD. |
| `holiday` | string or null | yes | Name of the holiday price applied, if any. |
| `lines` | array of PriceLine | yes | The price, line by line, as quoted when the booking started. |
| `total_cents` | integer | yes | Total price in US cents, at the booking's payment method. |

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

### `BookingPayment`

Used by: `start_booking`, `get_booking`, `report_bank_transfer_sent`, `cancel_booking`, `request_change`, `request_cancellation`.

| Name | Type | Always present | Description |
|---|---|---|---|
| `payment_id` | string | yes | Starts with `pay_`. |
| `label` | string | yes | e.g. "Deposit (25%)". |
| `amount_cents` | integer | yes | US cents. |
| `status` | string | yes | "due", "processing" (a card payment the bank is still confirming), "paid", "refund_due", "refunded" or "cancelled". |
| `paid_at` | string or null | yes | When it was received: ISO 8601, UTC. |
| `refund_cents` | integer or null | yes | What is due back, or was refunded, in US cents. |

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

### `BookingRequest`

Used by: `start_booking`, `get_booking`, `report_bank_transfer_sent`, `cancel_booking`, `request_change`, `request_cancellation`.

| Name | Type | Always present | Description |
|---|---|---|---|
| `request_id` | string | yes | Starts with `rq_`. |
| `kind` | string | yes | "change" or "cancellation". |
| `text` | string | yes | What the client asked, in their words. |
| `sent_at` | string | yes | ISO 8601, UTC. |
| `answer` | string or null | yes | The owner's answer; none while waiting. |
| `answered_at` | string or null | yes | ISO 8601, UTC. |
| `accepted` | boolean or null | yes | Whether the owner accepted it; none while waiting, or if the booking ended first. |
