{
  "markdown": "# Zenoti MCP Server\n\nA Model Context Protocol (MCP) server for the [Zenoti](https://www.zenoti.com/) spa/wellness/medspa management platform. Exposes appointments, guests, service booking, invoices, catalog, and forms as tools an AI agent can call.\n\n### Hosted version available\n\nDo not want to manage credentials, hosting, and updates yourself? [DOCK](https://dockhq.vercel.app) 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\n\n## Installation\n\n```bash\nnpm install -g zenoti-mcp-server\n```\n\nOr run from source:\n\n```bash\ngit clone https://github.com/tacit-code/zenoti-mcp-server.git\ncd zenoti-mcp-server\nnpm install\nnpm run build\n```\n\n## Configuration\n\n| Variable | Required | Description |\n|---|---|---|\n| `ZENOTI_API_KEY` | yes | API key from Zenoti Admin → Settings → Apps (create a backend app) |\n| `ZENOTI_API_URL` | no | Base URL, default `https://api.zenoti.com` (with or without `/v1`) |\n| `ZENOTI_CENTER_ID` | recommended | Default center GUID; tools accept `center_id` to override per call |\n\nClaude Desktop / Claude Code config:\n\n```json\n{\n  \"mcpServers\": {\n    \"zenoti\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"zenoti-mcp-server\"],\n      \"env\": {\n        \"ZENOTI_API_KEY\": \"your_api_key\",\n        \"ZENOTI_CENTER_ID\": \"your_center_guid\"\n      }\n    }\n  }\n}\n```\n\nThe 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.\n\n## Tools\n\n### Catalog\n| Tool | Purpose |\n|---|---|\n| `zenoti-centers-list` | List organization centers (find center GUIDs) |\n| `zenoti-services-list` | Services of a center (compact by default, `verbose` for raw) |\n| `zenoti-services-get` | Full service details |\n| `zenoti-therapists-list` | Therapists of a center, optionally filtered to a service |\n| `zenoti-employee-schedules` | Who is on shift for a date range (date-scoped staffing) |\n\n### Guests\n| Tool | Purpose |\n|---|---|\n| `zenoti-guests-search` | Search by name/email/phone/code/tags (≥1 criterion required) |\n| `zenoti-guests-create` | Create a guest profile |\n| `zenoti-guests-get` | Guest details by GUID |\n| `zenoti-guests-update` | Update fields — does a safe read-merge-write (Zenoti replaces the whole object on update) |\n| `zenoti-guests-appointments` | Appointment history for a guest |\n| `zenoti-guests-notes-list` / `zenoti-guests-notes-add` | Guest notes and profile alerts |\n| `zenoti-guests-memberships` | Guest's memberships (status, credits, dues) |\n| `zenoti-guests-packages` | Guest's packages/series with remaining redemptions |\n\n### Appointments\n| Tool | Purpose |\n|---|---|\n| `zenoti-appointments-list` | Center appointments for a date range (compact by default) |\n| `zenoti-appointments-get` | Appointment details (`appointment_id`) |\n| `zenoti-appointments-checkin` / `zenoti-appointments-undo-checkin` | Check-in state (`appointment_group_id`) |\n| `zenoti-appointments-noshow` | Mark no-show (`appointment_group_id`) |\n| `zenoti-appointments-progress` | Start/open/complete service (`appointment_id`) |\n| `zenoti-appointments-cancel` | Cancel a booking (by `invoice_id`) |\n| `zenoti-appointments-reschedule` | Start a reschedule (creates a booking draft tied to the invoice) |\n\n### Booking flow\n1. `zenoti-availability-slots` — creates a booking draft for guest+service+date and returns `booking_id` plus open slots\n2. `zenoti-booking-reserve` — hold a chosen slot (holds are short-lived)\n3. `zenoti-booking-confirm` — finalize; the response includes the invoice\n\n### Invoices\n| Tool | Purpose |\n|---|---|\n| `zenoti-invoices-get` | Invoice with line items, payments, and optional dues/fees |\n| `zenoti-invoices-pay-custom` | Record a cash/custom payment (financial action) |\n| `zenoti-invoices-pay-card` | Charge the guest's card on file (financial action) |\n| `zenoti-invoices-close` | Close a fully-paid invoice |\n| `zenoti-invoices-email` | Email the receipt/invoice to the guest |\n| `zenoti-invoices-confirm-visit` | Confirm (or undo-confirm) the visit — a scheduling status, despite living on the invoice |\n\n### Reports\n| Tool | Purpose |\n|---|---|\n| `zenoti-reports-sales` | What was sold over a date range |\n| `zenoti-reports-collections` | Money received over a date range |\n\n### Forms & feedback\n| Tool | Purpose |\n|---|---|\n| `zenoti-forms-list` / `zenoti-forms-get` | Forms and submitted form data of an appointment |\n| `zenoti-guest-forms-list` | Forms on a guest profile |\n| `zenoti-feedback-submit` | Insert externally collected guest feedback |\n\n## Zenoti API gotchas this server handles\n\n- **Three identifiers in one workflow.** Check-in/no-show/feedback take `appointment_group_id`; details/progress/forms take `appointment_id`; cancel and payments take `invoice_id`. Tool schemas name the exact one required.\n- **Guest updates replace the whole object.** The update tool fetches the current profile and merges your changes; a naive partial `PUT` would erase fields.\n- **Rate limit is 60 calls/minute** (org-wide). The HTTP layer honors `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).\n- **Pagination caps at `size=100`**; larger values are rejected by Zenoti with a 422.\n- **Webhooks have no subscription API** — they are configured in the Zenoti web UI (Admin → Webhooks) and require the Zenoti API package. This server intentionally has no webhook tool.\n- **Undocumented numeric enums.** Gender and appointment-progress codes aren't in Zenoti's public docs; the mappings used here are documented in the tool descriptions and can be overridden (`progress_code`).\n\n## Development\n\n```bash\nnpm run dev        # run from source (tsx)\nnpm test           # unit + end-to-end tests (mock Zenoti API; no real credentials needed)\nnpm run typecheck  # tsc --noEmit\nnpm run build      # emit dist/\n```\n\nThe 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.\n\n## License\n\nMIT\n",
  "bytes": 6375,
  "sha": "73040da20ac2f501721178d227f5ac63a75b90a1a9cebe3741aceb5042312016",
  "repo_slug": "tacit-code/zenoti-mcp-server",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_com_jamesrosingmd_zenoti_1fcda62d/readme"
}