Source : la page d'aide générée https://<host>/ApplicationService/Help, qui documente des champs et des endpoints que le MCP n'utilise pas. Toutes les affirmations ci-dessous ont été testées contre LIMAGRAI2512. D3 corrigé — QueryContextType a quatre valeurs, pas deux : Reading 0 (ApplicationReadingContext), Writing 1 (ApplicationWritingRepository), DataWarehouse 2 (non configuré sur ce tenant : IDataWarehouse non résolu), Metrics 3 (ApplicationMetricDataContext, présent, modèle non exploré). Le message d'erreur nomme le contexte, ce qui donne un moyen rapide de savoir quel QueryType a servi. L4.1 étendu aux quatre contextes. L4.2 tranché sur son point dur : le champ Application ne partitionne pas le contexte de lecture. Context.AgvTasks répond aussi bien avec Application AGV qu'avec EasyWMS — le contexte est commun au tenant. La table de résolution du lot 2 devra donc agréger le Metadata de toutes les applications, mais un paramètre application sur QueryExecute serait inutile. Les entités CustomApp restent inatteignables sous les quatre QueryType, au singulier comme au pluriel, et Metadata renvoie 0 entité pour cette application : ce sont des définitions EasyBuilder sans projection requêtable. L'API AD est le seul accès au spécifique client. Trois chantiers ajoutés : - L4.3 ClientModule, non renseigné, d'où des requêtes du MCP journalisées sous « Client: GNA » et indistinguables du vrai client GNA. - L4.4 API WorkflowLog (GetInstances, GetLogs, Validate), joignable et fonctionnelle, susceptible de remettre en cause D16. - L4.5 champs inexploités de QueryExecute : Parameters (requêtes paramétrées, piste pour D13), CommandTimeout, QueryId + QueryCancel, QueryExecuteStream (piste pour L3.1), plus les endpoints event sourcing et les sondes healthcheck/ready. CLAUDE.md pointe désormais vers la page d'aide comme source de vérité. MONITORING.md documente healthcheck/ready comme sonde légère. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
13 KiB
Roadmap
Travaux planifiés, par lot. Chaque lot est livrable indépendamment.
Constats issus de la session de diagnostic du 24/08/2026 (profil LIMAGRAIN,
host 10.255.255.2, tenant LIMAGRAI2512), déclenchée par un rapport d'usage
d'une session Cowork. Toutes les anomalies ci-dessous ont été reproduites
contre le WMS réel — ce ne sont pas des hypothèses.
Les décisions actées vivent dans DECISIONS.md ; ce fichier ne contient que ce qui reste à faire.
Cause racine commune
Le MCP interpole entity_type dans Context.{entity_type} sans aucune
validation (vérifié : aucune liste blanche dans le code). Or le nom attendu
par le contexte de lecture n'est pas le nom d'entité de l'Application
Dictionary.
L'API Metadata (GET /Metadata/Entities, 232 entités) donne la
correspondance exacte :
Name (renvoyé par search_ad_elements) |
TableName (attendu par Context.) |
|---|---|
Container |
Containers |
Product |
Products |
ContainerType |
ContainerTypes |
Alias |
Alias — invariant, pas de pluriel |
Item |
n'existe pas dans le modèle Reading |
Ce n'est donc pas une règle de pluralisation : c'est un mapping, et seul
TableName fait foi. TableName est unique sur les 232 entités.
Conséquences déjà constatées :
- une session utilisant les noms de l'AD (singuliers) déclenche un HTTP 500 sur chaque requête ;
- la liste d'entités documentée était fausse (
Aliasesn'existe pas, c'estAlias) ; - le MCP n'expose que 12 entités figées là où l'API en connaît 232.
Lot 1 — Déblocage
Objectif : rendre le MCP auto-diagnosticable et réparer ce qui est cassé. Ce lot seul aurait suffi à ce qu'une session se débrouille sans intervention.
L1.1 — Remonter le détail des erreurs HTTP
Aujourd'hui toute erreur d'API se résume à Request failed with status code 500.
Or le WMS renvoie déjà le diagnostic complet dans le corps de la réponse :
{"ClassName":"System.AggregateException","Message":"Compile Error: ...
'ApplicationReadingContext' ne contient pas de définition pour 'Container' ..."}
Enrichir l'erreur au point de passage unique (api-service.post / .get) avec :
statut, URL, verbe, payload envoyé, corps de réponse tronqué à ~2000 caractères.
Fichier : src/services/api-service.js (catch de post et get).
L1.2 — Fiabiliser le routage des outils
Deux outils sont listés dans tools/list mais ne sont routés vers aucun module,
à cause du routage par préfixe :
| Outil | Cause | Erreur observée |
|---|---|---|
get_entity_metadata |
capté par startsWith('get_entity_') avant sa propre branche |
Unknown WMS query tool |
list_log_files |
ne contient pas _logs mais _log_files |
Unknown tool |
Remplacer le routage par préfixe par une table explicite nom → module,
construite depuis les listTools() de chaque module. Un outil listé mais non
routé devient alors impossible par construction, au lieu d'être rattrapé au cas
par cas.
Fichier : src/index.js (handler tools/call).
L1.3 — Corriger les projections de champs des workflows
L'API AD renvoie les champs en minuscules (id, name, version,
applicationName). Deux endroits supposent une autre forme :
search_workflowsprojettew.Id,w.Code,w.Name,w.Category→ tousundefined, supprimés parJSON.stringify→ 50 objets vides pour uncountpourtant correct ;workflow-servicelitw.category || w.Category, deux clés inexistantes →list_workflow_categoriesrenvoie 0 catégorie et classe les 4012 workflows enUncategorized.
Le champ le plus proche d'une catégorie est applicationName, mais il vaut
EasyWMS pour tous les workflows : la notion de catégorie n'a aucun support
dans les données. Décider en connaissance de cause plutôt que d'inventer une
taxonomie.
Fichiers : src/tools/workflow-tools.js, src/services/workflow-service.js.
Lot 2 — Correctif de fond
L2.1 — Résolution des entités via l'API Metadata
Accepter entity_type au nom d'entité (Container) ou au nom de jeu
(Containers), insensible à la casse, et émettre Context.{TableName}. Cache
identique aux autres (TTL partagé, invalidation au changement de profil).
Sur nom inconnu, échouer avant tout appel réseau, avec un message actionnable :
« Item » n'existe pas dans le modèle Reading. Proches : ItemGroup, StockItem. 232 entités disponibles — utilisez
get_entity_metadatapour la liste.
Supprime la cause des 500 et débloque 232 entités au lieu de 12.
L2.2 — Rejeter les paramètres inconnus
Le SDK MCP ignore silencieusement les paramètres non déclarés : un appel
read_recent_logs(lines: 60) retombe sur le défaut count = 100 sans le
moindre signal, et l'appelant conclut à un paramètre ignoré.
Ajouter additionalProperties: false aux 23 schémas d'outils.
C'est le correctif retenu à la place d'une uniformisation des noms de paramètres : renommer casse les usages existants pour un gain cosmétique, alors que la cause réelle est l'absence de signal.
Lot 3 — Ergonomie et documentation
L3.1 — Bornage des sorties volumineuses
get_system_parameters: ajouterlimit/offset, aujourd'hui absents (sortie constatée : 70 000 caractères, rejetée par le client).search_logs: garde-fou de taille.max_resultsexiste déjà, mais lescontext_linesmultiplient le volume (88 000 caractères pour 50 résultats).- Renvoyer
truncated: trueexplicitement plutôt que de laisser le client se faire rejeter.
L3.2 — Documentation
- DECISIONS.md : D21 la règle
TableName, D22 le routage par table explicite. - CLAUDE.md : corriger la liste d'entités (
Aliases→Alias) et renvoyer versget_entity_metadatacomme source de vérité. wms://query-examples: un exemple singulier/pluriel commenté.
Lot 4 — Modèle de données et applications
Deux angles morts constatés le 24/08/2026, plus larges que les lots 1 à 3. Les
chiffres ci-dessous sont mesurés sur le tenant LIMAGRAI2512.
L4.1 — Le modèle Writing est inatteignable
QueryType est figé à 0 (Reading) en dur dans api-service.js
(executeQuery et executeScalarQuery). Or QueryContextType a quatre
valeurs. Testées une à une :
| Valeur | Contexte | Résultat sur LIMAGRAI2512 |
|---|---|---|
0 |
Reading | opérationnel (seul utilisé aujourd'hui) |
1 |
Writing | opérationnel — Context.Products répond |
2 |
DataWarehouse | non configuré : Could not resolve serviceType 'IDataWarehouse…' |
3 |
Metrics | contexte présent (ApplicationMetricDataContext), modèle non exploré |
Exposer query_type sur les outils de requête, défaut 0. Attention : D3 reste
vrai — en Writing les champs de statut sont des énumérations, donc
== "Release" échoue. La bascule doit être un choix explicite et documenté.
Le contexte Metrics mérite une exploration à part : c'est probablement là que
vivent les données agrégées produites par les jobs MetricGatherer.
L4.2 — Une seule application sur neuf est visible
Application vient de WMS_APPLICATION dans .env, partagé par tous les
profils, sans surcharge par appel ni paramètre d'outil. Le MCP n'interroge donc
jamais que EasyWMS.
POST /AD/api/Application/GetAll en déclare 9 :
| Application | Workflows | Queries | Entities |
|---|---|---|---|
| EasyWMS | 4012 | 2239 | 338 |
| CustomApp | 153 | 54 | 11 |
| AGV | 71 | 14 | 5 |
| Notifications | 26 | 35 | 24 |
| GalileoFaults | 9 | 20 | 24 |
| Common | 1 | 7 | 25 |
| SmartUI, User, WarehouseWebDesigner | 0 | 0–8 | 0 |
CustomApp porte le spécifique client — ses workflows sont préfixés CST_
(CST_SendRejectContainersToPK, CST_Task, CST_Container…). C'est
précisément ce qu'on cherche en debug, et c'est aujourd'hui invisible. Au total
260 workflows et ~130 queries hors périmètre.
Deux chantiers de difficulté très différentes :
API AD — simple. L'application est un champ du payload
([application, tenant, pageSize, offset]). Vérifié : ["CustomApp", tenant, 5, 0] sur /Workflow/GetByApplication renvoie bien les workflows CST_. Il
suffit d'un paramètre application sur les outils AD et workflow, avec une clé
de cache incluant l'application (sinon un cache pollué mélange les
applications).
QueryExecute — tranché : le champ Application ne partitionne rien.
Context.AgvTasks (entité de l'application AGV) répond aussi bien avec
Application: "AGV" qu'avec Application: "EasyWMS". Le contexte de lecture est
commun au tenant : toutes les applications y déversent leurs entités.
Conséquence pour L2.1 : la table de résolution doit agréger le Metadata de
toutes les applications (GET /Metadata/Entities?applicationName=… par
application, 232 + 20 + 6 + …), et non se limiter à EasyWMS. Inutile en
revanche d'ajouter un paramètre application à QueryExecute : il ne changerait
rien.
Les entités CustomApp ne sont interrogeables dans aucun contexte. Les 11
entités CST_ ont été testées sous les quatre QueryType, au singulier et au
pluriel : échec partout, et Metadata/Entities comme Metadata/EntitiesAll
renvoient 0 entité pour CustomApp. Aucune n'est marquée
isDataWarehouse. Ce sont des définitions EasyBuilder (FromMetadata: false)
sans projection dans un contexte requêtable.
L'API AD reste donc le seul accès au spécifique client — ce qui rend le
paramètre application sur les outils AD et workflow d'autant plus utile.
L4.3 — Identifier le MCP dans les logs du WMS
QueryExecute accepte un champ ClientModule que le MCP n'envoie pas.
Résultat : ses requêtes apparaissent dans les logs du WMS sous
Execute error. Client: GNA — le client OAuth partagé — donc indistinguables de
celles du vrai client GNA.
Renseigner ClientModule ("MCP-WMS" ou le nom du profil actif) rend chaque
requête du MCP traçable côté serveur. Vérifié : le champ est accepté.
L4.4 — Historique d'exécution des workflows par API
ApplicationService expose une API WorkflowLog que le MCP n'utilise pas :
| Endpoint | Usage |
|---|---|
GET /WorkflowLog/GetInstances?processDefinitionId=&skip=&take=&startDateFrom=&startDateTo= |
instances d'un workflow sur une plage de dates, filtrables par attribut |
GET /WorkflowLog/GetInstance?processId= |
une instance |
GET /WorkflowLog/GetLogs?processId=&skip=&take=&logDateFrom=&logDateTo= |
journal d'exécution d'une instance |
GET /WorkflowLog/Validate?applicationName=&processDefinitionId= |
validation d'une définition |
Endpoints joignables et fonctionnels — Validate renvoie
{"Success":true,"ErrorMessage":null,"Warnings":[]}. GetInstances répond []
sur le workflow testé : à confirmer sur un workflow ayant réellement tourné, la
journalisation n'étant pas forcément active partout.
Peut remettre en cause D16 (historique des shipment templates jugé hors de portée faute de logs fichier) : si l'historique d'exécution est disponible par API, la conclusion change. À vérifier avant d'écrire quoi que ce soit.
L4.5 — Champs de QueryExecute inexploités
La référence de l'API documente des champs que le MCP n'envoie jamais :
| Champ | Intérêt |
|---|---|
Parameters |
requêtes paramétrées (dictionnaire nom -> {TypeName, Value}) — supprimerait toute concaténation de chaîne dans les filtres, et pourrait débloquer D13 (Select) |
CommandTimeout |
timeout par requête, au lieu du timeout HTTP global de 30 s |
QueryId + POST /QueryCancel |
annulation d'une requête longue |
POST /QueryExecuteStream |
résultats en flux — piste sérieuse pour L3.1 (sorties volumineuses) |
Autres endpoints jamais utilisés, à évaluer : QueryEvents, QueryCommands,
QueryCorrelationEvents, QuerySnapshots (event sourcing — utile en debug),
GET /Metadata/Commands|Events|Aggregates et leurs variantes …All,
GET /configuration/applications (liste les applications avec leur version,
plus riche que /AD/api/Application/GetAll), GET /healthcheck?tenantCode= et
GET /ready?tenantCode= (sondes de disponibilité, répondent 200).
Écarté
| Proposition | Raison |
|---|---|
Uniformiser les noms de paramètres (entity_type / query partout) |
Casse les usages existants ; les alias de transition doublent la surface à maintenir. La cause réelle est traitée par L2.2. |
Exposer un indexStatus sur generic_search |
TotalDocuments: 0 est déjà le signal. Le MCP n'a aucun moyen d'interroger l'état de l'index de recherche. |
Outil dédié get_query_syntax_help |
L'information doit se trouver dans le message d'erreur, là où elle est lue (L2.1), pas dans un outil qu'il faut penser à appeler. |
Points ouverts (hors lots)
select_expression: les projections via le paramètreSelectprovoquent des erreurs de compilation côté serveur (D13). Irritant principal restant.- Déploiement SSH sur la VM : l'exécutable est validé, la configuration SSH reste à faire.
- Historique des shipment templates : hors de portée, les logs concernés n'existent pas sur l'hôte joignable (D16).