Skip to main content
Glama

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.

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 install

Quick 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 test

Multiple 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 credentials

Switching 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_types with {"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

  1. ACUITY_USER_ID + ACUITY_API_KEY env vars (direct override, no accounts file needed)

  2. account argument on a tool call, or the ACUITY_ACCOUNT env var — looked up by name

  3. accounts.json's own default account

  4. accounts.json with exactly one account configured — used automatically

  5. Legacy flat ~/.config/acuity-mcp/credentials file (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 types

  • list_calendars — list calendars/staff

  • list_appointments — filterable by date range / calendar / type / canceled status

  • get_appointment — full detail on one appointment by ID

  • check_availability_dates — available dates in a month for an appointment type

  • check_availability_times — available time slots on a date for an appointment type

  • list_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 appointment

  • reschedule_appointment — change an appointment's date/time

  • cancel_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 OK from a mutating call does not prove the mutation happened. reschedule_appointment originally called PUT /appointments/:id, which returned 200 and echoed back the unchanged appointment — Acuity silently ignored the datetime field on that endpoint. The fix was the dedicated PUT /appointments/:id/reschedule route, matching the pattern cancel_appointment already used (/appointments/:id/cancel). Always re-fetch with get_appointment after a write before trusting it, especially for any new mutating tool added later.

  • npx @modelcontextprotocol/inspector --cli does not reliably forward ad-hoc env vars to the node server.js process 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. Use node 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/list to 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 correctly

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/walakaka77/acuity-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server