WebMCP & MCP API
Three read-only yacht-charter tools over remote MCP, plus a human-confirmed browser-only reservation hold, with or without an account.
document.modelContext · POST /api/mcp · search → details → quote · browser-only hold
On this page
Overview
Browser WebMCP registers tools on document.modelContext. Remote MCP exposes onlysearch_charters, get_charter_details and quote_charter over Streamable HTTP at POST /api/mcp.
Read tools make no business-state changes; request telemetry is still recorded. Browser book_charter supports guest booking without registration. After an in-tab confirmation and human verification, it creates an unpaid PENDING hold and never charges the customer.
browser: document.modelContext
→ WebMCP adapter
├─ three read-only tools
└─ book_charter (guest or account)
→ confirmation dialog
→ PENDING hold
→ hosted checkout
remote: POST /api/mcp
→ MCP adapter
└─ three read-only tools
shared agent-tools core
├─ availability
├─ price engine
└─ request telemetryImplementation notes
Charter search is not enough to make a reservation: the exact dates must be available, the stay must satisfy the yacht's rules, and mandatory fees paid at the port must be shown separately from the online charter price. The tools reuse the website's availability and pricing code instead of extracting a price from page text or maintaining a second booking engine.
- Initial version: four browser tools called dedicated server actions.
- Protocol review: browser results were reduced to one JSON value rather than an MCP content envelope. Search responses were limited to six rows, and registration uses document.modelContext with AbortController cleanup when the provider unmounts.
- Current version: browser and remote transports share the validated read core. Consequential booking is deliberately browser-only and protected by server-verified human checks, quote validation and abuse limits. Guest booking does not require an account.
- Booking recovery: the server revalidates the exact accepted quote inside the booking flow. If payment startup fails after the order is saved, the tool returns the existing reservation's recovery link rather than asking the agent to book again.
Every core call rechecks the feature flag and requires a positively identified NaCzarter flagship host. Unknown hosts, lookup failures, admin previews and white-label storefronts fail closed.
Quick start
Browser WebMCP
Open naczarter.pl/en in a compatible browser, then check whether the registration API is available.
Checking this browser
Looking for document.modelContext locally.
Local feature detection only. No network request or reservation is made.
typeof document.modelContext?.registerTool === "function"// Chrome 152: run in the console of this tab.
const mc = document.modelContext;
if (!mc) throw new Error("WebMCP is unavailable in this browser");
const tools = await mc.getTools();
const search = tools.find(tool => tool.name === "search_charters");
if (!search) throw new Error("NaCzarter tools are not registered in this tab");
const result = await mc.executeTool(
search,
JSON.stringify({ city: "Giżycko", minPeople: 6 })
);
console.log(result);API presence alone does not prove that registration succeeded; check getTools(). This read-only example uses the JSON-string argument accepted by Chrome 152's imperative API. WebMCP is experimental; the current draft and browser releases can differ. See the Chrome API documentation.
Remote MCP
Configure https://naczarter.pl/api/mcp as a read-only Streamable HTTP endpoint. It exposes three public read tools and no reservation or payment mutation. Every POST must use Content-Type: application/json.
curl -s https://naczarter.pl/api/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": {},
"clientInfo": { "name": "docs-example", "version": "1.0" }
}
}'curl -s https://naczarter.pl/api/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2025-11-25' \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list"
}'curl -s https://naczarter.pl/api/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2025-11-25' \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "search_charters",
"arguments": {
"city": "Giżycko",
"minPeople": 6
}
}
}'tools/list is the runtime contract: it returns required fields, enums, limits, annotations and the exact three-tool remote catalogue. Supported protocol revisions are 2025-11-25 and 2025-06-18. The WebMCP manifest is descriptive, not runtime discovery.
Tools
This is a compact summary rendered from the shared AGENT_TOOL_CONTRACT. Use tools/list for the exact remote inputSchema, including required fields, enums and bounds.
Remote MCP exposes the first three read-only tools only. Browser WebMCP exposes all four tools. Calls to book_charter open a confirmation dialog for guests and account holders before any reservation is created.
Scroll the table horizontally to inspect every column.
| Tool | Input and result | Business effect |
|---|---|---|
search_charters | Find a compact set of suitable yachts. Input: City, dates, category, capacity, maximum daily price and page. Up to six yachts with stable slugs, location, capacity, a starting daily price and range availability. | No business-state changes; request telemetry is recorded. |
get_charter_details | Check whether one yacht fits the trip. Input: A yacht slug returned by search_charters. Model, year, berths, dimensions, engine, port, stay limits and licence or skipper options. | No business-state changes; request telemetry is recorded. |
quote_charter | Obtain the source-of-truth price and availability. Input: Yacht slug, exact dates and an optional one-way return. Online charter price, mandatory on-site fees, total, currency and a server-revalidated acceptedQuote snapshot for the yacht, dates, one-way choice and current terms. | No business-state changes; request telemetry is recorded. |
book_charter | Hold the selected dates pending human payment. Input: Yacht, dates, contact details and explicit acceptance of the linked booking terms. No account required; the in-tab dialog supplies separate human verification. A provisional reservation, hosted checkout URL and private statusUrl; a checkout failure returns a bookingUrl recovery handoff. | Creates an unpaid temporary hold; it does not make a payment. |
Browser annotations mark discovery tools read-only and book_charter consequential. Catalogue-backed output is marked untrusted where applicable; server validation remains authoritative.
Browser vs remote
Scroll the table horizontally to compare both transports.
| Boundary | Browser | Remote MCP |
|---|---|---|
| Discovery | Runtime page registration | Client-configured endpoint |
| Entry point | document.modelContext | JSON-RPC over POST |
| Tools | Three reads plus book_charter for guests and account holders | search_charters, get_charter_details and quote_charter only |
| Result | One JSON-serialisable value | content plus structuredContent |
| Authentication | No account required; verified matching sessions attach bookings to the account | None; the transport is read-only |
| Consent | NaCzarter in-tab dialog and human verification before a hold | Not applicable; no mutation is exposed |
| Context | Current locale and browser session | Stateless; search uses pl, quote and details use en, result URLs use pl |
| Payment | Customer opens hosted checkout after the hold | Not available through remote MCP |
Browser booking
book_charter is not available over remote MCP. A compatible browser registers it for guests and signed-in users. No account required: every booking still needs explicit confirmation and human verification in the current tab.
- 1. Quote. Call
quote_charterfor the selected yacht, dates and one-way option. It returns online charter price, mandatory on-site fees, currency, terms revision and a server-revalidatedacceptedQuotesnapshot. - 2. Identify. Supply the customer's name, e-mail and phone. A signed-in session with a matching verified e-mail attaches the booking to that account. Otherwise the server creates a guest reservation with a random access token; the supplied e-mail alone never authorizes account attachment in this flow.
- 3. Confirm. NaCzarter opens its own in-tab dialog with the fresh quote, customer details, linked terms and a required consent checkbox. A human-verification proof from that dialog is bound to this booking action and checked by the server. Cancelling, expiry or timing out creates no reservation.
- 4. Revalidate. The server validates contact details, human verification, rate and hold limits, quote snapshot, price and availability, locks the yacht row and repeats the overlap check.
- 5. Hold. A successful call creates an unpaid
PENDINGorder that temporarily holds the selected dates. The tool does not charge or receive payment credentials. - 6. Hand off. The customer opens
checkoutUrland pays personally. The result also includesstatusUrl: a private guest link or the authenticated account-page URL. If checkout startup fails after the hold exists, the browser tool returns this link asbookingUrlin a handoff response. Do not create a second hold for the same dates. Guest links carry a bearer token in the URL fragment (#token=…); do not publish them or put them in analytics or tool logs.
Consent and telemetry
Browser cancellation before confirmation prevents the mutation. A late abort is not a rollback and requires state reconciliation. Booking contact data is stored on the reservation but excluded from the tool-call summary; telemetry includes a salted IP hash and user agent, so it is pseudonymous rather than anonymous. Read calls also emit operational telemetry even though they do not change booking or catalogue state.
Errors & limits
Scroll the table horizontally to inspect recovery actions.
| Code | Meaning | Recovery |
|---|---|---|
NOT_ENABLED | Agent tools are disabled for this host or deployment | Use the standard website; do not retry automatically |
INVALID_ARGUMENT | Malformed or out-of-range input | Correct the fields; do not book |
AGREEMENT_REQUIRED | Booking terms were not explicitly accepted | Show the linked terms and obtain explicit consent |
PRICE_CHANGED | Live price, fees or currency differ | Request a fresh quote and confirmation |
RATE_LIMITED | A transport or booking limit was reached | Wait before retrying |
CAPTCHA_FAILED | The in-tab human verification failed or expired | Ask the customer to complete the confirmation again |
SERVICE_UNAVAILABLE | Shared agent-tool abuse protection is temporarily unavailable | Nothing was booked; use the yacht page or try again later |
TOO_MANY_PENDING | The customer already has two unpaid agent holds | Pay or cancel one before creating another hold |
HOLD_LIMIT | The yacht and start date reached the unpaid-hold cap | Choose another date or yacht |
AGENT_HOLDS_SATURATED | The global cap of 20 active unpaid agent holds was reached (not an hourly quota) | An existing hold must be paid, cancelled or released by cleanup; alternatively use the yacht page |
CHECKOUT_FAILED | The hold exists but checkout startup failed | Do not create another hold; send the customer to the returned account-page URL |
- Experimental API: without compatible browser support, the standard website works and tool registration remains inert.
- Date bounds: date ranges may span at most 31 days and every supplied date must be within 730 days of the request date.
- Location filter:
cityaccepts city names, not ports. If no city matches, the response includes anoteand unfiltered locations; do not present these as matches for the requested location. - Quote is not a lock: price or availability can change before the booking transaction.
- Temporary hold: an unpaid agent order becomes eligible for
GHOSTEDafter 90 minutes; cleanup timing is not exact. - Remote transport: stateless and read-only,
application/jsonPOST bodies only, no server-initiated SSE stream, no batches, 32 KB body limit, one request per POST and 60 requests per minute per limiter key. - Shared limits: all four browser tools and the three remote tools share an aggregate 60 calls per minute per client IP. Remote HTTP requests also have a separate 60 requests per minute limit. Production counters are shared across instances and fail closed if unavailable. HTTP 429 means an exhausted limit; HTTP 503 means unavailable protection. Respect the
Retry-Afterheader. Limit rejections are not persisted as individual tool-call logs. - Descriptor:
/.well-known/webmcp.jsonis informative. Browser runtime registration is authoritative.