███╗ ███╗ █████╗ ██████╗ ██╗ ██████╗██╗ ██╗███╗ ██╗███████╗ ████╗ ████║██╔══██╗██╔════╝ ██║██╔════╝██║ ██║████╗ ██║██╔════╝ ██╔████╔██║███████║██║ ███╗██║██║ ██║ ██║██╔██╗ ██║█████╗ ██║╚██╔╝██║██╔══██║██║ ██║██║██║ ██║ ██║██║╚██╗██║██╔══╝ ██║ ╚═╝ ██║██║ ██║╚██████╔╝██║╚██████╗███████╗██║██║ ╚████║███████╗ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝╚══════╝╚═╝╚═╝ ╚═══╝╚══════╝
Model Context Protocol lets AI assistants securely connect to external tools. This server sits in the middle, translating plain language into safe, scoped calls to the Magicline Open API. There's nothing to run or keep alive: your client starts it on demand and shuts it down when finished.
94 hand-curated tools covering classes, bookings, members and contracts, plus SQL analytics over the Magicline data warehouse, every one gated behind permission tiers you control.
An interactive wizard validates your credentials against the live API, stores your key securely, and configures every AI client you pick.
It brings its own Python, nothing else to install. One line for macOS, Linux or Windows.
Run uvx magicline-mcp setup, no clone, no install step, uv fetches the package from PyPI. It asks whether your studio is production or sandbox, validates your credentials live, stores the key in your OS secret store, then lets you pick clients from a checklist, detected ones are pre-selected.
Magicline appears in the client's tools list. In Claude Desktop: Settings → Developer. In Cursor: Settings → Tools.
“What classes are running tomorrow?” If it answers, you're done.
# install uv (macOS / Linux)
curl -LsSf https://astral.sh/uv/install.sh | sh
# run the setup wizard
uvx magicline-mcp setup
# enable member data + writes
uvx magicline-mcp setup --advanced
# always launch the latest release
uvx magicline-mcp setup --auto-update
Test in a sandbox firstThe setup wizard asks whether your studio is production or sandbox and configures the endpoint for you, choose sandbox before you enable writes against anything real.
Tiers control which tools exist at all: the server never even registers write tools without the write tier. Change them anytime with magicline-mcp permissions, which also lets you enable or disable individual tools per category (memberships, appointments, classes, ...), so you can allow bookings while keeping cancelations off entirely.
readpiiwriteEnabling writes and member data has real consequencesThe agent can take irreversible actions, including cancelling real member contracts, and member data exposes personal data under GDPR. If you can't review each tool call before approving it, keep these off, especially against production. Pre-approval (Claude Code's --allow-all) controls whether Claude asks; tiers control what exists. They're independent.
Independently of the tiers, Claude Code asks for approval before every tool call. When setup configures it, it offers to pre-approve Magicline tools so those prompts disappear, a bypass you choose the scope of.
Lookups, schedules, previews and validations run without prompting. Write actions (bookings, cancellations, check-ins) still ask first.
No prompts at all, writes included. setup --allow-all sets this in one shot, for scripted or headless installs.
Keep Claude's ask-every-time behaviour: nothing is pre-authorised, and you approve each call as it happens.
Under the hood this merges mcp__Magicline… rules into permissions.allow in ~/.claude/settings.json, which both the CLI and desktop app read. Your existing rules are preserved, remove the Magicline entries there to get the prompts back.
Other clients differClaude Desktop has no pre-approval file. Use its “Always allow” dialog option, once per tool. Cursor, Windsurf and Gemini CLI each have their own auto-approve settings in their own UIs.
Just ask. The assistant figures out which tools to use. As with any AI, if the first phrasing doesn't land, try another.
The complete set of 94 tools. Read tools are always available; member-data and write tools only exist once their tier is enabled. Click any tool for its description, or run magicline-mcp tools in your terminal.
read25 tools · always onGet the studio's additional modules (paid add-ons like drink flatrate, solarium) available in member self-service.
Get available time slots for a bookable appointment type. Slots are calculated from slot_window_start_date (YYYY-MM-DD, default today) up to days_ahead later (maximum 6 days). An empty result means no free slots in that window, try a later start date.
Get one bookable appointment type by its ID.
Get a single class (group fitness course) by its ID.
Get one specific class slot with its current state (times, instructor, free capacity, booking windows). If class_id is omitted, the slot is located by scanning upcoming slots across all classes.
Get the studio's configured contract cancelation reasons (needed to create a cancelation).
Get the studio's lead configuration: which fields are required or available when creating a lead.
Get one membership offer with full details (terms, pricing, modules).
Get general information about the studio: name, address, contact details, opening hours and configuration.
Get the studio's current utilization (how busy the gym is right now).
Get available slots for a trial-offer appointment type.
Get bookable trial-offer slots for one class.
Get a trial offer configuration by its ID.
List the studio's configured additional information fields, the custom profile fields available on every customer (IDs, names, types and allowed values), e.g. a 'Front desk notes' text field. When asked to add a note or custom info to a customer's PROFILE, check here first for a matching field, then write it with set_additional_information_fields.
List the studio's bookable appointment types (e.g. personal training, body analysis, consultations).
List upcoming bookable class slots (scheduled sessions) with start time, instructor and free capacity, across all classes, or for one class via class_id. Optional from_date/to_date (YYYY-MM-DD, inclusive) filter by day. Slots exist only as far ahead as the studio has published its schedule (often ~2 weeks): schedule_published_until in the response is that horizon, dates beyond it aren't bookable *yet*, rather than free or full.
List the studio's active classes (group fitness courses) with title, description and schedule information.
List all membership offers (tariffs/plans) the studio currently sells.
List appointment types that can be booked as a trial offer.
List classes that can be booked as a trial offer.
Describe the columns of a warehouse table: column_name, data_type, is_nullable, and column_default.
Look up data warehouse documentation by topic: business definitions, per-table analyst notes (correct filters, join keys, gotchas) and SQL rules. Call without a topic to list available topics; with a topic it matches section names first, then falls back to keyword search (e.g. "churn", "KPI", "idle", "tables"). Consult this before writing non-trivial SQL.
List the queryable schemas in the data warehouse.
List tables and views in a warehouse schema. Returns table_name and table_type (BASE TABLE or VIEW) for each entry. Entries flagged deprecated: true (names ending __old) are stale copies, ignore them.
Run a read-only SQL query against the data warehouse. Values in string/varchar columns are masked as "<withheld>" (they may contain PII); row counts and structure stay truthful. Alias derived period labels AS month/year/quarter/week to keep them visible. Use warehouse_query_pii for unmasked results when the pii tier is enabled. Redshift SQL dialect: no FILTER clause (use SUM(CASE WHEN ... END)), no ILIKE ANY; DATE_TRUNC, LISTAGG and window functions are available. Results are capped at 500 rows (truncated: true when the cap hits), prefer aggregates. Numeric/decimal values are returned as JSON strings to preserve precision. Returns {columns, rows, withheldColumns, truncated}.
pii35 tools · opt-inGet a customer's past account transactions (charges with their open amounts). Optional from_date/to_date (YYYY-MM-DD, inclusive) filter by the transaction's dueDate. Note: the API exposes charges only, no settlement records (payment-received dates or payment method per transaction).
Get a single appointment booking by its booking ID.
Get a customer's appointment bookings within roughly +/- 2 weeks of today.
Get a single class booking by its booking ID (including the customer).
Get all class bookings for a specific customer.
Get a customer's communication preferences (which channels they accept per message category: CONTRACT, GENERAL, APPOINTMENT, NEWSLETTER, LOYALTY_PROGRAM).
Get a customer's contract data as shown in member self-service, including cancelation options.
Get a customer's full profile by their ID. Includes cardNumbers: the member's club access card number(s), ordinary front-desk data that staff can freely see and share with the member (NOT a payment card number).
Get a customer's account balance data (credits and open amounts).
Get a customer's (partner integration) benefits, optionally filtered by benefit keys.
Get a customer's benefits by a member identifier (access card number, barcode or PIN) instead of their customer ID. Provide exactly one identifier. Optional keys filter checks only those benefits.
Look up a customer by a member identifier: club access card number, customer number, barcode, QR code UUID, PIN, or debtor ID. Provide exactly one. card_number is the number on the member's access card (not a payment card). card_number_format (for card lookups): DECIMAL, HEX_MSB or HEX_LSB.
Get a customer's studio check-in history. Dates are YYYY-MM-DD; the range must not exceed 365 days.
Get one membership contract of a customer by contract ID.
Get a customer's membership contracts. Optional status filter: ACTIVE or INACTIVE.
Get a customer's transactions in a date range (YYYY-MM-DD, max 365 days).
Preview the future debt claims (upcoming dues) for one of the customer's contracts, e.g. what they would still owe through the remaining term.
Get a single employee by their ID.
Get one idle period (pause/freeze/hold) by its ID, current state, dates and verification status.
Get the idle period (pause/freeze/hold) configuration of a contract: allowed reasons, durations and limits. Call this before validate_idle_period/create_idle_period, its temporalUnit is the only unit the contract accepts.
Get the idle periods (contract pauses/freezes/holds) of a contract.
Get one membership switch configuration for a customer, including the destination offers, terms and modules available for that switch path.
Get the membership switch paths (upgrades/downgrades) available to a customer. An empty list means the customer is not eligible for any switch.
Get the payment details a customer has on file (payment method / mandate information).
Get the additional modules (add-ons) a specific contract could purchase.
Get how many idle-period (pause/freeze) free terms and max terms the contract has left.
Get a tax advisor export by its ID (status and download information).
Get a customer's upcoming account transactions within the next year (future dues and scheduled charges).
List customers. Optional customer_status filter: MEMBER, PROSPECT or FORMER_MEMBER.
List the studio's employees (trainers and staff).
Preview adding a new contract to an existing customer without creating it, the authoritative price calculation including their discounts. dueOnSigningAmount is the mandatory amount payable at signing; the payment schedule may also list same-day charges flagged as non-mandatory (e.g. optional modules), those are NOT part of the amount due at signing. Get term IDs from get_membership_offer. The actual signup requires the studio's payment frontend and is not available as a tool.
Preview a brand-new membership signup (price quote for a prospect) without creating anything. customer follows the Magicline customer schema, at minimum firstName, lastName, dateOfBirth, email, street, city, zipCode, countryCode and language {"languageCode": ...}. dueOnSigningAmount is the authoritative mandatory amount payable at signing; the payment schedule may also list same-day charges flagged as non-mandatory (e.g. optional modules), those are NOT part of the amount due at signing. If dueOnSigningAmount is 0, the signup can be completed with signup_membership; otherwise it must go through the studio's payment frontend.
Preview a membership switch (upgrade/downgrade) without performing it, the authoritative source for pro-rated costs and fees (paymentPreview.dueOnSigningAmount). Performing the actual switch requires the studio's payment frontend and is not available as a tool.
Search customers by name (prefix match), email, date of birth (YYYY-MM-DD) or phone number (+49... format). Provide at least one criterion.
Run a read-only SQL query against the data warehouse with full, unmasked results including all string/varchar columns (PII). Requires the pii tier. Redshift SQL dialect: no FILTER clause (use SUM(CASE WHEN ... END)). Results are capped at 500 rows (truncated: true when the cap hits), prefer aggregates. Numeric/decimal values are returned as JSON strings to preserve precision. Returns {columns, rows, truncated}.
write34 tools · opt-in**Destructive, never pre-approved; a human confirms every call.** Assign a membership contract to an existing customer, a REAL, binding contract; confirm details with the user first. Always run preview_add_membership first: this works directly only when the preview's dueOnSigningAmount is 0 (nothing to charge at signing). If it is greater than 0, the signup must go through the studio's payment frontend instead, tell the user rather than attempting it. Get term IDs from get_membership_offer.
Add a communication entry to an existing thread on a customer's record. Same fields as create_communication_thread; thread_status updates the thread (CREATED, ONGOING or CLOSED). The API cannot list or read existing threads, so thread_id must come from a create_communication_thread response, keep that ID if follow-ups are expected; otherwise start a new thread.
Book an appointment for a customer. Times are ISO-8601 with timezone, e.g. '2026-07-22T08:00:00+02:00'. Pick times from get_appointment_slots. Omit instructor_ids to book the first available instructor; pass one to request a specific trainer. Validate with validate_appointment_booking first.
Book a class slot for a customer. Use validate_class_booking first if you are unsure the slot is bookable.
Book a trial-offer appointment for a lead customer. Times are ISO-8601 with timezone; pick them from get_trial_offer_appointment_slots.
Book a trial-offer class slot for a lead customer (create the lead with create_trial_lead first).
Cancel an existing appointment booking by its booking ID.
Cancel an existing class booking by its booking ID.
**Destructive, never pre-approved; a human confirms every call.** Create an ordinary contract cancelation for a customer. cancelation_date is YYYY-MM-DD; get valid reason IDs from get_contract_cancelation_reasons. This is a real cancelation, confirm details with the user first.
Create a manual studio check-in for a customer. Optional ISO-8601 time (e.g. '2026-07-17T10:15:30+01:00'); defaults to now.
Create a manual studio checkout for a customer. Optional ISO-8601 time; defaults to now.
Confirm a trial offer booking. Required when the trial config sets a confirmationOfBookingTerm, unconfirmed bookings are auto-cancelled after the deadline. Returns CONFIRMED, or EXPIRED if confirmed too late.
Log a past communication/interaction on a customer's record as a new thread (e.g. record a phone call or email that happened). NOT for notes on the customer's profile, for profile notes or custom fields (e.g. 'front desk notes') use set_additional_information_fields instead. Threads cannot be read back through this API (write-only). communication_channel: PHONE, EMAIL, CHAT, CONVERSATION, LETTER, TEXT_MESSAGE, FAX or OTHER; communication_direction: INCOMING or OUTGOING; thread_status: CREATED, ONGOING or CLOSED.
Create a new customer (prospect, no contract). date_of_birth is YYYY-MM-DD; country_code and language_code are ISO codes (e.g. 'DE', 'de'); gender is MALE, FEMALE or UNISEX. Address is mandatory in Magicline.
Freeze or pause a membership: create an idle period (hold) on a contract. start_date is YYYY-MM-DD; temporal_unit must be the temporalUnit from get_idle_period_config, with term_value, or set unlimited=true instead. Get valid reason IDs from get_idle_period_config. Run validate_idle_period first.
Create a new lead (prospect). gender is MALE, FEMALE or UNISEX; date_of_birth is YYYY-MM-DD. Check get_lead_config for required fields.
**Destructive, never pre-approved; a human confirms every call.** Create a tax advisor export. The payload follows the Magicline 'Create tax advisor export' schema (period, export options).
Create a lead customer for a trial offer, mandatory before booking a trial session; returns the customerId to book with. Get the trial_offer_config_id from the bookable trial class/appointment, and check get_trial_offer_config for which fields the studio requires. Studios typically reject duplicates by email (DUPLICATE_CUSTOMER).
Preview the charges/fees of changing an existing idle period (pause/freeze), without applying it, e.g. what extending or shortening a freeze would cost. Use end_date to shorten to an exact date (if the config allows it).
Set a customer's additional information field values (custom profile fields), THE tool for putting notes on a customer's profile (e.g. a 'Front desk notes' field), not create_communication_thread (which logs a phone call/email interaction instead). assignments is a list of {"additionalInformationFieldId": <id>, "value": <string>}. This REPLACES the customer's full set of assignments, include every field that should keep its value (current values are in get_customer's additionalInformationFieldAssignments; field IDs come from list_additional_information_fields). To append to an existing note, send the old value plus the new text.
**Destructive, never pre-approved; a human confirms every call.** Sign up a brand-new member: creates the customer AND a REAL, binding membership contract in one step, confirm details with the user first. Always run preview_membership_signup first: this works directly only when the preview's dueOnSigningAmount is 0 (nothing to charge at signing). If it is greater than 0, the signup must go through the studio's payment frontend instead, tell the user rather than attempting it. customer follows the same schema as preview_membership_signup (at minimum firstName, lastName, dateOfBirth, email, street, city, zipCode, countryCode and language {"languageCode": ...}). For an EXISTING customer use add_membership, not this. Get term IDs from get_membership_offer.
..., "active": bool, "customerOverridable": bool}]}. Read the current preferences first, modify, and send the result back.
Change an existing idle period / freeze (extend, shorten, move, or convert an unlimited freeze to a fixed end). Run preview_idle_period_update first to show the customer the resulting charges.
Record a usage of a customer's benefit (consumes one unit of their contingent). Check get_customer_benefits first.
Check whether an additional module could be added to a contract, without purchasing it. IDs come from get_purchasable_additional_modules.
Check whether an appointment can be booked for a customer without booking it, some appointments are restricted to certain memberships. Use before book_appointment. The response carries valid: true/false alongside the raw validationStatus.
Check whether a class slot can be booked for a customer, without booking it. The response carries valid: true/false alongside the raw validationStatus.
Check whether an idle period (pause/freeze/hold) request is valid, catches overlaps, max-term violations and too-early start dates, without creating it. Use before create_idle_period. validationStatus IDLEPERIOD_CREATABLE means the request is valid (also flagged as valid: true). temporal_unit must be exactly the temporalUnit from get_idle_period_config (e.g. a DAY-based contract rejects MONTH with IDLEPERIOD_TEMPORALUNIT_INVALID).
Validate lead data against the studio's lead config without creating it.
Check whether a trial-offer appointment can be booked for a lead customer, without booking it. Use before book_trial_appointment. The response carries valid: true/false alongside the raw validationStatus.
Check whether a trial class slot can be booked for a lead customer, without booking it. Use before book_trial_class. The response carries valid: true/false alongside the raw validationStatus.
Validate trial-lead data against the trial offer config without creating the lead, catches missing required fields and duplicate customers. Use before create_trial_lead. The response carries valid: true/false alongside the raw validationStatus.
Withdraw (undo) an ordinary cancelation of a customer's contract.
Withdraw (cancel) a scheduled idle period / freeze that hasn't started yet. Withdrawn idle periods cannot be reactivated, a new one must be created.
Operators with access to the Magicline enterprise data warehouse (Amazon Redshift) get six extra SQL analytics tools: churn, revenue, attendance, any question your studio data can answer. The setup wizard asks once; skip it and nothing changes, the warehouse tools only exist when a connection is configured.
Queries run in read-only transactions that are always rolled back, with a 60-second statement timeout. Results are capped at 500 rows with an honest truncated flag, multi-statement SQL is rejected, and driver errors come back cleaned up with corrective hints for common Redshift-dialect mistakes.
At read tier, warehouse_query masks values in string columns and known personal-data columns as "<withheld>", row counts and structure stay truthful, while status columns and period labels stay visible. Unmasked rows require the pii tier via warehouse_query_pii. The masking is best-effort hygiene, not a security boundary: the database user's read-only grants are the real enforcement.
A key-tables cheat sheet is embedded in the server instructions, and the full business glossary (definitions, join keys, correct status filters) is available on demand, by topic through warehouse_docs, or wholesale as MCP resources. The assistant learns the schema before it writes SQL.
# read tier, always on when configured
warehouse_docs glossary topic lookup
warehouse_list_schemas queryable schemas
warehouse_list_tables tables in a schema
warehouse_describe_table columns and types
warehouse_query SQL, PII masked
# pii tier, opt-in
warehouse_query_pii SQL, unmasked rows
# store / inspect / remove the password
uvx magicline-mcp warehouse set
uvx magicline-mcp warehouse status
uvx magicline-mcp warehouse delete
Connect with a read-only warehouse userThe server opens read-only transactions and rolls every query back, but arbitrary SQL could escape that. The database user's permissions are the real enforcement, grant it SELECT and nothing else.
Run these with uvx magicline-mcp <command> from anywhere, uv fetches the published package from PyPI on demand.
| Command | What it does |
|---|---|
setup | One-time interactive setup (safe read-only mode) |
setup --advanced | Setup with elevated capabilities (member data, writes, optional per-tool fine-tuning) |
setup --auto-update | Clients always launch the latest published version |
setup --claude-code | Also configures Claude Code via claude mcp add |
setup --allow-all | Pre-approve tools in Claude Code, writes included, but destructive contract/payment actions still ask |
test | Verify stored credentials against the live API |
tools | List every tool, grouped by permission tier |
permissions | Change tiers or enable/disable individual tools, across all configured clients |
keys list | Show stored keys (masked), environments, active tenant |
keys add | Store a key for another studio |
keys activate <tenant> | Switch all clients to another studio (and its environment) |
keys delete <tenant> | Remove a stored key |
warehouse set\|status\|delete | Manage the data-warehouse password in the OS keyring |
magicline-mcp | Run the MCP server on stdio, your AI client does this for you |
Actual key values live in your OS secret store: macOS Keychain, Windows Credential Manager (DPAPI), or Secret Service on Linux. Only tenant names are kept in ~/.magicline-mcp/tenants.json. On headless Linux without a keyring, fall back to the MAGICLINE_API_KEY environment variable.
Magicline keys are per studio. Multi-studio operators store one key per tenant and switch with keys activate, which rewrites MAGICLINE_TENANT across every configured client at once. Each key remembers its environment (production, sandbox, or a custom URL), so activating a tenant switches the endpoint with it. Restart your client afterwards.
# list keys (masked) + active tenant
uvx magicline-mcp keys list
# add another studio (validated live)
uvx magicline-mcp keys add
# switch every client to another studio
uvx magicline-mcp keys activate <tenant>
# remove a stored key
uvx magicline-mcp keys delete <tenant>
The wizard edits these files for you, but every client uses the same format, so you can also edit them yourself.
{
"mcpServers": {
"Magicline": {
"command": "uvx",
"args": ["magicline-mcp"],
"env": {
"MAGICLINE_TENANT": "mystudio",
"MAGICLINE_TOOLS": "read"
}
}
}
}
{
"mcpServers": {
"Magicline": {
"command": "uvx",
"args": ["magicline-mcp"],
"env": {
"MAGICLINE_TENANT": "mystudio",
"MAGICLINE_TOOLS": "read,pii",
"MAGICLINE_API_KEY": "your-api-key"
}
}
}
}
Let the wizard write these filesOn Windows it writes the full path to uvx.exe as command, since GUI apps don't reliably inherit your shell's PATH, and with --auto-update it writes magicline-mcp@latest so clients always launch the newest release. You don't need to think about any of it.
Variables marked managed are written by the wizard; you only set them yourself in non-interactive environments.
| Variable | Managed | Description |
|---|---|---|
MAGICLINE_TENANT | managed | Your tenant/studio name: the <tenant> in the base URL. Required. |
MAGICLINE_TOOLS | managed | Enabled tiers, comma-separated: read (default), pii, write. read is always included. |
MAGICLINE_TOOLS_EXCLUDE | managed | Individual tools to disable, comma-separated names. Applied after tier filtering; unknown names are ignored with a warning. Managed by magicline-mcp permissions. |
MAGICLINE_API_KEY | - | API key. Overrides the keyring, for CI, Docker or headless machines. |
MAGICLINE_BASE_URL | managed | Custom API base URL: written when you pick a sandbox or custom environment. HTTPS required (plain http only for localhost). |
WAREHOUSE_HOST | managed | Redshift endpoint of the enterprise data warehouse. Warehouse tools register only when host, database and user are all set. |
WAREHOUSE_PORT | managed | Warehouse port (default 5439). |
WAREHOUSE_DATABASE | managed | Warehouse database name. |
WAREHOUSE_USER | managed | Warehouse user, use one with read-only grants. |
WAREHOUSE_PASSWORD | - | Warehouse password. Overrides the OS keyring, only needed where no keyring exists. |
| Symptom | Fix |
|---|---|
| “No API key found” | Run setup, or set MAGICLINE_API_KEY. Verify with test. |
| 401 Unauthorized | Tenant and key don't match, or the integration was deactivated. Both come from the same activation email. |
| 403 Permission denied | Missing API-key scope, entity from another studio, or the member opted out of third-party access; the message says which. |
| Tools missing | Member-data and write tools only appear when their tier is on, and individual tools may be disabled: check permissions, then restart the client. |
| “Server disconnected” (Claude Desktop) | Check ~/Library/Logs/Claude/mcp-server-Magicline.log, the last Python traceback usually names the cause. |
| Keyring issues on Linux | Headless machines often have no Secret Service; use the MAGICLINE_API_KEY env var in the client config. |