kicksite-mcp
by sanjibani
README.md
# kicksite-mcp
First MCP (Model Context Protocol) server for the
[Kicksite](https://kicksite.com) martial-arts-school management API. Read and
write students, prospects, memberships, recurring billings, invoices, class
sessions, attendance, belt promotions, communications, and notes — all in
plain English from Claude, Cursor, or any MCP client.
## What is Kicksite?
Kicksite is the leading SaaS for US martial-arts schools (taekwondo, karate,
jiu-jitsu, MMA, Krav Maga, etc.). Schools use it to manage students, run the
trial-to-active funnel, schedule classes, take attendance, promote belt
ranks, and bill via EFT or credit-card autopay. Public REST API since the
mid-2010s — but no one had wrapped it for MCP clients until now.
## Quick start
### 1. Create OAuth credentials in Kicksite
1. Log in to your school's Kicksite web UI (`https://{yourschool}.kicksite.net`)
2. Click **Quick Links** → **Settings** → **Integrations**
3. Click the **Zapier** card → **Get Started**
4. Kicksite will show three values — copy all of them:
- **Subdomain** (the bit before `.kicksite.net` in your school URL)
- **Client ID**
- **Client Secret** (shown only once)
### 2. Install + run
```bash
pip install kicksite-mcp
export KICKSITE_SUBDOMAIN=dragonkarate
export KICKSITE_CLIENT_ID=<your_client_id>
export KICKSITE_CLIENT_SECRET=<your_client_secret>
kicksite_mcp
```
The MCP server runs over stdio. Wire it into Claude Desktop, Cursor, or any
MCP client:
```json
{
"mcpServers": {
"kicksite": {
"command": "kicksite_mcp",
"env": {
"KICKSITE_SUBDOMAIN": "dragonkarate",
"KICKSITE_CLIENT_ID": "your_client_id",
"KICKSITE_CLIENT_SECRET": "your_client_secret"
}
}
}
}
```
## Tools (25)
| Tool | What it does |
| --- | --- |
| `health_check` | Verify credentials work, return the authenticated school profile |
| `list_students` / `get_student` / `search_students` | List, fetch, or free-text-search students |
| `create_student` / `update_student_status` | Create students directly or change status (Active / Frozen / Inactive) |
| `list_prospects` / `get_prospect` / `search_prospects` | List, fetch, or search prospects (leads in the trial funnel) |
| `create_prospect` | Add a new lead to the trial funnel |
| `list_memberships` / `get_membership` | List a student's memberships or fetch one by id |
| `list_recurring_billings` | List EFT / credit-card autopay plans (filter by student) |
| `list_invoices` | List one-time charges (filter by student or date range) |
| `list_classes` | List class definitions (the recurring class schedule) |
| `list_class_sessions` | List scheduled class sessions in a date range |
| `list_attendance` / `record_attendance` | View and write attendance records |
| `list_belt_promotions` / `create_belt_promotion` | View and write rank history (martial-arts-specific) |
| `list_programs` | List program definitions (Little Dragons, Adult Karate, BJJ, etc.) |
| `list_locations` | List school branch locations |
| `list_staff` | List school staff (instructors, admins, front-desk) |
| `list_communications` / `send_communication` | View and log email / SMS communications |
| `list_notes` / `create_note` | View and write internal notes |
## Real-world queries it unlocks
- *"Show me all active trial prospects from the Westside location this month"*
- *"Find student by phone 555-1234"*
- *"Who got promoted to black belt in the last 5 years?"*
- *"List every class session for the Adult Karate program next Tuesday"*
- *"Record student 1234 as late to class session 4455 with note 'traffic'"*
- *"Add a follow-up note to prospect 4321 - 'Call tomorrow at 5pm'"*
- *"List the recurring billings for student 5678 and the autopay date"*
- *"Find all one-time invoices from last month"*
- *"Send student 1234 a 'Welcome to the dojo' email"*
## Architecture
Built on the industry-leading patterns documented in
`engineering-playbook.md`:
- **Shared `httpx.AsyncClient`** with connection pooling (100 max, 20 keepalive)
and transport-level retries (3x) for transient network blips.
- **OAuth 2 client_credentials** with proactive token refresh — 60s buffer
before expiry, `asyncio.Lock` to serialize concurrent refreshes, and
forced refresh on a 401 (single retry, then surface the auth error).
- **Typed exception hierarchy** — `KicksiteAuthError`, `KicksiteNotFoundError`,
`KicksiteRateLimitError`, `KicksiteAPIError`, `KicksiteConnectionError` —
each carrying structured fields (`http_status`, `error_code`, `request_id`,
`retry_after`) so callers can branch on cause, not message text.
- **Application-level retry** with exponential backoff + full jitter, honoring
the `Retry-After` header on 429s. 5xx responses are retried up to 3x.
- **HTTP status dispatch table** — one row per status code → exception class.
Adding a new status code = one row, no new `if/elif` branches.
- **Async iterator pagination** — `iter_students`, `iter_prospects` auto-page
until the server returns a short page.
- **isError-compliance** per the Blackwell MCP security audit — every tool
raises typed exceptions on failure; FastMCP wraps them with
`isError=true` on the wire response. The old `return _format_error(e)`
pattern (which leaves `isError=false`) is NOT used.
- **JSONL audit logging** per tool call (`audit.py`) — one structured record
per call with `ts`, `tool`, `args` (secrets redacted), `result_size`,
`is_error`, `error_type`, `duration_ms`, `request_id`. Sink defaults to
stderr; override with `KICKSITE_AUDIT_LOG=/path/to/audit.jsonl`. Fail-open
semantics — sink failure never breaks the tool.
## Development
```bash
git clone https://github.com/sanjibani/kicksite-mcp
cd kicksite-mcp
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest
```
### Code quality
- **ruff** — full rule set (`E`, `F`, `W`, `I`, `N`, `UP`, `B`, `A`, `C4`,
`DTZ`, `T20`, `PT`, `Q`, `RET`, `SIM`, `TID`, `ARG`, `PTH`, `ERA`, `PL`,
`RUF`)
- **mypy** — strict mode, every function annotated, all union types narrowed
- **pytest** — 50 tests via `respx` + `hypothesis`, async-mode auto, no live
API calls
- **pre-commit** — ruff + ruff-format + mypy
```bash
ruff check src tests
ruff format --check src tests
mypy src tests
pytest --cov=kicksite_mcp --cov-fail-under=80 tests
```
## Distribution
- 89.8K-star `awesome-mcp-servers` PR (pending)
- `mcp.so` + `Glama` auto-index via GitHub topics
- Direct vendor outreach to Kicksite's partner team (cold-email track via
`vertical-mcp-distribute` cron)
## License
MIT — see `LICENSE`.
## Related MCPs
Part of the same vertical-MCP portfolio (all MIT, all `sanjibani/<name>-mcp`):
`hawksoft`, `open-dental`, `ezyvet`, `jobber`, `practicepanther`,
`cox-automotive`, `qualia`, `campspot`, `cleancloud`, `playmetrics`, `foreup`,
`storedge`, `courtreserve`, `procare`, `passare`, `funraise`.
Also: `mcp-shield` (Tier 3 — MCP security sidecar for any untrusted MCP) and
`paid-skills` / `skill-sandbox` / `mcp-skills-pack` (Skills monetization and
sandbox runtime).
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues