---
title: "Connecteur MCP — ISI-APP dans un client Claude"
module: ai
type: functional
status: draft
updated: 2026-10-01
---

# Connecteur MCP — ISI-APP dans un client Claude

## À quoi ça sert

ISI-APP expose un **serveur MCP** (« connecteur Claude ») : un client MCP externe —
Claude Code dans un terminal, Claude Desktop — peut interroger directement les
projets, sprints, backlogs et tâches de l'application, en langage naturel, sans
ouvrir l'application.

Ce n'est **pas** un nouveau moteur d'IA ni une nouvelle logique métier. Les outils
interrogés sont exactement ceux du *tool-calling* déjà utilisés par le chat IA interne
(packs `core` et `project`, cf. [`ai-tool-calling-lot-bc.md`](ai-tool-calling-lot-bc.md)) :
le connecteur n'est qu'un **second chemin d'accès** à ces mêmes outils, pour un client
qui n'est pas le chat d'ISI-APP.

Cas d'usage visé : un chef de projet ou un développeur qui travaille déjà dans Claude
et veut poser une question sur l'état d'un projet sans changer d'outil.

## Ce qu'il peut écrire, et ce qu'il ne peut pas

Le connecteur lit, et il sait **créer et modifier des backlogs**, **créer et modifier des
étapes**, **charger des mairies prospectes dans le CRM**, et — pour les release notes client —
**générer un brouillon, le modifier, et gérer ses catégories** (création, modification,
**suppression**). Il permet aussi de **saisir, corriger et supprimer vos propres temps** (voir
*Saisir ses temps* plus bas). Chaque outil d'écriture n'agit que sous confirmation explicite
(voir plus bas). Tout le reste est hors de sa portée : les tâches, les tickets liés, les
clients liés, les charges, et la suppression d'une release note elle-même, qui reste dans
l'application.

**Prospects CRM.** `crm_prospects_import` charge un lot de 50 mairies au plus, avec leur
DGS quand il est connu : chaque ligne est rapprochée d'une fiche existante (SIRET, SIREN, puis
nom et département), l'aperçu détaille création ou avant/après, et la confirmation écrit tout
le lot ou rien. Il faut le module CRM et les droits de création et de modification des fiches.
Détail : [Import de prospects](../crm/crm-prospects-import.md).

**Release notes client.** Six outils, réservés aux comptes ISI-admin (indépendamment de
tout module souscrit) :

- `release_notes` — lecture seule, sans confirmation : liste les release notes
  (brouillons compris) et rend la taxonomie des catégories avec leurs `id`. C'est le seul
  moyen de retrouver les identifiants attendus par les cinq outils suivants.
- `release_note_create` — génère puis crée une release note à partir d'un changelog
  technique : l'IA catégorise chaque entrée en réutilisant une catégorie existante par son
  nom exact, ou en proposant une nouvelle catégorie sans jamais la créer d'elle-même. La
  génération IA a lieu **dès le premier appel**, donc l'aperçu montre déjà le résultat
  définitif.
- `release_note_update` — modifie une release note existante : sa version, sa date, et ses
  items (texte, type, catégories, ajout, suppression, réordonnancement). Une catégorie
  inconnue est refusée, jamais créée à la volée — c'est `release_note_category_create` qui
  s'en charge.
- `release_note_category_create` / `release_note_category_update` — créent et modifient
  une catégorie (nom, couleur, icône). Le nom doit rester unique, insensible à la casse et
  aux accents.
- `release_note_category_delete` — supprime définitivement une catégorie : l'aperçu
  annonce combien d'items en perdent le rattachement, et combien appartiennent à une
  release note déjà **publiée**. Suppression dure (la table n'a pas de colonne de
  suppression logique) : c'est le seul outil du connecteur qui détruit des données, et le
  seul dont le client MCP est prévenu par un `destructiveHint` à part.

Toutes les release notes créées le sont **toujours en brouillon** (`blactive = false`), et
`release_note_update` ne porte aucun paramètre pour publier : la publication reste un
geste manuel dans l'admin, après relecture humaine. Voir *La confirmation en deux temps*
plus bas.

L'outil de migration de backlogs entre sprints (`migrate_sprint_backlogs`), qui existe
dans le pack `project` du chat IA, est **volontairement exclu** : le connecteur expose une
liste d'outils nommés un par un, jamais un pack entier.

### La confirmation en deux temps

Un client MCP n'a pas d'écran pour afficher un bouton « Confirmer ». Le cycle est donc
porté par le protocole :

1. Claude appelle l'outil **sans jeton** : rien n'est écrit. Il reçoit l'avant/après champ
   par champ, et la liste des répercussions.
2. Il vous les présente, et attend votre accord.
3. Il rappelle l'outil avec le jeton reçu — et **la modification appliquée est celle qui
   vous a été montrée**, pas celle des paramètres du second appel.

Le jeton ne sert qu'une fois, expire au bout de 5 minutes, n'est valable que pour son
porteur, et devient caduc si le backlog a changé entre-temps : dans ce cas Claude doit
refaire un aperçu, parce que l'avant/après que vous avez validé ne décrit plus la réalité.

> **La limite honnête de ce dispositif.** Rien, côté serveur, ne peut *contraindre* Claude
> à vous montrer l'aperçu avant de confirmer : c'est une consigne, doublée du fait que les
> outils s'annoncent au client comme modifiants, ce qui déclenche sa demande
> d'autorisation. Si vous lancez votre client en mode permissions permissives, ou que vous
> autorisez l'outil de façon permanente, l'enchaînement peut se faire sans que vous voyiez
> l'aperçu. Le protocole MCP n'offre pas aujourd'hui de moyen de rendre cette étape
> contraignante côté serveur.

### Saisir ses temps

**À quoi ça sert.** Déclarer sa journée sans quitter Claude Code. Le cas visé est celui du
développeur qui, en fin de journée, dit ce qu'il a fait : le travail sur le sprint s'impute
sur la mission « Évolutions / Sprints » (libellé habituel « Dev »), la revue de PR sur la
mission « Tests » (libellé habituel « PR »). Claude retrouve la mission, propose la saisie,
et n'écrit qu'après votre accord.

Quatre outils, ouverts à tout compte disposant du module CRM (B2B) :

- `my_times` — lecture seule : vos temps jour par jour sur une période (par défaut, du lundi
  de la semaine courante à aujourd'hui), avec le total de chaque jour et la liste des
  **jours manquants** (jours ouvrés, week-ends et jours fériés exclus, dont le total est
  inférieur à une journée). Chaque temps indique s'il est modifiable ou supprimable.
- `my_time_create` — déclare un ou plusieurs temps (jusqu'à 20 d'un coup, par exemple une
  quinzaine entière en une seule confirmation). Tout le lot passe, ou rien.
- `my_time_update` — corrige un de vos temps : date, période, horaires, mission, libellé,
  catégorie, lieu, description.
- `my_time_delete` — supprime un de vos temps.

Pour retrouver la bonne mission, Claude s'appuie sur la liste des missions que vous pouvez
imputer (`time_missions_list`, déjà utilisée par le chat IA) ; il ne devine jamais un
identifiant.

**Journée ou demi-journée.** Chaque temps porte une période :

- `day` — une journée entière (1 jour), sans horaires ;
- `morning` / `afternoon` — une demi-journée (0,5 jour) avec horaires, par défaut
  **08:00–12:30** le matin et **13:30–17:00** l'après-midi. Vous pouvez les modifier à la
  demande (« matin de 9h à 12h ») ; un début postérieur ou égal à la fin est refusé, et on
  ne précise pas d'horaires sur une journée entière.

**Ce que Claude complète à votre place**, comme le fait le formulaire de saisie :
la catégorie et le libellé de votre dernier temps sur la même mission (à défaut, le libellé
de la mission ; la catégorie est alors à préciser), le lieu (celui d'un autre temps du même
jour, sinon le bureau — Claude vous le demande si vous ne l'avez pas précisé), et le tarif
jour, qui n'est pas modifiable mais figure dans l'aperçu. Un temps créé est toujours
**programmé**.

**Exemples de phrases.**

- « Quels jours me manque-t-il du temps cette semaine ? »
- « Déclare ma journée d'hier sur Évolutions / Sprints. »
- « Mets lundi, mardi et mercredi en journée sur le sprint, et jeudi matin en revue de PR. »
- « Ajoute demain après-midi sur la mission Tests, libellé "PR", de 14h à 17h. »
- « Décale mon temps de jeudi matin au vendredi. »
- « Supprime le temps que j'ai saisi deux fois lundi. »

**Le cycle aperçu → confirmation** est celui des autres outils d'écriture (voir *La
confirmation en deux temps*). L'aperçu liste chaque temps tel qu'il sera enregistré
(date, période, horaires, mission, libellé, catégorie, lieu, tarif) et les points
d'attention : une date un week-end ou un jour férié, ou hors des dates de la mission, est
**signalée mais pas refusée**. Si le temps a changé entre l'aperçu et la confirmation, la
confirmation est refusée et Claude refait un aperçu.

**Les limites.**

- **Vos temps uniquement.** Vous ne pouvez ni voir, ni modifier, ni supprimer ceux d'un
  collègue ; un temps qui n'est pas le vôtre est traité comme introuvable.
- **Pas d'absences.** Congés, RTT et autres catégories d'absence déclenchent une validation
  par le manager dans l'application : ils se saisissent là-bas. Une mission clôturée, ou
  sur laquelle vous n'êtes pas affecté, est refusée.
- **Pas de synchronisation Outlook.** Un temps créé depuis le connecteur n'est pas poussé
  dans votre calendrier, et un temps déjà lié à un événement Outlook ne peut être ni
  modifié ni supprimé ici : passez par l'application.
- **Un jour ne dépasse pas une journée déclarée.** Si le total du jour, avec la saisie
  demandée, dépasse 1, elle est refusée et Claude vous montre les temps déjà présents ce
  jour-là. Deux demi-journées dont les horaires se chevauchent sont également refusées.
- **L'état n'est jamais modifiable** depuis le connecteur (programmé, réalisé, validé) :
  il suit son cycle dans l'application.
- **Un temps validé n'est pas modifiable**, et **seul un temps programmé peut être
  supprimé** — mêmes règles que dans l'application. La suppression est définitive (la
  table n'a pas de suppression logique) ; les totaux de la mission sont recalculés.

## Ce qu'on peut demander

Trente outils sont exposés : le contexte de l'utilisateur (`me`), la résolution d'un nom
en identifiant (`resolve`), les projets (`projects`), les tâches de projet
(`project_tasks`), les backlogs (`backlogs`), le texte intégral d'un backlog
(`backlog_description_get`), les sous-tâches de checklist (`backlog_tasks`), quatre outils
d'écriture sur les backlogs et les étapes — création (`backlog_create`, `sprint_create`) et
modification (`backlog_update`, `sprint_update`) —, six outils sur les **tickets support** :
la fiche (`tickets`), la demande intégrale (`ticket_description_get`), les échanges avec le
client et les commentaires internes (`ticket_messages_get`), l'inventaire des pièces
jointes (`ticket_attachments_get`), l'historique (`ticket_history_get`) et les sujets
(`ticket_subjects_list`) —, et six outils sur les **release notes client**, réservés aux
comptes ISI-admin : la lecture (`release_notes`), la génération d'un brouillon
(`release_note_create`), sa modification (`release_note_update`), et la gestion des
catégories (`release_note_category_create`, `release_note_category_update`,
`release_note_category_delete`) —, et deux outils sur les **journaux d'erreurs
applicatives**, réservés eux aussi aux comptes ISI-admin : l'agrégat par signature
(`error_logs_summary`, ce qui casse le plus sur une période) et la consultation détaillée
(`error_logs`, listing ou fiche d'une ligne) —, et, pour **vos temps**, la consultation
de la semaine (`my_times`), la liste des missions imputables (`time_missions_list`) et trois
outils d'écriture : `my_time_create`, `my_time_update`, `my_time_delete`.

Concrètement, cela permet des questions du type :

- « Où en est mon sprint en cours ? » — `me` renvoie directement vos sprints en cours avec
  leur identifiant, Claude enchaîne sur `backlogs` filtré sur ce sprint et fait la
  synthèse par statut.
- « Donne-moi tout le contexte du ticket 71958 avant qu'on le corrige. » — la fiche, la
  demande, les échanges avec le client, les commentaires internes et l'inventaire des
  pièces jointes. De quoi lancer une correction en connaissant le dossier.

> **Sur les pièces jointes.** Claude obtient leurs métadonnées — nom, type, taille,
> auteur, URL — jamais leur contenu. Une capture d'écran citée dans un échange ne lui est
> donc pas lisible : il est instruit de te demander ce qu'elle montre plutôt que de le
> supposer.
- « Quels backlogs sont bloqués sur le projet Alpha ? » — `resolve` retrouve
  l'identifiant du projet à partir de son nom, puis `backlogs` filtre sur le statut
  `Bloqu`.
- « Détaille-moi le backlog des imprimantes OCS. » — `backlogs` en mode détail rend la
  fiche : la demande elle-même, la proposition technique, le demandeur, les charges
  estimées et réelles, la branche git, les tickets liés.
- « Liste mes tâches en retard, projet par projet. » — `project_tasks` avec le filtre
  « mes tâches », qui couvre aussi les tâches que vous avez créées sans les affecter.
- « Qui porte quoi sur le projet Alpha ? » — un backlog peut avoir **plusieurs**
  assignés ; la réponse rend tous les noms et leurs identifiants, pour que le
  regroupement par personne soit fiable même en cas d'homonymes.
- « Quels jours me manque-t-il du temps cette semaine ? » — `my_times` rend la semaine jour
  par jour et liste les jours incomplets ; Claude propose ensuite la saisie.
- « Qu'est-ce qui plante le plus cette semaine ? » — `error_logs_summary` renvoie les
  signatures d'erreur (classe + fichier + ligne) triées par nombre d'occurrences, avec la
  sévérité maximale observée ; Claude enchaîne sur `error_logs` pour la fiche complète
  d'une occurrence, avant d'aller lire le code concerné.

Les listes sont **paginées** : Claude est instruit de parcourir les pages plutôt que de
conclure sur la première. Depuis le connecteur, il peut demander jusqu'à 50 résultats par
appel — lire un projet entier par pages de 10 coûtait 139 allers-retours, contre 28. Le
chat IA d'ISI-APP conserve ses pages de 10.

Les champs de texte riche (la demande, la proposition) sont mis au texte brut — ils sont
saisis dans un éditeur WYSIWYG et la moitié d'entre eux contient du HTML — puis tronqués
à 4 000 caractères, ce qui rend environ 99 % des backlogs en entier. Au-delà, la réponse
porte `request_truncated: true` et Claude enchaîne sur `backlog_description_get` pour le
texte complet.

## Mise en route

### 1. Obtenir un jeton

Un jeton personnel est nécessaire ; il vaut « agir en tant que cet utilisateur, sur les
outils du connecteur ». Deux façons de l'obtenir.

**Depuis l'écran d'administration** — le plus simple, et la voie recommandée :
**Administration → onglet Actions → Jetons MCP**, ou directement `/admin/mcp-tokens`.

L'écran liste les comptes autorisés — profil 1 de l'entité ISI, une dizaine aujourd'hui —
avec leurs jetons, leur dernier usage et leur expiration. Un bouton par compte émet un
jeton ; un bouton par jeton le révoque, après confirmation.

Après l'émission, l'écran affiche **une seule fois** le jeton et la commande complète à
coller dans le terminal de son porteur, jeton compris. Le clair n'existe qu'à cet instant :
la base n'en garde qu'une empreinte, et quitter l'écran le perd définitivement. À
transmettre par un canal sûr, jamais par e-mail en clair.

**En ligne de commande**, côté serveur, si tu n'as pas accès à l'écran :

```bash
php artisan isi:mcp:token prenom.nom@exemple.fr
```

Options utiles : `--days=0` pour un jeton sans expiration (90 jours par défaut),
`--list` pour lister ses jetons, `--revoke=<id>` pour en révoquer un. Lister et révoquer
restent possibles même pour un compte devenu inéligible — c'est justement le moment où
l'on en a besoin.

Les deux voies partagent la même logique, donc les mêmes règles : un compte hors profil 1
de l'entité ISI se voit refuser l'émission, et le jeton ne porte que la capacité du
connecteur.

### 2. Brancher son client

Le client local lance le serveur en **stdio** — un processus dédié, piloté par le
client :

```json
{
    "mcpServers": {
        "isi-app": {
            "command": "php",
            "args": ["/chemin/vers/isi-app/artisan", "isi:mcp:serve"],
            "env": {
                "ISI_MCP_TOKEN": "COLLER_ICI_LE_JETON"
            }
        }
    }
}
```

Un modèle est fourni à la racine du dépôt dans `.mcp.json.example`.

### 3. Choisir le transport

| Transport | Comment | Quand le choisir |
|-----------|---------|------------------|
| **stdio** | `php artisan isi:mcp:serve`, jeton dans `ISI_MCP_TOKEN` | Poste de dev, client local ayant accès au code et à la base. C'est le cas courant. |
| **HTTP** | `POST /mcp`, jeton en en-tête `Authorization: Bearer …` | Client distant qui ne peut pas exécuter l'application (client hébergé, poste sans accès au serveur). |

Les deux transports servent le même serveur : mêmes outils, mêmes droits. Seule
l'origine de l'identité change.

## Règles d'accès

- **Réservé à l'équipe de développement ISI.** Le temps de la mise au point, seuls les
  comptes de profil 1 de l'entité ISI peuvent ouvrir une session ou se faire émettre un
  jeton. Un compte 1 chez un client ne passe pas : la condition porte sur l'entité **et**
  le profil. La commande de jeton refuse d'en émettre pour tout autre compte, et le
  message d'erreur ne dit pas pourquoi — les autres comptes n'ont pas à découvrir
  l'existence du connecteur. Un seul réglage (`mcp.isi_admins_only`) l'ouvrira le jour où
  ce sera décidé.
- **Vous ne voyez que votre propre périmètre.** L'acteur est toujours l'utilisateur
  propriétaire du jeton : le client ne peut pas demander à agir pour quelqu'un d'autre.
  **Exception :** les deux outils de journaux d'erreurs (`error_logs`,
  `error_logs_summary`) sont une vue plateforme et couvrent toutes les entités — pas
  seulement la vôtre. C'est volontaire (diagnostiquer une régression qui touche plusieurs
  clients), et sans risque supplémentaire : le connecteur est déjà réservé à l'équipe ISI.
- **L'entité et les droits s'appliquent normalement.** Le connecteur rejoue l'ACL de
  l'application : filtrage multi-entités, projets confidentiels (`blsecret`), ACL
  ressources. Ce que votre profil ne vous montre pas dans ISI-APP, il ne le montre pas
  ici.
- **Les modules souscrits filtrent les outils.** Une personne dont l'entité n'a pas le
  module `projet` obtient un connecteur sans aucun outil projet — pas un outil qui
  échoue, un outil qui n'existe pas pour elle. Il ne reste alors que `me` et `resolve`.
- **La liste d'outils est calculée à chaque connexion.** Deux personnes branchées sur le
  même serveur ne voient donc pas forcément les mêmes outils.
- **Le jeton ne vaut que pour ce connecteur** : il porte la seule capacité `mcp:read` et
  ne sert pas de jeton d'API générique.

## Points d'attention

- **Un jeton = un utilisateur réel, en lecture, sur tout son périmètre.** Un jeton fuité
  donne accès aux projets et backlogs visibles par cette personne : le révoquer
  (`--revoke`) est la seule réponse.
- **Entité de rattachement.** La session ouverte par le connecteur retient l'entité du
  **profil favori** de l'utilisateur, comme un login normal. Il n'y a pas de moyen de
  changer d'entité depuis le client MCP ; pour interroger une autre entité, il faut
  basculer son profil favori dans l'application.
- **Une absence de résultat n'est pas une absence de donnée** : ce peut être un défaut de
  droits. Le connecteur transmet cette consigne au modèle, mais la nuance mérite d'être
  gardée en tête quand une réponse paraît trop vide.
- **Statuts terminés.** `Valid` et `Real` valent « terminé » : ils ne doivent pas être
  comptés comme du reste à faire. Cette sémantique est fournie au modèle avec la liste
  d'outils.
- **Un jeton ne s'affiche qu'une fois.** Ni l'écran ni la commande ne peuvent le
  réafficher : la base n'en conserve qu'une empreinte. S'il est perdu, il faut le
  révoquer et en émettre un autre.
- **Le mode assistance n'est pas couvert** : un assistant ISI qui impersonne un client
  dans l'application ne peut pas le faire via le connecteur — le jeton désigne toujours
  son propriétaire.

## Ce qui est prévu ensuite

La **suppression** reste hors périmètre pour les backlogs, les étapes et les release
notes elles-mêmes (les temps programmés de l'utilisateur, eux, sont supprimables), et le restera sans décision explicite : elle est irréversible côté
backlog (la table n'a pas de suppression logique) et l'application la gère bien. Seule
exception, délibérée : les **catégories** de release note (`release_note_category_delete`),
dont la suppression est déjà dure côté application — le connecteur ne fait qu'exposer un
geste déjà sans filet, sous confirmation explicite et un `destructiveHint` dédié.

Les autres pistes non engagées : élargir l'écriture aux tâches et aux liens (tickets,
clients), une capacité de jeton distincte pour la lecture et l'écriture (aujourd'hui un
seul `mcp:read` ouvre les deux), et l'ouverture du connecteur au-delà de l'équipe de
développement.

Autres pistes non engagées : élargissement à d'autres domaines déjà couverts par des
packs d'outils (contrats), la saisie des absences et la synchronisation Outlook des
temps depuis le connecteur.

## Voir aussi

- Doc technique : [`.claude/technical-docs/ai/mcp-server.md`](../../.claude/technical-docs/ai/mcp-server.md)
- Les outils réexposés : [`ai-tool-calling-lot-bc.md`](ai-tool-calling-lot-bc.md) (packs
  `core` et `project`)
- Le socle IA côté chat : [`ai-tool-calling-ui.md`](ai-tool-calling-ui.md)
