Aller au contenu

MCP pour les agents

Un client MCP relié à Perstat répond à « qu’est-ce qui est tombé et qui s’en occupe » à partir de vos données, puis agit dans les limites de son autorisation. Le catalogue source vérifié le 26 août 2026 définit quinze outils : sept lisent, deux agissent sur un incident et six gèrent projets et monitors. Pour le serveur connecté, tools/list fait foi ; create_project n’a pas été vérifié séparément en production. Aucun outil défini ne supprime le registre.

Endpoint https://api.perstat.io/mcp
Transport Streamable HTTP, sans état
Versions du protocole 2025-06-18 (préférée), 2025-03-26, 2024-11-05

Un message JSON-RPC entre par POST, une réponse JSON ressort. GET /mcp répond 405 : ce serveur n’ouvre aucun flux d’événements de sa propre initiative. Les lots JSON-RPC ont disparu avec 2025-06-18 et sont rejetés avec un message clair.

Dans Claude Code :

Terminal window
claude mcp add --transport http perstat https://api.perstat.io/mcp \
--header "Authorization: Bearer pst_…"

Cette forme fonctionne avec les clients qui acceptent un en-tête HTTP d’autorisation personnalisé. La clé finit alors dans l’historique de votre shell.

Pour Claude Code, il existe un plugin. Il se branche sur le même serveur et ajoute quatre skills qui transforment les outils en workflows : traiter un incident, gérer les monitors et lire l’état actuel.

Terminal window
claude plugin marketplace add datargo/perstat-plugin
claude plugin install perstat@datargo

Au premier appel d’un outil Perstat, Claude ouvre l’authentification OAuth dans votre navigateur. Choisissez l’organisation de la connexion : aucune clé à copier ni profil shell à modifier. La connexion reste liée à cette organisation et à votre rôle actuel. Vérifiez-la avec claude mcp list ; Perstat doit indiquer Connected.

Gardez la commande avec clé API ci-dessus pour la CI, cron ou un accès volontairement limité à certains projets. Le plugin est la voie interactive authentifiée par navigateur.

Perstat accepte une clé API d’organisation limitée par scopes comme bearer :

Authorization: Bearer pst_…

Un client compatible OAuth peut utiliser le flux Authorization Code publié avec PKCE. Les documents de découverte sont https://api.perstat.io/.well-known/oauth-protected-resource/mcp et https://api.perstat.io/.well-known/oauth-authorization-server ; ils publient aussi les endpoints de refresh et de révocation. Un cookie de session navigateur seul n’authentifie pas MCP : le flux OAuth se termine par un bearer token.

Les clients OAuth sont acceptés depuis Claude, Claude Code et ChatGPT, reconnus à leurs documents client sous https://claude.ai/oauth/ et https://chatgpt.com/oauth/. L’écran de consentement nomme l’hôte d’où vient le client, pas seulement le nom qu’il se donne, et un client ne reçoit que les droits dont ses outils ont besoin : monitors et incidents, chacun en lecture ou en écriture.

Une clé d’organisation appartient à une seule organisation et porte des scopes : elle ne peut jamais faire plus que ce que dit la clé.

Les owners et les admins créent les clés dans l’application, sous Intégrations, clés API.

tools/list ne montre que ce que l’autorisation actuelle permet. tools/call revérifie le même scope, parce qu’une liste n’est pas une protection.

Le catalogue source complet compte quinze outils. L’OAuth navigateur accorde actuellement les scopes monitors et incidents : les utilisateurs du plugin ne reçoivent donc pas list_status_pages. Une clé API avec status-pages:read le permet. Pour l’accès concret, la réponse tools/list du serveur connecté reste la référence.

Outil Scope Effet
get_organization_summary monitors:read Toute la situation en un appel : les services par état, les incidents ouverts
list_projects monitors:read Les projets avec leur nombre de monitors. Le point d’entrée pour create_monitor
list_monitors monitors:read Les services avec leur dernier état confirmé, filtrables. Passez archived: true pour l’archive
get_monitor monitors:read Un service avec configuration, régions et incidents récents. Les valeurs des en-têtes de requête personnalisés reviennent en [redacted]
list_incidents incidents:read Incidents ouverts et résolus, les plus récents d’abord
get_incident incidents:read Un incident en détail
acknowledge_incident incidents:write Prendre l’incident, ce qui arrête l’alerte et l’escalade
resolve_incident incidents:write Fermer un incident ouvert à la main
list_status_pages status-pages:read Les pages de statut de l’organisation
create_project monitors:write Créer le dossier qui contient les monitors. Clés à l’échelle de l’organisation uniquement
create_monitor monitors:write Mettre un nouveau service sous monitoring. Clés à l’échelle de l’organisation uniquement
update_monitor monitors:write Changer le nom, les réglages, l’intervalle de check ou les régions
set_monitor_enabled monitors:write Mettre un monitor en pause ou le remettre en service
archive_monitor monitors:write Retirer un service de l’exploitation et libérer sa place dans votre formule
restore_monitor monitors:write Ramener un service archivé. Il revient en pause et a besoin d’une place libre dans le forfait

write implique read sur la même ressource, jamais d’une ressource à l’autre.

Tout ce que l’agent voit est en anglais : noms d’outils, descriptions, textes de schéma, motifs d’erreur. Le journal d’activité dans l’application n’est pas concerné : celui-là, ce sont des humains qui le lisent.

create_project et create_monitor sont les deux outils non idempotents, et ils le déclarent au client. Répéter l’un ou l’autre appel peut créer une seconde ressource ou échouer sur le nom. Regardez d’abord avec list_projects ou list_monitors.

Les outils qui modifient ou terminent un état existant (acknowledge_incident, resolve_incident, update_monitor, set_monitor_enabled, archive_monitor) sont marqués comme destructifs, afin qu’un client puisse demander confirmation avant de les appeler. Créer et restaurer ne font qu’ajouter.

Les en-têtes de requête personnalisés d’un moniteur sont des identifiants et ne sont jamais relus par une clé ou un agent : get_monitor montre leurs noms avec la valeur [redacted]. Renvoyez une configuration avec le marqueur via update_monitor et la valeur enregistrée est conservée, tant que l’URL et la méthode restent exactement identiques. Après toute modification de l’une ou de l’autre, le marqueur est refusé, pour qu’un identifiant ne suive jamais une requête que son auteur n’a pas configurée. L’application web continue d’afficher les valeurs aux membres connectés.

Un agent peut archiver un service. Il ne peut jamais en supprimer un, et la raison n’est pas la prudence.

La suppression d’un monitor se propage en cascade dans onze tables et emporte l’historique des incidents, les agrégats SLA quotidiens et les fenêtres d’exclusion. Pour un produit dont tout l’intérêt est le registre, un appel d’agent ne doit pas pouvoir aller jusque-là. Donc l’outil qui le ferait n’existe pas.

archive_monitor arrête le service, le retire des listes actives et libère sa place dans votre formule, tout en gardant la ressource restaurable. L’archivage ne supprime pas lui-même l’historique, mais les règles normales de rétention par objet continuent de s’appliquer ; ce n’est pas un stockage permanent. restore_monitor le ramène en pause et occupe de nouveau une place du forfait : si le forfait est plein, la restauration est refusée avec le même message que create_monitor, jusqu’à ce qu’un autre monitor soit archivé ou que le forfait change. Le nom est libéré à l’archivage : un nouveau monitor peut le reprendre.

Pour votre quota, la différence compte : mettre en pause ne libère pas de place, le monitor est toujours là et toujours voulu. Archiver, si. Pour faire vraiment disparaître une chose, supprimez-la dans l’application, où une personne regarde les conséquences en face.

Le retour ne doit pas dépendre de la mémoire de quelqu’un. list_monitors avec archived: true montre l’archive, et get_monitor trouve aussi les services archivés : vous pouvez regarder avant de restaurer. Sans cela, un monitor archivé deviendrait inaccessible par MCP dès que son ID se perd. Ce qui ne marche pas sur un monitor archivé, c’est le modifier ou le rallumer : update_monitor et set_monitor_enabled le rejettent avec « is archived, call restore_monitor first » plutôt qu’avec « not found », parce qu’il n’a pas disparu.

Hors de portée en écriture par MCP également : les modifications de pages de statut, les connecteurs, les clés API, les membres et votre formule. list_status_pages est une exception en lecture pour les clés API avec status-pages:read ; l’OAuth navigateur ne reçoit pas ce scope aujourd’hui. Les écritures opérationnelles restent dans le monitoring et les incidents.

Une action par MCP est attribuée à l’identité humaine du credential : créateur de la clé API ou sujet OAuth. La prise d’un incident porte ainsi un nom, pas seulement un token. La chronologie de l’incident note en plus que l’action est passée par MCP. Les monitors qu’un agent crée ou modifie apparaissent de la même façon dans le journal d’activité de votre organisation, sous le nom de cette identité.

Parce que cette identité est empruntée pour l’attribution, elle décide aussi des droits. À chaque écriture, le serveur revérifie que l’identité est encore membre de l’organisation et porte encore le rôle que l’action exige. Le seuil est celui de l’application : traiter un incident demande le droit de répondre, jusqu’au rôle responder ; gérer des monitors demande le droit de gérer des projets, donc owner, admin ou developer. Rétrogradez ou retirez cette identité, et son credential cesse d’écrire dès l’appel suivant. La lecture n’est pas touchée et ne dépend que des scopes du credential. Si le compte de cette personne a été supprimé, le serveur refuse aussi l’écriture, et dit pourquoi.

Une clé limitée à certains projets ou monitors ne voit que ses propres ressources dans list_monitors et list_incidents. Le reste n’existe tout simplement pas pour elle, et rien ne lui permet de vérifier si quelque chose existe ailleurs. À l’écriture, même chose : update_monitor et set_monitor_enabled répondent qu’aucun monitor ne porte cet ID, pas que c’est interdit.

Les outils à l’échelle de l’organisation, get_organization_summary, list_status_pages, create_project et create_monitor, ne sont pas proposés du tout à une clé restreinte. Les deux outils de création lui permettraient sinon d’écrire dans des projets dont elle ignore tout.

Les outils de liste renvoient total_matching et truncated à côté des lignes : une réponse tronquée se reconnaît comme telle au lieu de ressembler à un résultat complet.

Un échec à l’intérieur d’un outil n’est pas une erreur de protocole. Il revient comme un résultat marqué en erreur, avec un motif en clair : le modèle voit ce qui a raté et peut essayer autre chose. Les erreurs de protocole restent réservées aux requêtes réellement malformées.