
Connects Claude to the Zenoti spa and wellness management platform through their REST API. Exposes tools for the full booking lifecycle: search and create guest profiles, book services through a consolidated 4-step workflow, manage appointment status and check-ins, and handle invoices and payments. Returns context-efficient responses with human-readable formatting instead of raw IDs. You'd reach for this to build AI-powered front desk operations, automated booking assistants, or conversational interfaces for spa scheduling. Requires a Zenoti API key from their admin dashboard with appropriate module permissions. Built to minimize token usage and guide agents through multi-step workflows like availability checks and reservation confirmations.
A Model Context Protocol (MCP) server for the Zenoti spa/wellness/medspa management platform. Exposes appointments, guests, service booking, invoices, catalog, and forms as tools an AI agent can call.
Do not want to manage credentials, hosting, and updates yourself? DOCK is the managed version of this server: encrypted per-practice auth, audit logs, draft-first write actions, and a workflow library. Founding practices lock lifetime pricing: Front Desk $49/mo (Zenoti), Billing Desk $99/mo (Tebra, BAA included), Full Practice $129/mo (both). https://dockhq.vercel.app
npm install -g zenoti-mcp-server
Or run from source:
git clone https://github.com/tacit-code/zenoti-mcp-server.git
cd zenoti-mcp-server
npm install
npm run build
| Variable | Required | Description |
|---|---|---|
ZENOTI_API_KEY | yes | API key from Zenoti Admin → Settings → Apps (create a backend app) |
ZENOTI_API_URL | no | Base URL, default https://api.zenoti.com (with or without /v1) |
ZENOTI_CENTER_ID | recommended | Default center GUID; tools accept center_id to override per call |
Claude Desktop / Claude Code config:
{
"mcpServers": {
"zenoti": {
"command": "npx",
"args": ["-y", "zenoti-mcp-server"],
"env": {
"ZENOTI_API_KEY": "your_api_key",
"ZENOTI_CENTER_ID": "your_center_guid"
}
}
}
}
The server starts even without credentials and returns a readable configuration error on each tool call, so a misconfigured client shows the problem instead of crash-looping.
| Tool | Purpose |
|---|---|
zenoti-centers-list | List organization centers (find center GUIDs) |
zenoti-services-list | Services of a center (compact by default, verbose for raw) |
zenoti-services-get | Full service details |
zenoti-therapists-list | Therapists of a center, optionally filtered to a service |
zenoti-employee-schedules | Who is on shift for a date range (date-scoped staffing) |
| Tool | Purpose |
|---|---|
zenoti-guests-search | Search by name/email/phone/code/tags (≥1 criterion required) |
zenoti-guests-create | Create a guest profile |
zenoti-guests-get | Guest details by GUID |
zenoti-guests-update | Update fields — does a safe read-merge-write (Zenoti replaces the whole object on update) |
zenoti-guests-appointments | Appointment history for a guest |
zenoti-guests-notes-list / zenoti-guests-notes-add | Guest notes and profile alerts |
zenoti-guests-memberships | Guest's memberships (status, credits, dues) |
zenoti-guests-packages | Guest's packages/series with remaining redemptions |
| Tool | Purpose |
|---|---|
zenoti-appointments-list | Center appointments for a date range (compact by default) |
zenoti-appointments-get | Appointment details (appointment_id) |
zenoti-appointments-checkin / zenoti-appointments-undo-checkin | Check-in state (appointment_group_id) |
zenoti-appointments-noshow | Mark no-show (appointment_group_id) |
zenoti-appointments-progress | Start/open/complete service (appointment_id) |
zenoti-appointments-cancel | Cancel a booking (by invoice_id) |
zenoti-appointments-reschedule | Start a reschedule (creates a booking draft tied to the invoice) |
zenoti-availability-slots — creates a booking draft for guest+service+date and returns booking_id plus open slotszenoti-booking-reserve — hold a chosen slot (holds are short-lived)zenoti-booking-confirm — finalize; the response includes the invoice| Tool | Purpose |
|---|---|
zenoti-invoices-get | Invoice with line items, payments, and optional dues/fees |
zenoti-invoices-pay-custom | Record a cash/custom payment (financial action) |
zenoti-invoices-pay-card | Charge the guest's card on file (financial action) |
zenoti-invoices-close | Close a fully-paid invoice |
zenoti-invoices-email | Email the receipt/invoice to the guest |
zenoti-invoices-confirm-visit | Confirm (or undo-confirm) the visit — a scheduling status, despite living on the invoice |
| Tool | Purpose |
|---|---|
zenoti-reports-sales | What was sold over a date range |
zenoti-reports-collections | Money received over a date range |
| Tool | Purpose |
|---|---|
zenoti-forms-list / zenoti-forms-get | Forms and submitted form data of an appointment |
zenoti-guest-forms-list | Forms on a guest profile |
zenoti-feedback-submit | Insert externally collected guest feedback |
appointment_group_id; details/progress/forms take appointment_id; cancel and payments take invoice_id. Tool schemas name the exact one required.PUT would erase fields.Retry-After on 429. Reads also retry on 5xx/network failures/timeouts; writes retry only on 429 (a rate-limit rejection was never processed, so retrying can't duplicate a booking — any other write failure surfaces immediately).size=100; larger values are rejected by Zenoti with a 422.progress_code).npm run dev # run from source (tsx)
npm test # unit + end-to-end tests (mock Zenoti API; no real credentials needed)
npm run typecheck # tsc --noEmit
npm run build # emit dist/
The e2e suite spawns the real server over stdio via the MCP SDK client and asserts every tool's method, path, query, and body against Zenoti's documented endpoints.
MIT
ZENOTI_API_KEY*secretZenoti API key from Org Settings → API
ZENOTI_API_URL*Zenoti API base URL (e.g. https://api.zenoti.com/v1)
ZENOTI_CENTER_ID*Center/location identifier
ZENOTI_ORG_ID*Organization identifier