vitta-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@vitta-mcp Book me a gel manicure at studio-ana this Friday afternoon"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
vitta-mcp
An MCP server that lets AI agents book appointments at the beauty and health businesses that run on Vitta: salons, barbershops, nail and brow studios and clinics in Brazil.
"Book me a manicure at Studio Ana on Friday afternoon."
The agent looks the business up, finds Friday's free times, reads them back, waits for a yes, and books. Or, if you haven't given it your Vitta login, it hands you the booking link with the time already chosen.
Vitta is a scheduling SaaS I built. Until now its only user was a person tapping through the booking page. This server makes agents a second kind of user, without giving them any power that person doesn't have.
Try it in a minute
With no configuration the server runs Vitta's demo: the same two sample businesses the app shows, studio-ana (nails) and barbearia-nove (barbershop), with their services, prices, opening hours and a week of appointments counted from today. You act as a demo customer, and bookings live in memory until the server stops.
git clone https://github.com/leonardobrigolini/vitta-mcp.git
cd vitta-mcp
npm install
npm run build
claude mcp add vitta -- node "$PWD/dist/index.js"Then ask Claude something like "What can I book at studio-ana, and when is the first free time for a gel manicure?".
Related MCP server: salonrunner-mcp
Tools
Tool | What it does | Needs a customer login |
| Services (id, duration, price in BRL), opening hours, contact, booking rules | No |
| Free start times for one service, grouped by day, in the business's time zone | No |
| Books one of those times | Yes (otherwise returns the booking link) |
| The customer's appointments across every Vitta business | Yes |
| Cancels one of them | Yes |
The server also sends the agent short instructions on the expected flow: look up, find, confirm with the person, book.
Built for an agent, not a form
The booking page can lean on its UI. An agent can't, so the guarantees moved into the server:
Same answer as the booking page. The availability engine is the app's own (
src/lib, copied with its tests). An agent can never be offered a time a person on the page wouldn't see. This matters more than it looks: the database function that books checks double booking and minimum notice, but not opening hours. On the page, the UI keeps people inside opening hours. For agents,book_appointmentre-computes the free times and refuses anything that isn't on that list.Errors say what to do next. "Someone else just booked 09:00. Call find_available_slots again and offer the person new times." Every failure names the tool to call or the link to hand over, so the agent can recover without a human reading a stack trace.
No time-zone math for the model. Every time goes out as ISO 8601 with the business's offset (
2026-10-02T09:00:00-03:00), plus the date, weekday and wall-clock time.starts_atonly accepts that format:Date.parsewould happily read "amanhã às 9" as a date, and a timestamp without an offset would land in whatever zone the server runs in.Honest annotations. Look-ups are
readOnlyHint, cancelling isdestructiveHint, and the booking and cancelling descriptions tell the agent to get an explicit yes first.Read-only without a login. Connected to a real Vitta but without a customer login, the server can't write anything. It still does the useful part, finding the time, and returns the booking link to finish by hand.
Connect to a real Vitta
Point the server at a Vitta deployment with its Supabase URL and publishable key, the same pair its booking page ships in its JavaScript. Add the customer's own Vitta login (WhatsApp number + password) to let the agent book:
claude mcp add vitta \
-e VITTA_SUPABASE_URL="https://<project>.supabase.co" \
-e VITTA_SUPABASE_KEY="sb_publishable_..." \
-e VITTA_CUSTOMER_WHATSAPP="(54) 99999-1234" \
-e VITTA_CUSTOMER_PASSWORD="your-vitta-password" \
-- node /absolute/path/to/vitta-mcp/dist/index.jsFor Claude Desktop, Cursor and other clients, the same goes in the MCP config:
{
"mcpServers": {
"vitta": {
"command": "node",
"args": ["/absolute/path/to/vitta-mcp/dist/index.js"],
"env": {
"VITTA_SUPABASE_URL": "https://<project>.supabase.co",
"VITTA_SUPABASE_KEY": "sb_publishable_...",
"VITTA_CUSTOMER_WHATSAPP": "(54) 99999-1234",
"VITTA_CUSTOMER_PASSWORD": "your-vitta-password"
}
}
}
}Variable | Default | |
| none (demo) | The Vitta deployment to talk to. Set both or neither. |
| none (demo) | Its publishable key. |
| none | The customer's Vitta login. Set both or neither. |
| none | |
|
| Base of the booking links it hands out. |
|
| Vitta signs customers in with an e-mail derived from their WhatsApp. |
Security
Against a real Vitta it uses only the four database functions the public booking page already calls:
public_org,book_appointment,my_bookings,cancel_booking. Row-level security answers per signed-in user, so the server can't see another customer's data even if an agent asks for it.The customer login lives only in the person's local MCP config. It's used to sign in once per process and is never logged.
No secrets in this repository: the demo needs none, and a real deployment's publishable key is public by design.
Development
npm test # 82 tests
npm run smoke # the built server over stdio: demo by default, read-only against a real VittaThe tests come in four layers:
The availability engine, with the app's own tests: lunch breaks, existing appointments, services that don't fit before closing, businesses that close at midnight, computing in the business's time zone instead of the machine's.
Every tool, in memory, against a fake API: the times it refuses to book, the messages it sends back, the read-only mode.
The demo, end to end: the seeded agenda blocks the right times, and a booking takes its slot until it's canceled.
The real process over stdio, with the real Supabase client talking HTTP to a fake Vitta that answers like the SQL functions. This layer covers what the in-memory tests can't: argument names on the wire, the sign-in, the JSON shapes coming back, the environment handling.
src/lib and the demo data are copied from the Vitta app. If the booking page's rules or the demo change, copy them again, so the two never disagree.
Built by Leonardo Brigolini · MIT license
Available Tools
5 toolsbook_appointmentBook an appointmentA
Book a service for the customer account configured on this server. Only call this after the person has explicitly confirmed the business, service, day, time and price. starts_at must be copied exactly from find_available_slots. If no customer account is configured, this returns a booking link to hand to the person instead.
Inputs: business (required), starts_at (required), service_id (required).
cancel_appointmentCancel an appointmentADestructiveIdempotent
Cancel one of the configured customer's upcoming appointments. The time goes back to other people and this can't be undone, so confirm with the person first. Get appointment_id from list_my_appointments.
Inputs: appointment_id (required).
find_available_slotsFind free timesARead-only
List the start times a business would offer for one service on its own booking page, grouped by day, in the business's time zone. Only these exact times can be booked: don't invent, round or shift them, and pass starts_at to book_appointment unchanged. Times change as other people book, so look again if the person takes a while to decide.
Inputs: business (required), service_id (required), days, from_date.
get_businessLook up a businessARead-only
Look up a business on Vitta by its booking link or slug. Returns the services it offers (with service_id, duration and price in BRL), opening hours, address, contact and whether it's taking online bookings. Call this first: the other tools need a service_id from here.
Inputs: business (required).
list_my_appointmentsList my appointmentsARead-only
List the appointments of the customer account configured on this server, across every Vitta business, soonest first. By default only upcoming pending or scheduled ones. Use it to answer "when is my appointment?" and to get the appointment_id for cancel_appointment.
Inputs: include_past.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 5 tools
Each tool targets a distinct step of the booking lifecycle: business lookup, availability discovery, booking, listing the user's appointments, and cancellation. There is no overlap or risk of misselection, and descriptions explicitly state prerequisites (service_id, appointment_id, starts_at).
All names follow a consistent verb_noun snake_case pattern (get_business, list_my_appointments, find_available_slots, book_appointment, cancel_appointment). Verbs are distinct and predictable throughout.
Five tools map cleanly onto the minimal end-to-end booking flow, with each tool earning its place. Nothing feels padded or thin for a single-purpose booking server.
The core lifecycle (discover business → check availability → book → list → cancel) is fully covered with no dead ends. Minor gaps remain: no reschedule/update appointment and no business search by name or location, though agents can work around these.
Related MCP Connectors
Find a salon, barber or studio, see free time, get the booking link. Serves claude.ai and ChatGPT.
Manage an EasyWeek business from AI: bookings, availability, customers, services, orders, messaging.
Find real businesses and book appointments. Books via Cal.com; imports 12 platforms.
Verified local businesses, bookable by AI agents: services, prices, availability and appointments.
Related MCP Servers
- AlicenseCqualityDmaintenanceEnables AI agents to manage spa/wellness operations via Zenoti API, including appointments, guests, services, and billing.2374 npmMIT
- AlicenseAqualityDmaintenanceEnables AI assistants to find, book, and cancel salon appointments via SalonRunner accounts. Self-hosted for local or remote use.639 npmMIT
- AlicenseAqualityBmaintenanceBook a table, an appointment or a place in a class at a real local business. Live availability, instant confirmation, no account and no API key. Eight tools: search, fetch, get_business, check_availability, create_booking, check_booking, cancel_booking and request_listing. Guest emails in eight languages. Hosted at https://g-guest.app/api/mcp810 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to discover availability, place expiring holds, and confirm or cancel appointments for connected booking businesses, with idempotent retries and explicit user consent.1Apache 2.0