Skip to main content
Glama
JunnB

AniList MCP

by JunnB
README.md
# AniList MCP (Convex)

Serveur [MCP](https://modelcontextprotocol.io) personnel pour [AniList](https://anilist.co). **Convex expose le MCP** à `https://<déploiement>.convex.site/mcp` — pas de process Node local, pas de backend OAuth.

AniList n’a qu’un endpoint GraphQL (`https://graphql.anilist.co`) et un **grant implicite** : tu crées un client, tu récupères un JWT valable un an, tu le poses en variable d’environnement Convex. C’est le raccourci mono-utilisateur.

## Cinq outils

| Outil | Rôle |
| --- | --- |
| `chercher` | Recherche un titre, rend l’id AniList et le nombre d’épisodes |
| `ma_liste` | Ta collection, filtrable par statut (`CURRENT`, `PLANNING`, …) |
| `progression` | `SaveMediaListEntry` avec `progress` — l’épisode que tu viens de voir |
| `noter` | `SaveMediaListEntry` avec `score` et `status` |
| `en_cours_de_diffusion` | Ce qui sort **cette semaine** parmi tes séries suivies |

Le dernier utilise le calendrier AniList (`airingAt`), pas une liste tenue à la main. « Quoi regarder ce soir » devient l’épisode sorti aujourd’hui.

## 1. Convex

```bash
npm install
npx convex dev
```

Ça crée (ou relie) le projet sur **ton** compte Convex et pousse les fonctions. L’URL HTTP du site apparaît dans le dashboard (`*.convex.site`).

## 2. Jeton AniList (implicit grant)

1. [anilist.co/settings/developer](https://anilist.co/settings/developer) → Create New Client
2. **Redirect URL** : `https://anilist.co/api/v2/oauth/pin` (page PIN, aucun backend)
3. Ouvre :

```
https://anilist.co/api/v2/oauth/authorize?client_id=TON_CLIENT_ID&response_type=token
```

4. Copie le JWT, puis :

```bash
npx convex env set ANILIST_TOKEN 'eyJ...'
npx convex env set ANILIST_TIMEZONE Europe/Paris
```

Optionnel, pour verrouiller `POST /mcp` :

```bash
npx convex env set MCP_SECRET 'un-secret-long'
```

## 3. Cursor

Dans `~/.cursor/mcp.json` (ou Settings → MCP) :

```json
{
  "mcpServers": {
    "anilist": {
      "url": "https://VOTRE_DEPLOIEMENT.convex.site/mcp"
    }
  }
}
```

Si `MCP_SECRET` est défini :

```json
{
  "mcpServers": {
    "anilist": {
      "url": "https://VOTRE_DEPLOIEMENT.convex.site/mcp",
      "headers": {
        "Authorization": "Bearer un-secret-long"
      }
    }
  }
}
```

Le transport est **Streamable HTTP**, sans session persistante (spec récente). Convex reste l’hôte.

## Exemples

- « Cherche Frieren » → `chercher` → id + 28 épisodes
- « Marque l’épisode 12 de Frieren » → `progression`
- « Note 85 et COMPLETED » → `noter`
- « Qu’est-ce qui sort ce soir dans ma liste ? » → `en_cours_de_diffusion`

## Dev

```bash
npm test
npm run lint
npx convex dev          # watch + push (dev uniquement)
```

`npx convex deploy` uniquement pour la prod.

Les appels AniList sont des **actions** Convex (`convex/anilist.ts`). Le routeur HTTP (`convex/http.ts`) traduit JSON-RPC MCP → ces actions.