Files
mcp-wms-api/ROADMAP.md
T
Arthur Ria 86923542fa Roadmap et décisions : exploitation de la référence API du service
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>
2026-08-24 15:58:28 +02:00

13 KiB
Raw Blame History

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 Aliasinvariant, 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 (Aliases n'existe pas, c'est Alias) ;
  • 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_workflows projette w.Id, w.Code, w.Name, w.Category → tous undefined, supprimés par JSON.stringify50 objets vides pour un count pourtant correct ;
  • workflow-service lit w.category || w.Category, deux clés inexistantes → list_workflow_categories renvoie 0 catégorie et classe les 4012 workflows en Uncategorized.

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_metadata pour 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 : ajouter limit / offset, aujourd'hui absents (sortie constatée : 70 000 caractères, rejetée par le client).
  • search_logs : garde-fou de taille. max_results existe déjà, mais les context_lines multiplient le volume (88 000 caractères pour 50 résultats).
  • Renvoyer truncated: true explicitement 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 (AliasesAlias) et renvoyer vers get_entity_metadata comme 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érationnelContext.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 08 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ètre Select provoquent 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).