MCP Scopes
Les scopes sont les permissions fines des jetons MCP. Chaque outil déclare les scopes qu'il exige ; un jeton n'a accès qu'aux outils dont il possède tous les scopes. C'est l'équivalent d'un « scope » OAuth, pensé pour borner le rayon d'action d'un agent LLM.
Concept
Trackily expose 43 scopes, en paires :read / :write par domaine, sauf quatre domaines en lecture seule (stats:read, reports:read, checkouts:read, analytics:read) et ai:generate, qui n'a pas de paire.
Le contrat :
- Un outil déclare ses scopes dans son
registerTool(scopes: [S.CAMPAIGNS_WRITE]). tools/listne rend à un jeton que les outils dont il a tous les scopes (même règle pourresources/listetprompts/list). Un outil absent de la liste d'un agent est un scope manquant, pas un outil manquant.- À l'appel, le serveur vérifie que tous les scopes requis sont dans le jeton. Sinon : erreur JSON-RPC
-32002, messageMissing scope for <outil>, eterror.data.requiredporte la liste des scopes que l'outil exige — tous, pas seulement ceux qui manquent. L'appel refusé entre au journal d'audit comme un appel d'outil en erreur (event_typetool,result_statuserror). - Un outil qui exige plusieurs scopes les exige tous :
bind_landing_to_email_listdemandeemail:writeetlandings:write.
La vérification se fait dans autopilot.js, fonction hasScope() :
function hasScope(tokenRow, required) {
if (!Array.isArray(required) || !required.length) return true;
const granted = Array.isArray(tokenRow?.scopes) ? tokenRow.scopes : [];
return required.every(s => granted.includes(s));
}
La liste complète
Tracker d'affiliation
| Scope | Ce qu'il ouvre |
|---|---|
stats:read |
Stats agrégées, brief du jour, anomalies, santé du tracking, parcours d'un visiteur, attribution |
campaigns:read |
Lecture des campagnes |
campaigns:write |
Campagnes : création, pause, reprise, coût, duplication, création de flow, branchement d'une landing |
offers:read |
Offres d'affiliation, smartlinks, plan de duplication par marché |
offers:write |
Offres d'affiliation (pause, reprise, payout, synchro réseau, rotation dans les flows), duplication d'un produit ou d'une offre commerce pour un autre marché |
landings:read |
Landings, leads, funnels, thèmes, Product Truth, smartlinks |
landings:write |
Landings (création, import, retouche, traduction, génération), funnels, thèmes, Product Truth, smartlinks |
sources:read |
Sources de trafic, et vérification de leur branchement API |
sources:write |
Pause, reprise, budget et enchère d'une campagne directement chez la régie |
networks:read |
La resource trackily://networks (réseaux d'affiliation) |
networks:write |
Aucun outil ne l'exige aujourd'hui |
flows:read |
Lecture des flows d'une campagne |
flows:write |
Écriture dans les flows (branchement d'une landing, rotation d'offre) |
automizer:read |
Règles Automizer et leur journal d'exécution |
automizer:write |
Règles Automizer : création, modification, suppression, pause, reprise |
reports:read |
Journal des clics et des conversions, stats par produit natif, stats de routage des smartlinks |
ai:generate |
La plupart des appels LLM : génération de landings, translate_landing, audit de conformité, descriptions et traductions de produits. Trois outils qui appellent aussi un LLM n'en dépendent pas : translate_landing_html, duplicate_funnel_for_language et propose_funnel (landings:write seul) |
settings:read |
Zones de livraison, comptes de paiement, domaines, types de conversion, règles de notification, workflows de cloaking |
settings:write |
Écriture de ces mêmes réglages, relais SMTP compris — sensible |
E-commerce
| Scope | Ce qu'il ouvre |
|---|---|
stores:read |
Boutiques externes connectées (Shopify…) et boutiques natives, codes d'export |
stores:write |
Boutiques natives : création, domaines, thème, duplication, suppression, export et import ; rattacher une offre à une boutique |
products:read |
Produits Shopify et natifs, offres commerce, merchandising, audits de catalogue |
products:write |
Produits Shopify et natifs, variantes, metafields, offres commerce et leurs bundles, merchandising |
orders:read |
Commandes Shopify et natives, clients natifs |
orders:write |
Commandes : exécution, remboursement, annulation, tags, notes, paiement reçu |
checkouts:read |
Paniers abandonnés Shopify |
customers:read |
Clients Shopify |
customers:write |
Clients Shopify : création, modification |
analytics:read |
KPI e-commerce Shopify (chiffre d'affaires, conversion, meilleures ventes) |
inventory:read |
Emplacements et niveaux de stock Shopify |
inventory:write |
Niveau de stock Shopify |
collections:read |
Collections Shopify |
collections:write |
Collections Shopify : création, modification, suppression, ajout et retrait de produits |
discounts:read |
Codes promo Shopify |
discounts:write |
Codes promo et price rules Shopify |
marketing:read |
Script tags et webhooks Shopify |
marketing:write |
Script tags et webhooks Shopify : création, suppression |
content:read |
Pages, blogs et articles Shopify |
content:write |
Pages et articles Shopify : création, modification, suppression |
| Scope | Ce qu'il ouvre |
|---|---|
email:read |
Listes, abonnés, séquences, envois, suppression, relais SMTP, déclencheurs |
email:write |
Listes, séquences et étapes, inscriptions et désinscriptions, suppression, déclencheurs, e-mail de test |
Le canal WhatsApp a sa propre paire, jamais celle de l'e-mail : sur un compte de l'API officielle, chaque message est facturé par le fournisseur et engage la note de qualité du numéro ; sur la voie « web » (une SIM par WhatsApp Web), rien n'est facturé, mais chaque envoi engage la SIM elle-même, et un numéro banni est perdu. Un jeton taillé pour l'e-mail ne doit pas hériter du droit d'envoyer sur ce canal.
| Scope | Ce qu'il ouvre |
|---|---|
whatsapp:read |
Comptes (jetons masqués), modèles, listes, abonnés, séquences, journal des envois, mesures, suppression, déclencheurs, réglages, modèles locaux, état d'appairage, groupes de SIM, règles de routage, simulation du routage |
whatsapp:write |
Vérifier un compte, resynchroniser ses modèles, listes, inscriptions, séquences et étapes, message de test, suppression, déclencheurs, réglages, modèles locaux, groupes de SIM, règles de routage |
Aucun scope, pas même whatsapp:write, ne permet de créer un compte WhatsApp, d'en changer les identifiants ou de démarrer un appairage : aucun outil ne le fait. Cf. Tools Reference — whatsapp-tools.
Les 4 presets
Pour éviter de cocher 43 cases, l'écran de création d'un jeton propose des presets (MCP Autopilot → onglet Tokens → + New token → Scope preset). Ils sont définis dans autopilot.js, SCOPE_PRESETS.
read_only
23 scopes : tous les :read, aucune écriture. Ni ai:generate, ni aucun :write. Pour un agent de lecture : résumé de la semaine, surveillance, tableau de bord.
operator
40 scopes : toutes les lectures et les écritures du quotidien, sauf trois — settings:write, networks:write et ai:generate.
Ce que ça veut dire en pratique : un jeton operator pilote campagnes, landings, funnels, boutiques, commandes, e-mail et WhatsApp, mais il ne peut ni appeler les outils qui exigent ai:generate (générer une landing, translate_landing, audit de conformité — même en mode rules —, description ou traduction de produit), ni écrire un réglage (domaines, zones de livraison, workflows de cloaking, relais SMTP, état d'un compte de paiement). Attention : translate_landing_html, duplicate_funnel_for_language et propose_funnel appellent un LLM sans exiger ai:generate — un jeton operator peut donc les lancer.
full
42 scopes : tous, sauf settings:write. C'est operator plus ai:generate et networks:write.
admin
43 scopes, tous, settings:write compris. À réserver à un seul jeton « bris de glace » pour la maintenance ponctuelle, gardé en coffre.
Tableau de correspondance preset → scopes
| Scope | read_only |
operator |
full |
admin |
|---|---|---|---|---|
stats:read |
OK | OK | OK | OK |
campaigns:read |
OK | OK | OK | OK |
campaigns:write |
— | OK | OK | OK |
offers:read |
OK | OK | OK | OK |
offers:write |
— | OK | OK | OK |
landings:read |
OK | OK | OK | OK |
landings:write |
— | OK | OK | OK |
sources:read |
OK | OK | OK | OK |
sources:write |
— | OK | OK | OK |
networks:read |
OK | OK | OK | OK |
networks:write |
— | — | OK | OK |
flows:read |
OK | OK | OK | OK |
flows:write |
— | OK | OK | OK |
automizer:read |
OK | OK | OK | OK |
automizer:write |
— | OK | OK | OK |
reports:read |
OK | OK | OK | OK |
ai:generate |
— | — | OK | OK |
settings:read |
OK | OK | OK | OK |
settings:write |
— | — | — | OK |
stores:read |
OK | OK | OK | OK |
stores:write |
— | OK | OK | OK |
products:read |
OK | OK | OK | OK |
products:write |
— | OK | OK | OK |
orders:read |
OK | OK | OK | OK |
orders:write |
— | OK | OK | OK |
checkouts:read |
OK | OK | OK | OK |
customers:read |
OK | OK | OK | OK |
customers:write |
— | OK | OK | OK |
analytics:read |
OK | OK | OK | OK |
inventory:read |
OK | OK | OK | OK |
inventory:write |
— | OK | OK | OK |
collections:read |
OK | OK | OK | OK |
collections:write |
— | OK | OK | OK |
discounts:read |
OK | OK | OK | OK |
discounts:write |
— | OK | OK | OK |
marketing:read |
OK | OK | OK | OK |
marketing:write |
— | OK | OK | OK |
content:read |
OK | OK | OK | OK |
content:write |
— | OK | OK | OK |
email:read |
OK | OK | OK | OK |
email:write |
— | OK | OK | OK |
whatsapp:read |
OK | OK | OK | OK |
whatsapp:write |
— | OK | OK | OK |
Composition multi-scope
Quelques outils demandent plusieurs scopes. Exemples (la colonne Scopes de la Tools Reference les donne tous) :
| Outil | Scopes requis | Pourquoi |
|---|---|---|
bind_landing_to_email_list |
email:write + landings:write |
l'outil modifie la landing pour la brancher sur une liste |
create_email_smtp_server |
email:write + settings:write |
un relais SMTP porte un mot de passe : c'est un réglage |
link_landing_to_campaign |
landings:write + campaigns:write + flows:write |
la landing entre dans un flow de la campagne |
generate_landing_for_offer |
ai:generate + landings:write + offers:read |
lit l'offre, appelle le LLM, crée la landing |
create_shipping_zone |
settings:read + settings:write |
les zones de livraison sont des réglages |
add_offer_to_smartlink |
offers:read + landings:write |
lit l'offre, écrit dans le pool du smartlink |
search_entities |
campaigns:read + offers:read + landings:read + sources:read |
cherche dans les quatre familles à la fois |
Si le jeton n'a qu'une partie des scopes requis, l'appel est refusé comme décrit plus haut, et error.data.required rend la liste complète exigée par l'outil.
Choisir un preset
Tu veux qu'un agent fasse...
... du reporting, de la surveillance uniquement
→ read_only
... le quotidien : pauses, budgets, landings écrites à la main, funnels,
boutiques, commandes, e-mail, WhatsApp
→ operator
... le quotidien + la génération par IA (landings, traductions,
audit de conformité — compliance_check, dans ses deux modes,
même rules —, descriptions de produits)
→ full (ou un jeton custom : operator + ai:generate)
... écrire des réglages : domaines, zones de livraison, workflows de
cloaking, relais SMTP, état des comptes de paiement
→ admin (réservé à ce jeton-là, jamais partagé)
Custom (cocher à la main)
L'option Custom — pick scopes manually du même menu permet de cocher les scopes un par un plutôt que d'appliquer un preset. Utile pour :
- Un agent dédié au commerce Shopify :
stores:read,products:read/write,orders:read/write,customers:read/write,analytics:read,inventory:read/write,discounts:read/write,collections:read/write,content:read/write. - Un agent dédié à l'e-mail :
email:read,email:write, etlandings:writes'il doit brancher une landing sur une liste (bind_landing_to_email_list). Les déclencheurs postback → e-mail n'exigent queemail:write. - Un agent dédié à WhatsApp :
whatsapp:readetwhatsapp:write. En lecture seule,whatsapp:readsuffit pour consulter journal, suppression et règles, et pour simuler un routage (simulate_whatsapp_routingn'écrit rien). - Un agent de reporting financier :
stats:read,analytics:read,reports:read,orders:read,customers:read.
Un jeton au scope minimal est plus sûr : moins de surface si le jeton fuite, moins de dégâts si le LLM se trompe.
Évolutions
Un jeton garde les scopes qu'il avait à sa création : le serveur les enregistre sur le jeton, et ne recalcule rien depuis les presets. Quand un domaine arrive — whatsapp:read et whatsapp:write en sont l'exemple —, les presets l'incluent pour les nouveaux jetons, mais un jeton operator créé avant ne voit toujours aucun outil WhatsApp.
Pour lui donner le nouveau domaine :
- crée un nouveau jeton avec le preset voulu, puis révoque l'ancien ;
- ou modifie ses scopes par l'API d'administration,
PUT /admin/api/autopilot/tokens/:idavec un tableauscopescomplet (l'écran des jetons ne propose pas d'édition des scopes).
La rotation (l'icône « Rotate » de la liste des jetons) ne suffit pas : elle recopie les scopes de l'ancien jeton sur le nouveau.
Retirer ou renommer un scope retirerait des droits aux jetons existants sans qu'ils le sachent : un scope inconnu est écarté à la création du jeton, et à l'appel le serveur compare des chaînes exactes.
Erreurs courantes
Missing scope for Xavec un jetonoperator— l'outil exige sans douteai:generateousettings:write, les deux scopes utiles qu'operatorn'a pas. La colonne Scopes de la Tools Reference le dit. Passe par un jetonfull(pour l'IA),admin(pour les réglages), ou un jeton custom.- L'agent ne voit aucun outil WhatsApp — le jeton date d'avant
whatsapp:read/whatsapp:write(voir la section Évolutions ci-dessus), ou il a été créé en custom sans eux. - L'agent lit mais n'écrit pas — jeton
read_onlyau lieu d'operator. Recrée-le avec le bon preset. - Un outil qui marche en local mais pas en production — le jeton de production n'a pas le même jeu de scopes. Compare les deux jetons.
- Le journal d'audit se remplit d'erreurs « Missing scope for … » — l'agent tente des outils hors de son jeton. Restreins ses instructions, ou élargis ses scopes.
Voir aussi
- Tokens — créer un jeton avec un jeu de scopes
- Tier System — l'autre couche de défense, pour les actions destructrices
- Tools Reference — le scope requis de chaque outil