Metadata-Version: 2.4
Name: magicline-mcp
Version: 0.1.1
Summary: Magicline Studio MCP — MCP server for the Magicline Open API. Run once with `uvx magicline-mcp setup`, then it just works.
Project-URL: Repository, https://github.com/sportalliance/spa-openapi-mcp-wrapper
Project-URL: Documentation, https://developer.sportalliance.com/apis/magicline/openapi/general-information
Author: Karl Foster
License: MIT
License-File: LICENSE
Keywords: fitness,llm,magicline,mcp,sportalliance
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: keyring>=25.0
Requires-Dist: mcp>=1.2.0
Requires-Dist: questionary>=2.0
Requires-Dist: redshift-connector>=2.1
Requires-Dist: rich>=13.0
Description-Content-Type: text/markdown

# Magicline Studio MCP

Run your [Magicline](https://www.magicline.com) studio with natural language.
Ask questions or give instructions like *"Book Jonas Weber into tonight's Spin
class"*, *"Pause Anna Schmidt's contract for August"*, or *"When can Anna
cancel her contract at the latest?"* — and get instant answers without opening
dashboards or writing code.

Built on the [Magicline Open API](https://developer.sportalliance.com/apis/magicline/openapi/general-information)
by Sport Alliance, with optional SQL analytics over the Magicline
[enterprise data warehouse](https://data-warehouse-docs.magicline.com/index.html)
(Amazon Redshift).

![Setup wizard](setup-screenshot.svg)

**Supported AI clients:**

- [Claude Desktop](https://www.claude.com/download)
- [Claude Code](https://github.com/anthropics/claude-code)
- [Cursor](https://cursor.com/)
- [Windsurf](https://windsurf.com/)
- [Gemini CLI](https://github.com/google-gemini/gemini-cli)
- [Antigravity by Google](https://antigravity.google/)
- any other MCP-compatible client (manual config below)

## What is MCP?

[Model Context Protocol](https://modelcontextprotocol.io) (MCP) is an open
standard that lets AI assistants securely connect to external tools and APIs.
This server acts as a bridge between your AI client and Magicline, translating
natural language requests into safe, scoped API calls. There is no server to
run or keep alive — your AI client starts it on demand and shuts it down when
finished.

## Installation

**Prerequisites:**

- [uv](https://docs.astral.sh/uv/) (installs its own Python — nothing else needed):

  ```sh
  # macOS / Linux
  curl -LsSf https://astral.sh/uv/install.sh | sh

  # Windows (PowerShell)
  powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
  ```

- A Magicline Open API key (tenant name + key are in your integration
  activation email — the base URL looks like `https://<tenant>.open-api.magicline.com`)

Then run the setup wizard:

```sh
uvx magicline-mcp setup
```

It asks whether your studio is a **production or sandbox** environment (sandbox
studios live on `<tenant>.open-api.sandbox.magicline.com`; a custom URL is also
supported), validates your credentials against the live API, stores the key in
your OS secret store (macOS Keychain / Windows Credential Manager / Secret
Service — never in a plain-text config file), then lets you pick which AI
clients to configure from an interactive checklist — detected clients are
pre-selected, and Claude Code is configured via `claude mcp add` automatically.
Restart your AI client and you're done.

To always use the latest version (auto-update on each client restart), add `--auto-update`:

```sh
uvx magicline-mcp setup --auto-update
```

By default, setup configures the server in a **safe, read-only mode** (no
member data, no writes). To selectively enable elevated capabilities during
setup, pass `--advanced`:

```sh
uvx magicline-mcp setup --advanced
```

What you'll choose (optional):

- **Member data / PII** (`pii` tier): access member profiles (including lookup
  by card/barcode/QR), contracts, check-in history, account balances, payment
  details, transactions, membership switch/add previews, and debt collection
  data.
- **Writes** (`write` tier): book and cancel classes and appointments, check
  members in and out, create customers and leads, assign memberships (zero-due
  offers), cancel contracts, manage
  idle periods (contract freezes), log communications, and create payment
  sessions.
- **Individual tools** (optional): after picking tiers, setup offers the same
  per-category tool editor as `magicline-mcp permissions` — e.g. keep class
  bookings but disable `cancel_membership` entirely. Existing per-tool
  disables survive a re-run of setup either way.

> **IMPORTANT:** Enabling writes allows the AI agent to take real, potentially
> irreversible actions in your studio — including cancelling real member
> contracts and creating real bookings. Enabling member data exposes personal
> data of real members, with everything that implies under GDPR. If you are not
> in a position to review each tool call before approving it, keep these
> disabled — especially against a production studio. If you enable them, it is
> your responsibility to review every action before allowing the agent to
> proceed.

You can change permissions at any time without re-running setup:

```sh
uvx magicline-mcp permissions
```

Besides switching tiers, this opens a per-category tool editor: pick a
category (payments, memberships, appointments, ...), then check or uncheck
individual tools. Disabled tools are never registered with the AI client —
the agent doesn't see them at all. For example, you can enable the `write`
tier for class bookings and check-ins but disable `cancel_membership` and
`create_payment_session` entirely. Selections are stored as a deny-list
(`MAGICLINE_TOOLS_EXCLUDE`), so tools added in future versions are enabled
by default.

### Skipping permission prompts (Claude Code)

Independently of the tiers above, Claude Code asks for approval before
**every** tool call ("Claude wants to use List customers…"). When setup
configures Claude Code, it offers to pre-approve Magicline tools so those
prompts disappear:

- **Non-personal reads** (recommended): schedules, offers and studio info run
  without prompting; anything touching member data, and every write action
  (bookings, cancelations, check-ins), still asks first.
- **Everything except destructive actions**: no prompts for reads and routine
  writes; contract signups/cancellations, payment sessions and financial
  exports **always** ask — they are never pre-approved, by design.
- **No**: keep Claude's default ask-every-time behavior.

To skip the question and pre-approve everything (e.g. scripted installs):

```sh
uvx magicline-mcp setup --allow-all
```

This works by merging `mcp__Magicline…` rules into the `permissions.allow`
list in `~/.claude/settings.json`, which both the Claude Code CLI and its
desktop app read. Your existing rules are preserved; remove the Magicline
entries from that file to get the prompts back.

Note the two layers are different: the **tiers** (and any per-tool disables)
control which tools exist at
all (the server never even registers write tools without the `write` tier),
while **pre-approval** only controls whether Claude asks before using the
tools that do exist. Read-only pre-approval with a read-only tier is safe;
`--allow-all` with the `write` tier enabled means the agent can take routine
actions (bookings, check-ins, freezes) without you confirming each one —
though destructive operations (contract and payment changes) keep their
prompt no matter what.

> **Claude Desktop** has no pre-approval config file — use the "Always allow"
> option in its permission dialog, once per tool. Other clients (Cursor,
> Windsurf, Gemini CLI) have their own auto-approval settings in their UIs.

## What you can do

Run `uvx magicline-mcp tools` to see all 99 tools with descriptions, grouped
by permission tier. Tools are hand-curated over the Magicline Open API
with pagination, rate limiting and retries handled internally. The six
warehouse tools only appear when the optional
[data warehouse](#data-warehouse-optional) connection is configured.

Try these prompts — a day at the front desk:

- "Book Jonas Weber into tonight's Spin class"
- "Check Anna Schmidt in"
- "When can Anna cancel her contract at the latest?"
- "What payment method does she have on file, and what's her balance?"
- "Pause her contract for August — vacation"
- "Extend that freeze by a month — what would it cost?"
- "Create a lead for Max Mustermann, max@example.com, and book him a free
  trial session for tomorrow morning"
- "Assign the 12 Month Fixed membership to customer 10023 from next month"
- "Log that phone call on their record"

…and for the back office:

- "What classes are running tomorrow, and which still have free spots?"
- "How busy is the gym right now?"
- "What membership offers do we sell, and what would Premium cost customer 10023?"
- "Show the account balance and upcoming charges for customer 10023"

## Data warehouse (optional)

Operators with access to the Magicline [enterprise data warehouse](https://data-warehouse-docs.magicline.com/index.html)
(Amazon Redshift) can enable six extra SQL analytics tools. The setup wizard
asks about this ("Configure a Redshift data warehouse connection?") — skip it
and nothing changes: the warehouse tools are only registered when a
connection is configured.

| Tool | Tier | What it does |
| --- | --- | --- |
| `warehouse_docs` | read | Topic lookup in the built-in glossary (business terms, join keys, KPI definitions, SQL rules) |
| `warehouse_list_schemas` | read | List queryable schemas |
| `warehouse_list_tables` | read | List tables/views in a schema (stale `__old` copies flagged deprecated) |
| `warehouse_describe_table` | read | Column names, types, nullability |
| `warehouse_query` | read | Read-only SQL with PII values masked |
| `warehouse_query_pii` | pii | Read-only SQL, unmasked rows |

Queries run with guardrails: results are capped at 500 rows (with a
`truncated` flag), a 60-second statement timeout is set, 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/varchar columns and
known personal-data columns such as `date_of_birth` as `"<withheld>"` —
row counts and structure stay intact, and enum-like status/type columns
plus period aliases (`AS month`, `AS year`, …) stay visible. This masking
is **best-effort hygiene, not a security boundary** — it keys on result
column names, so aliased queries can slip past it. If you must guarantee
no PII at read tier, disable `warehouse_query` (via
`magicline-mcp permissions`) or enforce masking in the warehouse itself.

> **IMPORTANT:** connect with a warehouse user that has **read-only grants**.
> The 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.

The password lives in the OS keyring (manage it with
`magicline-mcp warehouse set|status|delete`); host, port, database and user
go into the client config's env block as `WAREHOUSE_*` variables (see
[Environment variables](#environment-variables)).

When a warehouse is configured, the server also teaches the AI how to query
it: the key-tables cheat sheet is embedded in the server instructions, and
the full business glossary (definitions, join keys, correct status filters
for every `erp_v2` table) is available on demand — by topic through the
`warehouse_docs` tool, or wholesale as MCP resources
(`magicline://warehouse/glossary`, `magicline://warehouse/tables`).

## API Key Management

**Key storage:** actual key values live in your OS secret store (macOS
Keychain, Windows Credential Manager / DPAPI, 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.

**How key selection works:** keys are stored per tenant (studio). The *active*
tenant is whatever `MAGICLINE_TENANT` is written in your client configs —
`keys activate` rewrites it everywhere in one command. After switching,
restart your AI client so the server picks up the new tenant.

```sh
# List stored keys (masked) and show which tenant is active
uvx magicline-mcp keys list

# Add a key for another studio (validated against the live API)
uvx magicline-mcp keys add

# Switch every configured client to another studio
uvx magicline-mcp keys activate <tenant>

# Delete a stored key (warns if it's the active one)
uvx magicline-mcp keys delete <tenant>
```

Magicline API keys are **per studio**: multi-studio operators store one key per
tenant and switch with `keys activate`. Each key remembers its environment
(production, sandbox, or a custom URL — chosen when the key is added), and
`keys activate` switches the endpoint together with the tenant.

## Claude Code

`setup --claude-code` configures Claude Code automatically by running
`claude mcp add` for you, and then offers to pre-approve tools so Claude
stops asking for permission on every call (see
[Skipping permission prompts](#skipping-permission-prompts-claude-code)).
Or do it manually:

```sh
claude mcp add Magicline -e MAGICLINE_TENANT=<tenant> -e MAGICLINE_TOOLS=read -- uvx magicline-mcp

# Verify it was added
claude mcp list
```

## Manual configuration

The setup wizard edits these files for you, but you can also edit them by hand:

- **Claude Desktop:** `~/Library/Application Support/Claude/claude_desktop_config.json`
  (Windows: `%APPDATA%\Claude\claude_desktop_config.json`)
- **Cursor:** `~/.cursor/mcp.json`
- **Windsurf:** `~/.codeium/windsurf/mcp_config.json`
- **Gemini CLI:** `~/.gemini/settings.json`
- **Antigravity:** `~/.gemini/antigravity/mcp_config.json`

All use the same format (for Gemini CLI, the `mcpServers` block lives inside
its existing `settings.json` — the wizard merges without touching your other
settings). Recommended (key comes from the OS keyring, stored by
`setup` or `keys add`):

```json
{
  "mcpServers": {
    "Magicline": {
      "command": "uvx",
      "args": ["magicline-mcp"],
      "env": {
        "MAGICLINE_TENANT": "mystudio",
        "MAGICLINE_TOOLS": "read"
      }
    }
  }
}
```

Alternative — environment variable instead of the keyring (CI, Docker,
headless Linux):

```json
{
  "mcpServers": {
    "Magicline": {
      "command": "uvx",
      "args": ["magicline-mcp"],
      "env": {
        "MAGICLINE_TENANT": "mystudio",
        "MAGICLINE_TOOLS": "read,pii",
        "MAGICLINE_API_KEY": "your-api-key-here"
      }
    }
  }
}
```

> On Windows, prefer the full path to `uvx.exe` as `command` — GUI apps don't
> always inherit your shell's PATH. The setup wizard does this automatically.

## CLI reference

| Command | What it does |
| --- | --- |
| `magicline-mcp setup` | One-time interactive setup (safe read-only mode) |
| `magicline-mcp setup --advanced` | Setup with elevated capabilities (member data, writes, optional per-tool fine-tuning) |
| `magicline-mcp setup --auto-update` | Clients always launch the latest published version |
| `magicline-mcp setup --claude-code` | Also configures Claude Code via `claude mcp add` |
| `magicline-mcp setup --allow-all` | Pre-approve tools in Claude Code — writes included, but destructive contract/payment actions still ask |
| `magicline-mcp test` | Verify stored credentials against the live API |
| `magicline-mcp tools` | List every tool, grouped by permission tier |
| `magicline-mcp permissions` | Change tiers or enable/disable individual tools, across all configured clients |
| `magicline-mcp keys list` | Show stored keys (masked), environments, active tenant |
| `magicline-mcp keys add` | Store a key for another studio |
| `magicline-mcp keys activate <tenant>` | Switch all clients to another studio (and its environment) |
| `magicline-mcp keys delete <tenant>` | Remove a stored key |
| `magicline-mcp 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 |

(Prefix with `uvx`, or `uv run` inside the repo.)

## Environment variables

Variables marked *managed* are written by the setup wizard; you only set them
yourself in non-interactive environments.

| Variable | Managed | Description |
| --- | --- | --- |
| `MAGICLINE_TENANT` | ✅ | Your tenant/studio name (the `<tenant>` in the base URL). Required. |
| `MAGICLINE_TOOLS` | ✅ | Enabled tiers, comma-separated: `read` (default), `pii`, `write`. `read` is always included. |
| `MAGICLINE_TOOLS_EXCLUDE` | ✅ | Individual tools to disable, comma-separated tool names (e.g. `cancel_membership,create_payment_session`). Applied after tier filtering; unknown names are ignored with a warning. Managed by `magicline-mcp permissions`. |
| `MAGICLINE_API_KEY` |  | API key. Overrides the OS keyring — for CI, Docker, or headless machines. |
| `MAGICLINE_BASE_URL` | ✅ | Custom API base URL — written by the wizard when you pick a sandbox or custom environment. E.g. `https://<tenant>.open-api.sandbox.magicline.com` for sandbox studios. HTTPS required (plain http only for localhost). |
| `MAGICLINE_MAX_RPS` | — | Client-side request ceiling in requests/second (default `3`). Keeps the MCP to a small slice of the API key's rate allowance, which your other integrations share. `0` disables the throttle. |
| `WAREHOUSE_HOST` | ✅ | Redshift endpoint of the enterprise data warehouse. Warehouse tools register only when host, database and user are all set. |
| `WAREHOUSE_PORT` | ✅ | Warehouse port (default `5439`). |
| `WAREHOUSE_DATABASE` | ✅ | Warehouse database name. |
| `WAREHOUSE_USER` | ✅ | Warehouse user — use one with read-only grants. |
| `WAREHOUSE_PASSWORD` |  | Warehouse password. Overrides the OS keyring — only needed where no keyring exists. |

## Troubleshooting

- **"No API key found for tenant"** — run `uvx magicline-mcp setup`, or set
  `MAGICLINE_API_KEY`. Verify with `uvx magicline-mcp test`.
- **401 Unauthorized** — tenant and key don't match, or the integration was
  deactivated. Both come from the same activation email.
- **403 Permission denied** — three possible causes: your API key lacks the
  scope for that operation, the entity belongs to a different studio, or the
  member has opted out of third-party data access (their right — the error
  message says which).
- **Tools missing in your client** — member data and write tools only appear
  when their tier is enabled, and individual tools may have been disabled:
  check `uvx magicline-mcp permissions`. Restart
  the client after any config change.
- **`claude` CLI not found** (with `--claude-code`) — install Claude Code
  first, then re-run `uvx magicline-mcp setup --claude-code`.
- **"Server disconnected" in Claude Desktop** — check the server log at
  `~/Library/Logs/Claude/mcp-server-Magicline.log` (macOS); 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 instead.

## Development

```sh
uv sync
uv run magicline-mcp tools
uv run pytest
```

Project layout:

```
src/magicline_mcp/
├── cli.py            # entry point + subcommands
├── config.py         # tenant/key/tier resolution (env > keyring)
├── client.py         # httpx wrapper: auth, retries, backoff, pagination
├── server.py         # FastMCP assembly, tier- and exclusion-gated registration
├── setup_wizard.py   # the one-time setup experience
├── manage.py         # keys + permissions management
├── warehouse.py      # read-only Redshift client (optional warehouse tools)
├── branding.py       # terminal UI (gradient banner, styled prompts)
└── tools/            # one module per Magicline domain
```

> **Note (macOS + iCloud):** if this repo lives in an iCloud-synced folder
> (e.g. `~/Documents`), iCloud recursively stamps the macOS *hidden* flag on
> dot-directories — and Python ≥ 3.13.4 refuses to load hidden `.pth` files,
> which silently breaks the venv (`ModuleNotFoundError: magicline_mcp`).
> Do **not** work around it with a `.venv` symlink — iCloud materializes
> symlinks into broken directory copies. Instead, keep the venv in a
> `*.nosync` directory (iCloud ignores those) by setting, e.g. in `~/.zshenv`:
>
> ```sh
> export UV_PROJECT_ENVIRONMENT=".venv.nosync"
> ```
>
> The simplest alternative: keep code outside iCloud-synced folders entirely.

## License

This project is licensed under the MIT License — see [LICENSE](LICENSE).
