# Connect your app to cliply

> Let coaches authorize your app to read their cliply match data over MCP and OAuth 2.1.

Source: https://cliply.video/developers/connect-your-app?lang=en
Updated: 2026-11-04

Your app can read a coach's cliply data the same way Claude and ChatGPT do: through the cliply MCP server, with the coach's own authorization. You don't need an API key from us and you don't have to ask to be registered. Your app registers itself, the coach approves it, and you call the tools with the token you get back.

Your app receives data as JSON: matches, tags, facts, stats, sequences, players and clip ids. It never receives video. Video plays in cliply, and every clip id becomes a link that opens the cliply workbench on that play.

## At a glance

| What | Value |
| --- | --- |
| MCP server | `https://cliply.video/api/mcp` (Streamable HTTP, stateless) |
| Authorization server metadata | `https://cliply.video/.well-known/oauth-authorization-server/api/auth` |
| Protected resource metadata | `https://cliply.video/.well-known/oauth-protected-resource/api/mcp` |
| Client registration | `POST https://cliply.video/api/auth/oauth2/register` (open, RFC 7591) |
| Authorize | `https://cliply.video/api/auth/oauth2/authorize` |
| Token | `https://cliply.video/api/auth/oauth2/token` |
| Revoke | `https://cliply.video/api/auth/oauth2/revoke` |
| Grants | `authorization_code`, `refresh_token` |
| PKCE | required, `S256` |
| Scopes | `cliply:read`, `cliply:write` (optional), `offline_access` |

## Quick start with the MCP SDK

The official MCP SDKs ship a client that discovers the endpoints, registers your app and runs the OAuth flow for you. In TypeScript (`@modelcontextprotocol/sdk`):

```ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

// authProvider implements OAuthClientProvider: it stores the client
// registration, the PKCE verifier and the tokens per coach, and redirects
// the coach's browser to the authorize URL.
const transport = new StreamableHTTPClientTransport(
  new URL("https://cliply.video/api/mcp"),
  { authProvider },
);
const client = new Client({ name: "your-app", version: "1.0.0" });
await client.connect(transport);

const { tools } = await client.listTools();
const result = await client.callTool({
  name: "list_matches",
  arguments: {},
});
```

Your side of the work: a **Connect cliply** button, a callback route, token storage per coach, and the provider above. The rest of this page describes what the SDK does, for teams that build the flow themselves.

## The OAuth flow, step by step

### 1. Discover

`GET https://cliply.video/.well-known/oauth-protected-resource/api/mcp` names the authorization server, and its metadata document lists every endpoint in the table above. A `401` from `/api/mcp` carries the same pointer in its `WWW-Authenticate` header.

### 2. Register your app (once)

```http
POST https://cliply.video/api/auth/oauth2/register
Content-Type: application/json

{
  "client_name": "Your App",
  "redirect_uris": ["https://yourapp.example/cliply/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none"
}
```

Store the returned `client_id` and use the same one for every coach. Don't register again for each coach. Registration is rate limited.

### 3. Send the coach to cliply

When the coach chooses **Connect cliply**, redirect their browser to:

```text
https://cliply.video/api/auth/oauth2/authorize
  ?response_type=code
  &client_id=<client_id>
  &redirect_uri=https://yourapp.example/cliply/callback
  &scope=cliply:read cliply:write offline_access
  &code_challenge=<S256 challenge>
  &code_challenge_method=S256
  &state=<random>
  &resource=https://cliply.video/api/mcp
```

cliply handles the rest of this step. The coach signs in (or creates an account and an organization), picks the organization the connection will read, and approves.

### 4. Exchange the code

cliply redirects back to `redirect_uri` with `code` and your `state`. Check that `state` matches the one you sent, then exchange the code:

```http
POST https://cliply.video/api/auth/oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=<code>
&redirect_uri=https://yourapp.example/cliply/callback
&client_id=<client_id>
&code_verifier=<PKCE verifier>
&resource=https://cliply.video/api/mcp
```

The response carries an `access_token` and, when you asked for `offline_access`, a `refresh_token`. Store both against the coach.

### 5. Refresh

When the access token expires, request a new one with `grant_type=refresh_token`, your `client_id` and the refresh token. The coach doesn't see this step. Keep the refresh token the response returns; it may differ from the one you sent.

## Scopes and what the coach approves

- **`cliply:read`**: read everything the coach can see in the organization they picked.
- **`cliply:write`**: optional. Lets your app create collections and presentations and comment on clips. It can never edit or delete anything. The consent screen shows it as a checkbox the coach can untick. When they do, the token is read-only and the create tools are not listed.
- **`offline_access`**: issues a refresh token.

A token is bound to **one coach and one organization**. It sees what that coach sees there, private projects included only when the coach can open them, and it never falls back to another membership. Player accounts cannot authorize. To read a second organization, the coach connects again and picks it.

The consent screen shows the `client_name` you registered next to the host of your `redirect_uri`. Register a name coaches will recognize.

## Calling tools

Every call is a JSON-RPC request to `/api/mcp` with the coach's token:

```http
POST https://cliply.video/api/mcp
Authorization: Bearer <access_token>
Content-Type: application/json
Accept: application/json, text/event-stream

{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"match_analysis","arguments":{"matchId":"<id>"}}}
```

The server is stateless, so you don't need a session id. A revoked token is refused on the very next request. Call `tools/list` for the live schema of every tool. Each tool also returns its own input schema there.

| Tool | Reads |
| --- | --- |
| `whoami` | The coach, the organization, its sport and which features it has |
| `list_projects`, `list_matches` | Where to start: projects and matches with their urls |
| `match_analysis` | One match as facts with F-ids, a `tagMeaning` map (whose action each tag is, good or bad for the team, its opposite) and a baseline of comparable matches |
| `match_report` | The stored AI report of a match, when the organization generated one |
| `find_clips` | Clips by match, tag, player or period |
| `find_sequences` | One action followed by another within a window, for example a recovery that becomes a circle entry |
| `compare_matches` | Up to 8 matches side by side |
| `cliply_read` | Everything else by name: players, player stats, teams, season stats such as `team_tag_season`, events, lineups, GPS, comments, collections, share views, calendar, activity |
| `cliply_describe` | The exact input of a `cliply_read` name |
| `search`, `fetch` | Search across matches, players, teams and help articles, then fetch one by id |
| `cliply_help_search`, `cliply_help_article`, `cliply_whats_new` | This help center and the release notes |
| `create_collection`, `create_presentation`, `comment_clip` | Only on `cliply:write` tokens |

Some reads depend on features the organization has turned on, such as GPS, bench stats or season stats. When one is off, the tool says so instead of returning data.

## Links and citations

- Times are seconds from the start of the video.
- A match links to its `url`. One play links to the match url plus `?clip=<clipId>`, and any clip id from any read works there.
- Facts from `match_analysis` carry ids (`F1`, `F2`…). Cite them so the coach can trace each claim back to the match.
- Links open the cliply workbench and need the coach to be signed in to cliply. To show clips to players, create a collection with `cliply:write` and the coach shares it from cliply.
- Your model reads tags, not video. Answers are only as complete as the coach's tagging.

## Limits, credits and errors

- **Rate limits:** 120 requests per minute per coach and 300 per minute per IP. Over the limit, `/api/mcp` answers `429` with `Retry-After: 60`.
- **Credits:** reads through the connector don't consume cliply credits.
- **`401`:** the token is missing, expired or revoked. Refresh it, or send the coach through the flow again.
- **Tool errors** come back as a normal tool result with `isError: true` and a message your model can read.

## Disconnecting

A coach disconnects your app in cliply under **Account → Sessions → AI apps**. Organization owners and admins can disconnect any member's app under **Organization settings → General → AI apps**, and the organization's audit log records every connection. Your app can also revoke its own tokens at the revoke endpoint. In every case, the next call with that token gets a `401`.

For questions, write to hi@cliply.video.
