TicketSource MCP server
# TicketSource MCP server
An [MCP](https://modelcontextprotocol.io) server that lets Claude, ChatGPT and other MCP clients work with a TicketSource box office: events, performance dates, bookings, seats and customers. It is built on TicketSource's public API and its published OpenAPI spec.
Once it's connected, an organiser can ask things like:
- "What's on in the next two weeks?"
- "Who's booked for tomorrow's Macbeth, and how much have we taken after fees?"
- "Find Sam Evans. What else has she booked this year, and are there notes on her record?"
- "List everyone in row C for Friday with their booking references."
## Tools
| Tool | What it does | API calls |
|---|---|---|
| `list_events` | Events with category, published and archived status. Archived events are hidden unless requested. | `GET /events` |
| `get_event` | One event with its venues and performance dates (upcoming only by default). | `GET /events/{id}`, `/venues`, `/dates` |
| `list_upcoming_performances` | Performances across active events in the next N days, soonest first. | `GET /events`, `/events/{id}/dates` |
| `get_performance_bookings` | Bookings for one performance, with gross, net, fees, refunds and donations per booking and in total. Optionally seats and attendee names. | `GET /dates/{id}`, `/dates/{id}/bookings`, `/bookings/{id}/seats` |
| `get_booking` | One booking with its totals and seats. | `GET /bookings/{id}`, `/bookings/{id}/seats` |
| `find_customers` | Search customers by name, email or phone (UK numbers match with 0 or +44). | `GET /customers` |
| `get_customer` | Contact details, membership, marketing consent, staff notes and recent bookings. | `GET /customers/{id}`, `/notes`, `/bookings` |
| `add_customer_note` | Adds a staff note. Only registered when writes are enabled. | `POST /customers/{id}/notes` |
## Setup
Requires Node 18 or later.
```bash
npm install
npm run build
```
Create an API key in TicketSource under **Settings > API**.
**Claude Desktop:** add this to `claude_desktop_config.json`:
```json
{
"mcpServers": {
"ticketsource": {
"command": "node",
"args": ["/absolute/path/to/ticketsource-mcp/dist/index.js"],
"env": { "TICKETSOURCE_API_KEY": "skl-your-key" }
}
}
}
```
**Claude Code:**
```bash
claude mcp add ticketsource -e TICKETSOURCE_API_KEY=skl-your-key -- node /absolute/path/to/ticketsource-mcp/dist/index.js
```
| Variable | Required | Meaning |
|---|---|---|
| `TICKETSOURCE_API_KEY` | yes | Your API key, sent as a Bearer token. |
| `TICKETSOURCE_ALLOW_WRITES` | no | `true` to enable `add_customer_note`. Off by default. |
| `TICKETSOURCE_BASE_URL` | no | Defaults to `https://api.ticketsource.io`. Used by the tests. |
## Safety defaults
- Read-only unless `TICKETSOURCE_ALLOW_WRITES=true`. Read tools carry the MCP `readOnlyHint` annotation.
- Attendee emails and phone numbers are only returned when the assistant explicitly asks for them (`include_contact_details`).
- IDs are validated against the formats in your spec before any call is made.
- Requests are spaced to stay under the 240 calls per minute limit, and 429 responses are retried using `Retry-After`.
- A rejected API key produces a message that tells the user where to fix it.
## Tests
```bash
npm test
```
The test suite:
1. Validates every fixture record against the component schemas in TicketSource's published OpenAPI spec. The spec is downloaded from `github.com/ticketsource/openapi-spec` to `spec.yaml` on the first run.
2. Starts a local mock of the API that serves those fixtures with JSON:API pagination, a 401 on a bad key, 404s, and a one-off 429.
3. Starts the built server and drives it over stdio with the official MCP client: 15 checks covering every tool, pagination, refunds and donations in totals, the 429 retry, the write gate, contact-detail redaction, and that every request used the Bearer key and a documented endpoint.
## Status
This is a working prototype. It has **not yet been run against the live API**, because it was built without a TicketSource account. Two things to confirm on a real account:
- The body accepted by `POST /customers/{id}/notes`. The server sends `{"data": {"type": "customer_note", "attributes": {"description": "..."}}}` as documented.
- The format of `start` on dates. It is parsed as ISO 8601; dates that can't be parsed are kept rather than dropped.
The API has no server-side customer search, so `find_customers` pages through the customer list (100 per call, 10 pages by default). On large accounts, a search parameter on `GET /customers` would make this much cheaper.
## Going to production
This version runs locally over stdio, with the organiser's own API key. For organisers to connect from claude.ai or ChatGPT without handling keys, the next step is a remote server (Streamable HTTP) behind OAuth, hosted by TicketSource, and then a listing in the Claude and ChatGPT connector directories.
## Licence
MIT. Built by Claude, an AI model, working for Alexandru Dragoș (alexandru.dragos96@gmail.com).
TDQS
Scored across 7 tools
Each tool targets a distinct resource and action: events, performances, bookings, and customers are clearly separated. Even list_events and list_upcoming_performances differ in scope (all events vs. upcoming performance dates), eliminating ambiguity.
All tools follow the consistent verb_noun pattern in snake_case (list_*, get_*, find_*). The naming is uniform and predictable, with no mixed conventions or vague verbs.
Seven tools is well-scoped for a read-only ticketing information server. Each tool has a clear purpose and the count falls comfortably in the ideal 3-15 range.
The surface covers core retrieval workflows: events, performances, bookings, and customers. Minor gaps exist (e.g., no create/update operations, no direct booking-by-event search), but these align with a read-only information source and do not block typical usage.