Skip to main content
Voir en Markdown

Votre configuration en MCP

sovrium mcp remet la configuration de votre projet à l'assistant d'IA que vous utilisez déjà, pour que le modèle qui modifie votre app.yaml voie ce que le fichier veut dire au lieu de le deviner à partir des octets.

>_ terminal
sovrium mcp --project ~/apps/crm

Voilà toute l'installation. Aucun serveur à monter, aucun bloc auth: à écrire, aucune clé à émettre.

Ce qui tourne, et ce qui ne tourne pas

Ce verbe est un processus éphémère. Il ne démarre aucun serveur, n'écrit aucun fichier de verrou et n'occupe aucun port : il lit un fichier de configuration, répond en JSON-RPC ligne à ligne sur l'entrée standard, et s'arrête à la fermeture de celle-ci.

Il n'ouvre pas davantage de connexion à la base de données, à une exception près : lorsque l'écriture est activée et qu'une instance tourne, une écriture demande d'abord à cette base ce que le changement coûterait, en lecture, avant de toucher au fichier.

Comme la sortie standard ne transporte que des messages MCP, tout le reste — bannières, avis, erreurs — part sur la sortie d'erreur, y compris la ligne qui vous dit quel fichier de configuration a été trouvé.

Il n'y a aucun identifiant, et rien à configurer

Le processus a été lancé par vous, s'exécute sous votre compte et lit un répertoire que vous avez nommé : la frontière de processus du système d'exploitation constitue donc à elle seule toute l'authentification. Poser un jeton sur un tube entre deux processus du même utilisateur relèverait du cérémonial, pas de la sécurité.

Deux conséquences en découlent, et il vaut mieux les connaître avant de partir en quête d'un réglage qui n'existe pas :

  • Une configuration sans bloc auth: fonctionne. Aucune instance d'authentification n'est jamais construite.
  • MCP_ENABLED n'a aucun effet ici. La combinaison qui fait refuser le démarrage à sovrium startMCP_ENABLED=true sans app.auth — ne concerne pas ce verbe.

Y diriger un client

Tous les clients ci-dessous lisent les deux mêmes valeurs : la commande à lancer et ses arguments.

Claude Code

>_ terminal
claude mcp add sovrium -- sovrium mcp --project ~/apps/crm

Le -- est obligatoire : tout ce qui le suit constitue la commande du serveur, transmise telle quelle. Ajoutez --scope project pour écrire l'entrée dans un .mcp.json partagé à la racine du projet plutôt que dans vos réglages personnels.

La forme fichier, c'est le même bloc écrit à la main :

app.json
{
  "mcpServers": {
    "sovrium": {
      "command": "sovrium",
      "args": ["mcp", "--project", "/Users/moi/apps/crm"]
    }
  }
}

Claude Desktop

Ajoutez la même entrée mcpServers à claude_desktop_config.json, puis redémarrez l'application.

Cursor

Ajoutez la même entrée à .cursor/mcp.json pour un seul projet, ou à ~/.cursor/mcp.json pour tous.

Quelle configuration il lit

Le répertoire est résolu du plus spécifique au plus général :

  1. --project <dir>
  2. SOVRIUM_PROJECT_DIR
  3. Le répertoire de travail — lequel, quand c'est un client qui a lancé le processus, relève de son choix et non du vôtre. Nommez le répertoire explicitement.

À l'intérieur, le fichier de configuration est trouvé exactement comme sovrium start le trouve : SOVRIUM_CONFIG_FILE s'il est défini, sinon le premier de app.yaml, app.yml, app.ts.

Un répertoire sans configuration ne provoque pas de plantage. La poignée de main et la liste des outils répondent quand même, et chaque outil renvoie le constat de configuration manquante comme un résultat ordinaire — l'assistant dirigé vers le mauvais dossier l'apprend donc dans quelque chose qu'il est déjà en train de lire :

app.json
{
  "valid": false,
  "findings": [
    {
      "path": "",
      "message": "No config file found. `sovrium mcp` reads app.yaml, app.yml or app.ts from the project directory — pass --project <dir> to point it at the right one.",
      "severity": "error"
    }
  ],
  "notices": []
}

Les quatre outils

Les outils portent le nom de votre application : un app.yaml dont le name vaut crm donne crm_config_read et ses trois voisins. Tous les quatre sont des lectures, et tous le déclarent — ils portent readOnlyHint, si bien qu'un client peut les appeler sans s'arrêter pour demander.

Outil Arguments Renvoie
_config_read aucun { config, files, configHash } — la configuration telle que démarrée, secrets déclarés caviardés
_config_validate aucun { valid, findings, notices } — dans le vocabulaire de sovrium validate --json
_config_schema path facultatif Le JSON Schema Draft 2020-12, ou le sous-schéma à un chemin de configuration pointé
_config_status aucun Le document d'état qu'une instance en marche publie, ou { "state": "not-running" }

_config_read caviarde. Il sérialise par le caviardeur qui sert déjà la vue « configuration » de la console d'administration : un secret écrit en dur revient sous forme de marqueur, la structure autour restant intacte. Un jeton $env.X, lui, survit — un nom de variable n'est pas un secret, et c'est précisément ce qui vous dit quelle variable alimente le champ.

_config_validate lit le disque, pas l'instance en marche. C'est tout l'intérêt : un assistant qui vient de réécrire config/tables/contacts.yaml a besoin du verdict sur ce qu'il a écrit. Une configuration invalide est ici un résultat normal, pas une erreur d'outil.

_config_schema prend un chemin de configuration pointé, pas un pointeur JSON — tables.fields, et non /properties/tables/items/properties/fields. La forme pointée est le vocabulaire que vous écrivez déjà dans votre configuration. Un chemin qui ne se résout pas est refusé par un message nommant les clés qui, elles, sont disponibles au dernier segment résolu.

_config_status est une lecture de fichier. Il rapporte le fichier d'état qu'un serveur en marche publie à son propre sujet, et répond { "state": "not-running" } quand il n'y en a pas.

Ces quatre outils sont en lecture seule, et ils sont tout ce qu'une session propose tant que vous n'en décidez pas autrement.

Le laisser écrire

Réglez MCP_CONFIG_WRITE=1 et quatre outils supplémentaires apparaissent, capables de modifier le fichier de configuration lui-même. Ils sont désactivés par défaut, et c'est délibérément une variable d'environnement plutôt qu'une clé de configuration : une configuration qui pourrait autoriser sa propre modification serait une configuration qui s'autorise elle-même.

La variable n'est honorée que si les deux conditions tiennent : elle est définie, et le répertoire du projet a été nommé explicitement, par --project ou par un SOVRIUM_PROJECT_DIR hérité. Une session retombée sur le répertoire de travail n'obtient que les lectures, et le dit sur la sortie d'erreur. Une surface d'écriture se confine à un seul dossier ; encore faut-il que ce dossier ait été choisi exprès, et non celui dans lequel un client s'est trouvé démarrer.

app.json
{
  "mcpServers": {
    "sovrium": {
      "command": "sovrium",
      "args": ["mcp", "--project", "/Users/moi/apps/crm"],
      "env": { "MCP_CONFIG_WRITE": "1" }
    }
  }
}
Outil Arguments Renvoie
_config_list_files aucun { files: [{ path, sha256, bytes }] }, chaque chemin relatif au projet
_config_read_file path { path, content, sha256 }, les octets tels quels
_config_write_file path, content, expectedSha, acknowledgeDataLoss facultatif { path, sha256, snapshot, reloadHint }
_config_undo aucun { snapshot, files }, quel instantané, et ce qu'il a changé

Les deux outils de lecture portent readOnlyHint. Les deux outils d'écriture sont marqués destructifs : un client qui vous demande confirmation avant un outil destructif vous la demandera donc, car écraser un fichier est une modification destructrice de ce fichier quoi que l'outil refuse ensuite de faire à une table, et l'annulation en écrase plusieurs d'un coup.

Les octets du fichier entier, jamais un correctif. Il n'y a ici aucun rédacteur de configuration et aucun sérialiseur : content remplace le fichier, donc vos commentaires, l'ordre de vos clés, vos ancres et vos lignes vides survivent intacts à une modification. Le prix, c'est que l'appelant doit lire avant d'écrire, et expectedSha est ce qui rend ce prix réel plutôt qu'indicatif.

Ce pour quoi une écriture est refusée

Chaque écriture passe les mêmes contrôles, dans le même ordre, et chaque refus nomme ce qu'il a refusé. Les contrôles structurels, les moins chers, viennent d'abord ; ceux qui ouvrent une base de données viennent en dernier.

  • Hors du projet. Le chemin est résolu depuis le répertoire du projet et doit tomber à l'intérieur.
  • Pas un fichier de configuration. .yaml, .yml et .json uniquement, et jamais un lien symbolique : un lien symbolique peut pointer n'importe où, y compris hors du dossier.
  • Un emplacement protégé. .env et ses voisins, .git/, .claude/, le répertoire de données et le marqueur de modèle .sovrium-template.json. Un outil capable d'écrire .env est un outil qui écrit des identifiants ; un outil capable d'écrire .git/ réécrit l'historique.
  • Un expectedSha périmé. L'empreinte contre laquelle vous avez édité ne correspond plus au fichier : quelque chose a donc enregistré par-dessus, très possiblement vous, dans votre propre éditeur. Le refus demande de relire, parce qu'un assistant à qui l'on répond seulement « non » réessaie indéfiniment le même appel.
  • Le résultat ne se décoderait pas. Le candidat est superposé en mémoire au graphe de $ref résolu, et l'application entière est décodée avant que quoi que ce soit ne soit écrit. Une configuration invalide n'atteint jamais le disque ; ce sont les constats qui reviennent à sa place, dans le vocabulaire que _config_validate parle déjà. C'est ce qui rend sûre la modification d'un seul partiel extrait : il est jugé comme un morceau de l'application à laquelle il appartient, et non comme un document qui se trouve à être bien formé.
  • Une nouvelle référence hors du dossier. Un candidat qui introduit un $ref se résolvant hors du répertoire du projet est refusé, sans quoi le fichier lu pourrait sortir du dossier que le fichier écrit n'a pas le droit de quitter.
  • La base de données en marche le refuserait. Là où un serveur tourne, le changement passe par le même planificateur de migration que rapporte sovrium migrate --dry-run, et un refus de sa part est le refus de l'écriture, avant que le fichier ne change plutôt qu'après que le serveur a renoncé à l'appliquer.
  • Il détruit des données. Un candidat qui introduit allowDestructive: true exige acknowledgeDataLoss: true à ses côtés, et l'outil ne pose jamais ni l'un ni l'autre de lui-même. Supprimer une colonne supprime les lignes qu'elle contient : la décision reste la vôtre, chaque fois.
  • Il renumérote une table. L'id d'un champ est facultatif, et un id omis vaut la position du champ. Insérer un champ au-dessus de l'un d'eux décale tous les id suivants et repointe les données derrière eux : l'insertion est donc refusée jusqu'à ce que les id de la table soient explicites. La même insertion dans une table qui écrit chaque id en toutes lettres est acceptée, puisque rien ne bouge.

Revenir en arrière

Une écriture acceptée copie l'état d'avant l'écriture dans l'historique des configurations avant de changer un seul octet, si bien que _config_undo a quelque part où revenir même lorsque aucun serveur ne tourne et que rien n'a jamais atteint l'état « accepté ». La copie est omise lorsque l'entrée la plus récente contient déjà exactement ces octets : un projet sous surveillance se retrouve donc avec une entrée avant la modification et une après, plutôt que trois.

_config_undo restaure l'instantané le plus récent dont les fichiers diffèrent de ce qui est sur le disque, et répond avec les fichiers qu'il a changés. Lorsque aucun ne diffère, il n'y a nulle part où revenir, et il refuse plutôt que de rapporter un succès qui n'a rien changé.

L'annulation remet le fichier en place sans condition. Qu'une instance en marche la suive est une autre question : revenir sur un champ que vous venez d'ajouter est une suppression de colonne, donc le contrôle en pré-vol de la surveillance refuse ce rechargement sans allowDestructive, conserve la configuration qu'elle sert déjà, et publie la raison. Votre application reste debout et vos lignes restent où elles sont.

Une écriture ne met rien en service. Elle pose des octets sur le disque ; _config_status est la façon de savoir si une instance les a pris. Les appels sont traités un à la fois, dans l'ordre où vous les avez envoyés : une écriture suivie d'une annulation se produit donc dans cet ordre.

Vérifier à la main

Le serveur est un tube : vous pouvez donc le piloter avec printf. Envoyez un message d'ouverture et lisez la réponse :

>_ terminal
printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}\n' \
  | sovrium mcp --project ~/apps/crm
code
[mcp] Using app.yaml (auto-discovered)
{"result":{"protocolVersion":"2025-06-18","capabilities":{"tools":{"listChanged":false}},"serverInfo":{"name":"sovrium","version":"0.25.0"}},"jsonrpc":"2.0","id":1}

La première ligne est sur la sortie d'erreur, la seconde sur la sortie standard. Cette séparation est le contrat : détournez la sortie d'erreur et il ne reste sur la sortie standard que du JSON-RPC valide, rien d'autre.

Ajoutez d'autres messages, un par ligne, pour aller plus loin — ils sont traités dans la même session :

>_ terminal
printf '%s\n%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"crm_config_validate","arguments":{}}}' \
  | sovrium mcp --project ~/apps/crm 2>/dev/null

La réponse de l'outil arrive sous forme de contenu textuel ; une fois déballée, elle se lit ainsi :

app.json
{
  "valid": true,
  "findings": [],
  "notices": [
    "field-id-implicit: table \"contacts\"\"email\", \"full_name\" declare no id, so the id is the field's position in the list. Inserting a field above one of them shifts every id after it, and the migration diff reads that as a rename. Give each field an explicit id — keep the ones it has today, and give new fields the next unused number."
  ]
}

Une méthode que le serveur ne sert pas reçoit l'erreur JSON-RPC -32601 plutôt qu'une fermeture du tube : un client qui sonde une fonctionnalité que Sovrium n'offre pas reste donc connecté.

Les mêmes quatre outils en HTTP

Une application déployée qui fait tourner le mode serveur sert ces quatre mêmes outils sur son point de terminaison /mcp — où il y a, cette fois, une session à vérifier. Ils y sont donc réservés aux administrateurs, et filtrés hors de la liste d'outils pour tous les autres rôles. Le chemin local décrit sur cette page n'a pas de session, et n'en invente pas.

Les quatre outils d'écriture, eux, n'y figurent pas : une instance servie en HTTP n'en enregistre aucun, quelle que soit la valeur de MCP_CONFIG_WRITE.

Pages associées

Dernière mise à jour 23 septembre 2026

Cette documentation a été rédigée avec de l'IA : des erreurs ou du contenu obsolète sont donc possibles. Sovrium est en bêta. Les contributions et corrections sont les bienvenues.

Construit avec Sovrium