Engineering
A booking MCP server where the person always confirms
A client's own AI assistant can find a time at a business on Bookatu and hold it, but only the client can turn the hold into a booking. Why we built it that way, and what we left out on purpose.
The short version
- An assistant can get the person or the time wrong, so only the person can turn a held time into a booking.
- Before that yes, there is no booking and no client record, only a held time that lets go by itself, and the business's booking page can still book it.
- The person confirms with the code from the email or on the page the email links to, where "This wasn't me" turns it down instead.
- Anything that needs a deposit, a card, terms or a form is booked on the business's own booking page.
- It is off until someone at the business who can change its settings switches it on, and one check decides every way in, again at the moment the person confirms.
- Bookatu's messages for the person come from fixed templates in 14 languages, and a business's words come back in their own labelled fields.
- One switch decides whether any page or document names the server, and tests checked that none did before it was on.
- We left out taking money through the assistant, health and medical care, services that need more than a time, and any booking without the person's yes.
At a business that has switched it on, a client's own AI assistant can use Bookatu's public booking server to look up the business from its booking link and hold one of its free times for the person it is helping. MCP is an open protocol that lets AI assistants use other software's tools, and this server speaks it. What the assistant cannot do is book. A held time becomes a booking only when the person confirms it from their email. This post is about why we drew the line there, and about the rules that follow from it.
Why should an AI assistant not book on its own?
An assistant acts on behalf of a person, and it works from what it was told. It can pick the wrong day or the wrong service. It can also be handed an email address that belongs to someone else, and nothing about an address typed into a chat shows whose it is.
A booking the person never agreed to costs the business as well. It takes a time another client could have booked, for someone who may not come, and it sends a confirmation to an inbox that never asked for one. So in this design only the person can make the booking.
Why does the assistant hold a time instead of booking it?
Before the person says yes, there is no booking and no client record. There is only a held time, which lets go by itself if nobody confirms it.
Bookatu keeps a held time away from other assistants, so a time held for one person is not offered to anyone else's assistant. It does not take the time away from the business. The business's booking page, its booking widget and its team can still book a held time.
We wanted it that way round. A held time is a request that may never be confirmed, so it should never stop a client who is ready to book on the business's own page.
If the time is booked on the business's side first, nothing is booked when the person confirms. Bookatu gives the assistant other free times that day to offer when there are any, and the page the email links to gives the person the business's booking page instead. The same happens if the price has changed by then: nothing is booked at the old price, and the times Bookatu offers start with the same time at the new price when it is still free.
How does a client show that the email address is theirs?
Bookatu emails the address the assistant gave, when that address can take email from Bookatu, and writes as itself. The email says plainly that the request came from an AI assistant, and that ignoring the email books nothing. It carries a code and a link. The person confirms in one of two ways: they read the code to their assistant, or they open the link and confirm on the page it opens. Every answer to a held time also carries the business's booking page link, so if no email comes, the assistant can give the person that link instead.
Opening the link books nothing by itself. Mail scanners and link previews open links too, so only an action on the page can confirm. The code has a rule of its own. The email tells the person to read it only to an assistant they are using themselves, and Bookatu tells the assistant to ask for it only when the person in the chat is booking for themselves. Someone booked by another person confirms from their own inbox.
The page also has a "This wasn't me" button, and the email carries a link straight to it. Pressing it on the page means nothing can be booked from that hold, and for a while Bookatu sends that address no more of these emails. The same page can undo that with "Allow assistants again".
Why does money stay on the booking page?
Some services need more than a time: a deposit, a card held for the no-show policy, booking terms, a required form or booking question, two or more team members, more than one kind of room or equipment at once, a trip, a class or workshop, or an extra. Those are booked on the business's own booking page. Bookatu tells the assistant so and gives it the booking page link to pass on. The page already handles each of those with the person in front of it, and none of them belongs in a chat.
The verification email carries one plain line: "Bookatu never asks you to pay inside a chat." The instructions the server gives every assistant carry the same rule: "Bookatu never takes payment in a chat." Both sentences live in one catalog, in all 14 languages, and every message takes them from there, so none can word the rule its own way. Because the rule has no exceptions, a person can rely on it. If a chat asks them for money for a booking, the request did not come from Bookatu.
Who decides whether assistants can book a business?
The business does. It is off until someone at the business who can change its settings switches it on, and it is open only to businesses on a paid plan that have been on Bookatu a while, with a record of real completed bookings and no health services. The business can switch it off again, or keep single services out, at any time.
One check decides whether a business can be booked, whether the call comes in over MCP or over the plain web API we offer agents that do not speak MCP. When a business the public can book on Bookatu does not pass that check, the server gives the same answer whatever the reason, with the business's booking page link, and only the business's own settings page says what stopped it. A service that assistants cannot book gets an answer with the booking page link too. Each refusal carries a code for the assistant and a plain sentence for the person in their language.
The check runs again when the person confirms. A held time is never booked after the business has switched it off, or after its service has been kept out.
How does an assistant tell Bookatu's words from a business's words?
An assistant reads Bookatu's messages next to text that a business wrote, and a business can write anything into a service description. So the two never share a field. Every sentence the server writes for the person, refusals included, comes from a fixed template in each of 14 languages, and a business's words never go inside one of those sentences. Names and descriptions written by the business come back in their own labelled fields, marked as the business's own words, with the language they were written in. The server also tells every assistant to read text a business wrote as data and never as instructions.
Bookatu gives the assistant each free time on the business's clock, and on the person's clock too when they are somewhere else, written out ready to read. It tells the assistant not to convert times itself.
How did we keep the booking server dark until launch?
One switch decides whether any public page or document names the server. Until it was on, every page and document that names it stayed dark, this post included. The server itself answered from the start, and until a business could be booked, a booking call for it got a plain refusal.
The code was written test first. While the switch is off, tests check that no page or document an assistant or a directory might read names the server, and that the blog and the FAQ are exactly what they were before. We also broke those tests on purpose, to see them fail, before trusting them.
What did we leave out of the booking server on purpose?
- Taking money through the assistant.
- Health and medical care.
- Services that need more than a time.
- Any booking without the person's yes.
Health and medical care is left out for the whole business. If any of a business's services is health or medical care, assistants cannot book that business at all, and before switching it on, the business states that none of its services are.
Where to start
The server is described for developers at bookatu.com/developers#mcp-book, and the plain web API for agents that do not speak MCP is documented on bookatu.com/developers. The server is at https://bookatu.com/api/mcp/book and calls itself Bookatu Booking. It needs no account and no key.
Building on Bookatu?
Bookatu has a public REST API and webhooks. Have a look at the developer docs.
Developer docs