
# Intégration MCP

Le Model Context Protocol (MCP) est un standard ouvert pour connecter les assistants IA aux outils et données. Sovrium parle MCP dans **les deux sens** :

- **Mode serveur** — des clients IA externes (Claude Desktop, Claude Code, ChatGPT Dev Mode, Cursor) se connectent à Sovrium et appellent des outils générés : CRUD de table, invocation d'automatisation manuelle, et exécution de modèle d'action.
- **Mode client** — les agents Sovrium appellent des outils hébergés sur des serveurs MCP _externes_ (recherche web, récupération de documents, exécution de code) dans le cadre de leurs flux de travail.

Les deux modes sont configurés indépendamment et servent des rôles opposés.

| Mode    | Contrôlé par     | Où                                 | LLM requis sur Sovrium ?                 |
| ------- | ---------------- | ---------------------------------- | ---------------------------------------- |
| Serveur | Opérateur (env)  | `MCP_ENABLED`, `MCP_TRANSPORT`, …  | Non — le LLM vit chez le client connecté |
| Client  | Auteur de schéma | Bloc `mcp.allowedTools` d'un agent | Oui — `AI_PROVIDER` défini               |

:::callout
**Le mode serveur ne nécessite pas `AI_PROVIDER`.** Lorsque Sovrium est le _serveur_ MCP, le LLM s'exécute chez le client connecté. La plateforme expose uniquement des outils ; elle n'appelle pas de modèle. `AI_PROVIDER` n'est requis que pour le mode client (et le reste de la couche IA).
:::

## Mode serveur

### Activation

Le serveur MCP est **désactivé par défaut**. L'opérateur s'engage via des variables d'environnement ; le serveur ne monte la route `/mcp` que lorsque `MCP_ENABLED=true`.

| Variable                    | Description                                                                                            | Défaut                      |
| --------------------------- | ------------------------------------------------------------------------------------------------------ | --------------------------- |
| `MCP_ENABLED`               | Interrupteur principal — monte la route MCP uniquement lorsque `true`.                                 | `false`                     |
| `MCP_TRANSPORT`             | `streamable-http` pour les clients distants, `stdio` pour l'intégration IDE locale.                    | `streamable-http`           |
| `MCP_MOUNT_PATH`            | Préfixe de route lorsque le transport est `streamable-http`.                                           | `/mcp`                      |
| `MCP_AUTH_STRATEGY`         | `oauth2` (lorsque `app.auth` est configuré) ou `token`.                                                | `oauth2` lorsque auth câblé |
| `MCP_TOKEN_ADMIN`           | Jeton bearer accordant le rôle admin (≥32 caractères ; `openssl rand -hex 32`).                        | —                           |
| `MCP_TOKEN_MEMBER`          | Jeton bearer accordant le rôle member (≥32 caractères).                                                | —                           |
| `MCP_TOKEN_VIEWER`          | Jeton bearer accordant le rôle viewer (≥32 caractères).                                                | —                           |
| `MCP_RATE_LIMIT_PER_MINUTE` | Requêtes par jeton par minute.                                                                         | `60`                        |
| `MCP_RATE_LIMIT_PER_DAY`    | Requêtes par jeton par jour.                                                                           | `5000`                      |
| `MCP_AUDIT_ENABLED`         | Journaliser chaque appel d'outil dans `system.ai_tool_calls` + le flux d'activité.                     | `true`                      |
| `MCP_EXPOSE_INTERNALS`      | Exposer les tables auth/system en lecture seule au rôle admin.                                         | `true`                      |
| `MCP_CONFIRM_DESTRUCTIVE`   | Compiler `destructiveHint=true` sur les outils de suppression et les automatisations non idempotentes. | `true`                      |

```bash
MCP_ENABLED=true
MCP_TRANSPORT=streamable-http
MCP_AUTH_STRATEGY=token
MCP_TOKEN_ADMIN=$(openssl rand -hex 32)
MCP_TOKEN_VIEWER=$(openssl rand -hex 32)
```

### Connecter un client

Une fois le serveur monté (`MCP_ENABLED=true`), pointe un client compatible MCP vers le chemin de montage. Avec `MCP_TRANSPORT=streamable-http`, le serveur expose un unique point d'entrée JSON-RPC sur `MCP_MOUNT_PATH` — `https://votre-app.example.com/mcp` par défaut.

La plupart des clients (Claude Desktop, Claude Code, Cursor, ChatGPT Dev Mode) lisent un bloc `mcpServers` :

```json
{
  "mcpServers": {
    "sovrium": {
      "url": "https://votre-app.example.com/mcp",
      "transport": "http"
    }
  }
}
```

**Authentification par jeton.** En mode `token`, envoie le jeton porteur du rôle à chaque requête. Le rôle du jeton connecté pilote le RBAC — un jeton `viewer` ne voit jamais que des outils de lecture.

```text
Authorization: Bearer <MCP_TOKEN_ADMIN>
```

**Authentification OAuth2.** Lorsque `app.auth` est configuré (`oauth2` devient alors la valeur par défaut), enregistre un client une fois via l'enregistrement dynamique, puis complète le flux OAuth :

```bash
curl -X POST 'https://votre-app.example.com/api/auth/oauth2/register' \
  --header 'Content-Type: application/json' \
  --data '{
    "client_name": "Sovrium MCP — Claude",
    "redirect_uris": ["https://votre-app.example.com/oauth/callback"],
    "grant_types": ["authorization_code", "refresh_token"],
    "token_endpoint_auth_method": "client_secret_post"
  }'
```

Une requête non authentifiée renvoie un `401` avec un en-tête `WWW-Authenticate: Bearer` de découverte, pour que les clients conformes démarrent le flux d'eux-mêmes.

**IDE local (stdio).** Pour une intégration locale, définis `MCP_TRANSPORT=stdio` ; le client lance le binaire Sovrium comme processus enfant et parle MCP via stdin/stdout (la route HTTP `/mcp` n'est pas montée dans ce mode).

**Vérifier la connexion.** Un échange minimal, c'est `initialize` puis `tools/list` :

```bash
curl -X POST 'https://votre-app.example.com/mcp' \
  --header 'Authorization: Bearer <MCP_TOKEN_ADMIN>' \
  --header 'Content-Type: application/json' \
  --data '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }'
```

La réponse liste exactement les outils que ton rôle peut appeler — le CRUD de tables, les actions et les automatisations que tu as marqués avec `aiAccess`.

### Surfaces exposées

Lorsqu'il est monté, le serveur génère des outils à partir de quatre surfaces — toutes encadrées par RBAC et `aiAccess` :

```
/mcp ─── tools/list ───▶ filtré par le rôle connecté
            │
   ┌────────┴───────────────────────────────────┐
   │ 1. Tables utilisateur  {app}_{table}_{op}     │  CRUD
   │ 2. Automatisations manuelles {app}_automation_{name}│ invocation
   │ 3. Modèles d'action    {app}_action_{name}    │  exécution
   │ 4. Internes admin      {app}_auth_*_read/_list │  lecture seule, secrets en liste noire
   └─────────────────────────────────────────────┘
            │
   Audit → system.ai_tool_calls   Limite de débit → par jeton / client_id OAuth
```

### Déclarer les entités éligibles à l'IA

Un auteur de schéma marque une entité comme éligible à l'exposition MCP avec `aiAccess`. Cela déclare l'_intention_ ; l'opérateur doit encore activer le serveur avec `MCP_ENABLED`. `aiAccess` s'applique de manière identique à `app.tables[]`, aux `app.automations[]` à déclenchement manuel, et à `app.actions[]`.

Il prend deux formes — un raccourci booléen ou un objet de configuration riche :

```yaml
# Raccourci booléen — activer avec les valeurs par défaut.
tables:
  - name: contacts
    aiAccess: true
```

```yaml
# Config riche — fournir un objet EST le signal d'activation (pas de champ `enabled`).
tables:
  - name: contacts
    aiAccess:
      description: Customer contacts. Use this when the user asks about people.
      operations: [read, list, create, update]
      fieldExposure: permissioned
      annotations:
        readOnly: false
        destructive: false
```

| Propriété             | Description                                                                                                             |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `description`         | Description d'outil écrite à la main montrée au client IA — le plus grand levier pour orienter le comportement de l'IA. |
| `operations`          | Sous-ensemble de `read`, `list`, `create`, `update`, `delete` à exposer (les tables exposent les cinq par défaut).      |
| `fieldExposure`       | `permissioned` (par défaut — uniquement les champs que le rôle peut lire/écrire), `all`, ou `whitelist`.                |
| `whitelistFields`     | Champs à exposer lorsque `fieldExposure: whitelist` (requis et non vide dans ce mode).                                  |
| `annotations`         | Indices de risque MCP — voir ci-dessous.                                                                                |
| `requireConfirmation` | Forcer `destructiveHint=true` quel que soit le type d'opération (ex. pour les automatisations envoyant des e-mails).    |

### Annotations de risque d'outil

Les annotations se compilent dans les définitions d'outils MCP afin que les clients puissent décider d'approuver automatiquement un appel ou d'exiger une confirmation. Elles correspondent directement à la spécification MCP :

| Annotation    | Indice MCP        | Signification                                                                          |
| ------------- | ----------------- | -------------------------------------------------------------------------------------- |
| `readOnly`    | `readOnlyHint`    | L'outil lit uniquement des données ; sûr à approuver automatiquement.                  |
| `destructive` | `destructiveHint` | Effectue des opérations destructrices ; les clients devraient exiger une confirmation. |
| `idempotent`  | `idempotentHint`  | Appeler deux fois avec les mêmes arguments est sûr (pas d'effets de bord dupliqués).   |
| `openWorld`   | `openWorldHint`   | Atteint l'extérieur de l'application locale (API externe, appel réseau).               |

Des valeurs par défaut raisonnables sont dérivées du type d'opération lorsque les annotations ne sont pas définies.

### Authentification

| Stratégie | Quand                                    | Comment                                                                                           |
| --------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `token`   | Par défaut lorsque `app.auth` est absent | Jetons bearer statiques par rôle (`MCP_TOKEN_ADMIN/MEMBER/VIEWER`). Au moins un doit être défini. |
| `oauth2`  | Par défaut lorsque `app.auth` est câblé  | OAuth 2.1 contre le plugin serveur OAuth de Better Auth.                                          |

Le rôle de la crédentielle connectée pilote le RBAC : un jeton `viewer` ne peut que lire/lister même lorsque l'`aiAccess.operations` d'une entité autorise les écritures. La validation de démarrage rejette `MCP_AUTH_STRATEGY=token` sans jeton défini, et `oauth2` lorsque `app.auth` n'est pas configuré.

### RBAC, audit & limitation de débit

- **RBAC** — les clients MCP sont régis par les mêmes permissions de rôle et règles au niveau des lignes que les sessions humaines. Il n'y a aucun contournement IA.
- **Audit** — chaque appel d'outil est journalisé dans `system.ai_tool_calls` et le flux d'activité lorsque `MCP_AUDIT_ENABLED` est `true` (la valeur par défaut).
- **Limitation de débit** — appliquée par jeton (ou `client_id` OAuth) ; les requêtes hors limite retournent `429` avec des en-têtes de limitation de débit standard.

### Internes admin

Lorsque `MCP_EXPOSE_INTERNALS=true` (la valeur par défaut), le rôle admin obtient des outils en lecture seule sur les tables des schémas `auth` et `system` (`{app}_auth_*_read/_list`, `{app}_system_*_read/_list`), avec les colonnes de secrets en liste noire. Définissez-le à `false` pour retirer tous les outils internes de `tools/list`, même pour les admins.

## Mode client

Les agents Sovrium peuvent consommer des outils depuis des serveurs MCP externes. Le bloc `mcp` d'un agent définit la liste blanche de noms d'outils externes qu'il peut invoquer.

```yaml
agents:
  - name: research-agent
    role: analyst
    systemPrompt: Research topics using approved external tools.
    mcp:
      allowedTools: [web_search, fetch_url]
```

| Propriété          | Description                                                     |
| ------------------ | --------------------------------------------------------------- |
| `mcp.allowedTools` | Noms d'outils MCP externes que l'agent est autorisé à utiliser. |

Ceci complète la liste blanche `tools` interne de l'agent : `tools` délimite ce que l'agent peut faire _à l'intérieur_ de Sovrium, tandis que `mcp.allowedTools` délimite quels outils MCP _externes_ il peut appeler.

## Pages connexes

- [Vue d'ensemble de l'IA](/fr/docs/ai-overview) — l'écosystème IA complet et la philosophie de configuration.
- [Agents IA](/fr/docs/ai-agents) — agents qui agissent comme clients MCP.
- [Vue d'ensemble des tables](/fr/docs/tables-overview) — la propriété de table `aiAccess`.
- [Actions](/fr/docs/automation-actions-overview) — modèles d'action exposés comme outils MCP.
- [Rôles & RBAC](/fr/docs/auth-roles-rbac) — les permissions que MCP applique toujours.
- [Variables d'environnement](/fr/docs/env-vars) — référence complète `MCP_*`.
