acuity-mcp
Provides an alternative path to access Acuity Scheduling accounts that may be restricted by API plan tier, using Zapier's Acuity connector.
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., "@acuity-mcpShow me available slots for a 30-min consult tomorrow"
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.
acuity-mcp
A local MCP server exposing the Acuity Scheduling API as Claude Code tools — list/create/reschedule/cancel appointments, check availability, list appointment types, calendars, and clients, all directly from a Claude session. Supports multiple Acuity accounts side by side, switchable per tool call.
Built custom because no maintained free MCP for Acuity exists — the only GitHub repo found during
research pointed at an npm package that was never published. Uses @modelcontextprotocol/sdk +
zod, runs over stdio.
If you're Claude: read this first
If a user asks you to set this up, add an Acuity account, switch accounts, or troubleshoot a
connection, load .claude/skills/acuity-mcp-setup/SKILL.md in this repo — it has the full
step-by-step for all of that. This README is the human-facing reference; the skill is what you
should actually follow.
Related MCP server: leximo-ai-call-assistant-mcp-server
What you need before setup
An Acuity Scheduling User ID and API Key, from Acuity: Business Settings → Integrations → API. One pair per Acuity account you want to connect.
⚠️ Acuity gates API access by plan tier. Some plans return 403: API access is only available on Powerhouse plans for every request — this is Acuity rejecting your account, not a bug here.
Basic Auth succeeding (no 401) but every call still 403-ing is the signature of this. If you
hit it, either upgrade the plan, or use an alternative path to the same account (e.g. a Zapier
Acuity connector, which has empirically not been subject to the same restriction).
Install
npm installQuick start — one account
node bin/acuity-accounts.js add production --user-id <your-user-id> --api-key <your-api-key>The first account you add automatically becomes the default. Then register the server with Claude Code:
claude mcp add acuity -s user -- node "$(pwd)/server.js"Start a new Claude Code session (or run /mcp in an existing one) so the tools show up.
Verify it works without a Claude session at all:
node bin/acuity-accounts.js testMultiple accounts
Add as many named accounts as you want:
node bin/acuity-accounts.js add production --user-id 1111111 --api-key aaaa... --label "Real account"
node bin/acuity-accounts.js add sandbox --user-id 2222222 --api-key bbbb... --label "Trial/test account"Credentials live in ~/.config/acuity-mcp/accounts.json (chmod 600, never inside this repo,
never committed). Manage them:
node bin/acuity-accounts.js list # see configured accounts (never prints API keys)
node bin/acuity-accounts.js set-default sandbox # change which one is used by default
node bin/acuity-accounts.js remove sandbox # remove one
node bin/acuity-accounts.js test sandbox # verify one specific account's credentialsSwitching accounts inside a Claude session doesn't require re-registering anything — every
tool this server exposes accepts an optional account argument:
"List appointment types for the sandbox account" → Claude calls
list_appointment_typeswith{"account": "sandbox"}.
Ask Claude to run list_accounts at any time to see what's configured and which is default.
If you'd rather run fully separate MCP server registrations per account instead (e.g. so each
shows up as a distinctly-named server), that still works — point ACUITY_ACCOUNT at a name
instead of passing account per call:
claude mcp add acuity-production -s user -e ACUITY_ACCOUNT=production -- node "$(pwd)/server.js"
claude mcp add acuity-sandbox -s user -e ACUITY_ACCOUNT=sandbox -- node "$(pwd)/server.js"Credential resolution order
ACUITY_USER_ID+ACUITY_API_KEYenv vars (direct override, no accounts file needed)accountargument on a tool call, or theACUITY_ACCOUNTenv var — looked up by nameaccounts.json's owndefaultaccountaccounts.jsonwith exactly one account configured — used automaticallyLegacy flat
~/.config/acuity-mcp/credentialsfile (ACUITY_USER_ID=.../ACUITY_API_KEY=...lines) — supported for backward compatibility with older single-account setups
Tools
Local only, no Acuity API call:
list_accounts— list configured account names/labels and the default (never API keys)
Read-only:
list_appointment_types— list bookable consult typeslist_calendars— list calendars/stafflist_appointments— filterable by date range / calendar / type / canceled statusget_appointment— full detail on one appointment by IDcheck_availability_dates— available dates in a month for an appointment typecheck_availability_times— available time slots on a date for an appointment typelist_clients— clients who have booked appointments
Mutating (real changes to the live calendar — Claude will ask for confirmation before calling these):
create_appointment— book a new appointmentreschedule_appointment— change an appointment's date/timecancel_appointment— cancel an appointment
All tools accept an optional account argument (see Multiple accounts).
Not implemented (same pattern, add later if needed): payments, blocks, forms, webhooks, gift certificates.
Lessons learned (read before extending this server)
A
200 OKfrom a mutating call does not prove the mutation happened.reschedule_appointmentoriginally calledPUT /appointments/:id, which returned200and echoed back the unchanged appointment — Acuity silently ignored thedatetimefield on that endpoint. The fix was the dedicatedPUT /appointments/:id/rescheduleroute, matching the patterncancel_appointmentalready used (/appointments/:id/cancel). Always re-fetch withget_appointmentafter a write before trusting it, especially for any new mutating tool added later.npx @modelcontextprotocol/inspector --clidoes not reliably forward ad-hoc env vars to thenode server.jsprocess it spawns. If you're testing credentials that aren't already the resolved default (e.g.ACUITY_USER_ID=x ACUITY_API_KEY=y npx @modelcontextprotocol/inspector --cli ...), it can silently fall back to whatever's already configured and give a false positive/negative. Usenode bin/acuity-accounts.js test <name>instead — built specifically to avoid this trap. The inspector CLI remains fine for its original purpose: testing the resolved default credentials, or--method tools/listto check tool schemas.
Manual verification
node bin/acuity-accounts.js test # tests the default/env-resolved account
node bin/acuity-accounts.js test <name> # tests one specific named account
npx @modelcontextprotocol/inspector --cli node server.js --method tools/list # confirms the server starts and tools register correctlyThis server cannot be deployed
Maintenance
Related MCP Connectors
Hosted MCP server for Cliniko — patients, appointments, availability, and invoices for AI agents.
MCP server unifying ERPs, CRMs, APIs and knowledge base for Claude, ChatGPT and Gemini.
MCP server for Cronofy — read calendars, events and free/busy, and create, update or delete events.
Hosted Amazon Seller Central and Amazon Ads MCP server for Claude, ChatGPT, Cursor, and agents.
Related MCP Servers
- AlicenseAqualityDmaintenanceAn MCP server that connects Claude Desktop and Claude Code to your Calendly account, enabling natural-language scheduling management.7MIT
- AlicenseAqualityFmaintenanceAn MCP server that lets you schedule AI phone calls and manage Leximo assignments directly from Claude Desktop or Claude Code.1325 npm2MIT
- FlicenseBqualityDmaintenanceMCP server for Cal.com scheduling, providing ~70 tools to manage schedules, event types, bookings, calendars, webhooks, and teams. Enables natural language control of Cal.com from Claude or any MCP-compatible client.68-
- AlicenseNot gradedqualityBmaintenanceA local MCP server for CalDAV that gives Claude read access to your calendar, enabling planning, conflict checking, and schedule summaries.MIT