# Brancher le serveur MCP

En quittant cette page, vous saurez ce que le serveur MCP de SealTrust autorise un assistant à faire, comment le brancher dans votre client, quels identifiants lui passer, et ce que rend chacun de ses sept outils.

Source : https://docs.sealtrust.io/mcp/

---

Le serveur MCP est un petit programme que vous lancez sur votre poste. Il donne à
un assistant conversationnel le droit d'interroger l'API publique de SealTrust,
en lecture seule. MCP, pour Model Context Protocol, est le protocole normalisé par
lequel un assistant appelle des outils extérieurs. En quittant cette page, vous
saurez installer le serveur, le déclarer dans votre client, choisir
l'identifiant à lui passer et appeler ses sept outils.

Le parcours tient en quatre étapes : vérifier que le périmètre correspond à votre
besoin, brancher le serveur dans votre client, apprendre quel identifiant vous
avez sous la main, appeler les outils.

## 1. Le périmètre, avant tout le reste

Le serveur n'émet que des requêtes `GET`, vers des points d'entrée publics de
`https://api.sealtrust.io`. Il n'envoie aucune clef d'API et n'en accepte aucune.
Aucun de ses outils ne crée, ne modifie ni ne supprime quoi que ce soit.

Conséquence directe : le serveur voit exactement ce que voit un visiteur anonyme
qui ouvre un passeport dans son navigateur. Le règlement ESPR distingue plusieurs
publics : le public, les consommateurs, les professionnels de la chaîne de valeur
et les autorités de surveillance du marché. SealTrust applique cette distinction
avec six niveaux d'accès : `public`, `end_user`, `repairer`, `recycler`,
`upstream` et `authority`. Ces valeurs sont celles de SealTrust. Le règlement, lui, nomme des publics. Le serveur MCP lit le niveau
**public** et uniquement lui. Les champs réservés aux professionnels ou aux
autorités ne sont pas atteignables par ce chemin.

> [!INFO] Ce serveur n'a rien à voir avec votre clef d'API partenaire
> La clef d'API de votre marque sert à créer des produits, à déclarer des ventes
> et à gérer vos abonnements aux notifications. Le serveur MCP n'y touche pas.
> Vous pouvez le brancher sans compte SealTrust.

Ce que le serveur annonce à votre client au moment de la connexion : son nom,
`sealtrust`, sa version, et une phrase d'instructions qui rappelle à l'assistant
que toutes les données sont publiques et qu'aucun outil ne modifie rien.

## 2. Brancher le serveur

Il vous faut Node.js en version 18 ou plus récente. Le paquet s'appelle
`@sealtrust-io/mcp-server` et la dernière version publiée est `0.4.0`.

Vous pouvez le lancer directement, ce qui sert à vérifier qu'il démarre.

```bash
npx @sealtrust-io/mcp-server
```

Le serveur communique par son entrée et sa sortie standard. Une ligne de
démarrage part sur la sortie d'erreur et indique la version ainsi que l'adresse
d'API utilisée. La sortie standard est réservée au dialogue avec le client, donc
rien d'autre n'y est écrit.

### Déclarer le serveur dans un client

Un client MCP se configure avec une commande et ses arguments. Le bloc ci-dessous
est la forme attendue par les clients de bureau, à placer dans leur fichier de
configuration.

```json
{
  "mcpServers": {
    "sealtrust": {
      "command": "npx",
      "args": ["-y", "@sealtrust-io/mcp-server"]
    }
  }
}
```

En ligne de commande avec Claude Code, la même déclaration s'écrit ainsi.

```bash
claude mcp add sealtrust -- npx -y @sealtrust-io/mcp-server
```

Redémarrez le client après avoir modifié sa configuration. Les sept outils
apparaissent alors dans sa liste d'outils disponibles.

### Les deux réglages disponibles

Deux variables d'environnement, et deux seulement, changent le comportement du
serveur.

| Variable | Valeur par défaut | Effet |
| --- | --- | --- |
| `SEALTRUST_API_URL` | `https://api.sealtrust.io` | L'adresse de l'API interrogée. Les barres obliques finales sont retirées. |
| `SEALTRUST_TIMEOUT_MS` | `15000` | Le délai maximal d'un appel, en millisecondes. Une valeur qui n'est pas un nombre strictement positif est ignorée, et la valeur par défaut s'applique. |

Le délai couvre l'aller-retour complet, en-têtes et corps de réponse compris. Un
dépassement rend une erreur de réseau explicite, jamais un blocage silencieux.

Ces deux variables se posent dans la configuration de votre client, sous la clef
`env`. Le bloc ci-dessous est complet et copiable tel quel. Il porte un délai de
30 secondes.

```json
{
  "mcpServers": {
    "sealtrust": {
      "command": "npx",
      "args": ["-y", "@sealtrust-io/mcp-server"],
      "env": {
        "SEALTRUST_TIMEOUT_MS": "30000"
      }
    }
  }
}
```

> [!ATTENTION] `SEALTRUST_API_URL` prend un hôte, sans chemin
> Le serveur ajoute lui-même le préfixe `/v1` devant chaque chemin qu'il appelle.
> Ce préfixe est figé dans le programme et ne se désactive pas. Écrivez
> `https://api.sealtrust.io` et rien de plus.

## 3. Savoir quel identifiant vous avez

Six outils sur sept prennent un identifiant de produit. Quatre formes existent, et
elles ne sont pas acceptées partout.

| Forme | À quoi elle ressemble | Où vous la trouvez |
| --- | --- | --- |
| Numéro de série | 12 caractères, chiffres et lettres majuscules, par exemple `EXEMP1E00000` | C'est le seul identifiant lisible sur un produit. Le QR imprimé le porte. Une personne qui a scanné ou recopié une étiquette a celui-là. |
| Empreinte d'identifiant (`uid_hash`) | `0x` suivi de 64 caractères hexadécimaux | Rendue par nos propres réponses. C'est l'identifiant interne du produit. Il vient de la puce NFC quand le produit en porte une. SealTrust le tire au hasard quand le produit est identifié par QR seul. |
| Identifiant de jeton | Une suite de chiffres | L'identifiant du jeton en chaîne, rendu sous le nom `token_id`. |
| Numéro de certificat | Commence par `ST-CERT-` | Sur le certificat d'authenticité. Accepté par `verify_product` et `get_certificate` seulement. |

L'alphabet du numéro de série exclut les lettres I, L, O et U, pour qu'une
personne qui recopie une étiquette ne confonde pas une lettre avec un chiffre.
Le serveur MCP transmet le numéro tel qu'on le lui donne, sans réécrire
aucun caractère. C'est l'API qui remet le numéro en majuscules et qui ramène
les caractères ambigus à leur forme canonique : `I` et `L` valent `1`, `O`
vaut `0`.

Deux outils prennent en plus un GTIN, le code article à 8, 12, 13 ou 14 chiffres.
Un GTIN désigne un modèle. Il ne désigne aucun exemplaire en particulier.

> [!INFO] Un identifiant inconnu reste une réponse
> Un identifiant bien formé mais introuvable rend un résultat normal, portant
> `found: false` ou `status: "unknown"`. L'assistant peut raisonner dessus.
> Une erreur d'outil survient dans trois cas : un argument mal formé, refusé
> avant tout appel réseau, une réponse d'erreur de l'API autre qu'un 404, et une
> panne de réseau. Un 404 rend un résultat normal portant `found: false`.

## 4. Les sept outils

### `verify_product`

Répond à la question « ce produit est-il authentique ». L'outil enchaîne deux
appels : la résolution de l'identifiant, puis la lecture du certificat.

| Paramètre | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `identifier` | `string` | oui | Numéro de série, empreinte d'identifiant, identifiant de jeton ou numéro de certificat. |

La réponse porte un champ `status` qui prend cinq valeurs.

| Valeur | Ce qu'elle signifie |
| --- | --- |
| `authentic` | Un certificat d'authenticité actif est enregistré. |
| `revoked` | Le certificat a été révoqué. Le produit est à traiter comme suspect. |
| `expired` | Le certificat a dépassé sa date de fin. |
| `found_no_certificate` | Le produit existe dans le registre et aucun certificat actif n'y est rattaché. |
| `unknown` | Aucune trace de cet identifiant. |

Viennent avec : un champ `message` en clair, un bloc `product` qui porte le nom du
produit, le nom de la marque, la catégorie, l'identifiant de jeton, l'empreinte
d'identifiant, l'adresse du contrat, l'opération de frappe et la date de création, un bloc
`certificate` ou la valeur nulle, un booléen `has_published_passport`, et un
booléen `anchored_on_base`.

`anchored_on_base` vaut vrai quand un ancrage existe, quel qu'il soit : celui du
lot de produits, ou celui du contenu du passeport. Les deux sont indépendants. Un
passeport peut être ancré alors que son lot ne l'a pas été, et l'inverse. Pour
savoir lequel des deux, et avec quelle opération, appelez `get_passport_proof`.

Attendez-vous à ce que ce booléen vaille faux la plupart du temps. L'ancrage est
une opération que SealTrust déclenche à la main. Une demande d'ancrage venue d'un
compte de marque est refusée. Frapper un produit ne l'ancre pas, et publier un
passeport ne l'ancre pas non plus. La plupart des produits ne sont jamais ancrés. Un `anchored_on_base` à faux ne dit
donc rien contre le produit, et votre assistant ne doit jamais le présenter comme
un soupçon.

### `get_passport`

Rend le passeport numérique publié, au niveau d'accès public.

| Paramètre | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `identifier` | `string` | oui | Numéro de série, empreinte d'identifiant ou identifiant de jeton. Un numéro de certificat n'est pas accepté ici. |
| `format` | `string` | non | `json` par défaut, ou `jsonld` pour une représentation en vocabulaire Schema.org et GS1. Toute autre valeur est refusée avant l'appel réseau. |

La réponse au format par défaut porte la version du passeport, le contenu publié
sous le champ `data`, l'empreinte SHA-256 de ce contenu sous `data_hash`, le nom
du produit et de la marque, le GTIN et le lien GS1 Digital Link du produit.

Les deux champs qui pointent vers la copie IPFS valent toujours la valeur nulle
sur ce chemin. Ils sont réservés aux niveaux d'accès authentifiés. Le lien vers
la copie immuable, quand elle est publiée, apparaît dans la réponse de
`get_passport_proof`.

### `get_passport_proof`

Rend les preuves publiques qui permettent de vérifier un passeport sans nous faire
confiance.

| Paramètre | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `identifier` | `string` | non | L'exemplaire dont vous voulez la preuve. |
| `gtin` | `string` | non | Le modèle dont vous voulez la preuve, au niveau référence. |

Vous devez fournir exactement l'un des deux. Aucun des deux, ou les deux à la
fois, donne un refus immédiat avec un message qui explique la différence. Les deux
paramètres ne désignent pas la même chose : la preuve d'un exemplaire date
l'objet, la preuve d'une référence date le document.

La réponse contient l'empreinte du contenu, le lien vers la copie IPFS quand
elle est publiée, un bloc `seal` qui dit si la version est scellée et si son contenu
correspond encore à ce qui a été scellé, l'état d'émission de l'attestation
vérifiable, et le nombre de vérifications physiques réussies. Une preuve absente
est absente de la réponse, sans champ vide.

> [!ATTENTION] Fondez votre lecture sur `anchored`
> Le bloc `anchor` porte deux formes. Quand le lot du produit a été ancré, il
> porte la racine de l'arbre de Merkle, `anchored` vaut vrai et `proves` vaut
> `batch_inclusion`. Quand le lot n'a jamais été ancré, ce même bloc porte
> l'opération de frappe du produit, `anchored` vaut faux et `proves` vaut
> `token_minted`. La seconde forme prouve que le jeton existe et ne dit rien du
> contenu du passeport. Une interface qui annonce « ancré » sur la seule
> présence de la clef `anchor` affirme davantage que la preuve ne porte.

Un passeport de niveau référence, celui qu'on obtient avec `gtin`, ne porte
légitimement ni bloc `anchor` ni compte de vérifications. Il n'est lié à aucun
exemplaire physique. Sa preuve est l'ancrage de son propre contenu, qui date le
document. La réponse porte alors `level: "model"` et le GTIN normalisé.

### `get_product_history`

Rend l'historique d'un produit : les mouvements de propriété et les scans
d'authentification, réunis dans une seule chronologie, du plus récent au plus
ancien. Le premier élément de `timeline` est l'événement le plus récent.

| Paramètre | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `identifier` | `string` | oui | Numéro de série, empreinte d'identifiant ou identifiant de jeton. |

Chaque entrée porte un champ `type` qui vaut `verify` pour un scan ou `transfer`
pour un mouvement de propriété, un horodatage, l'identifiant de jeton et
l'empreinte d'identifiant. Le reste dépend du type. Une entrée `verify` porte un
indicateur de validité et aucun libellé de partie. Une entrée `transfer` porte
deux libellés prêts à l'affichage, pour la partie qui cède et celle qui reçoit,
et aucun indicateur de validité.

Pour un appelant anonyme, et le serveur MCP en est un, les identités sont
masquées : les adresses électroniques sont anonymisées et les adresses de
portefeuille brutes ne sont pas rendues.

> [!ATTENTION] Aucune entrée ne porte sa propre opération en chaîne
> Ne proposez pas un lien vers l'explorateur de blocs pour chaque mouvement, il
> n'y a rien à lier. L'opération de frappe se trouve dans `verify_product`, et
> l'ancrage dans `get_passport_proof`.

### `get_certificate`

Rend le certificat d'authenticité public d'un produit.

| Paramètre | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `identifier` | `string` | oui | Numéro de série, empreinte d'identifiant, identifiant de jeton ou numéro de certificat. |

La réponse porte le numéro du certificat, son état, sa date d'émission, sa date
de fin quand elle existe, le nom de l'émetteur, le nom du produit et celui de la
marque, ainsi que les champs personnalisés enregistrés à l'émission, rendus tels
quels. Tout ce qui y est écrit est public.

### `resolve_gs1`

Part d'un lien GS1 Digital Link et rend le passeport qu'il désigne.

| Paramètre | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `gtin` | `string` | oui | Le code article du modèle. |
| `serial` | `string` | non | Le numéro de série imprimé sur l'exemplaire. Omettez-le pour viser le modèle. |

La présence du numéro de série change ce que le lien désigne. Avec lui, le lien
`/01/{gtin}/21/{serial}` désigne un exemplaire précis et la réponse porte
`level: "item"`. Sans lui, le lien `/01/{gtin}` désigne la classe d'articles et
rend le passeport de niveau référence, celui que partagent tous les exemplaires du
modèle, avec `level: "model"`. C'est ce second niveau qu'utilisent les
marchandises vendues au mètre, à la boîte ou à la palette. Une chaîne vide dans
`serial` est lue comme une absence.

La réponse porte aussi le lien reconstruit, l'adresse vers laquelle la résolution
redirige, l'identifiant retenu, et le passeport public quand il en existe un.

Sans passeport de référence publié, `/01/{gtin}` répond 404 et l'outil rend
`found: false` avec le message « Unknown GS1 Digital Link ». Le résultat
`resolved: true` accompagné d'un passeport nul ne survient que lorsque vous
fournissez un `serial` et que cet exemplaire n'a pas de passeport publié.

Le numéro de série attendu ici est bien celui qui est imprimé sur le produit.
L'identifiant de jeton en chaîne ne convient pas à cet endroit.

### `verify_credential`

Vérifie la signature de l'attestation vérifiable du passeport, au format
SD-JWT-VC, contre la clef publiée par la marque émettrice sous la forme
`did:web`.

| Paramètre | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `identifier` | `string` | oui | Numéro de série, empreinte d'identifiant ou identifiant de jeton. |

La réponse porte `verified`, l'identifiant décentralisé de l'émetteur, le type de
l'attestation, la version de la clef de signature, le niveau d'accès appliqué, un
champ `error` valant `verification_failed` en cas d'échec, et le contenu de
l'attestation quand la signature est valide.

> [!INFO] Une vérification vraiment indépendante se fait chez vous
> Cet outil demande à SealTrust de vérifier une signature produite par
> SealTrust. Pour un contrôle indépendant, récupérez vous-même le document
> d'identité décentralisé de la marque et vérifiez la signature contre la clef
> qui y est publiée.

## 5. Lire les réponses et les erreurs

Le serveur sépare trois situations, et cette séparation compte pour un assistant
qui raisonne sur le résultat.

| Situation | Ce que rend le serveur | Ce qu'il faut en conclure |
| --- | --- | --- |
| Produit, passeport ou attestation introuvable | Un résultat normal portant `found: false` et le message de l'API, ou `status: "unknown"` pour `verify_product` | La question a reçu une réponse. Rien ne s'est cassé. |
| Réponse d'erreur de l'API autre qu'un 404 | Une erreur d'outil dont le message s'écrit `SealTrust API error (`, le code HTTP, `): `, puis le détail rendu par l'API. Il n'y a aucune espace avant les deux-points. | L'API a répondu et a refusé. Le code dit pourquoi. |
| API injoignable, délai dépassé, DNS, connexion refusée | Une erreur d'outil qui commence par `Network error` | Aucune information sur le produit. Ne concluez rien sur son authenticité. |

> [!DANGER] Ne confondez jamais les deux dernières lignes
> « Le produit n'existe pas » et « l'API n'a pas répondu » mènent à des décisions
> opposées. Le serveur les distingue par construction, votre traitement doit les
> distinguer aussi.

Un argument mal formé est refusé avant tout appel réseau : un identifiant vide,
un `format` qui n'est ni `json` ni `jsonld`, ou l'absence de choix entre
`identifier` et `gtin` sur la preuve.

## 6. Les plafonds d'appels

Les points d'entrée publics sont plafonnés par adresse IP appelante, sur une
fenêtre de 60 secondes. Les familles de chemins qui ont un plafond à elles
tiennent chacune leur propre compteur. Les autres relèvent d'un compteur
général, commun à toutes les routes sans plafond dédié.

| Outil | Chemin appelé | Plafond |
| --- | --- | --- |
| `verify_product` | résolution, puis certificat | 60 par minute sur chacun des deux |
| `get_passport`, `get_passport_proof`, `verify_credential` | passeport | 60 par minute |
| `get_certificate` | certificat | 60 par minute |
| `get_product_history` | chronologie | 30 par minute |
| `resolve_gs1` | résolution GS1, puis passeport | compteur général sur la résolution GS1, partagé avec les autres chemins sans plafond propre, puis 60 par minute sur le passeport |

Deux outils consomment deux appels au lieu d'un. `verify_product` interroge la
résolution puis le certificat. `resolve_gs1` lit la redirection du résolveur
sans la suivre, puis demande le passeport directement. Comptez-les comme deux.

Un dépassement rend une réponse 429, que le serveur remonte en erreur d'outil.
Un cas fait exception. Sur `verify_product`, seul le premier appel remonte un
429. Un dépassement sur la lecture du certificat est journalisé sur la sortie
d'erreur et l'outil répond quand même, avec le certificat résumé que porte déjà
la résolution.

## Ce qui peut vous arrêter

| Symptôme | Cause | Que faire |
| --- | --- | --- |
| Le client ne montre aucun outil | Le serveur n'a pas démarré, ou le client n'a pas été redémarré après la modification de sa configuration | Lancez `npx @sealtrust-io/mcp-server` à la main. La ligne de démarrage doit apparaître. Redémarrez ensuite le client. |
| `Network error` sur tous les outils | L'API n'est pas joignable depuis la machine, ou `SEALTRUST_API_URL` pointe ailleurs | Vérifiez la variable, puis la sortie réseau de la machine. |
| Un appel dépasse systématiquement le délai | Le délai de 15 secondes est trop court pour votre liaison | Augmentez `SEALTRUST_TIMEOUT_MS` sous la clef `env` de la configuration de votre client, comme au point 2, puis redémarrez le client. |
| `found: false` sur un identifiant que vous savez juste | La forme utilisée n'est pas acceptée par cet outil | Vérifiez la forme dans le tableau des identifiants. Un numéro de certificat ne passe que sur `verify_product` et `get_certificate`. |
| Les outils se contredisent sur un exemplaire retiré du marché | Chaque outil traite la fin de vie à sa manière | `verify_product` rend `status: "unknown"`. `get_passport_proof` et `get_certificate` rendent `found: false`. `get_passport` rend le passeport, assorti d'un bloc `lifecycle` qui indique que l'exemplaire n'est plus courant. |
| Le passeport revient sans lien IPFS | Le niveau d'accès public ne le porte pas | Utilisez `get_passport_proof`, qui rend le lien vers la copie immuable quand elle est publiée. |
| Une erreur 429 | Un plafond d'appels est atteint | Espacez les appels. Le compteur repart après 60 secondes. |
