Files
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

9.2 KiB

Supervision du serveur MCP

Comment savoir si le serveur tourne, ce qu'il fait, et pourquoi il ne répond pas. Ce document décrit l'existant — il n'y a ni endpoint de santé, ni métriques exportées : toute l'observabilité passe par stderr et par le smoke test npm test.

Pour lire les logs du WMS (et non ceux du serveur MCP), voir docs/logs.md.


1. Où regarder

Quoi
Logs du serveur MCP %APPDATA%\Claude\logs\ (fichier mcp-server-wms.log)
Logs applicatifs du WMS partages \\<host>\... — voir docs/logs.md
État de la connexion WMS npm test (voir §5)
Profil actif / caches outils get_current_wms_profile, get_application_summary

Tout passe par stderr. stdout est réservé au JSON du protocole MCP : la moindre écriture sur stdout casse la session Claude Desktop (voir D6 dans DECISIONS.md). En pratique, cela veut dire que les logs sont la seule sortie observable, et qu'ils sont complets.

Suivre les logs en direct :

Get-Content -Wait -Tail 50 "$env:APPDATA\Claude\logs\mcp-server-wms.log"

2. Lire les préfixes

Chaque ligne est préfixée par son composant. Le préfixe suffit à localiser le problème.

Préfixe Composant Ce qu'il signale
[Server] src/index.js démarrage, routage des outils, erreurs non rattrapées
[Profile] config/profile-manager.js chargement des profils, bascule de profil
[API] services/api-service.js OAuth, chaque requête HTTP, retries 401
[Workflow] services/workflow-service.js cache workflows, pagination
[AD] services/ad-service.js cache par type d'élément, pagination
[Logs] services/log-service.js chemins de logs illisibles ou absents
[WMSQuery], [Metadata] services construction des requêtes
[*Tools] src/tools/ exécution d'un outil précis

3. Démarrage : à quoi ressemble un boot sain

[dotenv@17.2.4] injecting env (30) from .env
[Profile] Loaded 3 profile(s). Active: LIMAGRAIN
[Server] Starting WMS MCP Server...
[Server] Architecture: 100% API-based (no direct database access)
[Server] Profiles available: AD, EUROTRAFIC, LIMAGRAIN
[Server] Active profile: LIMAGRAIN
[Server] WMS MCP Server running on stdio
[Server] Ready to accept requests from Claude Desktop

Trois points à contrôler dans cet ordre :

  1. injecting env (N) — si N vaut 0, le .env n'a pas été trouvé. En mode packagé il est attendu à côté de l'exe (D7).
  2. Loaded N profile(s) — si 0, WMS_PROFILES est vide ou les variables <NOM>_HOST/USERNAME/PASSWORD/TENANT manquent.
  3. Active profile: … — si le message est No active profile, ce n'est pas une panne : Claude doit appeler switch_wms_profile avant la première requête, et l'erreur renvoyée le lui indique explicitement (D8).

Aucune connexion au WMS n'est tentée au démarrage : un boot propre ne prouve donc pas que le WMS est joignable. Pour cela, voir §5.


4. Cycle de vie du token OAuth

Le token est obtenu paresseusement, à la première requête, puis rafraîchi automatiquement. Réglages dans .env :

Variable Défaut Rôle
TOKEN_REFRESH_THRESHOLD 1000 s âge au-delà duquel un refresh est déclenché avant la requête
TOKEN_MAX_AGE 1190 s âge au-delà duquel on ne tente plus le refresh_token mais une ré-authentification complète
QUERY_TIMEOUT 30000 ms timeout HTTP de toute requête WMS

Séquence observable :

[API] Authenticating profile="LIMAGRAIN" tenant="LIMAGRAI2512" ...
[API] Authentication successful. Token expires in ~1190s
[API] POST /QueryExecute
...  (~17 min plus tard)
[API] Refreshing token with refresh_token grant...
[API] Token refreshed successfully

Trois filets de sécurité, dans cet ordre :

  1. Avant la requête — si âge > TOKEN_REFRESH_THRESHOLD, refresh préventif.
  2. Refresh en échec — bascule automatique sur le grant password ([API] Token refresh failed, re-authenticating).
  3. Réponse 401 — un refresh est déclenché et la requête est rejouée une fois ([API] Unauthorized, refreshing token and retrying...).

Ce qui est normal. Une ligne Token refresh failed isolée suivie d'une authentification réussie : le filet a joué son rôle.

Ce qui ne l'est pas. Ces trois lignes en boucle rapprochée signalent des credentials invalides ou un tenant erroné — le serveur n'abandonne jamais de lui-même, il retentera à chaque requête.


5. Test de bout en bout

npm test

Teste le profil actif ; npm test -- AD cible un profil, npm test -- --all les teste tous. Quatre vérifications en lecture seule, aucune écriture WMS :

Test Ce qu'il prouve
OAuth host joignable, credentials et tenant corrects
QueryExecute API ApplicationService opérationnelle
QueryScalarExecute requêtes scalaires (Count) opérationnelles
AD API (Validator) API Application Dictionary opérationnelle

Sortie attendue :

=== Profil LIMAGRAIN ===
  host=10.255.255.2 tenant=LIMAGRAI2512 saas=false
  OK   OAuth - token obtenu (age max ~1190s)
  OK   QueryExecute - 1 ligne(s)
  OK   QueryScalarExecute - 51160 produit(s)
  OK   AD API (Validator) - 10 element(s)
  -> 4/4 tests reussis

Code de sortie 0 si tout passe, 1 sinon — utilisable tel quel dans une tâche planifiée.

Sonde plus légère, si l'on veut seulement savoir si le WMS répond (sans authentification applicative) : GET https://<host>/ApplicationService/api/healthcheck?tenantCode=<TENANT> et .../api/ready?tenantCode=<TENANT> renvoient 200. Elles ne disent rien de la validité des credentials — pour ça, npm test.

C'est le premier réflexe quand Claude signale une erreur WMS : il isole en quelques secondes une panne de connectivité d'un problème de requête.


6. État des caches

Deux caches, TTL commun WORKFLOW_CACHE_TTL (1 h par défaut), tous deux vidés à chaque switch_wms_profile (D8).

Cache Contenu Purge
workflows ~3 700 workflows TTL, ou bascule de profil
AD un cache par type (20 types, ~38 800 éléments) TTL par type, ou bascule de profil

Les inspecter sans redémarrer : l'outil get_application_summary liste les types chargés et leur nombre d'éléments — un type absent signifie simplement qu'il n'a jamais été demandé dans cette session (D10).

Signature d'un chargement dans les logs :

[AD] Cache expired or empty, fetching Resource...
[AD] Fetching Resource: offset=0, pageSize=15000
[AD] Fetched 15000 Resource (total: 15000)
[AD] Fetching Resource: offset=15000, pageSize=15000
...
[AD] Successfully cached 29374 Resource
[AD] Cache hit: Resource (29374 elements)      <- appels suivants

Une première requête sur Resource prend plusieurs dizaines de secondes : ce n'est pas un blocage, c'est la pagination. Les suivantes sont instantanées.


7. Symptômes → causes

Symptôme Cause probable Vérification
Le serveur n'apparaît pas dans Claude Desktop chemin invalide dans claude_desktop_config.json, ou Claude pas redémarré ouvrir %APPDATA%\Claude\logs\
Unexpected token … is not valid JSON quelque chose a écrit sur stdout chercher un console.log() ajouté (D6)
injecting env (0) .env introuvable en packagé : le placer à côté de l'exe (D7)
No WMS profile selected DEFAULT_WMS_PROFILE absent ou invalide c'est un état normal — appeler switch_wms_profile
Authentication failed: … 400 tenant_code ou credentials erronés npm test -- <PROFIL> (D2)
Boucle refresh failed / Authenticating credentials invalides npm test
ETIMEDOUT / ECONNREFUSED host injoignable (VPN, pare-feu) Test-NetConnection <host> -Port 443
timeout of 30000ms exceeded requête trop lourde ajouter un Where, réduire take, ou augmenter QUERY_TIMEOUT
Successfully cached 0 workflows réponse non enveloppée par entities D4
Recherche vide sur un élément existant casse des propriétés (name vs Name) D5
Log access is disabled for SaaS profile profil SAAS=true comportement voulu (D9), utiliser les outils API
Erreur de compilation LINQ sur une date DateTime.Now employé date littérale (D12)

8. Ce qui n'est pas instrumenté

À connaître avant de promettre une supervision qui n'existe pas :

  • Pas de healthcheck exposé, ni HTTP ni MCP. npm test est le seul contrôle automatisable, et il faut le lancer soi-même.
  • Pas de métriques : ni compteur d'appels, ni latence, ni taux d'erreur.
  • Pas de fichier de log propre au serveur : tout est capté par Claude Desktop, avec sa rotation à lui.
  • Pas d'alerte : une panne d'authentification n'est visible qu'au prochain appel d'un outil.
  • uncaughtException et unhandledRejection sont journalisés mais n'arrêtent pas le processus (src/index.js). Le serveur peut donc survivre dans un état dégradé — d'où l'intérêt de relire les logs jusqu'au début en cas de comportement erratique, et non seulement la dernière erreur.