Nettoyage du dépôt : doublons, code mort, secrets, build

Fichiers hors périmètre ou dupliqués :
- suppression des 5 .md dupliqués à la racine (copies md5-identiques de
  docs/api/ et docs/entities/)
- suppression de JANITOR_main.js / JANITOR_entities.json (application
  Electron sans lien avec le serveur MCP)
- suppression de temp/*.json (dumps de workflows versionnés par accident)
  et ajout de temp/ au .gitignore
- suppression de claude_desktop_config_ssh.json : mots de passe en clair et
  variables ORACLE_* d'une architecture abandonnée
- AD_API_TEST_RESULTS.md -> docs/ad-api-validation.md (credentials du
  snippet remplacés par des variables d'environnement)
- suppression d'IMPLEMENTATION_SUMMARY.md, doublon du précédent
- queries api.php -> docs/reference-queries-api.php (renommage seul)

Code mort :
- suppression de src/resources/documentation.js : la resource docs:// n'a
  jamais été branchée dans src/index.js
- suppression de src/config/constants.js : module entièrement inutilisé,
  requis par wms-query-service.js mais dont aucune constante n'était lue.
  Emporte RESOURCE_URIS.WORKFLOWS_CATEGORIES, URI déclarée jamais servie.
- log-service.js : suppression de findRecentErrors, readFullLog et
  getLogStats, exportées mais exposées par aucun outil MCP
- suppression de LOG_FILE_PATTERN (lue depuis .env, jamais appliquée : le
  scan filtre sur .log en dur), y compris dans .env.example
- log-service.js : préfixe [Logs] sur les messages, comme les autres modules

Secrets :
- test-ad-api.ps1 -> scripts/test-ad-api.ps1, credentials passés en
  paramètres ou par WMS_USERNAME / WMS_PASSWORD au lieu d'être en dur

Build et test :
- @yao-pkg/pkg en devDependency, cible node22-win-x64 : npm run build
  échouait faute de pkg, et node20 n'a pas de binaire prébuilt (bascule sur
  une compilation de Node qui échoue sans toolchain MSVC)
- index.js : le .env est lu à côté de l'exécutable quand le serveur est
  packagé. Avec un chemin statique, pkg embarquait le .env dans le snapshot,
  figeant les credentials dans le binaire.
- scripts/test-connection.js : npm test pointait sur un fichier absent.
  Smoke test en lecture seule (OAuth, QueryExecute, QueryScalarExecute,
  API AD), par profil ou sur tous.

Vérifié après nettoyage : 23 outils et 6 resources répondent au handshake
MCP, npm test passe 4/4 contre le WMS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Arthur Ria
2026-08-24 15:15:08 +02:00
parent b59cbb3546
commit 9b95e15cbc
28 changed files with 2172 additions and 11497 deletions
-1
View File
@@ -14,7 +14,6 @@
# reference the active profile's HOST — the server substitutes it at runtime.
# Log access is automatically disabled when the active profile has SAAS=true.
LOGS_PATH=\\{host}\inetpub\logs\LogFiles\Mecalux;\\{host}\ProgramData\Mecalux\ETLLogs
LOG_FILE_PATTERN=*.log
# ----------------------------------------
# Shared WMS settings (same across all profiles)
+3
View File
@@ -20,3 +20,6 @@ Thumbs.db
.idea/
*.swp
*.swo
# Dumps temporaires (workflows exportes, etc.)
temp/
-669
View File
@@ -1,669 +0,0 @@
## Application
| API | Description |
| --- | --- |
| [GET api/application/apiversion](https://10.255.255.2/ApplicationService/Help/Api/GET-api-application-apiversion) |
No documentation available.
|
| [GET api/application/apichangelog](https://10.255.255.2/ApplicationService/Help/Api/GET-api-application-apichangelog) |
No documentation available.
|
| [POST api/application/GetResources](https://10.255.255.2/ApplicationService/Help/Api/POST-api-application-GetResources) |
No documentation available.
|
## CommandExecute
| API | Description |
| --- | --- |
| [POST api/CommandExecute](https://10.255.255.2/ApplicationService/Help/Api/POST-api-CommandExecute) |
No documentation available.
|
## CommandFiles
| API | Description |
| --- | --- |
| [POST api/CommandUploadFile](https://10.255.255.2/ApplicationService/Help/Api/POST-api-CommandUploadFile) |
No documentation available.
|
| [GET api/CommandDownloadFile?fileCode={fileCode}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-CommandDownloadFile_fileCode) |
No documentation available.
|
## Configuration
| API | Description |
| --- | --- |
| [GET api/configuration/apiversion](https://10.255.255.2/ApplicationService/Help/Api/GET-api-configuration-apiversion) |
No documentation available.
|
| [GET api/configuration/apichangelog](https://10.255.255.2/ApplicationService/Help/Api/GET-api-configuration-apichangelog) |
No documentation available.
|
| [POST api/configuration/updateorganization](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updateorganization) |
No documentation available.
|
| [POST api/configuration/updateusergroups](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updateusergroups) |
No documentation available.
|
| [POST api/configuration/updaterfmenuitems](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updaterfmenuitems) |
No documentation available.
|
| [POST api/configuration/updatejobs](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updatejobs) |
No documentation available.
|
| [POST api/configuration/stopjobs](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-stopjobs) |
No documentation available.
|
| [POST api/configuration/startjobs](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-startjobs) |
No documentation available.
|
| [POST api/configuration/executejob](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-executejob) |
No documentation available.
|
| [POST api/configuration/updatesubscriptions](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updatesubscriptions) |
No documentation available.
|
| [POST api/configuration/updatetimelinetemplates](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updatetimelinetemplates) |
No documentation available.
|
| [POST api/configuration/updatetypes](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updatetypes) |
No documentation available.
|
| [POST api/configuration/updateprocesses](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updateprocesses) |
No documentation available.
|
| [POST api/configuration/updatequeries](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updatequeries) |
No documentation available.
|
| [POST api/configuration/updateDataWarehouseContext](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updateDataWarehouseContext) |
No documentation available.
|
| [POST api/configuration/updateresources](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updateresources) |
No documentation available.
|
| [POST api/configuration/updateapplication](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updateapplication) |
No documentation available.
|
| [POST api/configuration/updateapplications](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updateapplications) |
No documentation available.
|
| [POST api/configuration/updatelicense](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updatelicense) |
No documentation available.
|
| [POST api/configuration/updatehooks](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updatehooks) |
No documentation available.
|
| [POST api/configuration/updategenericsearch](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updategenericsearch) |
No documentation available.
|
| [POST api/configuration/undoLatestMigration?applicationName={applicationName}](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-undoLatestMigration_applicationName) |
No documentation available.
|
| [POST api/configuration/enableapplication?applicationName={applicationName}](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-enableapplication_applicationName) |
No documentation available.
|
| [POST api/configuration/disableapplication?applicationName={applicationName}](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-disableapplication_applicationName) |
No documentation available.
|
| [POST api/configuration/enabletelemetry](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-enabletelemetry) |
No documentation available.
|
| [POST api/configuration/disabletelemetry](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-disabletelemetry) |
No documentation available.
|
| [GET api/configuration/tenant](https://10.255.255.2/ApplicationService/Help/Api/GET-api-configuration-tenant) |
No documentation available.
|
| [POST api/configuration/enablefeature](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-enablefeature) |
No documentation available.
|
| [POST api/configuration/disablefeature](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-disablefeature) |
No documentation available.
|
| [POST api/configuration/getfeature](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-getfeature) |
No documentation available.
|
| [GET api/configuration/applications](https://10.255.255.2/ApplicationService/Help/Api/GET-api-configuration-applications) |
No documentation available.
|
| [GET api/configuration/applicationFeatures?applicationName={applicationName}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-configuration-applicationFeatures_applicationName) |
No documentation available.
|
| [GET api/configuration/tenants](https://10.255.255.2/ApplicationService/Help/Api/GET-api-configuration-tenants) |
No documentation available.
|
| [GET api/configuration/tenantinfo?tenantCode={tenantCode}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-configuration-tenantinfo_tenantCode) |
No documentation available.
|
| [GET api/configuration/serviceinfo](https://10.255.255.2/ApplicationService/Help/Api/GET-api-configuration-serviceinfo) |
No documentation available.
|
| [POST api/configuration/updateservicemode](https://10.255.255.2/ApplicationService/Help/Api/POST-api-configuration-updateservicemode) |
No documentation available.
|
## Events
| API | Description |
| --- | --- |
| [POST api/PublishEvents](https://10.255.255.2/ApplicationService/Help/Api/POST-api-PublishEvents) |
No documentation available.
|
## GatewayCommit
| API | Description |
| --- | --- |
| [POST api/GatewayCommit](https://10.255.255.2/ApplicationService/Help/Api/POST-api-GatewayCommit) |
No documentation available.
|
## GatewayExecuteCommand
| API | Description |
| --- | --- |
| [POST api/GatewayExecuteCommand](https://10.255.255.2/ApplicationService/Help/Api/POST-api-GatewayExecuteCommand) |
No documentation available.
|
## GatewayExecuteCustomCommand
| API | Description |
| --- | --- |
| [POST api/GatewayExecuteCustomCommand](https://10.255.255.2/ApplicationService/Help/Api/POST-api-GatewayExecuteCustomCommand) |
No documentation available.
|
## GatewayReject
| API | Description |
| --- | --- |
| [POST api/GatewayReject](https://10.255.255.2/ApplicationService/Help/Api/POST-api-GatewayReject) |
No documentation available.
|
## GatewayRollback
| API | Description |
| --- | --- |
| [POST api/GatewayRollback](https://10.255.255.2/ApplicationService/Help/Api/POST-api-GatewayRollback) |
No documentation available.
|
## GatewayUpdateRoutes
| API | Description |
| --- | --- |
| [POST api/GatewayUpdateRoutes](https://10.255.255.2/ApplicationService/Help/Api/POST-api-GatewayUpdateRoutes) |
No documentation available.
|
## GatewayUpdateStations
| API | Description |
| --- | --- |
| [POST api/GatewayUpdateStations](https://10.255.255.2/ApplicationService/Help/Api/POST-api-GatewayUpdateStations) |
No documentation available.
|
## GenericSearch
Generic Search Controller.
| API | Description |
| --- | --- |
| [POST api/GenericSearch/Search](https://10.255.255.2/ApplicationService/Help/Api/POST-api-GenericSearch-Search) |
Searches the specified documents.
|
| [POST api/GenericSearch/Document](https://10.255.255.2/ApplicationService/Help/Api/POST-api-GenericSearch-Document) |
Gets the specified category document.
|
| [GET api/GenericSearch/Categories?applicationName={applicationName}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-GenericSearch-Categories_applicationName) |
Gets the categories.
|
| [POST api/GenericSearch/Categories?applicationName={applicationName}](https://10.255.255.2/ApplicationService/Help/Api/POST-api-GenericSearch-Categories_applicationName) |
Gets the categories.
|
## Health
| API | Description |
| --- | --- |
| [GET api/healthcheck?tenantCode={tenantCode}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-healthcheck_tenantCode) |
No documentation available.
|
| [POST api/healthcheck?tenantCode={tenantCode}](https://10.255.255.2/ApplicationService/Help/Api/POST-api-healthcheck_tenantCode) |
No documentation available.
|
| [GET api/ready?tenantCode={tenantCode}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-ready_tenantCode) |
No documentation available.
|
## Metadata
| API | Description |
| --- | --- |
| [GET api/Metadata/Commands](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-Commands) |
No documentation available.
|
| [GET api/Metadata/Commands?applicationName={applicationName}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-Commands_applicationName) |
No documentation available.
|
| [GET api/Metadata/CommandProperties?assemblyFullName={assemblyFullName}&fullName={fullName}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-CommandProperties_assemblyFullName_fullName) |
No documentation available.
|
| [GET api/Metadata/CommandsAll](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-CommandsAll) |
No documentation available.
|
| [GET api/Metadata/CommandsAll?applicationName={applicationName}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-CommandsAll_applicationName) |
No documentation available.
|
| [GET api/Metadata/Entities](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-Entities) |
No documentation available.
|
| [GET api/Metadata/Entities?applicationName={applicationName}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-Entities_applicationName) |
No documentation available.
|
| [GET api/Metadata/EntityProperties?assemblyFullName={assemblyFullName}&fullName={fullName}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-EntityProperties_assemblyFullName_fullName) |
No documentation available.
|
| [GET api/Metadata/EntitiesAll](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-EntitiesAll) |
No documentation available.
|
| [GET api/Metadata/EntitiesAll?applicationName={applicationName}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-EntitiesAll_applicationName) |
No documentation available.
|
| [GET api/Metadata/Events](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-Events) |
No documentation available.
|
| [GET api/Metadata/Events?applicationName={applicationName}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-Events_applicationName) |
No documentation available.
|
| [GET api/Metadata/EventProperties?assemblyFullName={assemblyFullName}&fullName={fullName}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-EventProperties_assemblyFullName_fullName) |
No documentation available.
|
| [GET api/Metadata/EventsAll](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-EventsAll) |
No documentation available.
|
| [GET api/Metadata/EventsAll?applicationName={applicationName}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-EventsAll_applicationName) |
No documentation available.
|
| [GET api/Metadata/Aggregates](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-Aggregates) |
No documentation available.
|
| [GET api/Metadata/Aggregates?applicationName={applicationName}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-Aggregates_applicationName) |
No documentation available.
|
| [GET api/Metadata/AggregateProperties?assemblyFullName={assemblyFullName}&fullName={fullName}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-AggregateProperties_assemblyFullName_fullName) |
No documentation available.
|
| [GET api/Metadata/AggregatesAll](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-AggregatesAll) |
No documentation available.
|
| [GET api/Metadata/AggregatesAll?applicationName={applicationName}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-Metadata-AggregatesAll_applicationName) |
No documentation available.
|
## QueryCommands
| API | Description |
| --- | --- |
| [POST api/QueryCommands](https://10.255.255.2/ApplicationService/Help/Api/POST-api-QueryCommands) |
No documentation available.
|
## QueryEvents
| API | Description |
| --- | --- |
| [POST api/QueryEvents](https://10.255.255.2/ApplicationService/Help/Api/POST-api-QueryEvents) |
No documentation available.
|
| [POST api/QueryCommandEvents](https://10.255.255.2/ApplicationService/Help/Api/POST-api-QueryCommandEvents) |
No documentation available.
|
| [POST api/QueryCorrelationEvents](https://10.255.255.2/ApplicationService/Help/Api/POST-api-QueryCorrelationEvents) |
No documentation available.
|
## QueryExecute
| API | Description |
| --- | --- |
| [GET api/QueryExecuteStream](https://10.255.255.2/ApplicationService/Help/Api/GET-api-QueryExecuteStream) |
No documentation available.
|
| [POST api/QueryExecuteStream](https://10.255.255.2/ApplicationService/Help/Api/POST-api-QueryExecuteStream) |
No documentation available.
|
| [POST api/QueryCancel](https://10.255.255.2/ApplicationService/Help/Api/POST-api-QueryCancel) |
No documentation available.
|
| [POST api/QueriesCancel](https://10.255.255.2/ApplicationService/Help/Api/POST-api-QueriesCancel) |
No documentation available.
|
| [POST api/QueryExecute](https://10.255.255.2/ApplicationService/Help/Api/POST-api-QueryExecute) |
No documentation available.
|
## QueryScalarExecute
| API | Description |
| --- | --- |
| [POST api/QueryScalarExecuteAsync](https://10.255.255.2/ApplicationService/Help/Api/POST-api-QueryScalarExecuteAsync) |
No documentation available.
|
| [POST api/QueryScalarExecute](https://10.255.255.2/ApplicationService/Help/Api/POST-api-QueryScalarExecute) |
No documentation available.
|
## QuerySnapshots
| API | Description |
| --- | --- |
| [POST api/QuerySnapshots](https://10.255.255.2/ApplicationService/Help/Api/POST-api-QuerySnapshots) |
No documentation available.
|
## Workflow
| API | Description |
| --- | --- |
| [POST api/Workflow/Logon](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-Logon) |
No documentation available.
|
| [POST api/Workflow/GetUserScreen](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-GetUserScreen) |
No documentation available.
|
| [POST api/Workflow/GetUserScreenInfo](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-GetUserScreenInfo) |
No documentation available.
|
| [POST api/Workflow/GetUserScreenParameters](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-GetUserScreenParameters) |
No documentation available.
|
| [POST api/Workflow/GetUserProcessAttributes](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-GetUserProcessAttributes) |
No documentation available.
|
| [POST api/Workflow/ExecuteUserAction](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-ExecuteUserAction) |
No documentation available.
|
| [POST api/Workflow/ExecuteUserActionGetScreen](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-ExecuteUserActionGetScreen) |
No documentation available.
|
| [POST api/Workflow/TerminateUserSession](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-TerminateUserSession) |
No documentation available.
|
| [POST api/Workflow/Start](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-Start) |
No documentation available.
|
| [POST api/Workflow/GetScreen](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-GetScreen) |
No documentation available.
|
| [POST api/Workflow/GetScreenParameters](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-GetScreenParameters) |
No documentation available.
|
| [POST api/Workflow/GetProcessAttributes](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-GetProcessAttributes) |
No documentation available.
|
| [POST api/Workflow/ExecuteAction](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-ExecuteAction) |
No documentation available.
|
| [POST api/Workflow/ExecuteActionGetScreen](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-ExecuteActionGetScreen) |
No documentation available.
|
| [POST api/Workflow/Terminate](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-Terminate) |
No documentation available.
|
| [POST api/Workflow/GetSessions](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-GetSessions) |
No documentation available.
|
| [POST api/Workflow/ExecuteProcessAction](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-ExecuteProcessAction) |
No documentation available.
|
| [POST api/Workflow/Cancel](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-Cancel) |
No documentation available.
|
| [POST api/Workflow/ExecuteValidateDialogFormat](https://10.255.255.2/ApplicationService/Help/Api/POST-api-Workflow-ExecuteValidateDialogFormat) |
No documentation available.
|
## WorkflowLog
| API | Description |
| --- | --- |
| [GET api/WorkflowLog/GetInstances?processDefinitionId={processDefinitionId}&skip={skip}&take={take}&startDateFrom={startDateFrom}&startDateTo={startDateTo}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-WorkflowLog-GetInstances_processDefinitionId_skip_take_startDateFrom_startDateTo) |
No documentation available.
|
| [GET api/WorkflowLog/GetInstances?processDefinitionId={processDefinitionId}&skip={skip}&take={take}&startDateFrom={startDateFrom}&startDateTo={startDateTo}&filterAttributeName={filterAttributeName}&filterAttributeValue={filterAttributeValue}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-WorkflowLog-GetInstances_processDefinitionId_skip_take_startDateFrom_startDateTo_filterAttributeName_filterAttributeValue) |
No documentation available.
|
| [GET api/WorkflowLog/GetInstance?processId={processId}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-WorkflowLog-GetInstance_processId) |
No documentation available.
|
| [GET api/WorkflowLog/GetLogs?processId={processId}&skip={skip}&take={take}&logDateFrom={logDateFrom}&logDateTo={logDateTo}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-WorkflowLog-GetLogs_processId_skip_take_logDateFrom_logDateTo) |
No documentation available.
|
| [GET api/WorkflowLog/ValidateInstance?applicationName={applicationName}&processDefinitionId={processDefinitionId}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-WorkflowLog-ValidateInstance_applicationName_processDefinitionId) |
No documentation available.
|
| [GET api/WorkflowLog/Validate?applicationName={applicationName}&processDefinitionId={processDefinitionId}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-WorkflowLog-Validate_applicationName_processDefinitionId) |
No documentation available.
|
| [GET api/WorkflowLog/ValidateInstanceByVersionId?applicationName={applicationName}&processVersionId={processVersionId}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-WorkflowLog-ValidateInstanceByVersionId_applicationName_processVersionId) |
No documentation available.
|
| [GET api/WorkflowLog/ValidateByVersionId?applicationName={applicationName}&processVersionId={processVersionId}](https://10.255.255.2/ApplicationService/Help/Api/GET-api-WorkflowLog-ValidateByVersionId_applicationName_processVersionId) |
No documentation available.
|
-215
View File
@@ -1,215 +0,0 @@
# WMS MCP Server - Implementation Summary
**Date:** 2026-04-02
**Status:****COMPLETE AND VALIDATED**
## Overview
Successfully implemented a comprehensive MCP (Model Context Protocol) server for the WMS (Warehouse Management System) with 100% API-based architecture. The server provides Claude Desktop with full access to WMS data, workflows, and Application Dictionary elements.
## Implementation Highlights
### ✅ Phase 1: Core Infrastructure
- **API Service:** OAuth 2.0 authentication with automatic token refresh
- **MCP Server:** Full MCP SDK implementation with resources and tools
- **Configuration:** Environment-based configuration with .env support
- **Error Handling:** Comprehensive error handling and logging
### ✅ Phase 2: WMS APIs
- **Query API:** LINQ-based entity querying (12 entity types)
- **Command API:** WMS command execution
- **Workflow API:** Workflow fetching with lazy loading and caching
- Successfully validated: 3,712 workflows retrieved
### ✅ Phase 3: Application Dictionary (NEW)
- **20 Element Types:** Commands, Queries, Dialogs, Views, Entities, Events, etc.
- **38,765 Total Elements:** Comprehensive coverage of application definitions
- **17/19 Types Validated:** curl testing confirmed API endpoints work
- **Lazy Loading + Cache:** Same pattern as workflows (1-hour TTL)
## Test Results
### curl Validation (Application Dictionary)
| Status | Count | Percentage |
|--------|-------|------------|
| ✅ Working | 17 | 89.5% |
| ❌ Failed (404) | 2 | 10.5% |
**Working Types:**
- Command (1,872)
- Query (2,016)
- Dialog (734)
- View (373)
- Entity (331)
- Event (1,980)
- FieldType (320)
- Hook (60)
- List (243)
- Record (337)
- Relationship (49)
- Report (67)
- Resource (29,374) ← Largest type
- Subscription (500)
- Validator (17)
- ViewGroup (180)
- Workflow (3,712)
**Failed Types (Removed):**
- WorkflowAction (404 Not Found)
- WritingModel (404 Not Found)
**Empty Types (Available):**
- Dashboard (0)
- TimelineTemplate (0)
- Toggle (0)
## Files Created/Modified
### Services
-`src/services/api-service.js` - OAuth + HTTP client
-`src/services/workflow-service.js` - Workflow fetching
-`src/services/ad-service.js` - **NEW: Application Dictionary service**
-`src/services/wms-query-service.js` - LINQ query builder
-`src/services/log-service.js` - Log file operations
### Tools
-`src/tools/workflow-tools.js` - Workflow tools (3 tools)
-`src/tools/ad-tools.js` - **NEW: AD tools (5 tools)**
-`src/tools/wms-query-tools.js` - WMS query tools (3 tools)
-`src/tools/api-tools.js` - API tools (2 tools)
-`src/tools/log-tools.js` - Log tools (2 tools)
### Resources
-`src/resources/wms-entities.js` - Entity catalog
-`src/resources/entity-schemas.js` - Schema documentation
-`src/resources/query-examples.js` - LINQ examples
-`src/resources/workflows.js` - Workflow overview
-`src/resources/apis.js` - API documentation
-`src/resources/logs.js` - Log guide
### Core
-`src/index.js` - Main MCP server with AD integration
-`.env` - Environment configuration
-`package.json` - Dependencies
### Documentation
-`CLAUDE.md` - Updated with AD implementation details
-`AD_API_TEST_RESULTS.md` - **NEW: Detailed curl test results**
-`test-ad-api.ps1` - **NEW: PowerShell test script**
-`IMPLEMENTATION_SUMMARY.md` - This file
## Total MCP Tools Implemented
| Category | Tool Count | Tool Names |
|----------|------------|------------|
| **Workflow** | 3 | search_workflows, get_workflow_details, list_workflow_categories |
| **AD Elements** | 5 | get_application_summary, get_ad_elements, search_ad_elements, get_ad_element_details, list_ad_types |
| **WMS Queries** | 3 | query_wms_entities, get_entity_schema, search_wms_data |
| **APIs** | 2 | call_query_api, execute_command |
| **Logs** | 2 | read_recent_logs, search_logs |
| **TOTAL** | **15** | |
## Total MCP Resources Implemented
1. `wms://entities` - WMS entity catalog
2. `wms://entity-schemas` - Entity schema details
3. `wms://query-examples` - LINQ query examples
4. `workflows://overview` - Workflow overview
5. `api://catalog` - API catalog
6. `logs://guide` - Log file guide
**TOTAL: 6 resources**
## Critical Fixes Applied
### 1. dotenv stdout pollution
**Problem:** dotenv writes to stdout, breaking MCP protocol
**Solution:** Redirect stdout to stderr during dotenv loading
### 2. Missing tenant_code
**Problem:** OAuth returns 400 Bad Request
**Solution:** Added `tenant_code: process.env.WMS_API_TENANT` to auth request
### 3. API response structure
**Problem:** Code expected direct array, API returns `{entities: [...]}`
**Solution:** Extract entities: `response?.entities || []`
### 4. Property name inconsistency
**Problem:** API returns both lowercase and uppercase properties
**Solution:** Support both: `e.name || e.Name`
### 5. WorkflowAction & WritingModel 404
**Problem:** Two AD element types return 404 Not Found
**Solution:** Removed from AD_ELEMENT_TYPES configuration
## Performance Optimizations
1. **Lazy Loading:** Data fetched only when needed (not at startup)
2. **Caching:** 1-hour TTL for all cached data
3. **Pagination:** High page sizes to minimize API calls
- Workflows: 5,000 per page
- Resource: 15,000 per page
- Others: 100,000 per page (usually single fetch)
4. **Property Access:** Flexible property name handling (lowercase/uppercase)
## Architecture Achievements
**100% API-based:** No Oracle database dependency
**OAuth 2.0:** Secure token-based authentication
**Lazy Loading:** Minimal startup time
**Caching:** Reduced API load
**Error Resilient:** Comprehensive error handling
**MCP Compliant:** Full protocol compliance
**Validated:** curl testing confirmed functionality
## Usage Examples
### Query Workflows
```
"Search for workflows containing 'Order'"
"Get details of workflow 'Helper_MasterOutboundOrderById'"
```
### Query AD Elements
```
"Get all Command elements"
"Search Queries containing 'Load'"
"Get details of Dialog 'WorkStation_SelectDivision_V1'"
"Show me application summary"
```
### Query WMS Data
```
"Query the last 10 products"
"Get schema for Products entity"
```
### Read Logs
```
"Show me recent log entries"
"Search logs for 'error' keyword"
```
## Next Steps (Optional)
1. **Deploy to Production VM:** Copy to `C:\WMS\mcp\` on server
2. **SSH Configuration:** Set up SSH for remote access from dev PC
3. **Build Executable:** Create standalone .exe with `pkg`
4. **Monitor Performance:** Track cache hit rates and API call frequency
5. **Expand Coverage:** Add more AD element type tools as needed
## Conclusion
The WMS MCP Server implementation is **complete, validated, and ready for use**. All 17 working Application Dictionary element types have been tested with curl and confirmed functional. The server successfully integrates with Claude Desktop, providing comprehensive access to WMS workflows, application definitions, runtime data, and logs through a clean MCP interface.
**Total Coverage:**
- ✅ 15 MCP Tools
- ✅ 6 MCP Resources
- ✅ 5 API endpoints (Query, Command, Workflow, AD x20, OAuth)
- ✅ 20 AD element types (17 working, 3 empty)
- ✅ 38,765 AD elements accessible
- ✅ 3,712 workflows accessible
- ✅ 12 WMS entity types queryable
The implementation exceeds the original requirements by adding comprehensive Application Dictionary support beyond the initial workflow-only scope.
-129
View File
@@ -1,129 +0,0 @@
{
"entities": [
{
"id": "Stock",
"name": "Stocks",
"displayName": "Stocks",
"component": "StockId",
"remove_command": "Mecalux.ITSW.EasyWMS.Modules.Contracts.Commands.StockRemoveCommand"
},
{
"id": "Containers",
"name": "Containers",
"displayName": "Supports",
"component": "ComponentId",
"remove_command": "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.ContainerRemoveCommand"
},
{
"id": "ProductLocations",
"name": "ProductLocations",
"displayName": "Emplacements picking dédiés",
"component": "ProductLocationId",
"remove_command": "Mecalux.ITSW.EasyWMS.Modules.Expeditions.Contracts.Commands.ProductLocationRemoveCommand"
},
{
"id": "Tasks",
"name": "Tasks",
"displayName": "Tâches",
"component": "TaskId",
"remove_command": "Mecalux.ITSW.EasyWMS.Modules.Contracts.Commands.TaskRemoveCommand"
},
{
"id": "Products",
"name": "Products",
"displayName": "Articles",
"component": "ProductId",
"remove_command": "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.ProductRemoveCommand"
},
{
"id": "Accounts",
"name": "Accounts",
"displayName": "Clients",
"component": "AccountId",
"remove_command": "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.AccountRemoveCommand"
},
{
"id": "Suppliers",
"name": "Suppliers",
"displayName": "Fournisseurs",
"component": "SupplierId",
"remove_command": "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.SupplierRemoveCommand"
},
{
"id": "Kits",
"name": "Kits",
"displayName": "Kits",
"where1": "(z => z.IsEnable == true)",
"where1_name": "Kits actifs",
"btn1" : "Désactiver",
"component": "KitId",
"remove_command": "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.KitDeleteCommand",
"btn1_command": "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.KitDisableCommand"
},
{
"id": "Aliases",
"name": "Aliases",
"displayName": "Alias",
"component": "AliasId",
"remove_command": "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.AliasRemoveCommand"
},
{
"id": "InboundOrders",
"name": "InboundOrders",
"displayName": "Ordres d'entrée",
"component": "OutboundOrderId",
"remove_command": "Mecalux.ITSW.EasyWMS.Modules.Receptions.Contracts.Commands.InboundOrderRemoveCommand",
"where1": "(z => z.InboundStatus == Mecalux.ITSW.EasyWMS.Modules.Common.Domain.InboundStatus.ReceptionPending)",
"where1_name" : "Réception en attente",
"btn1" : "Annuler",
"btn1_command" :"Mecalux.ITSW.EasyWMS.Modules.Receptions.Contracts.Commands.InboundOrderCancelCommandV2",
"where2": "(z => z.InboundStatus == Mecalux.ITSW.EasyWMS.Modules.Common.Domain.InboundStatus.Receiving)",
"where2_name" : "Réception en cours",
"where3": "(z => z.InboundStatus == Mecalux.ITSW.EasyWMS.Modules.Common.Domain.InboundStatus.Completed)",
"where3_name" : "Complété",
"btn3": "Fermer",
"btn3_command" : "Mecalux.ITSW.EasyWMS.Modules.Receptions.Contracts.Commands.InboundOrderClosingCommandV2",
"where4": "(z => z.InboundStatus == Mecalux.ITSW.EasyWMS.Modules.Common.Domain.InboundStatus.PartiallyReceived)",
"where4_name" : "Reçu partiellement",
"where5": "(z => z.InboundStatus == Mecalux.ITSW.EasyWMS.Modules.Common.Domain.InboundStatus.Cancelled)",
"where5_name" : "Annulé",
"where6": "(z => z.InboundStatus == Mecalux.ITSW.EasyWMS.Modules.Common.Domain.InboundStatus.Closing)",
"where6_name" : "Fermeture"
},
{
"id": "Receptions",
"name": "Receptions",
"displayName": "Réceptions",
"component": "ReceptionId",
"remove_command": "Mecalux.ITSW.EasyWMS.Modules.Receptions.Contracts.Commands.ReceptionRemoveCommand"
},
{
"id": "OutboundOrders",
"name": "OutboundOrders",
"displayName": "Ordres de sortie",
"component": "OutboundOrderId",
"remove_command": "Mecalux.ITSW.EasyWMS.Modules.Expeditions.Contracts.Commands.OutboundOrderCancelCommand",
"where1": "(z => z.OutboundOrderStatus == Mecalux.ITSW.EasyWMS.Modules.Common.Domain.OutboundOrderStatus.Creating)",
"where1_name" : "Création",
"btn1" : "Annuler",
"btn1_command" :"Mecalux.ITSW.EasyWMS.Modules.Expeditions.Contracts.Commands.OutboundOrderCancelCommand",
"where2": "(z => z.OutboundOrderStatus == Mecalux.ITSW.EasyWMS.Modules.Common.Domain.OutboundOrderStatus.Waiting)",
"where2_name" : "En attente",
"btn2" : "Annuler",
"btn2_command" :"Mecalux.ITSW.EasyWMS.Modules.Expeditions.Contracts.Commands.OutboundOrderCancelCommand",
"where3": "(z => z.OutboundOrderStatus == Mecalux.ITSW.EasyWMS.Modules.Common.Domain.OutboundOrderStatus.Release)",
"where3_name" : "Lancé"
}
]
}
-1246
View File
File diff suppressed because it is too large Load Diff
-227
View File
@@ -1,227 +0,0 @@
## Request Information
### URI Parameters
None.
### Body Parameters
[QueryExecute](https://10.255.255.2/ApplicationService/Help/ResourceModel?modelName=QueryExecute)
| Name | Description | Type | Additional information |
| --- | --- | --- | --- |
| Application |
Application name.
| String |
None.
|
| ClientModule |
Client module that executes the query.
| String |
None.
|
| QueryType |
Type of the query.
| [QueryContextType](https://10.255.255.2/ApplicationService/Help/ResourceModel?modelName=QueryContextType) |
Default: Reading
|
| Expression |
Query expression.
| String |
None.
|
| OrderBy |
Order by to be applied to the expression.
| String |
None.
|
| Select |
Select to be applied to the expression.
| String |
None.
|
| Skip |
Skip to be applied to the expression.
| Int32 |
None.
|
| Take |
Take to be applied to the expression.
| Int32 |
None.
|
| Parameters |
Dictionary with the parameters and their values for the query.
| Dictionary of String \[key\] and [QueryParameterValue](https://10.255.255.2/ApplicationService/Help/ResourceModel?modelName=QueryParameterValue) \[value\] |
None.
|
| InlineCount |
Indicate if an inline count must be done to the query.
| Boolean |
None.
|
| CommandTimeout |
Gets or sets the command/query timeout.
| Int32? |
None.
|
| QueryId |
Gets or sets the query execution identifier.
| Guid? |
None.
|
### Request Formats
**Sample:**
```
{
"Application": "sample string 1",
"ClientModule": "sample string 2",
"QueryType": 0,
"Expression": "sample string 3",
"OrderBy": "sample string 4",
"Select": "sample string 5",
"Skip": 6,
"Take": 7,
"Parameters": {
"sample string 1": {
"TypeName": "sample string 1",
"Value": {}
},
"sample string 2": {
"TypeName": "sample string 1",
"Value": {}
}
},
"InlineCount": true,
"CommandTimeout": 1,
"QueryId": "e57b9e2d-1ba9-42c7-a035-fe964ce53fd6"
}
```
**Sample:**
Sample not available.
**Sample:**
```
Binary JSON content. See http://bsonspec.org for details.
```
## Response Information
### Resource Description
[QueryResultData](https://10.255.255.2/ApplicationService/Help/ResourceModel?modelName=QueryResultData)
| Name | Description | Type | Additional information |
| --- | --- | --- | --- |
| InLineCount |
Gets or sets the in line count.
| Int32 |
None.
|
| Table |
Gets or sets the table.
| [QueryTable](https://10.255.255.2/ApplicationService/Help/ResourceModel?modelName=QueryTable) |
None.
|
### Response Formats
**Sample:**
```
{
"InLineCount": 1,
"Table": {
"TableName": "sample string 1",
"Columns": [
{
"ColumnName": "sample string 1",
"TypeName": "sample string 2"
},
{
"ColumnName": "sample string 1",
"TypeName": "sample string 2"
}
],
"Rows": [
null,
{
"Values": {
"sample string 1": {},
"sample string 3": {}
}
}
]
}
}
```
**Sample:**
```
Binary JSON content. See http://bsonspec.org for details.
```
-39
View File
@@ -1,39 +0,0 @@
{
"mcpServers": {
"wms": {
"command": "ssh",
"args": [
"wms-vm",
"C:\\Users\\mecalux\\Desktop\\wms-mcp-server\\dist\\wms-mcp-server.exe"
],
"env": {
"ORACLE_USER": "db_read",
"ORACLE_PASSWORD": "PF9.43uAq17$U",
"ORACLE_CONNECTION_STRING": "localhost:1521/orcl",
"ORACLE_USER_WORKFLOWS": "db_ad",
"ORACLE_PASSWORD_WORKFLOWS": "PF9.43uAq17$U",
"ORACLE_CONNECTION_STRING_WORKFLOWS": "localhost:1521/orcl",
"WORKFLOWS_TABLE": "AD_WFPROCESSES",
"DOCS_PATH": "C:\\Users\\mecalux\\Desktop\\wms-mcp-server\\docs",
"LOGS_PATH": "C:\\inetpub\\logs\\LogFiles\\Mecalux;C:\\ProgramData\\Mecalux\\ETLLogs",
"LOG_FILE_PATTERN": "*.log",
"API_DEFINITIONS_TABLE": "API_DEFINITIONS",
"WMS_API_BASE_URL": "https://localhost/ApplicationService/api",
"WMS_API_TOKEN_URL": "https://localhost/EasySTS/OAuth/Token",
"WMS_API_AUTH": "Basic R05BOklFNGU3aXFoZHQ=",
"WMS_API_TENANT": "AD",
"WMS_API_USERNAME": "mecalux",
"WMS_API_PASSWORD": "ANDREZmlx6",
"TOKEN_REFRESH_THRESHOLD": "1000",
"TOKEN_MAX_AGE": "1190",
"MAX_QUERY_ROWS": "1000",
"QUERY_TIMEOUT": "30000",
"NODE_TLS_REJECT_UNAUTHORIZED": "0"
}
}
},
"preferences": {
"coworkScheduledTasksEnabled": false,
"sidebarMode": "chat"
}
}
@@ -119,8 +119,8 @@ $tokenResponse = Invoke-RestMethod -Uri "https://localhost/EasySTS/OAuth/Token"
-Body @{
grant_type = "password"
tenant_code = "AD"
username = "mecalux"
password = "ANDREZmlx6"
username = $env:WMS_USERNAME
password = $env:WMS_PASSWORD
}
$token = $tokenResponse.access_token
@@ -137,13 +137,21 @@ $response = Invoke-RestMethod -Uri "https://localhost/AD/api/Command/GetByApplic
$response.entities | Select-Object -First 5
```
## Next Steps
## Suivi
1. ✅ Remove WorkflowAction and WritingModel from AD_ELEMENT_TYPES
2. ✅ Update tool descriptions to reflect 20 types (not 22)
3. ⏭️ Test MCP server with Claude Desktop
4. ⏭️ Validate all 5 AD tools work correctly
5. ⏭️ Update CLAUDE.md with final implementation details
Toutes les actions issues de cette campagne sont closes :
- `WorkflowAction` et `WritingModel` retirés de `AD_ELEMENT_TYPES` (D17).
- Descriptions des outils alignées sur **20** types.
- Les 5 outils AD sont opérationnels et validés avec Claude Desktop.
- Architecture et pièges consignés dans [../CLAUDE.md](../CLAUDE.md) et
[../DECISIONS.md](../DECISIONS.md).
Pour rejouer la campagne complète :
```bash
powershell -ExecutionPolicy Bypass -File ../scripts/test-ad-api.ps1 -WmsHost <host> -Username <user> -Password '***' -Tenant AD
```
## Conclusion
File diff suppressed because one or more lines are too long
-137
View File
@@ -1,137 +0,0 @@
## OutboundOrder
Full name: **Mecalux.ITSW.EasyWMS.Modules.Expeditions.Reading.Domain.OutboundOrder**
## Summary
Represents an outbound order - Is used for managing and tracking outbound orders. It includes key details.
## Properties
| Name | Type | Description |
| --- | --- | --- |
| AccountCode | string | Gets or sets the \[Account\] code. The account code for the outbound order (An account is each of a company´s delivery points). Example: "ACC\_NIKE\_01025" |
| AccountId | Guid? | Gets or sets the \[Account\] identifier. The account identifier for the outbound order (An account is each of a company´s delivery points). Example: 85f988c3-t2f4-44fc-bd2d-ca3db667812t. |
| Address | [Address](https://msscc.mecalux.com/documentation/Development/master/ES/apis/easywms/Domain/Address.md) | Gets or sets the \[Address\]. The delivery address for the outbound order - Represents a physical address with properties (Street, number, door, floor, letter, city, neighborhood, country, zipcode and comments about the address). |
| AgencyCode | string | Gets or sets the \[Agency\] code. The carrier code for the outbound order (Transport agency code. There must be the transport agency code). Example: "SEUR" |
| AgencyId | Guid? | Gets or sets the \[Agency\] identifier. The carrier identifier for the outbound order (Transport agency code. There must be the transport agency code). Example: 15f9e8c3-g2f4-44fc-bd2d-ca3db667617y. |
| AllowDynamicReplenishment | bool | Indicates whether the outbound order allows dynamic replenishment. If allows dynamic replenishment (true). Otherwise (false). Example: false |
| AnyOutboundLineInWorkWave | bool | Flag that indicates if any of it's line is associated to a wave. Example: false |
| AnyStockShipped | bool | Indicates if the order has any stock shipped. Rule to get: Count all of the outbound order lines with the identifier of the outbound order, if the order has lines with quantity shipped or quantity shipped substitute greater than zero (true); otherwise (false) Example: true |
| AssignedUser | string | The user for whom the outbound order is assigned. Example: "mecalux001" |
| AutoCreated | bool | \[CANNOT BE USED\] Indicates if the outbound order has been auto created. Currently it is always `false`. |
| AutoRelease | bool | Indicates whether the outbound order should be auto released. If the outbound order should be auto released (true). Otherwise (false). Example: true |
| AutoReleaseDate | DateTime? | Indicates when the outbound order will be automatically released if the auto release flag is set to true. Example: 03/25/2025 0:00:00. |
| AutoReserve | bool | \[NOT IMPLEMENTED\] Indicates if the outbound order should reserve stock automatically. |
| AutoReserveDate | DateTime? | \[NOT IMPLEMENTED\] Indicates when the outbound order will be automatically reserved if the auto reserve flag is set to `true` |
| CalculatedNumAdjustStockIssues | long | Gets or sets the total number of adjust stock issues. |
| CalculatedNumCommunicationErrorIssues | long | Gets or sets the total number of communication error issues. |
| CalculatedNumExpiredDatesIssues | long | Gets or sets the total number of expired dates issues. |
| CalculatedNumNeedReplenishmentIssues | long | Gets or sets the total number of need replenishment issues. |
| ClientContainerTypeCode | string | The favourite container type code for picking. Example: "American". |
| ClientContainerTypeId | Guid? | The favourite container type identifier for picking. Example: 75f828c3-f2f4-44fc-bd2d-ca3db667896r. |
| Code | string | **Required**
It is a unique code that identifies the outbound order. Example: "ORDER\_SU1". |
| CreationDateOnERP | DateTime? | The ERP creation date for the outbound order. Example: 01/25/2024 0:00:00. |
| CurrentOperation | string | The operation for the outbound order. The possible values are the ones in [OutboundOrderOperation](https://msscc.mecalux.com/documentation/Development/master/ES/apis/easywms/Domain/OutboundOrderOperation.md). Example: "Releasing" |
| CustomAttribute | CustomAttribute | Gets or sets the \[Common.Domain.CustomAttribute\]. The outbound order's custom attributes. |
| DeliveryInstruction | string | \[USED IN MULTI-CARRIER SHIPPING APP\] The delivery instructions Example: "Ensure the package is not exposed to direct sunlight or rain". |
| Description | string | It is a description of the outbound order. Example: "Includes special packaging". |
| Document | string | The outbound order document Example: "DOC01". |
| ERPCode | string | The ERP code for the outbound order. Example: "ERP\_US\_001" |
| ExpectedDockStationCode | string | The expected dock station code for the outbound order. (A dock is an area in the warehouse where trucks (or any other vehicle used to transport goods). Example: "DOCK\_01". |
| ExpectedDockStationId | Guid? | The expected dock station identifier for the outbound order. (A dock is an area in the warehouse where trucks (or any other vehicle used transport goods). Example: 88f828c3-f334-44fc-bd2d-fa3db667896t. |
| FirstTroubleDate | DateTime? | The first trouble date. It is null if no trouble has occurred. Example: 02/25/2025 0:00:00. |
| FollowSequence | bool | Indicates whether the line number should be used as a sequencing method for the preparation. If the line number should be used as a sequencing method for the preparation (true). Otherwise (false). Example: false |
| GroupType | string | The group type of the outbound order. The possible values are the ones in [GroupType](https://msscc.mecalux.com/documentation/Development/master/ES/apis/easywms/Domain/GroupType.md) + an empty string when it is not a group. Example: Merge |
| HasTroubles | bool | Indicates whether the outbound order has troubles. Example: true. |
| IncompleteOrder | bool | Indicates whether the outbound order is incomplete (An incomplete order is when a order is not fully fulfilled, missing items, incorrect items, or partial delivery). Example: false. |
| InternalInfo | InternalInfo | Gets or sets the \[Application.Common.Domain.InternalInfo\]. The internal system information of the outbound order. |
| IsActive | bool | Indicates if the outbound order is active in the system Example: true. |
| IsSingleUnit | bool | Indicates if the outbound order is single unit. Example: true. |
| IsTenseFlow | bool | Indicates if the order is tense flow (Tense Flow is strategy that synchronizes the arrival of goods at the warehouse with their departure for distribution, reducing storage needs and costs while improving operational efficiency). Example: true |
| LoadDockStageLocationCode | string | The actual dock stage location code for the outbound order. Example: "DOCK\_03". |
| LoadDockStageLocationId | Guid? | The actual dock stage location identifier for the outbound order. Example: 09f828c3-g334-44fc-bd2d-fa3db667885g. |
| LoadDockStationCode | string | The actual dock station code for the outbound order. (A dock is an area in the warehouse where truck (or any other vehicle user to transport goods). Example: "DOCK\_02". |
| LoadDockStationId | Guid? | The actual dock station identifier for the outbound order. (A dock is an area in the warehouse where truck (or any other vehicle user to transport goods). Example: 19f828c3-g334-44fc-bd2d-fa3db667896f. |
| ManualEquipmentCode | string | The code of the manual equipment assigned to the outbound order. (It is managed by an operator using a radio frequency terminal. Manual equipment includes pallet, trucks, forklifts etc.). Example: "EQST\_PTL\_ONLYSTOCK\_01" |
| ManualEquipmentId | Guid? | The identifier of the manual equipment assigned to the outbound order. (It is managed by an operator using a radio frequency terminal. Manual equipment includes pallet, trucks, forklifts etc.). Example: 41f838c3-h354-442c-bd2d-fa32b667913y. |
| MinSupplyPercent | long | \[NOT IMPLEMENTED\] The minimum percentage of storaged stock necessary to supply stock to the order. |
| NumCancelledLines | long | The number of outbound lines from the order that are in cancelled status. |
| NumClientContainers | long | The number of client containers for the outbound order. |
| NumClosedLines | long | The number of outbound lines from the order that are in closed status. |
| NumCutInProcessTasks | long | The number of cut in process task for the outbound order. |
| NumCutPendingTasks | long | The number of cut pending task for the outbound order. |
| NumLoads | long | The number of loads for the outbound order. Example: 1 |
| NumOutboundOrderChildren | long | The number of outbound order children for the group or merge. |
| NumOutboundOrderLineDetails | long | The number of outbound order line details for the outbound order. Example: 2 |
| NumOutboundOrderLines | long | **Obsolete("Use NumTotalOutboundOrderLines")**
The number of outbound lines for the outbound order. Example: 2 |
| NumPendingTasks | long | The number of pending tasks for the outbound order. |
| NumPreparedTasks | long | The number of prepared tasks for the outbound order. |
| NumReleasedLines | long | The number of outbound lines from the order that are in released status. |
| NumStockLines | long | The number of stock lines for the outbound order. |
| NumStoppedLines | long | The number of outbound lines from the order that are stopped when the whole order is being stopped. |
| NumTotalOutboundOrderLines | long | The total number of outbound order lines. Rule to calculate: Count of all outbound order lines with the identifier of the outbound order and outbound order status different of the ´Cancelled´. Example: 5 |
| NumWavedLines | long | **Obsolete("Waves are no longer supported. Use WorkWaves")**
\[OBSOLETE\] The number of outbound lines from the outbound order included in a wave. |
| NumWaves | long | **Obsolete("Waves are no longer supported. Use WorkWaves")**
\[OBSOLETE\] The number of waves where the outbound order is included. |
| OrderWeight | decimal | **Obsolete("This field is no longer maintained. Please perform the necessary query to obtain the value")**
\[OBSOLETE\] The outbound order weight. |
| OutboundClassCode | string | Gets or sets the \[OutboundClass\] code. The outbound class code for the outbound order (The outbound class is a classification of the routes and shipping orders). Example: "SHIPPING\_GROUP\_01" |
| OutboundClassId | Guid? | Gets or sets the \[OutboundClass\] identifier. The outbound class identifier for the outbound order (The outbound class is a classification of the routes and shipping orders). Example: 08d877b3-t2e4-44fc-cd2d-ca3db667515t. |
| OutboundIssueCodes | string | Gets or sets the issues. |
| OutboundOrderGroupMasterCode | string | Gets or sets the \[OutboundOrderGroup\] code. The code of the master outbound order for the group the outbound order is part of. It is part of none, it is an empty string. Example: "GROUPING\_01". |
| OutboundOrderGroupMasterId | Guid? | Gets or sets the \[OutboundOrderGroup\] identifier. The identifier of the master outbound order for the group the outbound order is part of. It is part of none, it is null. Example: 41f838c3-h354-442c-bd2d-fa32b667913y. |
| OutboundOrderSituation | string | \[CANNOT BE USED\] The outbound order situation. |
| OutboundOrderStatus | string | **Required**
The outbound order's status. The possible values are the ones in [OutboundOrderStatus](https://msscc.mecalux.com/documentation/Development/master/ES/apis/easywms/Domain/OutboundOrderStatus.md). Example: "Creating" |
| OutboundType | string | The outbound order's outbound type. The possible values are the ones in [OutboundType](https://msscc.mecalux.com/documentation/Development/master/ES/apis/easywms/Domain/OutboundType.md). Example: "Customer" |
| OwnerCode | string | Gets or sets the \[Owner\] code. The owner code for the outbound order. Example: "VW\_02". |
| OwnerId | Guid? | Gets or sets the \[Owner\] identifier. The owner identifier for the outbound order. Example: 65f828c3-t2f4-44fc-bd2d-ca3db667896g. |
| PackagingLocationCode | string | The packaging location code for the outbound order. Example: "UDISTRIBUTION\_UAP\_02". |
| PackagingLocationId | Guid? | The packaging location identifier for the outbound order. Example: 39f838c3-g354-442c-bd2d-fa32b667882g. |
| PaperPick | bool | Indicates whether the outbound order will be prepared using paper pick. (Paper picking is a process by which the operator performs the picking manually, without using the RF terminal or the work station.) Example: true. |
| PartialClosedSequence | long? | The last partial closed sequence. Example: 3 |
| PendingReceipt | bool | Indicates whether the outbound order is waiting for receiving an ASN container. True if it is waiting for an ASN to be received or otherwise is false. Example: false. |
| Planning | [Planning](https://msscc.mecalux.com/documentation/Development/master/ES/apis/easywms/Domain/Planning.md) | Gets or sets the \[Planning\]. The outbound order planning information. |
| PrepackagingLogic | string | The pre-packaging logic for the outbound order. The possible values are the ones in [PrepackagingLogic](https://msscc.mecalux.com/documentation/Development/master/ES/apis/easywms/Domain/PrepackagingLogic.md). Example: MinimumParcels |
| PrepackagingProcess | string | The pre-packaging type for the outbound order. The possible values are the ones in [PrepackagingProcess](https://msscc.mecalux.com/documentation/Development/master/ES/apis/easywms/Domain/PrepackagingProcess.md). Example: Preparation |
| PrepackagingType | string | The pre-packaging type for the outbound order. The possible values are the ones in [PrepackagingType](https://msscc.mecalux.com/documentation/Development/master/ES/apis/easywms/Domain/PrepackagingType.md). Example: ERPInformed |
| PrepackagingWorkingMode | string | The pre-packaging working mode for the outbound order. The possible values are the ones in [PrepackagingWorkingMode](https://msscc.mecalux.com/documentation/Development/master/ES/apis/easywms/Domain/PrepackagingWorkingMode.md). Example: Strict |
| Priority | string | The outbound order priority. The possible values are the ones in [Priority](https://msscc.mecalux.com/documentation/Development/master/ES/apis/easywms/Domain/Priority.md). Example: "Urgent". |
| RealReleaseDate | DateTime? | Indicates the first release date for the outbound order. Example: 03/25/2025 0:00:00. |
| ReceivedFromERP | bool | Indicates whether the outbound order was received from the ERP. If received from the ERP (true). Otherwise (false). Example: true |
| ReleasedBy | string | The first user who released the outbound order. Example: "mecalux567" |
| RequiredClientContainerTypeCode | string | Gets or sets the \[ContainerType\] code. The required client container type code for picking. Example: "EuroPallet". |
| RequiredClientContainerTypeId | Guid? | Gets or sets the \[ContainerType\] identifier. The required client container type identifier for picking. Example: 85f828c3-t2f4-44fc-bd2d-ca3db667896t. |
| RouteCode | string | Gets or sets the \[Route\] code. The route code for the outbound order. Example: "NORTHERN\_ROUTE". |
| RouteId | Guid? | Gets or sets the \[Route\] identifier. The route identifier for the outbound order. Example: 48d877b3-c2e4-44fc-bd2d-ca3db667515c. |
| ShipExpiredStock | bool | Indicates if the outbound order shipped products with expired dates. |
| ShipmentTemplateCode | string | Gets or sets the \[ShipmentTemplate\] code. The code of the shipment template used in the outbound order. Example: "ST\_SINGLE\_UNIT" |
| ShipmentTemplateId | Guid? | Gets or sets the \[ShipmentTemplate\] identifier. The identifier of the shipment template used in the outbound order. Example: 21f838c3-e354-442c-td2d-ha32b667915u. |
| ShippingDeadline | DateTime? | Gets the shipping deadline. |
| ShippingDeadlineManuallySet | bool | Indicates whether the shipping deadline was received from the assistant. If received from the assistant (true). Otherwise (false). |
| ShipReq | [ShippingRequirements](https://msscc.mecalux.com/documentation/Development/master/ES/apis/easywms/Domain/ShippingRequirements.md) | Gets or sets the \[ShippingRequirements\]. The outbound order shipping requirements. |
| SkipTroubledTasks | bool | The flag to skip troubled tasks. When `true`, troubled tasks will be skipped. When `false`, they will block the execution of the following tasks. Example: true |
| Source | string | The outbound order source. Example: "L10". |
| SubwarehouseCode | string | Gets or sets the \[Subwarehouse\] code. The subwarehouse code for the outbound order (Subwarehouses is grouping locations to build rules that apply over a specific warehouse area or locations subset). Example: "ST\_SINGLE\_UNIT" |
| SubwarehouseId | Guid? | Gets or sets the \[Subwarehouse\] identifier. The subwarehouse identifier for the outbound order (Subwarehouses is grouping locations to build rules that apply over a specific warehouse area or locations subset). Example: 32f838c3-ef54-442c-td2d-ha32b6679r5g. |
| SupplierCode | string | Gets or sets the \[Supplier\] code. The supplier code for the outbound order (A supplier is a company or entity that supplies stock to the node). Example: "NIKE" |
| SupplierId | Guid? | Gets or sets the \[Supplier\] identifier. The supplier identifier for the outbound order (A supplier is a company or entity that supplies stock to the node). Example: 25f9e8c3-g2f4-45fc-bd2d-ca3db667718u. |
| TenseFlowStageCode | string | The tense flow stage code (Tense Flow is strategy that synchronizes the arrival of goods at the warehouse with their departure for distribution, reducing storage needs and costs while improving operational efficiency). Example: "STG\_01" |
| TenseFlowStageId | Guid? | The tense flow stage identifier (Tense Flow is strategy that synchronizes the arrival of goods at the warehouse with their departure for distribution, reducing storage needs and costs while improving operational efficiency). Example: 35f838c3-fg54-542c-td2d-ha32b667190t. |
| Transport | [OutboundOrderTransport](https://msscc.mecalux.com/documentation/Development/master/ES/apis/easywms/Domain/OutboundOrderTransport.md) | Gets or sets the \[OutboundOrderTransport\]. The outbound order transport information. |
| ValidDate | DateTime? | \[NOT IMPLEMENTED\] The outbound order valid date. |
| WarehouseCode | string | **Required**
Gets or sets the \[Warehouse\] code. The warehouse code for the outbound order. Example: "KITDEMO\_4". |
| WarehouseId | Guid | Gets or sets the \[Warehouse\] identifier. The warehouse identifier for the outbound order. Example: 07d877b3-c2e4-44fc-bd2d-ca3db667514a. |
| WarehouseToCode | string | Gets or sets the \[Warehouse\] code. The destination warehouse code for the outbound order. Example: "WH\_STORE\_01". |
| WarehouseToId | Guid? | Gets or sets the \[Warehouse\] identifier. The destination warehouse identifier for the outbound order. Example: 18d877b3-c2e4-44fc-bd2d-ca3db667515b. |
| WorkOrderCode | string | Gets or sets the \[WorkOrder\] code. The work order code for the outbound order (assembly or disassembly of kit). Example: "WORK\_ORDER\_ASSEMBLY\_01" |
| WorkOrderId | Guid? | Gets or sets the \[WorkOrder\] identifier. The work order identifier for the outbound order (assembly or disassembly of kit). Example: 78d877b3-f2e4-44fc-bd2d-ca3db667515g. |
| WorkWaveCode | string | Gets or sets the \[WorkWave\] code. The code of the wave to which the outbound order is associated. Example: "Wave\_A" |
| WorkWaveId | Guid? | Gets or sets the \[WorkWave\] identifier. Identifier used to track and manage wave. Example: 12f838c3-ff54-542c-td2d-ha32b6679r5t. |
If you have any suggestion or comment on this documentation, please submit it to [documentation@mecalux.com](mailto:documentation@mecalux.com)
@@ -1,32 +0,0 @@
## OutboundOrderStatus
Full name: **Mecalux.ITSW.EasyWMS.Modules.Common.Domain.OutboundOrderStatus**
## Summary
Represents the status of outbound orders.
## Values
| Name | Value | Description |
| --- | --- | --- |
| Creating | 0 | The outbound order is being created. this will occur when they are created by the ERP or manually through the user interface. |
| Waiting | 1 | The outbound order is waiting to be released. this will occur when the order is correctly received from the ERP or when it's creation is finished manually through the user interface. |
| Release | 2 | The outbound order is release and it's tasks may be generated. An order is released when it is released through the user interface, when it's auto release date is reached, when it is associated with a route with an auto release date which has been reached or when all the lines from the outbound order has been manually released. |
| PartiallyRelease | 3 | The outbound order is partially release and it's tasks may be generated. An order is partially released when one or more lines from the order, always less than it's total lines, has been released. |
| Working | 4 | The outbound order is working. The order will be in this status from the beggining to the end of it's preparation process. To be in this status, one of it's generated tasks must be "In Process" status. |
| PartiallyWorking | 5 | The outbound order is partially working. The order will be in this status from the beggining to the end of it's preparation process. Only the orders with the status "PartiallyRelease" can change to this status. To be in this status, one of it's generated tasks must be "In Process" status. |
| Pausing | 6 | The outbound order is being paused. Not used. |
| Paused | 7 | The outbound order was paused. All it's work has been halted and it's tasks will be cancelled. This can occur when the order has been paused from the user interface. |
| Cancelling | 8 | The outbound order is being cancelled. Not used. |
| Cancelled | 9 | The outbound order was cancelled. All it's work will be halted, it's tasks will be cancelled and the assigned stock to the order will be unassigned |
| Closing | 10 | The outbound order is being closed. Not used. |
| Closed | 11 | The outbound order was closed. The preparation process of it's lines has been finished and the order is ready to ship or already shipped. This will occur when a user close the order through the user interface or when the system is configured to auto close al prepared orders. Also, the order will be archived if the system is configured as well to auto archive closed orders. |
| Expired | 12 | The outbound order is outdated. The outbound order was not released before the valid date. Not used. |
| StockFailure | 13 | The outbound order has all theirs lines on stock failure. An order will be in this status when it has been released and all of it's lines couldn't be assigned |
| Merged | 14 | The outbound order was merged. The orders in this status has been fused through the user interface. |
| Grouped | 15 | The outbound order was grouped. The orders in this status has been grouped through the user interface or automatically from a shipment template configured by the user. |
| Secured | 16 | The outbound order has its stock secured. The orders in this status has been secured through the user interface and has a secured quantity. |
| Assigned | 17 | The outbound order has its stock assigned. The orders in this status has been assigned through the user interface and has a assigned quantity. |
If you have any suggestion or comment on this documentation, please submit it to [documentation@mecalux.com](mailto:documentation@mecalux.com)
+1998 -6
View File
File diff suppressed because it is too large Load Diff
+14 -5
View File
@@ -1,17 +1,21 @@
{
"name": "wms-mcp-server",
"version": "1.0.0",
"description": "MCP Server for WMS debugging and analysis",
"description": "Serveur MCP pour le debug et l analyse d un WMS EasyWMS (100% API)",
"main": "src/index.js",
"bin": {
"wms-mcp-server": "./src/index.js"
},
"scripts": {
"start": "node src/index.js",
"test": "node test-connection.js",
"build": "pkg . --targets node18-win-x64 --output dist/wms-mcp-server.exe"
"test": "node scripts/test-connection.js",
"build": "pkg . --targets node22-win-x64 --output dist/wms-mcp-server.exe"
},
"keywords": ["mcp", "wms", "debugging"],
"keywords": [
"mcp",
"wms",
"debugging"
],
"author": "",
"license": "ISC",
"type": "commonjs",
@@ -24,7 +28,12 @@
"assets": [
"node_modules/@modelcontextprotocol/**/*"
],
"targets": ["node18-win-x64"],
"targets": [
"node22-win-x64"
],
"outputPath": "dist"
},
"devDependencies": {
"@yao-pkg/pkg": "^6.22.0"
}
}
+22 -7
View File
@@ -1,15 +1,30 @@
# AD API Testing Script
# Tests each Application Dictionary element type endpoint
# Configuration
$baseUrl = "https://localhost"
# Configuration - aucun credential en dur : passer par les parametres ou l'environnement.
# Exemple : . est-ad-api.ps1 -Host 10.255.255.2 -Username mecalux -Password '***' -Tenant AD
param(
[string]$WmsHost = $(if ($env:WMS_HOST) { $env:WMS_HOST } else { "localhost" }),
[string]$Username = $env:WMS_USERNAME,
[string]$Password = $env:WMS_PASSWORD,
[string]$Tenant = $(if ($env:WMS_TENANT) { $env:WMS_TENANT } else { "AD" }),
[string]$Auth = $(if ($env:WMS_API_AUTH) { $env:WMS_API_AUTH } else { "Basic R05BOklFNGU3aXFoZHQ=" }),
[string]$Application = "EasyWMS"
)
if (-not $Username -or -not $Password) {
Write-Host "Username / Password manquants. Passez -Username / -Password ou definissez WMS_USERNAME / WMS_PASSWORD." -ForegroundColor Red
exit 1
}
$baseUrl = "https://$WmsHost"
$tokenUrl = "$baseUrl/EasySTS/OAuth/Token"
$adApiBase = "$baseUrl/AD/api"
$auth = "Basic R05BOklFNGU3aXFoZHQ="
$username = "mecalux"
$password = "ANDREZmlx6"
$tenant = "AD"
$application = "EasyWMS"
$auth = $Auth
$username = $Username
$password = $Password
$tenant = $Tenant
$application = $Application
# Skip SSL certificate validation (self-signed cert)
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
+105
View File
@@ -0,0 +1,105 @@
#!/usr/bin/env node
/**
* Smoke test de connectivite WMS.
*
* npm test -> teste le profil DEFAULT_WMS_PROFILE
* npm test -- LIMAGRAIN -> teste le profil nomme
* npm test -- --all -> teste tous les profils declares dans WMS_PROFILES
*
* Verifie, pour chaque profil : chargement du profil, OAuth, QueryExecute,
* QueryScalarExecute et l'API AD. N'ecrit rien dans le WMS.
*/
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env') });
const profileManager = require('../src/config/profile-manager');
const apiService = require('../src/services/api-service').getInstance();
function ok(label, detail) {
console.log(` OK ${label}${detail ? ` - ${detail}` : ''}`);
}
function ko(label, error) {
console.log(` FAIL ${label} - ${error.message}`);
}
async function step(label, fn) {
try {
ok(label, await fn());
return true;
} catch (error) {
ko(label, error);
return false;
}
}
async function testProfile(name) {
console.log(`\n=== Profil ${name} ===`);
profileManager.switchTo(name);
const profile = profileManager.getCurrent();
console.log(` host=${profile.host} tenant=${profile.tenant} saas=${profile.saas}`);
let passed = 0;
const total = 4;
if (await step('OAuth', async () => {
await apiService.authenticate();
return `token obtenu (age max ~${process.env.TOKEN_MAX_AGE || 1190}s)`;
})) passed++;
if (await step('QueryExecute', async () => {
const rows = await apiService.executeQuery('Context.Products.OrderBy(z => z.Id)', { take: 1 });
return `${Array.isArray(rows) ? rows.length : 0} ligne(s)`;
})) passed++;
if (await step('QueryScalarExecute', async () => {
const count = await apiService.executeScalarQuery('Context.Products.Count()');
return `${count} produit(s)`;
})) passed++;
if (await step('AD API (Validator)', async () => {
const res = await apiService.post('/Validator/GetByApplication',
[profile.application, profile.tenant, 10, 0], true);
return `${res?.entities?.length ?? 0} element(s)`;
})) passed++;
console.log(` -> ${passed}/${total} tests reussis`);
return passed === total;
}
async function main() {
profileManager.loadProfiles();
const available = profileManager.listProfiles();
if (available.length === 0) {
console.error('Aucun profil charge. Verifiez WMS_PROFILES et <NAME>_HOST/USERNAME/PASSWORD/TENANT dans .env');
process.exit(1);
}
const arg = process.argv[2];
let targets;
if (arg === '--all') {
targets = available;
} else if (arg) {
targets = [arg];
} else {
targets = [profileManager.getCurrentName() || available[0]];
}
let allOk = true;
for (const name of targets) {
try {
allOk = (await testProfile(name)) && allOk;
} catch (error) {
console.log(`\n=== Profil ${name} ===\n FAIL ${error.message}`);
allOk = false;
}
}
console.log(`\n${allOk ? 'Tous les profils testes sont operationnels.' : 'Au moins un test a echoue (voir ci-dessus).'}`);
process.exit(allOk ? 0 : 1);
}
main();
-83
View File
@@ -1,83 +0,0 @@
/**
* Constants for WMS MCP Server
*/
// WMS Entity Types available via Query API
// Based on queries api.php reference
const WMS_ENTITY_TYPES = [
// Master Data
'Products',
'Containers',
'Accounts',
'Suppliers',
'Kits',
'Aliases',
// Operations
'Tasks',
'Stocks',
'ProductLocations',
// Inbound
'InboundOrders',
'Receptions',
// Outbound
'OutboundOrders'
];
// Entity Categories for documentation
const ENTITY_CATEGORIES = {
'Master Data': ['Products', 'Containers', 'Accounts', 'Suppliers', 'Kits', 'Aliases'],
'Operations': ['Tasks', 'Stocks', 'ProductLocations'],
'Inbound': ['InboundOrders', 'Receptions'],
'Outbound': ['OutboundOrders']
};
// Common WMS Commands
// These can be used with call_command_api tool
const WMS_COMMANDS = {
'ProductRemove': 'Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.ProductRemoveCommand',
'ProductUpdate': 'Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.ProductUpdateCommand',
'ContainerCreate': 'Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.ContainerCreateCommand',
'TaskCancel': 'Mecalux.ITSW.EasyWMS.Modules.Tasks.Contracts.Commands.TaskCancelCommand'
// Add more as needed
};
// MCP Resource URIs
const RESOURCE_URIS = {
WMS_ENTITIES: 'wms://entities',
ENTITY_SCHEMAS: 'wms://entity-schemas',
QUERY_EXAMPLES: 'wms://query-examples',
WORKFLOWS_OVERVIEW: 'workflows://overview',
WORKFLOWS_CATEGORIES: 'workflows://categories',
API_CATALOG: 'api://catalog',
LOGS_GUIDE: 'logs://guide'
};
// Log patterns for error detection
const LOG_ERROR_PATTERNS = [
'ERROR',
'EXCEPTION',
'FATAL',
'CRITICAL',
'FAILED',
'FAILURE',
'WARNING'
];
// Query limits
const QUERY_LIMITS = {
MAX_ROWS: parseInt(process.env.MAX_QUERY_ROWS) || 1000,
DEFAULT_LIMIT: 100,
TIMEOUT_MS: parseInt(process.env.QUERY_TIMEOUT) || 30000
};
module.exports = {
WMS_ENTITY_TYPES,
ENTITY_CATEGORIES,
WMS_COMMANDS,
RESOURCE_URIS,
LOG_ERROR_PATTERNS,
QUERY_LIMITS
};
+10 -3
View File
@@ -14,9 +14,16 @@ const path = require('path');
const originalStdoutWrite = process.stdout.write;
process.stdout.write = process.stderr.write.bind(process.stderr);
require('dotenv').config({
path: path.join(__dirname, '..', '.env')
});
// Resolve .env:
// - packaged (.exe built with pkg): next to the executable, so the deployed
// server can be reconfigured without a rebuild and no credential is ever
// baked into the binary snapshot.
// - from sources: project root.
const ENV_PATH = process.pkg
? path.join(path.dirname(process.execPath), '.env')
: path.join(__dirname, '..', '.env');
require('dotenv').config({ path: ENV_PATH });
// Restore stdout
process.stdout.write = originalStdoutWrite;
-193
View File
@@ -1,193 +0,0 @@
const fs = require('fs').promises;
const path = require('path');
/**
* Resources MCP pour la documentation
* Permet à Claude d'accéder à la documentation structurée en fichiers Markdown
*/
// Chemin vers le dossier de documentation
const DOCS_PATH = process.env.DOCS_PATH || path.join(__dirname, '..', '..', 'docs');
/**
* Scanne récursivement un dossier pour trouver tous les fichiers .md
* @param {string} dir - Dossier à scanner
* @param {string} baseDir - Dossier de base pour les chemins relatifs
* @returns {Promise<Array>} - Liste des fichiers .md
*/
async function scanMarkdownFiles(dir, baseDir = dir) {
let files = [];
try {
const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
// Récursion dans les sous-dossiers
const subFiles = await scanMarkdownFiles(fullPath, baseDir);
files = files.concat(subFiles);
} else if (entry.isFile() && entry.name.endsWith('.md')) {
// Fichier Markdown trouvé
const relativePath = path.relative(baseDir, fullPath);
files.push({
name: entry.name,
path: fullPath,
relativePath: relativePath.replace(/\\/g, '/'), // Normaliser les slashes
uri: `docs://${relativePath.replace(/\\/g, '/')}`,
});
}
}
} catch (err) {
// Dossier n'existe pas ou erreur de lecture
console.error(`Error scanning directory ${dir}:`, err.message);
}
return files;
}
/**
* Liste les resources disponibles pour la documentation
* @returns {Promise<Array>} - Liste des resources
*/
async function listResources() {
try {
// Scanner les fichiers Markdown
const mdFiles = await scanMarkdownFiles(DOCS_PATH);
const resources = [
{
uri: 'docs://index',
name: 'Documentation Index',
description: 'Sommaire de toute la documentation disponible',
mimeType: 'text/markdown',
},
];
// Ajouter chaque fichier .md comme resource
mdFiles.forEach((file) => {
resources.push({
uri: file.uri,
name: file.name.replace('.md', ''),
description: `Documentation: ${file.relativePath}`,
mimeType: 'text/markdown',
});
});
return resources;
} catch (err) {
console.error('Error listing documentation resources:', err);
return [
{
uri: 'docs://index',
name: 'Documentation Index',
description: 'Sommaire de toute la documentation disponible',
mimeType: 'text/markdown',
},
];
}
}
/**
* Génère un index/sommaire de la documentation
* @returns {Promise<string>} - Markdown avec le sommaire
*/
async function generateIndex() {
try {
const mdFiles = await scanMarkdownFiles(DOCS_PATH);
if (mdFiles.length === 0) {
return `# Documentation\n\n*Aucun fichier de documentation trouvé dans \`${DOCS_PATH}\`*\n\n` +
`Pour ajouter de la documentation :\n` +
`1. Créez un dossier \`docs\` à la racine du projet\n` +
`2. Ajoutez vos fichiers .md (organisation libre avec sous-dossiers)\n` +
`3. Redémarrez le serveur MCP\n`;
}
let markdown = '# Documentation WMS\n\n';
markdown += `**${mdFiles.length} fichiers de documentation disponibles**\n\n`;
markdown += `📁 Emplacement : \`${DOCS_PATH}\`\n\n`;
// Grouper par dossier
const grouped = {};
mdFiles.forEach((file) => {
const dir = path.dirname(file.relativePath);
const folder = dir === '.' ? '📄 Racine' : `📁 ${dir}`;
if (!grouped[folder]) {
grouped[folder] = [];
}
grouped[folder].push(file);
});
// Générer le sommaire
markdown += '## Sommaire\n\n';
Object.keys(grouped).sort().forEach((folder) => {
markdown += `### ${folder}\n\n`;
grouped[folder].forEach((file) => {
markdown += `- **${file.name.replace('.md', '')}** - \`${file.uri}\`\n`;
});
markdown += '\n';
});
markdown += '---\n\n';
markdown += '*Pour lire un fichier, demandez à Claude de lire la resource correspondante (par exemple: "Lis la documentation X")*\n';
return markdown;
} catch (err) {
return `# Erreur\n\nImpossible de générer l'index de documentation: ${err.message}`;
}
}
/**
* Lit un fichier de documentation
* @param {string} relativePath - Chemin relatif du fichier
* @returns {Promise<string>} - Contenu Markdown du fichier
*/
async function readDocFile(relativePath) {
try {
const filePath = path.join(DOCS_PATH, relativePath);
const content = await fs.readFile(filePath, 'utf8');
return content;
} catch (err) {
return `# Erreur\n\nImpossible de lire le fichier \`${relativePath}\`: ${err.message}`;
}
}
/**
* Lit une resource documentation selon son URI
* @param {string} uri - URI de la resource (format: docs://path/to/file.md)
* @returns {Promise<Object>} - Contenu de la resource
*/
async function readResource(uri) {
let content;
if (uri === 'docs://index') {
content = await generateIndex();
} else if (uri.startsWith('docs://')) {
// Extraire le chemin relatif de l'URI
const relativePath = uri.replace('docs://', '');
content = await readDocFile(relativePath);
} else {
throw new Error(`Unknown documentation resource: ${uri}`);
}
return {
contents: [
{
uri,
mimeType: 'text/markdown',
text: content,
},
],
};
}
module.exports = {
listResources,
readResource,
};
+4 -109
View File
@@ -20,8 +20,6 @@ const DEFAULT_LOG_PATHS = [
'\\\\{host}\\ProgramData\\Mecalux\\ETLLogs',
];
const LOG_FILE_PATTERN = process.env.LOG_FILE_PATTERN || '*.log';
/**
* Retourne les chemins de logs à scanner pour le profil actif.
* Substitue {host} par l'hostname du profil.
@@ -69,13 +67,13 @@ async function scanLogsRecursively(dir, fileList = []) {
});
} catch (statErr) {
// Ignorer les fichiers inaccessibles
console.error(`Cannot access file ${fullPath}: ${statErr.message}`);
console.error(`[Logs] Cannot access file ${fullPath}: ${statErr.message}`);
}
}
}
} catch (err) {
// Ne pas planter si un dossier n'existe pas ou n'est pas accessible
console.error(`Cannot scan directory ${dir}: ${err.message}`);
console.error(`[Logs] Cannot scan directory ${dir}: ${err.message}`);
}
return fileList;
@@ -163,7 +161,7 @@ async function resolveLogFilePath(logFile) {
try {
subEntries = await fs.readdir(basePath, { withFileTypes: true });
} catch (err) {
console.error(`Cannot read base log path ${basePath}: ${err.message}`);
console.error(`[Logs] Cannot read base log path ${basePath}: ${err.message}`);
}
const subDirs = subEntries.filter(e => e.isDirectory()).map(e => e.name);
@@ -286,7 +284,7 @@ async function searchLogs(keyword, maxResults = 50, contextLines = 2) {
}
} catch (readErr) {
// Ignorer les fichiers illisibles
console.error(`Cannot read file ${file.path}: ${readErr.message}`);
console.error(`[Logs] Cannot read file ${file.path}: ${readErr.message}`);
}
}
@@ -301,112 +299,9 @@ async function searchLogs(keyword, maxResults = 50, contextLines = 2) {
}
}
/**
* Recherche des erreurs dans les logs récents
* @param {number} maxResults - Nombre maximum de résultats
* @returns {Promise<Object>} - Erreurs trouvées
*/
async function findRecentErrors(maxResults = 20) {
const errorPatterns = ['error', 'exception', 'failed', 'fatal', 'critical'];
const allErrors = [];
try {
for (const pattern of errorPatterns) {
if (allErrors.length >= maxResults) break;
const results = await searchLogs(pattern, maxResults - allErrors.length, 1);
allErrors.push(...results.results);
}
// Dédupliquer par numéro de ligne et fichier
const unique = allErrors.filter(
(error, index, self) =>
index ===
self.findIndex(
(e) => e.fullPath === error.fullPath && e.lineNumber === error.lineNumber
)
);
return {
totalErrors: unique.length,
errors: unique.slice(0, maxResults),
};
} catch (err) {
throw new Error(`Failed to find errors: ${err.message}`);
}
}
/**
* Lit tout le contenu d'un fichier de log spécifique
* @param {string} logFilePath - Chemin complet du fichier
* @returns {Promise<Object>} - Contenu du fichier
*/
async function readFullLog(logFilePath) {
try {
const content = await fs.readFile(logFilePath, 'utf8');
const lines = content.split('\n').filter((line) => line.trim() !== '');
return {
file: path.basename(logFilePath),
fullPath: logFilePath,
totalLines: lines.length,
content: lines,
};
} catch (err) {
throw new Error(`Failed to read log file: ${err.message}`);
}
}
/**
* Obtient des statistiques sur les logs
* @returns {Promise<Object>} - Statistiques
*/
async function getLogStats() {
try {
const files = await listLogFiles();
const totalSize = files.reduce((sum, file) => sum + file.size, 0);
// Grouper par dossier
const byDirectory = {};
files.forEach(file => {
const dir = file.directory;
if (!byDirectory[dir]) {
byDirectory[dir] = {
directory: dir,
count: 0,
totalSize: 0,
files: [],
};
}
byDirectory[dir].count++;
byDirectory[dir].totalSize += file.size;
byDirectory[dir].files.push({
name: file.name,
sizeMB: (file.size / (1024 * 1024)).toFixed(2),
modified: file.modified.toISOString(),
});
});
return {
configuredPaths: getLogPaths(),
totalFiles: files.length,
totalSize,
totalSizeMB: (totalSize / (1024 * 1024)).toFixed(2),
oldestFile: files[files.length - 1]?.name,
newestFile: files[0]?.name,
byDirectory: Object.values(byDirectory).sort((a, b) => b.count - a.count),
};
} catch (err) {
throw new Error(`Failed to get log stats: ${err.message}`);
}
}
module.exports = {
listLogFiles,
findLatestLogFile,
readRecentLogs,
searchLogs,
findRecentErrors,
readFullLog,
getLogStats,
};
-1
View File
@@ -4,7 +4,6 @@
*/
const apiService = require('./api-service').getInstance();
const constants = require('../config/constants');
/**
* Build a LINQ select expression
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff