QueryType était figé à 0 en dur dans executeQuery/executeScalarQuery : le
modèle Writing, opérationnel et mesuré, était inatteignable. Paramètre
query_type (défaut 0) sur call_query_api, query_wms_entities,
count_wms_entities — get_entity_schema et search_wms_data restent des
raccourcis Reading.
D3 reste la règle par défaut : la bascule est un opt-in, avertie dans les
descriptions d'outils (statuts en énumérations en Writing). Garde de valeur
assertValidQueryType dans le code (le wrapper D23 ne valide pas les valeurs),
avant tout réseau. En query_type != 0, un nom inconnu du Metadata Reading
passe tel quel avec warning (allowUnknown du resolver) — conservé aussi dans
la réponse d'erreur si le WMS échoue ensuite. Acté en D25 ; CLAUDE.md nuancé,
L4.1 retiré de la ROADMAP (reliquat : exploration Metrics, rapport à part).
Vérifications rejouées via le protocole (LIMAGRAIN / LIMAGRAI2512) :
- call_query_api(Products, query_type:1, limit:1) -> success, 1 ligne,
queryType:1 dans la réponse.
- call_query_api(Products, query_type:3) -> erreur structurée contenant
'ApplicationMetricDataContext' ne contient pas de définition pour 'Products'.
- call_query_api(Products, query_type:7) -> erreur locale nommant les 4
contextes, aucun [API] POST/GET dans stderr.
- query_wms_entities(Container, limit:1) sans query_type -> comportement
inchangé (resolvedTableName Containers, Reading, pas de champ queryType).
- call_query_api(FooBar123, query_type:1) -> transmis tel quel (payload
QueryType:1 Expression Context.FooBar123...), erreur WMS
ApplicationWritingRepository + warning de résolution dans la réponse.
- count_wms_entities(Product, query_type:1) -> count 51145 (~51160).
Baseline : tools/list 23, resources 6, rejet D23 d'un paramètre inconnu OK.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Les deux bornages (L3.1a pagination, L3.1b plafond de volume) partagent
le même vocabulaire de signal — truncated présent uniquement quand la
réponse est coupée, hint actionnable, returned vs total avant coupe —
mais gardent des implémentations locales : paginer et plafonner un
volume sont deux mécanismes distincts, un helper commun forcerait une
abstraction qu'ils n'ont pas. D24 consigne ce contrat, les garde-fous
de cadrage (défauts inchangés, mesure protocolaire qui fait foi) et le
changement de sens de totalParameters.
ROADMAP : L3.1 livré, le lot 3 devenait vide — section retirée ; la
référence à L3.1 dans L4.5 (QueryExecuteStream) renvoie désormais à
D24. read_recent_logs est laissé tel quel : sans helper partagé, rien
de gratuit à lui apporter (L3.1c).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mesure V1 (24/08/2026) : le SDK MCP ignore additionalProperties: false —
read_recent_logs({lines: 5}) avec la clause sur le schéma répondait
success: true, returnedLines: 100 (retombée silencieuse sur le défaut).
La validation vit donc dans le wrapper tools/call de src/index.js,
pilotée par les schémas de la table de routage (D22) : paramètre inconnu
ou requis manquant -> erreur structurée nommant le fautif et les
paramètres valides, avant tout dispatch.
Les 23 schémas portent additionalProperties: false — inerte côté SDK,
mais c'est le contrat que lisent les clients. Pas de renommage de
paramètres (écarté, cf. ROADMAP).
Mesures (via le protocole) :
- read_recent_logs({"lines": 5}) -> "Paramètre(s) inconnu(s) pour
read_recent_logs : lines. Paramètres valides : count, log_file."
- read_recent_logs({"count": 5}) -> succès, returnedLines: 5
- boucle sur 22 outils avec {} (execute_command vérifié statiquement) :
22/22 répondent, aucun Unknown tool, les 11 outils à paramètres requis
échouent avec le message actionnable
- handshake : 23 outils, 6 resources
Docs : D23 dans DECISIONS.md, L2.2 retirée de la ROADMAP.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Context.{entity_type} attend le TableName du Metadata, pas le nom
d'entité de l'AD (Container -> Containers, mais Alias -> Alias) : un nom
faux partait en HTTP 500 de compilation LINQ. Nouveau service
entity-resolver.js : table Name|TableName (insensible à la casse) ->
TableName, agrégée sur les applications déployées (via
GET /configuration/applications — les applications sans contexte
requêtable n'y figurent pas et n'apportent 0 entité Metadata), cache TTL
partagé, invalidation par onSwitch (D8). Branché dans wms-query-service
(query/count/schema/search) et call_query_api.
Nom inconnu -> échec avant tout appel réseau de requête, suggestions
proches + renvoi vers get_entity_metadata. Metadata injoignable -> le
nom passe tel quel avec un warning dans la réponse.
Mesures (LIMAGRAIN, via le protocole) :
- query_wms_entities("Container", limit 1) -> succès, 1 ligne, résolu
Containers
- query_wms_entities("Alias") -> succès, invariant (pas de pluriel)
- query_wms_entities("Item") -> "Item" n'existe pas dans le modèle
Reading. Proches : RFMenuItems, Sites. 288 entités disponibles —
aucune ligne [API] POST dans stderr
- count_wms_entities("Product") -> 51160
- get_entity_schema("Container") et call_query_api("Container") : mêmes
résolutions
- 288 TableName distincts sur 5 applications, aucun conflit
Name -> TableName (mesuré le 24/08/2026)
Docs : D21 dans DECISIONS.md ; CLAUDE.md (piège retiré des points
ouverts, liste d'entités corrigée Aliases -> Alias, entity-resolver dans
la structure) ; exemple singulier/pluriel dans wms://query-examples ;
ROADMAP allégée (cause racine + L2.1 + L3.3 livrés).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Le routage par préfixe de nom laissait deux outils listés dans
tools/list mais injoignables : get_entity_metadata (capté par
startsWith('get_entity_') avant sa propre branche) et list_log_files
(aucune branche : le nom contient _log_files, pas _logs).
Une table nom d'outil -> module est construite au démarrage depuis les
listTools() des 8 modules de src/tools/. tools/list est servi depuis
cette même table et le dispatch devient un lookup : un outil listé est
un outil routé, par construction. Deux modules déclarant le même nom
font échouer le serveur au démarrage avec un message nommant les deux
modules. Le wrapper d'erreur du handler tools/call est inchangé, les
23 outils gardent leurs noms.
Vérifié contre le WMS réel : get_entity_metadata renvoie 232 entités,
list_log_files renvoie 19 fichiers, tools/list expose toujours 23
outils et chaque nom listé est traité par le executeTool() de son
module.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Nouveaux documents :
- README.md : porte d'entrée humaine, absente jusqu'ici. Objet du projet,
installation, npm test, branchement Claude Desktop, ajout d'un profil WMS,
compilation de l'exécutable.
- DECISIONS.md : 20 décisions et pièges vérifiés sur un WMS réel (D1..D20),
chacun avec son pourquoi. Extrait ce qui était noyé dans CLAUDE.md :
100 % API, tenant_code OAuth, réponses {entities}, casse des propriétés,
dotenv sur stderr, dates relatives LINQ non traduisibles, absence de
CommandParameterData, etc.
- MONITORING.md : supervision du serveur MCP. Préfixes de logs, séquence
d'un démarrage sain, cycle de vie du token OAuth et ses trois filets,
état des caches, table symptôme -> cause. Une section dit explicitement
ce qui n'est pas instrumenté (ni healthcheck, ni métriques, ni alerte).
- docs/logs.md : accès aux logs du WMS. Chemins, placeholder {host},
blocage volontaire sur les profils SaaS, les trois outils, format des
lignes, limites connues.
Mises à jour :
- CLAUDE.md réécrit et aligné sur le code. Correction de l'écart le plus
gênant : le code utilise QueryType 0 (Reading), la doc annonçait 1, soit
l'inverse de ce qui fonctionne pour les comparaisons de statut par
chaîne. Corrigés également : 6 resources et non 7 (workflows://categories
n'existe pas), section .env mono-profil obsolète, références à des
fichiers de test absents, README annoncé mais inexistant. Le suivi de
projet et les checklists de phases sont retirés.
- docs/README.md : index réel du dossier. L'ancien promettait une resource
docs:// qui n'a jamais existé.
- docs/getting_started.md : avertissement en tête, c'est une capture
partielle du portail Mecalux dont les liens internes ne résolvent pas.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>