Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

MCP

The Bookrail MCP server exposes 36 tools. This page is generated from the server itself: the build starts it over stdio, asks tools/list, and writes both this page and /mcp/tools.json, the same list with every input schema.

Terminal window
npx bookrail mcp install --client claude-code # writes ./.mcp.json
npx @bookrail/mcp # or run the server by hand, over stdio

The default environment is test. A tool refuses live unless the server was started with BOOKRAIL_MCP_ALLOW_LIVE=1 and a live key. Irreversible tools return a preview until they are called again with confirm: true.

ToolWhat it doesAnnotations
bookrail_docs_searchSearches the Bookrail documentation packaged with this server and returns the matching pages, ranked, each with the lines that matched.read only, idempotent
bookrail_docs_getReturns one page of the Bookrail documentation as markdown, offline. With no path, lists the pages available.read only, idempotent
bookrail_schemaReturns the JSON Schema of bookrail.config.ts, or of one of its collections, generated from the same Zod schemas that validate a push, so a config written against it cannot be refused for a field that does not exist.read only, idempotent
bookrail_examplesReturns a complete, valid bookrail.config.ts for one vertical, plus the calls that follow it in order.read only, idempotent
bookrail_edge_casesReturns the list of booking edge cases Bookrail handles, with how it handles each: simultaneous requests for the last seat, holds expiring mid-flow, schedule changes that orphan a booking, capacity reductions, overlapping buffers, bookings across midnight and across a clock change, splits across a group, blocks, pricing rules on a band that wraps midnight or on an hour that does not exist, and the pitfalls of driving the API.read only, idempotent
bookrail_project_infoReturns the project the configured key belongs to, the API URL and version, the key (masked) and where it came from, and whether the live environment is reachable from this server at all.read only, idempotent
bookrail_doctorRuns every check the bookrail doctor command runs (Node version, credentials and their file permissions, environment against key prefix, API reachability, API version drift, authentication, project and project environment, configuration file validity) and returns each as ok / warn / fail with a fix sentence.read only, idempotent
bookrail_config_validateValidates a configuration (locations, schedules, resources, resource groups, policies, services) against the same schema a push validates with, and cross-checks every logical reference (a service pointing at a group that the file does not declare, a resource pointing at a missing schedule).read only, idempotent
bookrail_config_pushReconciles a configuration with the project: creates what is missing, updates what differs, deletes what the configuration no longer declares. Objects with no metadata.config_id were not created from a configuration and are never touched: they come back in unmanaged.destructive, idempotent
bookrail_config_pullReturns the project as a configuration object, in the shape bookrail.config.ts declares. Read-only: nothing is written, on the project or on disk.read only, idempotent
bookrail_availabilityReturns every bookable instant for a service between two instants, with duration, remaining capacity, price and the resource combinations that could serve it.read only, idempotent
bookrail_availability_nextReturns the first instant a service can be booked at, searched in 30-day windows up to 90 days ahead.read only, idempotent
bookrail_availability_checkAnswers whether one precise instant is bookable, and when it is not, returns the structured reasons.read only, idempotent
bookrail_explain_unavailableThe “why not” of the availability engine for one instant: closed schedule, block, existing occupancy, buffer, booking window, grid alignment, capacity, policy. Each one comes back as a code, a message and, where it applies, the resource it came from.read only, idempotent
bookrail_hold_createTakes the capacity for an instant and keeps it for the policy’s hold duration (ten minutes by default), so you can collect a payment or a confirmation without racing anyone else.idempotent
bookrail_hold_getReturns one hold and, above all, its status: active (still convertible), released, expired, or converted, with booking_id when it became a booking.read only, idempotent
bookrail_hold_releaseReleases a hold and frees the capacity immediately, instead of waiting for it to expire.idempotent
bookrail_booking_createCreates a booking, optionally by converting a hold. The capacity is taken inside one database transaction, so two simultaneous requests for the last seat cannot both succeed: the loser gets slot_unavailable (409).idempotent
bookrail_booking_getReturns one booking with its status, times, price, refund expectation, allocations and the transition scheduled for it.read only, idempotent
bookrail_booking_listLists bookings, filtered by customer, service, resource, status or time window, with cursor pagination.read only, idempotent
bookrail_booking_transitionApplies one of the four forward transitions of a booking: confirm, check_in, complete, no_show. Each is checked against the state matrix; an illegal transition is a 409 that names the current status.
bookrail_booking_cancelCancels a booking, releases its capacity and computes the refund the frozen policy snapshot entitles the customer to.destructive
bookrail_booking_rescheduleMoves a booking to a new instant. The answer is the NEW booking; the old one becomes “rescheduled” and is reachable at rescheduled_from_booking_id.
bookrail_objects_listLists the objects of one collection: locations, resources, resource_groups, schedules, services, policies, customers.read only, idempotent
bookrail_resource_blocksLists the blocks on one resource: the periods it is closed for (holidays, maintenance) without the schedule saying so.read only, idempotent
bookrail_object_getReturns one object of one collection by its prefixed id.read only, idempotent
bookrail_object_createCreates one object through the API, bypassing the configuration file.
bookrail_object_updatePatches one object. Only the fields you send are changed, except the sub-lists (rules, resource_ids, requirements), where the set you send REPLACES the whole set.idempotent
bookrail_object_deleteDeletes one object. Resources and services are soft-deleted (they disappear from reads); everything else is removed. References from other objects become null.destructive
bookrail_events_listLists the events of the project (booking.created, booking.cancelled, booking.orphaned, hold.expired and the rest), newest page first, in a total order that is safe to page through.read only, idempotent
bookrail_event_getReturns one event with its full payload: the object as it is after the change, and the previous version where there is one.read only, idempotent
bookrail_webhook_listLists the webhook endpoints of the project with their URL, subscribed events and status.read only, idempotent
bookrail_webhook_createRegisters an endpoint to deliver events to, and returns its signing secret. That is the only time it is shown: no other call ever returns it again, not even an idempotent replay.
bookrail_webhook_testDelivers a synthetic event to one endpoint, synchronously, and returns what the endpoint answered.idempotent
bookrail_webhook_deliveriesLists the deliveries attempted to one endpoint, with attempt number, response status, duration, error and when the next retry is due.read only, idempotent
bookrail_webhook_deleteRemoves an endpoint. Events stop being delivered to it immediately, and its signing secret is gone: re-creating the endpoint gives a new one, and every handler verifying the old secret breaks.destructive

Searches the Bookrail documentation packaged with this server and returns the matching pages, ranked, each with the lines that matched. Use it whenever you are about to guess: how availability is computed, what a config field means, what an error code means, how holds and bookings relate. Returns: { query, hits: [{ topic, title, url, score, excerpts }] }. Next: bookrail_docs_get with the topic of the best hit, for the whole page.

Arguments: query (required), limit

Returns one page of the Bookrail documentation as markdown, offline. With no path, lists the pages available. Use it after bookrail_docs_search, or directly when you know the page: getting-started, config, entities, api, errors, timezones, agents. Returns: { topic, title, markdown, url }, or { topics: [...] } when path is omitted. Next: bookrail_schema for the exact shape of the configuration, then bookrail_config_validate.

Arguments: path

Returns the JSON Schema of bookrail.config.ts, or of one of its collections, generated from the same Zod schemas that validate a push, so a config written against it cannot be refused for a field that does not exist. Use it before writing or editing a configuration, and whenever bookrail_config_validate reported a field you do not recognise. Entities: config, locations, schedules, resources, resourceGroups, policies, services. Returns: the JSON Schema object, or { schemas: [...] } when entity is omitted. Next: bookrail_config_validate, then bookrail_config_push with dry_run: true.

Arguments: entity

Returns a complete, valid bookrail.config.ts for one vertical, plus the calls that follow it in order. Use it as the starting point for modelling a business: pick the closest vertical, then edit it. It is faster and safer than writing a configuration from the schema alone. Verticals: salon, padel, gym, rental, restaurant, clinic, coworking, tours, tutoring, empty. Returns: { vertical, summary, config, config_file, calls }. config is the object to pass to bookrail_config_push. Next: bookrail_config_validate with your edited config, then bookrail_config_push with dry_run: true.

Arguments: vertical, framework

Returns the list of booking edge cases Bookrail handles, with how it handles each: simultaneous requests for the last seat, holds expiring mid-flow, schedule changes that orphan a booking, capacity reductions, overlapping buffers, bookings across midnight and across a clock change, splits across a group, blocks, pricing rules on a band that wraps midnight or on an hour that does not exist, and the pitfalls of driving the API. Use it before building anything yourself: most of what looks like “a special case in my business” is already a tested case here. Topics: concurrency, daylight-saving, schedules, pricing, pitfalls, errors. Omit to get them all. Returns: { topics: [{ topic, title, source_page, markdown }] }. Next: bookrail_docs_get for the whole page a topic came from.

Arguments: topic

Returns the project the configured key belongs to, the API URL and version, the key (masked) and where it came from, and whether the live environment is reachable from this server at all. Use it first, before any other call that touches data: it proves the key works and names the project you are about to change. Returns: { environment, project: { id, name, default_timezone, default_currency }, api_key: { id, scopes, tenant_id }, api_url, api_version_served, live_allowed }. Next: bookrail_doctor if anything looks wrong; bookrail_config_pull to see what the project already contains.

Arguments: environment

Runs every check the bookrail doctor command runs (Node version, credentials and their file permissions, environment against key prefix, API reachability, API version drift, authentication, project and project environment, configuration file validity) and returns each as ok / warn / fail with a fix sentence. Use it when a call failed and you do not know why, or before starting work in a new project directory. Returns: { checks: [{ name, status, message, fix? }], summary: { ok, warn, fail } }. ok: false is never returned for a failed check: read summary.fail. Next: act on the fix of every failing check, then call bookrail_project_info.

Arguments: environment, config_path

Validates a configuration (locations, schedules, resources, resource groups, policies, services) against the same schema a push validates with, and cross-checks every logical reference (a service pointing at a group that the file does not declare, a resource pointing at a missing schedule). Use it after writing or editing a configuration and before every push. It touches no network and needs no key. Returns: { valid, issues: [{ path, message }], counts }. path is the position inside the configuration, e.g. services[1].requirements[0].group. Next: bookrail_config_push with dry_run: true.

Arguments: config, config_path

Reconciles a configuration with the project: creates what is missing, updates what differs, deletes what the configuration no longer declares. Objects with no metadata.config_id were not created from a configuration and are never touched: they come back in unmanaged. Use it after bookrail_config_validate. Call it first with dry_run: true (the default) to read the plan; then with dry_run: false and confirm: true to apply. Safety: dry_run: false requires confirm: true, and so does any plan that contains a deletion. Without it the tool returns the plan and requires_confirmation: true and changes nothing. Returns: { plan: [{ action, kind, config_id, remote_id, name, changes }], counts, unmanaged, applied }. Next: bookrail_objects_list with kind “services” to read back the svc_ ids, then bookrail_availability.

Arguments: environment, config, config_path, dry_run, confirm

Returns the project as a configuration object, in the shape bookrail.config.ts declares. Read-only: nothing is written, on the project or on disk. Use it to discover what a project already contains before changing anything, or to start a configuration from a project that was built through the API. Returns: { config, written: null, stamped: [], adopted }. adopted lists objects with no metadata.config_id: pushing this configuration would create copies of them, so take them over with the CLI (bookrail pull --adopt) before pushing. Next: bookrail_config_validate on the returned config, then bookrail_config_push with dry_run: true.

Arguments: environment

Returns every bookable instant for a service between two instants, with duration, remaining capacity, price and the resource combinations that could serve it. Use it before creating a hold or a booking. With explain: true it also returns, for every candidate instant that is NOT bookable, the structured reasons why, which is the fastest way to understand a model that is not doing what you expect. Window: at most 90 days, 7 with explain. Returns: { service_id, timezone, granularity, slots: [{ start, end, duration_minutes, available_capacity, price, price_rule, resource_options }], next_available, explain? }. Instants out are UTC. price is the price of that slot, not necessarily the flat price of the service: if the service carries pricing_rules, the first rule whose when matches decides, and price_rule is { index, label } naming it, or null when the flat price applied. It is the price the booking will freeze. Next: bookrail_hold_create to take the capacity for a few minutes, or bookrail_booking_create to book directly.

Arguments: environment, service_id (required), from (required), to (required), quantity, timezone, resource_ids, customer_id, granularity, explain

Returns the first instant a service can be booked at, searched in 30-day windows up to 90 days ahead. Use it when you need an instant rather than a window: a smoke test after a push, or the default a user is offered. Returns: { next_available, slot, searched_through, timezone }. next_available is null when nothing is bookable in 90 days. Next: bookrail_availability_check on that instant, then bookrail_hold_create or bookrail_booking_create.

Arguments: environment, service_id (required), from, quantity, timezone

Answers whether one precise instant is bookable, and when it is not, returns the structured reasons. Use it right before booking an instant you got from somewhere else (a UI, a cache, a user), and to close the loop after a configuration change. Returns: { available, available_capacity, price, resource_options, reasons? }. Next: bookrail_hold_create if available; bookrail_explain_unavailable or bookrail_availability with explain: true if not.

Arguments: environment, service_id (required), start (required), duration_minutes, quantity, resource_ids

The “why not” of the availability engine for one instant: closed schedule, block, existing occupancy, buffer, booking window, grid alignment, capacity, policy. Each one comes back as a code, a message and, where it applies, the resource it came from. Use it whenever an instant you expected to be bookable is not. It is the same computation bookrail_availability_check reports and the same one explain: true reports over a window, narrowed to one instant so the answer is short. Returns: { available, reasons: [{ code, message, resource_id? }] }. Next: fix the model (bookrail_config_push) or pick another instant (bookrail_availability_next).

Arguments: environment, service_id (required), start (required), duration_minutes, quantity

Takes the capacity for an instant and keeps it for the policy’s hold duration (ten minutes by default), so you can collect a payment or a confirmation without racing anyone else. Use it in any flow where something happens between choosing a slot and committing to it. Skip it and call bookrail_booking_create directly when nothing happens in between. Returns: { id, status, start, end, expires_at, quantity, price, allocations }. Next: bookrail_booking_create with hold_id to convert it, or bookrail_hold_release to give it back.

Arguments: environment, service_id (required), start (required), duration_minutes, quantity, resource_ids, ttl, metadata, customer_id, customer_email, customer_name, customer_phone, customer_external_id

Returns one hold and, above all, its status: active (still convertible), released, expired, or converted, with booking_id when it became a booking. Use it when a flow was interrupted and you do not know whether the hold you took is still yours, and before retrying a conversion that failed: a hold that is expired will never convert, and the answer is to take a new one. Returns: { id, status, service_id, start, end, expires_at, booking_id, allocations }. price is null on a read: a hold has no stored price, only a booking freezes one. Next: bookrail_booking_create with hold_id while it is active; bookrail_availability once it is not.

Arguments: environment, hold_id (required)

Releases a hold and frees the capacity immediately, instead of waiting for it to expire. Use it as soon as a flow is abandoned. It needs no confirmation: DELETE /v1/holds/{id} is idempotent and releasing is the intended end of a hold’s life. A hold already converted into a booking answers 409 hold_not_active. Returns: { id, deleted: true }. Next: nothing. Releasing twice is a success, not an error.

Arguments: environment, hold_id (required)

Creates a booking, optionally by converting a hold. The capacity is taken inside one database transaction, so two simultaneous requests for the last seat cannot both succeed: the loser gets slot_unavailable (409). Use it after bookrail_availability or bookrail_availability_check. Pass hold_id when you held the slot first: converting a hold cannot fail for capacity. Returns: the booking { id, status, start, end, price, allocations, next_transition }. Next: bookrail_booking_get to close the loop; bookrail_booking_confirm when the status is “pending”.

Arguments: environment, service_id (required), start (required), duration_minutes, quantity, hold_id, resource_ids, notes, source, metadata, customer_id, customer_email, customer_name, customer_phone, customer_external_id

Returns one booking with its status, times, price, refund expectation, allocations and the transition scheduled for it. Use it after every write, to close the loop on what actually happened. Returns: the booking object. Next: the transition the next_transition field names, or bookrail_booking_cancel.

Arguments: environment, booking_id (required), expand

Lists bookings, filtered by customer, service, resource, status or time window, with cursor pagination. Use it to answer “what is on the calendar” and to find a booking whose id you do not have. Returns: { data: [...], has_more, next_cursor }. Pass next_cursor back as starting_after for the next page. Next: bookrail_booking_get on one of them.

Arguments: environment, customer_id, service_id, resource_id, status, from, to, limit, starting_after

Applies one of the four forward transitions of a booking: confirm, check_in, complete, no_show. Each is checked against the state matrix; an illegal transition is a 409 that names the current status. Use it to record what happened. no_show is a fact being recorded, not a cancellation: to cancel, use bookrail_booking_cancel. Returns: the booking after the transition. Next: bookrail_booking_get, or the transition its next_transition names.

Arguments: environment, booking_id (required), action (required)

Cancels a booking, releases its capacity and computes the refund the frozen policy snapshot entitles the customer to. IRREVERSIBLE: a cancelled booking does not come back, it is created again. So without confirm: true this tool returns the booking as it stands today plus requires_confirmation: true, and changes nothing. Returns: the cancelled booking, with refund_percent and refund_amount_expected. Payments do not exist yet, so the refund is an expectation, not a movement. Next: bookrail_booking_get to read it back.

Arguments: environment, booking_id (required), reason, by, refund_percent, confirm

Moves a booking to a new instant. The answer is the NEW booking; the old one becomes “rescheduled” and is reachable at rescheduled_from_booking_id. Use it instead of cancel-and-rebook: rescheduling keeps the link, counts against max_reschedules, and applies the reschedule ladder of the policy rather than the cancellation one. Returns: the new booking. Next: bookrail_booking_get on the returned id.

Arguments: environment, booking_id (required), start (required), resource_ids

Lists the objects of one collection: locations, resources, resource_groups, schedules, services, policies, customers. Use it after bookrail_config_push to read back the ids the API assigned (svc_..., res_...): a configuration uses logical ids, and the prefixed ids only exist after a push. metadata.config_id on each object is the logical id it came from. Returns: { data: [...], has_more, next_cursor }. Next: bookrail_availability with the svc_ id of a service.

Arguments: environment, kind (required), limit, starting_after, all, expand

Lists the blocks on one resource: the periods it is closed for (holidays, maintenance) without the schedule saying so. Use it to find the blk_... of a block you want to lift, which is the only way to lift one, and to explain why a resource is unavailable on a day its schedule says it is open. Without from/to it returns the blocks that have not finished yet. Returns: { data: [{ id, resource_id, from, to, reason, metadata }], has_more, next_cursor }. Instants are UTC. Next: bookrail_explain_unavailable if a block is not what you expected; the unblock itself is POST /v1/resources/{id}/unblock with the blk_..., which no tool wraps yet.

Arguments: environment, resource_id (required), from, to, limit, starting_after, all

Returns one object of one collection by its prefixed id. Use it to close the loop after a write, and to read metadata.config_id to find out whether an object is managed by a configuration. Returns: the object. Next: bookrail_object_update, or bookrail_config_push if the object is managed by a configuration. Editing a managed object outside the file makes the next push undo the change.

Arguments: environment, kind (required), id (required), expand

Creates one object through the API, bypassing the configuration file. Prefer bookrail_config_push: an object created here carries no metadata.config_id, so a later push will never update or delete it, and it shows up as unmanaged. Use this for something genuinely outside the model: a customer, a one-off resource. The body uses the API field names (location_id, schedule_id), not the configuration ones (location, schedule). Call bookrail_docs_get with path “api” for the reference. Returns: the created object. Next: bookrail_object_get to read it back.

Arguments: environment, kind (required), data (required)

Patches one object. Only the fields you send are changed, except the sub-lists (rules, resource_ids, requirements), where the set you send REPLACES the whole set. If the object carries metadata.config_id it is managed by a configuration file, and the next bookrail_config_push will put it back the way the file describes. Change the file instead. Returns: the updated object. Next: bookrail_object_get, or bookrail_availability when the change could affect what is bookable.

Arguments: environment, kind (required), id (required), data (required)

Deletes one object. Resources and services are soft-deleted (they disappear from reads); everything else is removed. References from other objects become null. IRREVERSIBLE: without confirm: true this tool returns the object as it stands today plus requires_confirmation: true, and deletes nothing. Read the preview, in particular metadata.config_id, which tells you whether a configuration file still declares it. Returns: { id, deleted: true }. Next: bookrail_config_push with dry_run: true, to check the configuration and the project still agree.

Arguments: environment, kind (required), id (required), confirm

Lists the events of the project (booking.created, booking.cancelled, booking.orphaned, hold.expired and the rest), newest page first, in a total order that is safe to page through. Use it to find out what a call actually did, to check that a change produced the event you expected, and as the payload reference for a webhook handler: an event here is byte for byte what a delivery would have carried. Returns: { data: [{ id, type, occurred_at, actor, data: { object, previous } }], has_more, next_cursor }. Next: bookrail_event_get for one of them; bookrail_webhook_create to receive them instead of polling.

Arguments: environment, type, object_id, from, to, limit, starting_after

Returns one event with its full payload: the object as it is after the change, and the previous version where there is one. Use it when an event id came from a webhook delivery or from bookrail_events_list and you need the whole body. Returns: the event object. Next: bookrail_booking_get on data.object.id if it is a booking event.

Arguments: environment, event_id (required)

Lists the webhook endpoints of the project with their URL, subscribed events and status. Use it before creating one, so you do not add a second endpoint for the same URL. Returns: { data: [{ id, url, events, status }], has_more, next_cursor }. The signing secret is never returned here: it is shown only once, by bookrail_webhook_create. Next: bookrail_webhook_test to make one deliver now.

Arguments: environment, limit, starting_after

Registers an endpoint to deliver events to, and returns its signing secret. That is the only time it is shown: no other call ever returns it again, not even an idempotent replay. Use it when wiring an application to Bookrail. Store the secret in the application’s environment immediately (BOOKRAIL_WEBHOOK_SECRET) and verify every Bookrail-Signature with it. On live only https is accepted; on test http is allowed on ports 80, 443 and 8080-8099. Returns: { id, url, events, status, secret }. Next: bookrail_webhook_test to deliver a synthetic event and see what the endpoint answers.

Arguments: environment, url (required), events, description, metadata

Delivers a synthetic event to one endpoint, synchronously, and returns what the endpoint answered. Use it to check a handler end to end without creating a real booking. Returns: { status: "succeeded" | "failed", response_status, duration_ms, error? }. ok stays true even when the endpoint answers 500: the delivery happened, and that IS the answer. Branch on data.status. Next: bookrail_webhook_deliveries to read the endpoint’s log.

Arguments: environment, webhook_id (required)

Lists the deliveries attempted to one endpoint, with attempt number, response status, duration, error and when the next retry is due. Use it when an endpoint is not receiving what you expect: it distinguishes “never sent” from “sent and refused”. Returns: { data: [{ id, event_id, status, attempt, response_status, error, next_attempt_at }], has_more }. Next: bookrail_event_get on a delivery’s event_id to see what was sent.

Arguments: environment, webhook_id (required), status, event, limit

Removes an endpoint. Events stop being delivered to it immediately, and its signing secret is gone: re-creating the endpoint gives a new one, and every handler verifying the old secret breaks. IRREVERSIBLE: without confirm: true the tool returns the endpoint as it stands and requires_confirmation: true, and removes nothing. Returns: { id, deleted: true }. Next: bookrail_webhook_list to check what is left.

Arguments: environment, webhook_id (required), confirm