A Model Context Protocol server at /mcp — JSON-RPC 2.0 over a single HTTP POST, no SSE stream, no session id. It speaks protocol versions 2025-11-25, 2025-06-18 and 2025-03-26.
Authority
An agent's authority is exactly its API key's — the same authentication and the same read/write scopes as the REST API. An agent can do nothing to a calendar that the key's owner couldn't do themselves, and tools/list only returns the tools the presented key's scopes actually allow.
Connect
curl https://book.cccrafts.ai/mcp \
-X POST \
-H "Authorization: Bearer pk_..." \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25"}}'
The five tools
| Tool | Scope | Does | Parameters |
|---|---|---|---|
| list_event_types | read | List the bookable event types owned by the API key holder — id, title, duration, and public booking URL. | includeInactive (boolean, optional; default false) |
| get_available_slots | read | List bookable start times for an event type in a window. Each slot is a UTC instant plus a rendering in the requested timezone. | eventTypeId (required); from, to, timezone, limit (1–200, default 50) |
| create_booking | write | Book a slot for a guest. start must be exactly a slot start returned by get_available_slots. | eventTypeId, start, guestName, guestEmail (required); guestTimezone, answers, idempotencyKey |
| reschedule_booking | write | Move a confirmed booking to a new time. Returns a new booking id — the old one is marked rescheduled. | bookingId, newStart (required); reason |
| cancel_booking | write | Cancel a confirmed booking, free its time, and notify the guest. Cannot be undone. | bookingId (required); reason |
Example: calling a tool
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_available_slots",
"arguments": { "eventTypeId": "evt_abc123", "timezone": "Europe/Berlin" }
}
}
A tool that ran and refused — a taken slot, an unknown booking id — comes back as a normal JSON-RPC result with isError: true and a readable message, so the model can decide what to do next rather than treat it as a transport failure.
All times are UTC instants; a timezone parameter only changes how a slot is rendered, never which slots exist. create_booking's start must be copied exactly from a slot returned by get_available_slots — an arbitrary time is refused even if it looks free.
Full tool and schema definitions: src/http/mcp/server.ts.