AI agent integrations
Courtbooker publishes a public MCP server so ChatGPT, Claude, Gemini, Cursor and any MCP-compatible assistant can book, list and cancel court reservations on your behalf — with your community's rules enforced server-side.
https://courtbooker.app/mcpStreamable HTTP · OAuth 2.1 · Dynamic client registrationnavigator.modelContext. No extension, no OAuth round-trip — browser agents that implement the WebMCP proposal can call the tools directly as you.1. Add the connector
In ChatGPT / Claude / Cursor, add a custom connector and paste https://courtbooker.app/mcp.
2. Approve the connection
You'll be redirected to Courtbooker to sign in and approve. Your assistant acts as you — same access, same rules.
3. Ask in plain language
Ask about availability, next reservations, or book a slot. Cancel anytime from the chat.
Example prompts
Once connected, these are the sorts of things you can ask your assistant.
- "When is my next tennis reservation?"
- "Can I book a padel court this afternoon between 4pm and 8pm?"
- "Book me the 18:00 tennis slot on Court 1 tomorrow."
- "Cancel my Saturday morning booking."
- "What tennis slots are free this Sunday between 10 and 12?"
Available tools (7)
Every tool your assistant can call on Courtbooker. Live from /.well-known/mcp.json.
list_public_sitesList public communitiesRead-onlyList every publicly-visible residential community on Courtbooker. No authentication required — useful for agents to discover communities before a resident signs in.
list_public_sitesList public communitiesRead-onlyList every publicly-visible residential community on Courtbooker. No authentication required — useful for agents to discover communities before a resident signs in.
No parameters.
sitesobject[]required
list_sitesList my communitiesRead-onlyList residential communities the authenticated user belongs to,
with their site_id, name, slug, timezone, role, and residence.
Call this first for any user-scoped question ('my bookings',
'available slots today') to obtain the correct `site_id`.
If it returns more than one community, ask the user which one.
list_sitesList my communitiesRead-onlyList residential communities the authenticated user belongs to, with their site_id, name, slug, timezone, role, and residence. Call this first for any user-scoped question ('my bookings', 'available slots today') to obtain the correct `site_id`. If it returns more than one community, ask the user which one.
No parameters.
sitesobject[]requiredCommunities the caller belongs to. Use `site_id` for other tools.
list_courtsList courtsRead-onlyList active courts for a community, optionally filtered by sport
(tennis or padel). Useful when the user asks 'which courts do we
have' or to resolve a court name to an id. For availability, use
`list_available_slots` instead.
list_courtsList courtsRead-onlyList active courts for a community, optionally filtered by sport (tennis or padel). Useful when the user asks 'which courts do we have' or to resolve a court name to an id. For availability, use `list_available_slots` instead.
site_idstring (uuid)requiredSite UUID from list_sites.
sporttennis | padelFilter by sport.
courtsobject[]required
list_available_slotsList available slotsRead-onlyReturn bookable slots for a community on a given local calendar date.
Use this to answer questions like 'can I book tennis this afternoon' or
'what padel slots are free tomorrow between 18:00 and 21:00'.
Inputs:
- site_id: from `list_sites` (the community the user belongs to).
- date: YYYY-MM-DD in the community's local timezone.
- sport: 'tennis' or 'padel' to filter courts.
- court_id: restrict to a single court.
- from_time / to_time: optional local HH:MM window (24h). Slots must
START within [from_time, to_time). Use for 'between 4 and 8pm'.
Response: per court, `free_slots` with `start_at`/`end_at` in ISO-8601
UTC plus `start_local`/`end_local` HH:MM in the site's timezone. Slots
in the past or violating min-notice are omitted. Also returns each
court's existing reservations for that day for context.
list_available_slotsList available slotsRead-onlyReturn bookable slots for a community on a given local calendar date. Use this to answer questions like 'can I book tennis this afternoon' or 'what padel slots are free tomorrow between 18:00 and 21:00'. Inputs: - site_id: from `list_sites` (the community the user belongs to). - date: YYYY-MM-DD in the community's local timezone. - sport: 'tennis' or 'padel' to filter courts. - court_id: restrict to a single court. - from_time / to_time: optional local HH:MM window (24h). Slots must START within [from_time, to_time). Use for 'between 4 and 8pm'. Response: per court, `free_slots` with `start_at`/`end_at` in ISO-8601 UTC plus `start_local`/`end_local` HH:MM in the site's timezone. Slots in the past or violating min-notice are omitted. Also returns each court's existing reservations for that day for context.
site_idstring (uuid)requiredSite UUID from list_sites.
datestringrequiredLocal calendar date YYYY-MM-DD in the community's timezone.
sporttennis | padelcourt_idstring (uuid)from_timestringLocal HH:MM lower bound (inclusive) on slot start.
to_timestringLocal HH:MM upper bound (exclusive) on slot start.
siteobjectrequiredEcho of the site the results belong to.
datestringrequiredThe queried local calendar date (YYYY-MM-DD).
timezonestringrequiredIANA timezone the times are interpreted in.
slot_minutesintegerrequiredCommunity slot size in minutes. Pass this as `duration_minutes` to create_reservation.
min_notice_minutesintegerrequiredSlots starting sooner than this are omitted.
courtsobject[]required
create_reservationBook a courtBook a court for the authenticated user. Use this after confirming
an available slot with `list_available_slots` — pass one of the
returned `court_id` + `start_at` pairs and the site's `slot_minutes`
as `duration_minutes` (usually 60).
Recommended flow:
1. `list_sites` -> pick the community's site_id.
2. `list_available_slots` with sport/date/time-window.
3. Show the user the candidate slot and confirm.
4. Call `create_reservation` with that slot.
Enforced server-side by RLS and booking rules (min notice, per-day
and per-week quotas, max concurrent, days-in-advance). Errors from
those rules are returned verbatim so you can relay them to the user.
`apartment_id` is optional and defaults to the caller's residence
in the site.
create_reservationBook a courtBook a court for the authenticated user. Use this after confirming an available slot with `list_available_slots` — pass one of the returned `court_id` + `start_at` pairs and the site's `slot_minutes` as `duration_minutes` (usually 60). Recommended flow: 1. `list_sites` -> pick the community's site_id. 2. `list_available_slots` with sport/date/time-window. 3. Show the user the candidate slot and confirm. 4. Call `create_reservation` with that slot. Enforced server-side by RLS and booking rules (min notice, per-day and per-week quotas, max concurrent, days-in-advance). Errors from those rules are returned verbatim so you can relay them to the user. `apartment_id` is optional and defaults to the caller's residence in the site.
court_idstring (uuid)requiredstart_atstring (date-time)requiredISO 8601 start time (UTC or with offset).
duration_minutesintegerrequiredDuration in minutes. Must match the community's slot size (usually 60).
apartment_idstring (uuid)Optional residence UUID. Defaults to the caller's primary residence for the site.
reservationobjectrequiredThe row that was inserted. Its `id` is the `reservation_id` for cancel_reservation.
cancel_reservationCancel a reservationMutates dataCancel a reservation the authenticated user owns (or has admin
rights over). Sets status to 'cancelled'. Use `list_my_reservations`
first to look up the `reservation_id` — never guess it.
Idempotent: cancelling an already-cancelled reservation is a no-op.
Community cancellation-deadline rules are enforced server-side and
returned as errors if violated.
cancel_reservationCancel a reservationMutates dataCancel a reservation the authenticated user owns (or has admin rights over). Sets status to 'cancelled'. Use `list_my_reservations` first to look up the `reservation_id` — never guess it. Idempotent: cancelling an already-cancelled reservation is a no-op. Community cancellation-deadline rules are enforced server-side and returned as errors if violated.
reservation_idstring (uuid)requiredreasonstring
reservationobjectrequiredThe updated row with status='cancelled'.
list_my_reservationsList my reservationsRead-onlyList reservations belonging to the authenticated user. Use this to
answer 'when is my next booking', 'what do I have on Saturday', or to
look up a reservation_id before calling `cancel_reservation`.
Defaults: upcoming, non-cancelled, oldest-first (next up first),
limit 50. Set `include_past` or `include_cancelled` to widen the
result. Filter by `site_id` when the user belongs to multiple
communities.
Each item includes the court name, sport, site name, and start/end
times both in ISO-8601 UTC and formatted in the community's local
timezone (`start_local`, `end_local`).
list_my_reservationsList my reservationsRead-onlyList reservations belonging to the authenticated user. Use this to answer 'when is my next booking', 'what do I have on Saturday', or to look up a reservation_id before calling `cancel_reservation`. Defaults: upcoming, non-cancelled, oldest-first (next up first), limit 50. Set `include_past` or `include_cancelled` to widen the result. Filter by `site_id` when the user belongs to multiple communities. Each item includes the court name, sport, site name, and start/end times both in ISO-8601 UTC and formatted in the community's local timezone (`start_local`, `end_local`).
site_idstring (uuid)include_pastbooleanInclude reservations that already ended. Default false.
include_cancelledbooleanInclude cancelled reservations. Default false.
limitinteger
reservationsobject[]requiredOrdered by start_at ascending — index 0 is the next upcoming booking.
Ready to try it?
Sign in to Courtbooker, then paste the MCP URL into your favourite AI assistant. The connection is scoped to your account — you can revoke it any time from your profile.
