# MCP server

The YOGO MCP server lets AI assistants — Claude, ChatGPT, Gemini, and any other
client that speaks the [Model Context Protocol](https://modelcontextprotocol.io)
— call YOGO data directly. Every endpoint of this REST API is also exposed as an
MCP "tool" so the AI can list customers, look up classes, find orders, and
reassign teachers without you writing any glue code.

It's a thin proxy in front of the same REST API documented here. Same data,
same authentication (your existing YOGO API key), same plan-gating, same
audit log. The difference is the surface: instead of writing HTTP calls, you
plug your AI client into the MCP endpoint and ask questions in natural
language.

The MCP server is available at:


```
https://mcp.yogobooking.com/mcp
```

## Endpoint and authentication

Connect using the modern MCP **Streamable HTTP** transport (single endpoint;
the client does `POST /mcp` for tool calls and `GET /mcp` for server-sent
events). Authenticate with the same key you use for REST, sent as a bearer
token:


```http
POST /mcp HTTP/1.1
Host: mcp.yogobooking.com
Authorization: Bearer your_api_key_here
Content-Type: application/json
```

The MCP server forwards your bearer token to the REST API as the `X-API-KEY`
header on every upstream call, so plan-gating, rate limits, and audit logging
behave identically. There is no separate identity model.

## Compatibility

| Client | Status |
|  --- | --- |
| Claude Code (CLI) | Supported (native HTTP MCP). |
| Claude Desktop | Supported via the `mcp-remote` stdio bridge. |
| Gemini CLI / Gemini Code Assist | Supported (native HTTP MCP). |
| Any client supporting Streamable HTTP MCP with a custom `Authorization` header | Supported. |
| ChatGPT (custom connectors) | **Not supported yet.** ChatGPT's custom-connector flow requires OAuth 2.0/2.1; it doesn't accept static API keys or pre-shared bearer tokens. See the [ChatGPT section](#connecting-from-chatgpt) below for workarounds. |
| Claude.ai web (custom connectors) | **Not supported yet.** Same OAuth-2.1 requirement as ChatGPT. Use Claude Desktop or Claude Code instead. |


## Available tools

The server exposes 13 tools. Each maps to a single REST endpoint:

| Tool name | REST equivalent |
|  --- | --- |
| `list_customers` | `GET /customers` |
| `get_customer` | `GET /customers/{id}` |
| `list_teachers` | `GET /teachers` |
| `get_teacher` | `GET /teachers/{id}` |
| `list_orders` | `GET /orders` |
| `get_order` | `GET /orders/{id}` |
| `list_bookings` | `GET /bookings` |
| `get_booking` | `GET /bookings/{id}` |
| `list_classes` | `GET /classes` |
| `get_class` | `GET /classes/{id}` |
| `set_class_teachers` | `PUT /classes/{id}/teachers` |
| `list_write_logs` | `GET /write-logs` |
| `get_write_log` | `GET /write-logs/{id}` |


The canonical, always-up-to-date input schemas live on the server itself.
After connecting, your client can call `tools/list` to retrieve the full
descriptions and argument types.

`set_class_teachers` is the only write tool. It replaces the entire teacher
list on a class (pass `teacherIds: []` to clear). Every successful call is
recorded in the audit log and surfaces via `list_write_logs`.

## Connecting from Claude Desktop

Anthropic's hosted Custom Connectors (the "Connectors" panel inside
claude.ai) require OAuth 2.1, which YOGO MCP doesn't implement. The reliable
path for Claude Desktop is therefore the `mcp-remote` stdio bridge — a tiny
local proxy that speaks stdio MCP to Claude Desktop and Streamable HTTP to
our server, attaching your bearer token along the way.

Edit `claude_desktop_config.json`:

| OS | Path |
|  --- | --- |
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
| Linux | `~/.config/Claude/claude_desktop_config.json` |



```json
{
  "mcpServers": {
    "yogo": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://mcp.yogobooking.com/mcp",
        "--header",
        "Authorization: Bearer your_api_key_here"
      ]
    }
  }
}
```

Restart Claude Desktop. The plug/tools indicator in the input bar should
list `yogo` with 13 tools attached. Node.js must be installed locally for
`npx` to work.

## Connecting from Claude Code

The fastest path is the CLI. All flags come before the server name:


```bash
claude mcp add \
  --transport http \
  --scope user \
  --header "Authorization: Bearer your_api_key_here" \
  yogo https://mcp.yogobooking.com/mcp
```

Or edit `~/.claude.json` (user scope) or a project-local `.mcp.json`:


```json
{
  "mcpServers": {
    "yogo": {
      "type": "http",
      "url": "https://mcp.yogobooking.com/mcp",
      "headers": {
        "Authorization": "Bearer your_api_key_here"
      }
    }
  }
}
```

Run `/mcp` in Claude Code to confirm the connection and inspect the tools.

## Connecting from ChatGPT

ChatGPT can connect to remote MCP servers, but its custom-connector flow
**only accepts OAuth 2.0 / 2.1 authorization-code authentication**. It does
not accept static API keys or pre-shared bearer tokens. Since YOGO MCP
authenticates with your existing API key (a static bearer), ChatGPT can't
connect directly today.

Native ChatGPT support is on our roadmap; we'll update this page when YOGO
MCP exposes an OAuth flow.

## Connecting from Gemini

The fastest path is the Gemini CLI subcommand:


```bash
gemini mcp add \
  --transport http \
  --header "Authorization: Bearer your_api_key_here" \
  yogo https://mcp.yogobooking.com/mcp
```

Or edit `~/.gemini/settings.json` (or a workspace-local `.gemini/settings.json`):


```json
{
  "mcpServers": {
    "yogo": {
      "httpUrl": "https://mcp.yogobooking.com/mcp",
      "headers": {
        "Authorization": "Bearer your_api_key_here"
      }
    }
  }
}
```

Note: the field name is `httpUrl` (not `url`) — that's how the Gemini CLI
distinguishes Streamable HTTP from stdio MCP servers. Restart the CLI / IDE
extension. The same JSON works in Gemini Code Assist (the IDE extension)
when placed in the workspace settings file.

## Example prompts

Once connected, you can ask your AI assistant questions like these. The AI
picks the right tool automatically based on the prompt:

- *"Show me the YOGO classes scheduled for next week with their teachers."*
→ `list_classes` with `expand=teachers`.
- *"How many customers signed up in the last 30 days?"*
→ `list_customers` with `auto_paginate: true`, then count.
- *"Find all orders over 1,000 DKK in April and group them by customer."*
→ `list_orders` with `expand=customer`, then aggregate.
- *"Which teacher taught the most classes last month?"*
→ `list_classes` with `expand=teachers` over the date range.
- *"Replace the teachers on class 12345 with teacher 678."*
→ `set_class_teachers` with `id: 12345, teacherIds: [678]`.
- *"List any teacher reassignments made via the API today."*
→ `list_write_logs` filtered to today and `entityType: class.teachers`. The
audit log only records writes made through the public API (including writes
made via this MCP server). Changes made in the YOGO admin UI don't appear
here.


## Pagination

List tool results carry a `_pagination` object alongside `data`:


```json
{
  "data": [ /* page of records */ ],
  "_pagination": {
    "hasMore": true,
    "nextCursor": 456,
    "pagesFetched": 1
  }
}
```

When `_pagination.hasMore` is `true`, pass `_pagination.nextCursor` as the
`after` argument on the next call to fetch the next page. Or set
`auto_paginate: true` and the server will walk pages for you (capped at five
pages by default to keep responses bounded).

The cursor format is the same as on REST — see the [pagination guide](/guides/pagination).
The shape differs only because MCP tool results are structured JSON the
client deserializes; there's no `next` URL to follow.

## Rate limiting

The MCP server applies the same per-client rate limit as the REST API: 100
requests per minute. A 429 from upstream surfaces as a tool error containing
`_meta.retry_after_seconds`, which the AI client can use to back off cleanly.
See the [rate-limiting guide](/guides/rate-limiting) for the underlying behaviour.

## Errors

Errors fall into two buckets:

- **Tool errors** (the call ran, the upstream said no): `4xx` responses from
the REST API are returned as MCP tool-error results, so the AI sees the
message and can react — for example, retrying with a different ID on `404`,
or telling you to upgrade the plan on `403 PLAN_UPGRADE_REQUIRED`.
- **Protocol errors** (the call couldn't run): `5xx` upstream errors and
network failures bubble up as JSON-RPC errors. Read GETs are retried once
before failing.


The full status-code semantics are the same as REST — see the
[errors guide](/guides/errors).