mindbody-mcp-server
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., "@mindbody-mcp-server show today's class schedule with booked counts"
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.
mindbody-mcp-server
An unofficial Model Context Protocol (MCP) server for the Mindbody Public API v6. It lets an MCP client such as Claude Code or Claude Desktop answer questions about a Mindbody site — schedules, attendance, sales, services, contracts — without handing the model your members' personal details.
This project is not affiliated with, endorsed by, or supported by Mindbody. "Mindbody" is a trademark of its owner. You need your own Mindbody developer account and API key.
The problem
Mindbody data is mostly about people. A raw API response for one client includes their email, phone numbers, home address, birth date, staff alerts and custom fields, which is where staff often write medical or safeguarding notes. If you connect a model straight to the API, all of that goes into the model's context. Most questions you want to ask ("how many sessions did this member attend last month?", "which intro offers sold this week?") do not need any of it.
Related MCP server: google-ads-mcp
How it works
flowchart LR
A[MCP client<br/>Claude Code / Desktop] -- tool call --> B[Tool layer<br/>src/tools.ts]
B -- resolve m_... tokens<br/>to real ids --> C[Mindbody client<br/>src/mbo/client.ts]
C -- paced requests --> P[Pacer<br/>src/mbo/pacer.ts]
P --> M[(Mindbody Public API v6)]
M --> C
C --> B
B -- drop empty fields --> S[src/slim.ts]
S -- mask PII --> K[src/pii.ts]
K -- masked JSON --> AThe client calls a tool. If the arguments contain member tokens (
m_...) from an earlier result, the server swaps them for the real Mindbody ids. Only the outbound API request sees the real id.The request goes through a pacer that spaces calls to each site, then to Mindbody with retry and backoff.
The response has empty fields removed, then passes through the PII mask, then goes back to the client as compact JSON.
Tools
Read-only, always available:
Tool | What it returns |
| Members matching a name, email or phone search, or specific client ids |
| One client's profile, services, contracts and balances |
| A client's purchased services, with remaining counts and expiry |
| A client's contracts and autopay status |
| A derived verdict: paying, past due, on hold, promo, comp or none |
| A client's visit history in a date range |
| The class schedule for a date range, with booked and signed-in counts |
| Rosters for specific classes |
| Staff at a site |
| Sales in a date range |
| The site's price list (cached for 12 hours) |
| Sites, locations, programs, session types, memberships or resources |
| Any other v6 GET endpoint, with optional pagination |
Writes, only when MBO_ALLOW_WRITES=true:
Tool | What it does |
| Adds a contact-log entry to a client |
| Updates profile fields on a client |
Webhook admin, only when MBO_ALLOW_WEBHOOK_ADMIN=true:
Tool | What it does |
| Lists webhook subscriptions |
| Creates a subscription |
| Deletes a subscription |
Safety design
Read-only by default. With no flags set, the server registers only read tools. Write and webhook tools are not registered at all, so the model cannot see or call them.
PII masking before anything reaches the model. Every tool result passes through
src/pii.ts:Contact details (email, phones, address, city, postal code, birth date), notes, alerts, custom fields, contract text, photos and card or barcode fields are removed.
Member ids are replaced with stable pseudonyms (
m_plus 16 hex characters, an HMAC with a random key created when the server starts).Member names become initials.
On a person record, any other text field is withheld unless it is on a short allowlist (status, membership name, service name and similar) or is a date. The names of withheld fields are listed in
_withheldso the model knows they exist.Counts, totals, prices, dates and service names pass through unchanged.
Writes behind explicit flags.
MBO_ALLOW_WRITESandMBO_ALLOW_WEBHOOK_ADMINmust be set totrue,1oryes. Anything else leaves them off.Rate-limit pacing. The pacer keeps a minimum gap between calls to the same site, widens that gap if one site gets a sustained burst of calls, pauses a site after Mindbody returns a 429 that survives the client's own retries, and caps how many calls run at once. If a call would wait too long, it fails with a clear "busy" error instead of hanging. The client also retries 429 and 5xx responses with exponential backoff and honors
Retry-After.Errors do not echo requests. Error messages include the path, status and Mindbody's own error code and message, never request headers or bodies.
What it does not do
It does not expose contact logs for reading. Their content is free text written by staff, which a field-based mask cannot make safe.
It does not store anything. There is no database or cache on disk; the token-to-id map and the price-list cache live in memory and are gone when the process exits.
It does not run as a hosted, multi-user service. It is a local stdio server for one user.
It does not send anything to members.
Setup
You need Node.js 18 or later.
Create a developer account at developers.mindbodyonline.com and get an API key.
Use Mindbody's public sandbox site, SiteId
-99, while you try it out. The sandbox staff login is in the Mindbody developer documentation.Build the server:
git clone <this repo> cd mindbody-mcp-server npm install npm run build
Claude Code
claude mcp add mindbody \
-e MBO_API_KEY=your-api-key \
-e MBO_USERNAME=your-staff-username \
-e MBO_PASSWORD=your-staff-password \
-e MBO_SITE_ID=-99 \
-- node /absolute/path/to/mindbody-mcp-server/dist/index.jsClaude Desktop
Add this to claude_desktop_config.json:
{
"mcpServers": {
"mindbody": {
"command": "node",
"args": ["/absolute/path/to/mindbody-mcp-server/dist/index.js"],
"env": {
"MBO_API_KEY": "your-api-key",
"MBO_USERNAME": "your-staff-username",
"MBO_PASSWORD": "your-staff-password",
"MBO_SITE_ID": "-99"
}
}
}
}Configuration
Variable | Required | Default | Meaning |
| yes | Your Mindbody API key | |
| yes | Staff username for the site | |
| yes | Staff password for the site | |
| no | none | Default SiteId when a tool call does not pass one |
| no | off | Registers the write tools |
| no | off | Registers the webhook admin tools |
| no |
| API base URL |
| no |
| Webhooks API base URL |
| no | on | Set to |
.env.example lists the same variables. Do not commit real values.
Development
npm testThis builds the TypeScript and runs the tests in tests/ with Node's built-in test runner. The
tests use fake HTTP responses and synthetic data; they make no network calls.
Limitations
Member tokens are valid only for the server process that issued them. After a restart, search for the member again.
Staff records from
/staff/stafflook like person records to the mask, so staff names are reduced to initials and staff ids are pseudonymized there too. Fields named for staff, such asStaffNameorCoachName, and records that carry aStaffId, keep the full name.The mask works on field names and value types. It is conservative, and it is tested against the Mindbody response shapes I know about, but a new Mindbody field with an unexpected name could still carry personal data. Review results before sharing them.
mbo_api_getreaches any GET endpoint. Its results are masked like every other tool, but the mask has only been checked against the common endpoints.The pacer's gaps are conservative defaults, not Mindbody's published limits. Mindbody does not publish a per-second limit.
Status
This is a cleaned-up, standalone version of an MCP server I built for a private project. This public version has been tested only with the unit and smoke tests in this repo, using synthetic data. It has not yet been run against the Mindbody sandbox in this form.
License
MIT. See LICENSE.
Available Tools
13 toolsmbo_api_getRaw Mindbody GET (any endpoint)ARead-only
Escape hatch: GET any Mindbody Public API v6 path with query params — covers all ~150 read operations (appointment/, enrollment/, payroll/, pricingoption/, site/, staff/, ...). Paths are like /appointment/staffappointments. Query param names are PascalCase (StartDate, ClientId, Limit...); m_... member tokens are accepted as values. Set paginate=true for list endpoints to follow Limit/Offset pages.
Inputs: path (required), params, siteId, maxPages, +1 more.
mbo_classify_client_paymentClassify member payment statusARead-only
Derived tool: buckets a client into paying | pastDue | onHold | promo | comp | none from their contracts, plus join/churn lifecycle dates. 'paying' requires a recurring NormalAutoPay > 0 — one-time setup fees never count as proof of payment.
Inputs: clientId (required), siteId.
mbo_get_classesGet sessions (schedule)ARead-only
GET /class/classes — the session schedule for a date range: staff, description, TotalBooked, TotalSignedIn (actual attendance — use this for show-rate math), waitlist, capacity, cancellation status.
Inputs: endDate (required), startDate (required), siteId, maxPages, +2 more.
mbo_get_class_visitsGet session rosters (attendance per session)ARead-only
Session roster rows (who was booked/signed in, late cancels, and the service they used) for specific sessions. The v6 endpoint only accepts a SINGULAR ClassId, so this tool issues one request per session with bounded concurrency (5). Service.Name reveals intro-offer/first-timer members. Member ids come back as m_... tokens.
Inputs: classIds (required), siteId, lastModifiedDate.
mbo_get_clientGet member (complete info)ARead-only
GET /client/clientcompleteinfo — one client's full record: profile, membership icon, client services, contracts, and account balances in a single call.
Inputs: clientId (required), siteId.
mbo_get_client_contractsGet member contractsARead-only
GET /client/clientcontracts — a client's contracts (array is under Contracts). Includes AutopayStatus, NormalAutoPay, Start/End/TerminationDate. Use mbo_classify_client_payment for the derived paying/promo/comp verdict.
Inputs: clientId (required), siteId.
mbo_get_client_servicesGet member servicesBRead-only
GET /client/clientservices — a client's purchased services (memberships, class packs, intro offers) with Current flags, remaining counts, and expiration dates.
Inputs: clientId (required), siteId.
mbo_get_client_visitsGet member attendanceBRead-only
GET /client/clientvisits — a client's visit history (class check-ins) in a date range.
Inputs: clientId (required), siteId, endDate, maxPages, +1 more.
mbo_get_salesGet salesARead-only
GET /sale/sales — sales transactions in a datetime range (the refund/purchase source of truth). Dates are site-local.
Inputs: endDate (required), startDate (required), siteId, maxPages.
mbo_get_servicesGet services (price list)ARead-only
GET /sale/services — purchasable services/pricing options (memberships, packs, intro offers) with ProductId, Price, and program linkage. Cached per site for 12h; complete: false means the page cap was hit before every row returned.
Inputs: siteId.
mbo_get_site_infoGet site infoBRead-only
Site-level reference data: sites (name/timezone), locations, programs, sessiontypes, memberships, or resources.
Inputs: resource (required), siteId.
mbo_get_staffGet staffARead-only
GET /staff/staff — staff at a site. Contact details are removed and names are reduced to initials by the PII mask.
Inputs: siteId, maxPages.
mbo_search_clientsSearch membersARead-only
Search Mindbody members by name/email/phone text, or fetch specific ClientIds. Returns raw MBO client records (contact info, MembershipIcon, status). For bulk member scans set includeProspects=false and raise maxPages.
Inputs: offset, siteId, maxPages, clientIds, +2 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 13 tools
Most tools target clearly distinct resources (clients, classes, staff, sales, site info), and the detailed descriptions clarify boundaries well. However, mbo_get_client_services vs mbo_get_services, and mbo_get_classes vs mbo_get_class_visits, are near-collisions that require reading the descriptions to disambiguate.
Nearly all tools follow a consistent mbo_ + verb_noun snake_case pattern (mbo_get_client, mbo_get_sales, mbo_search_clients). mbo_api_get reverses the verb-noun order and mbo_classify_client_payment is a longer derived-tool name, but these are minor deviations rather than real inconsistency.
13 tools is well-scoped for a broad Mindbody API surface, with each tool earning its place across client, class, staff, sales, and reference domains. The escape hatch absorbs the long tail rather than spawning dozens of thin tools.
Read coverage is strong across the core domains, and mbo_api_get backstops all ~150 read operations, so agents rarely hit a dead end. The main gap is the absence of any write operations (booking, creating clients, updating contracts), though the server appears intentionally read/analytics-oriented.
Maintenance
Related MCP Connectors
Scopable MSP API: clients, quotes, assessments, compliance, QBRs. OAuth 2.1, read-only or read-write
Managed MCP gateway with OAuth, per-agent permissions, shared accounts and activity logs.
Read-only MCP access to sessions, funnels, campaigns, errors, live visitors, and anomalies.
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables MCP clients to access Amazon Selling Partner and Advertising APIs for orders, inventory, pricing, ads, reports, and related read paths.MIT
- AlicenseAqualityCmaintenanceEnables MCP clients to retrieve Google Ads performance data, run GAQL queries and keyword planner research, and create or manage search and P-MAX campaigns, budgets, keywords, and ad status. Includes safety defaults such as paused creation and read-only mode.16MIT
- AlicenseBqualityBmaintenanceEnables MCP clients to read account status, plans, and recent workouts, search official exercise names, and, when writes are enabled, apply confirmed preview-first plan changes and historical workout logs.22MIT
- AlicenseAqualityBmaintenanceEnables MCP clients to search and describe API routes, retrieve people, admissions, academics, and billing records, download exports, and optionally make changes against a school information system, read-only by default.6928 npmMIT