Charter Boats

Search 14,000+ charter boats with live prices, plus marinas, anchorages, routes and itineraries. Eleven read-only tools, no authentication.

Hosted MCP Server

npx add-mcp 'https://charter.boats/mcp'

Installs into Claude Code, Codex, Cursor and more

Documentation

Same in API v1.0 and v1.1

The Charter Boats MCP server lets Claude, ChatGPT, Cursor, and any MCP-compatible AI assistant search boats, locations, POIs, routes, trips, and content -- with rich HTML widgets for visual boat and destination cards.

Endpoint: https://charter.boats/mcp Install / quickstart page: open https://charter.boats/mcp in a browser. Transport: Streamable HTTP (JSON-RPC 2.0). Auth: None. The server passes only the caller's IP on to the API, so an API key sent to /mcp has no effect — MCP calls are neither attributed to an account nor affiliate-tagged. See also Rate limits. Spec: MCP Apps 2026-01-26.

Deployment

The server is a Cloudflare Worker routed at charter.boats/mcp. It proxies tool calls to the Charter Boats AI API (https://charter.boats/api/ai/*) and serves two HTML widgets as MCP App resources.

AI assistant → https://charter.boats/mcp (CF Worker) → charter.boats/api/ai/*

A single /mcp URL handles three things:

  • GET with Accept: text/html → install / quickstart page (HTML)
  • GET with Accept: application/json → server info JSON
  • POST → MCP JSON-RPC

Tools

Eleven read-only tools. Each returns the underlying API response as structuredContent (which the widgets render) plus a short text summary for the model. A search that finds nothing still returns the API's zero-results block — no_results (searched, why, try_next) and note — in structuredContent.

Search

ToolDescriptionWidget
search_boatsBoats by location, type, dates, capacity, budget. Returns up to 8 with prices, images, booking links.✓ boats
search_locationsMarinas, harbours and anchorages three ways — see below. Up to 10, each with its photo, boat count and cheapest day rate, on a numbered map.✓ locations
search_poisRestaurants, fuel, groceries, etc. near a destination. Up to 10.—
search_routesSailing passages between destinations. Up to 5.—
search_tripsMulti-day curated itineraries. Up to 5.—
search_contentArticles, guides, FAQs (semantic search); type: "api" searches these API docs. Up to 5.—

search_locations answers three different questions, picked by which inputs you send:

  • By name — q (min 2 characters): "Lefkada", "Dubrovnik".
  • By popularity in an area — region (a sailing region as guests say it: Dalmatia, the Ionian, the Cyclades…), country, city, optionally type (marina, harbour, anchorage, bay, mooring, spot — the same words the results carry back, spot being an unclassified stop) and month (1-12, default the current month). Ranked by sort: popularity (default — observed vessel traffic for that month), boats (charter fleet size) or rating.
  • By reach from a place — from (a location id or slug from an earlier result) plus within_nm (10, 20, 35, 55 or 100; default 35): the places boats were recorded sailing to from there, most-travelled first, with estimated distance and hours at 6 knots.

See Search Locations for the response of each mode.

Detail

ToolDescription
get_boat_detailsFull specs, 365-day availability + pricing ranges, bookable check-in/check-out slots, required/optional fees, active discounts, cancellation policy, check-in/out times.
get_boat_standoutsWhat is better or worse about one boat than similar boats for a week — each pro and con with how it compares; anything unlisted is ordinary for boats like it. compare_by picks similar boats by price (default), guests or length; cutoff_pct and fallback set how much is named. See What Stands Out.
get_poi_detailsDescription, opening hours, address, contact, nearby marinas, special offers. POIs carry no rating or review count.
get_location_detailsDescription, amenities, contact, boat count and cheapest day rate, plus tracked-AIS insight: how busy it is month by month (against its own peak, never another place), how boats use it (share of overnight visits, typical day-stop length, what hour it fills), whether it is a hidden gem, where boats sail to from it (most-travelled first, each with its share of the tracked trips and an estimated sailing time at 6 knots), and the nearest bookable base.
get_trip_detailsDay-by-day stops, distances, activities, highlights, notes.

Full input schemas are exposed via tools/list -- view them in MCP Inspector by connecting to https://charter.boats/mcp.

Prompt presets

The server registers three prompts surfaced as one-click starters in supporting clients:

  • plan-sailing-trip -- destination + optional guests/dates/budget
  • find-charter-boat -- location + optional type/guests/dates
  • explore-destination -- single destination, surfaces marinas + POIs + routes

UI widgets

Two HTML widgets are served as MCP App resources:

WidgetURIUsed by
Boatsui://widget/boats-{hash}.htmlsearch_boats
Locationsui://widget/locations-{hash}.htmlsearch_locations

The {hash} is a hash of that widget's own HTML, so the URI changes if and only if the widget does. ChatGPT caches MCP resources by URI with no expiry — a fixed URI means a redeployed widget is never re-read, however many times it ships — and OpenAI's guidance is to give the template a new URI when its HTML, JS or CSS changes. Read the current values from resources/list; never hard-code one. A read of a previously published URI (including the original unhashed ui://widget/boats.html) still returns the current widget rather than an error, so a host holding a stale URI degrades to old-metadata-but-correct-markup instead of a broken card.

Both widgets:

  • Use the text/html;profile=mcp-app MIME type.
  • Declare their image CSP twice over: _meta.ui.csp.resourceDomains (the MCP Apps standard, which Claude reads) and _meta["openai/widgetCSP"].resource_domains (the snake_case compatibility key, which is the only one ChatGPT reads — without it ChatGPT applies a locked-down default and every boat photo renders as a broken image). _meta.ui.prefersBorder / openai/widgetPrefersBorder and _meta.ui.resourceUri / openai/outputTemplate are paired the same way.
  • List exact origins, never wildcards — ChatGPT rejects a *.example.com entry and one bad entry discards the whole list. The allowed set is charter.boats, media.charter.boats, our storage bucket's direct origin, and wsrv.nl. Boat and location photos are served from media.charter.boats (listed explicitly, since a CSP host source matches that host alone and charter.boats does not cover its subdomains), and a boat photo not yet copied to our storage resizes through wsrv. The locations widget also draws a static map of its results from charter.boats/api/ai/map, pins numbered like the cards below it — the Mapbox token stays on our server, and search_pois has no widget — its image_url values are passed through as stored (some on our storage bucket, many at a third-party site's own address: a review site, a venue's website, a local guide), and nothing renders them inside a widget.
  • Implement the full MCP Apps handshake: sandbox-resource-ready → ui/initialize (with protocolVersion, appInfo, appCapabilities) → ui/notifications/initialized → render on ui/notifications/tool-result.
  • Report height via ui/notifications/size-changed, measured from body.scrollHeight / #app (the document element returns 0 inside Claude's sandbox).
  • Route link clicks through ui/open-link since sandboxed iframes block target="_blank".
  • Respect host theme: explicit theme: 'dark' | 'light' from host-context-changed overrides the prefers-color-scheme CSS fallback.

Install

For end users: open https://charter.boats/mcp in any browser -- the page has copy-paste install steps for Claude.ai, Claude Desktop, ChatGPT, Cursor, and MCP Inspector.

Quick reference

Claude.ai / Claude Desktop: Settings → Connectors → Add custom connector → https://charter.boats/mcp (Pro/Max/Team/Enterprise required).

ChatGPT: Settings → Apps → Create app → MCP Server → https://charter.boats/mcp. Widget rendering requires the ChatGPT Apps program; Developer mode shows tool calls as text only.

Cursor: add to ~/.cursor/mcp.json:

{
  "mcpServers": {
    "charter-boats": { "url": "https://charter.boats/mcp" }
  }
}

MCP Inspector: npx @modelcontextprotocol/inspector → Streamable HTTP → https://charter.boats/mcp.

Rate limits

Tool calls are subject to the no-key /api/ai/* rate limit, counted on the IP that calls /mcp — the server forwards that address, so each caller is limited on its own, not pooled with every other MCP user. Claude and ChatGPT, calling from Anthropic's and OpenAI's published address ranges, are counted per platform instead of per IP (see Rate limits). It forwards no key. A limited call surfaces as a tool error (API 429) whose message links to the same search on charter.boats.

Differences from the Custom GPT

Both integrations call the same /api/ai/* endpoints but expose them differently:

FeatureCustom GPT (Actions)MCP Server
ProtocolOpenAPI 3.1Model Context Protocol (Streamable HTTP)
Rich UINoYes -- boats + locations widgets
TransportHTTPSJSON-RPC over HTTP
Session stateGPT conversation IDStateless per request
Rate limitUp to 30 / 10 min per OpenAI user, plus the daily per-IP limitPer calling IP — see Rate limits
HostsChatGPT onlyClaude, ChatGPT Apps, Cursor, Continue, any MCP client