version mise à jour par claude , à tester

This commit is contained in:
Arthur Ria
2026-05-20 09:38:07 +02:00
commit b59cbb3546
58 changed files with 24548 additions and 0 deletions
+266
View File
@@ -0,0 +1,266 @@
/**
* API Resources
* Provides catalog of WMS APIs available
*/
function listResources() {
return [
{
uri: 'api://catalog',
name: 'API Catalog',
description: 'Catalog of WMS APIs available with parameters and documentation',
mimeType: 'text/markdown',
},
];
}
async function readResource(uri) {
let content;
switch (uri) {
case 'api://catalog':
content = getAPICatalog();
break;
default:
throw new Error(`Unknown API resource: ${uri}`);
}
return {
contents: [{
uri,
mimeType: 'text/markdown',
text: content,
}],
};
}
function getAPICatalog() {
return `# WMS API Catalog
## Overview
The WMS provides several REST APIs for querying and modifying data.
**Base URL:** \`${process.env.WMS_API_BASE_URL || 'https://10.255.255.2/ApplicationService/api'}\`
**Authentication:** OAuth 2.0 Bearer Token (automatic)
---
## Query API
Execute LINQ queries against WMS entities.
**Endpoint:** \`/api/QueryExecute\`
**Method:** POST
**Authentication:** Required
### Request Format
\`\`\`json
{
"Application": "EasyWMS",
"QueryType": 1,
"Expression": "Context.{EntityType}.Select(z => z)"
}
\`\`\`
### Supported Entity Types
| Entity Type | Description |
|-------------|-------------|
| Products | Product references and SKUs |
| Containers | Pallets, boxes, and container types |
| Stocks | Available inventory by location |
| ProductLocations | Product placement in warehouse |
| Tasks | WMS tasks (picks, puts, moves, etc.) |
| Accounts | Customer accounts |
| Suppliers | Supplier information |
| Kits | Product kits and bundles |
| Aliases | Product aliases and alternative codes |
| InboundOrders | Inbound/receiving orders |
| Receptions | Actual receptions |
| OutboundOrders | Outbound/shipping orders |
### Example Queries
\`\`\`
# Get all products (limited)
Context.Products.Take(100).Select(z => z)
# Get specific fields
Context.Products.Select(z => new { z.Id, z.Code, z.Name })
# Filter and select
Context.Tasks.Where(z => z.Status == "Pending").Take(50).Select(z => z)
\`\`\`
### MCP Tool
Use \`call_query_api\` tool to execute queries.
---
## Command API
Execute commands to modify WMS data.
**Endpoint:** \`/api/CommandExecute\`
**Method:** POST
**Authentication:** Required
### Request Format
\`\`\`json
[
{
"Name": "CommandName, Mecalux.ITSW.EasyWMS.Modules.Contracts",
"Properties": {
"PropertyName": "value"
}
}
]
\`\`\`
### Common Commands
| Command | Description |
|---------|-------------|
| ProductRemoveCommand | Remove a product |
| ProductUpdateCommand | Update product information |
| ContainerCreateCommand | Create a new container |
| TaskCancelCommand | Cancel a task |
| InboundOrderCancelCommandV2 | Cancel an inbound order |
| OutboundOrderCancelCommand | Cancel an outbound order |
### Example Command
\`\`\`json
[
{
"Name": "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.ProductRemoveCommand, Mecalux.ITSW.EasyWMS.Modules.Contracts",
"Properties": {
"Id": "product-guid-here"
}
}
]
\`\`\`
### MCP Tool
Use \`execute_command\` tool to execute commands.
**⚠️ WARNING:** Commands modify data. Use with caution.
---
## Workflow API
Retrieve workflow definitions by application.
**Endpoint:** \`/AD/api/Workflow/GetByApplication\`
**Method:** POST
**Authentication:** Required
### Request Format
\`\`\`json
["EasyWMS", "AD", 5000, 0]
\`\`\`
Parameters:
1. Application name (e.g., "EasyWMS")
2. Tenant code (e.g., "AD")
3. Page size (e.g., 5000)
4. Offset (e.g., 0 for first page)
### Response
Array of workflow objects with:
- Id, Code, Name
- Category, Description
- Version, Status
- Created, Modified
- Definition (JSON)
### MCP Tools
Use workflow tools to interact with workflows:
- \`search_workflows\` - Search by name, code, description
- \`get_workflow_details\` - Get full workflow definition
- \`list_workflow_categories\` - List all categories
---
## Authentication
All APIs use OAuth 2.0 authentication.
**Token Endpoint:** \`/EasySTS/OAuth/Token\`
**Grant Types:** password, refresh_token
### Token Management
- Tokens expire after ~1200 seconds
- Automatic refresh when < 1000 seconds remaining
- Credentials configured in .env file
The MCP server handles authentication automatically.
---
## Error Handling
### HTTP Status Codes
- \`200\` - Success
- \`400\` - Bad request (invalid query/command)
- \`401\` - Unauthorized (token expired or invalid)
- \`403\` - Forbidden (insufficient permissions)
- \`500\` - Internal server error
### Error Response Format
\`\`\`json
{
"error": "Error message",
"details": "Detailed error information"
}
\`\`\`
---
## Rate Limits and Constraints
- **Query Limit:** Maximum 1000 rows per query (configurable)
- **Query Timeout:** 30 seconds (configurable)
- **Workflow Cache:** 1 hour TTL (configurable)
---
## Configuration
API settings are configured via environment variables:
\`\`\`env
WMS_API_BASE_URL=https://10.255.255.2/ApplicationService/api
WMS_API_TOKEN_URL=https://10.255.255.2/EasySTS/OAuth/Token
WMS_API_TENANT=AD
WMS_API_USERNAME=your-username
WMS_API_PASSWORD=your-password
WORKFLOW_API_BASE=https://10.255.255.2/AD/api
WORKFLOW_PAGE_SIZE=5000
MAX_QUERY_ROWS=1000
QUERY_TIMEOUT=30000
\`\`\`
---
**Note:** Use MCP tools to interact with these APIs. Direct API calls require proper authentication handling.
`;
}
module.exports = {
listResources,
readResource,
};
+193
View File
@@ -0,0 +1,193 @@
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,
};
+156
View File
@@ -0,0 +1,156 @@
/**
* Entity Schema Resources
* Provides schema information for WMS entity types
*/
function listResources() {
return [
{
uri: 'wms://entity-schemas',
name: 'Entity Schemas',
description: 'Schema information and common fields for WMS entities',
mimeType: 'text/markdown',
},
];
}
async function readResource(uri) {
let content;
switch (uri) {
case 'wms://entity-schemas':
content = getEntitySchemas();
break;
default:
throw new Error(`Unknown entity schema resource: ${uri}`);
}
return {
contents: [{
uri,
mimeType: 'text/markdown',
text: content,
}],
};
}
function getEntitySchemas() {
return `# WMS Entity Schemas
## Overview
Entity schemas define the structure and available fields for each entity type.
Use the \`get_entity_schema\` tool to retrieve the actual schema from the API by querying one entity.
## Common Field Patterns
Most WMS entities follow these patterns:
### Standard Fields
- \`Id\` - Unique identifier (GUID or integer)
- \`Code\` - Business code/reference
- \`Name\` - Display name
- \`Description\` - Detailed description
- \`Created\` - Creation timestamp
- \`Modified\` - Last modification timestamp
- \`Status\` - Entity status
### Relationship Fields
- \`{Entity}Id\` - Foreign key to related entity (e.g., ProductId, AccountId)
- \`{Entity}Code\` - Related entity code
- \`{Entity}Name\` - Related entity name
## Entity-Specific Schemas
### Products
Common fields:
- Id, Code, Name, Description
- Category, Family, SubFamily
- Weight, Volume, Height, Width, Length
- UnitOfMeasure, BaseUnit
- Barcode, AlternativeCodes
- Active, Blocked
### Containers
Common fields:
- Id, Code, Name, Type
- Status, Location, Zone
- Weight, Tare, MaxWeight
- ProductId, Quantity
- Created, Modified
### Tasks
Common fields:
- Id, Code, Type, Status
- Priority, Sequence
- SourceLocation, TargetLocation
- ProductId, Quantity
- AssignedUser, AssignedDevice
- StartedAt, CompletedAt
### Stocks
Common fields:
- ProductId, ProductCode, ProductName
- LocationId, LocationCode
- Quantity, AvailableQuantity, ReservedQuantity
- UnitOfMeasure
- LotNumber, SerialNumber
- ExpirationDate
### InboundOrders / OutboundOrders
Common fields:
- Id, Code, ExternalCode
- Type, Status, Priority
- AccountId, AccountCode, AccountName
- SupplierId, SupplierCode (inbound only)
- ExpectedDate, PlannedDate, ActualDate
- TotalLines, TotalQuantity
- Created, Modified
## Retrieving Schemas
Use the \`get_entity_schema\` tool to dynamically retrieve the schema:
\`\`\`
# Get Products schema
get_entity_schema(entity_type="Products")
# Get Tasks schema
get_entity_schema(entity_type="Tasks")
\`\`\`
This will query one entity from the API and return all available fields with sample values.
## LINQ Field Selection
You can select specific fields using LINQ expressions:
\`\`\`
# Select specific fields
query_wms_entities(
entity_type="Products",
select_expression="z => new { z.Id, z.Code, z.Name, z.Category }"
)
# Nested object creation
query_wms_entities(
entity_type="Tasks",
select_expression="z => new {
Task = z.Code,
Product = z.ProductName,
Status = z.Status
}"
)
\`\`\`
---
**Note:** Field availability may vary depending on WMS configuration and version.
`;
}
module.exports = {
listResources,
readResource,
};
+295
View File
@@ -0,0 +1,295 @@
/**
* Logs Resources
* Provides guide for WMS log files
*/
function listResources() {
return [
{
uri: 'logs://guide',
name: 'Logs Guide',
description: 'Guide for WMS log files: formats, locations, common error patterns',
mimeType: 'text/markdown',
},
];
}
async function readResource(uri) {
let content;
switch (uri) {
case 'logs://guide':
content = getLogsGuide();
break;
default:
throw new Error(`Unknown logs resource: ${uri}`);
}
return {
contents: [{
uri,
mimeType: 'text/markdown',
text: content,
}],
};
}
function getLogsGuide() {
return `# WMS Logs Guide
## Log File Locations
**Primary Logs:** \`${process.env.LOGS_PATH || 'C:\\inetpub\\logs\\LogFiles\\Mecalux'}\`
Log files are typically named with date patterns:
- \`application_YYYYMMDD.log\`
- \`error_YYYYMMDD.log\`
- \`api_YYYYMMDD.log\`
---
## Log File Format
WMS logs typically follow this format:
\`\`\`
[YYYY-MM-DD HH:MM:SS.fff] [LEVEL] [Module] Message
Additional context or stack trace (if applicable)
\`\`\`
### Example Log Entries
\`\`\`
[2024-01-15 10:23:45.123] [INFO] [TaskService] Task TASK-001 created successfully
[2024-01-15 10:23:46.456] [ERROR] [StockService] Insufficient stock for product PROD-123
[2024-01-15 10:23:47.789] [WARN] [OrderService] Order ORD-456 delayed - expected date passed
\`\`\`
---
## Log Levels
| Level | Description | Severity |
|-------|-------------|----------|
| DEBUG | Detailed diagnostic information | Low |
| INFO | General informational messages | Low |
| WARN | Warning messages for potential issues | Medium |
| ERROR | Error messages for failures | High |
| FATAL | Critical errors causing system failure | Critical |
---
## Common Error Patterns
### Database Errors
\`\`\`
ORA-00001: unique constraint violated
ORA-01017: invalid username/password
ORA-12170: connection timeout
ORA-00060: deadlock detected
Connection timeout
Constraint violation
Foreign key violation
\`\`\`
### WMS Business Errors
\`\`\`
Insufficient stock
Stock not found
Product not found
Location occupied
Location not available
Task already completed
Order already processed
Invalid product code
Invalid container code
\`\`\`
### Integration Errors
\`\`\`
API call failed
Authentication failed
Token expired
Request timeout
JSON parse error
XML parse error
Connection refused
Service unavailable
\`\`\`
### System Errors
\`\`\`
Out of memory
OutOfMemoryException
StackOverflowException
File not found
Access denied
Permission denied
Disk full
Network unreachable
\`\`\`
---
## MCP Tools for Logs
### read_recent_logs
Read the most recent log entries from a log file.
**Parameters:**
- \`count\` - Number of lines to read (default: 100)
- \`log_file\` - Specific log file name (optional, uses most recent if not specified)
**Example:**
\`\`\`
read_recent_logs(count=200)
read_recent_logs(count=50, log_file="error_20240115.log")
\`\`\`
### search_logs
Search for a keyword across all log files with context.
**Parameters:**
- \`keyword\` - Search term (e.g., "ERROR", "PROD-123", "timeout")
- \`max_results\` - Maximum results to return (default: 50)
- \`context_lines\` - Lines of context before/after match (default: 2)
**Example:**
\`\`\`
search_logs(keyword="ERROR", max_results=100)
search_logs(keyword="PROD-123", context_lines=5)
search_logs(keyword="timeout", max_results=20)
\`\`\`
---
## Debugging Workflow
### 1. Check Recent Activity
Start by reading recent logs to understand current system state:
\`\`\`
read_recent_logs(count=200)
\`\`\`
### 2. Search for Errors
Look for error patterns:
\`\`\`
search_logs(keyword="ERROR", max_results=50)
search_logs(keyword="EXCEPTION", max_results=50)
search_logs(keyword="FAILED", max_results=50)
\`\`\`
### 3. Search for Specific Entity
Find references to specific orders, products, or tasks:
\`\`\`
search_logs(keyword="ORDER-123", context_lines=5)
search_logs(keyword="PROD-456", context_lines=5)
\`\`\`
### 4. Correlate with API/Database
Once you find relevant log entries:
- Use \`query_wms_entities\` to check current entity state
- Use \`search_workflows\` to find related workflows
- Use \`call_query_api\` to verify data consistency
---
## Log Analysis Tips
### Time-Based Analysis
Log timestamps help correlate events:
- Look for errors occurring at the same time
- Check for patterns (e.g., errors every hour, at specific times)
- Correlate with known system events (deployments, restarts)
### Frequency Analysis
- How often does this error occur?
- Is it increasing or decreasing over time?
- Does it happen at specific intervals?
### Context Analysis
Always request context lines when searching:
- See what happened before the error
- See what happened after the error
- Understand the execution flow
### Pattern Recognition
Look for common patterns:
- Same error message repeatedly
- Same product/order/task in multiple errors
- Same module or service causing issues
- Cascading failures (one error leading to others)
---
## Common Debugging Scenarios
### Scenario 1: Order Not Processing
\`\`\`
1. search_logs(keyword="ORDER-123", context_lines=5)
2. query_wms_entities(entity_type="OutboundOrders", filter='z.Code == "ORDER-123"')
3. Check order status and error messages in both logs and database
\`\`\`
### Scenario 2: Stock Discrepancy
\`\`\`
1. search_logs(keyword="PROD-456", context_lines=3)
2. query_wms_entities(entity_type="Stocks", filter='z.ProductCode == "PROD-456"')
3. Compare expected vs actual stock levels
4. Check for stock movement tasks
\`\`\`
### Scenario 3: Task Failures
\`\`\`
1. search_logs(keyword="TASK-789", context_lines=5)
2. query_wms_entities(entity_type="Tasks", filter='z.Code == "TASK-789"')
3. Check task status, error message, and assigned user/device
\`\`\`
### Scenario 4: Performance Issues
\`\`\`
1. search_logs(keyword="timeout", max_results=100)
2. search_logs(keyword="slow", max_results=100)
3. Look for patterns in timeouts (specific operations, times, modules)
\`\`\`
---
## Log Retention
- Log files are typically rotated daily
- Older logs may be compressed or archived
- Check with system administrator for retention policy
---
**Note:** Use log tools in combination with WMS entity queries for complete debugging picture.
`;
}
module.exports = {
listResources,
readResource,
};
+266
View File
@@ -0,0 +1,266 @@
/**
* Query Examples Resources
* Provides example LINQ queries and diagnostic recipes for WMS entities.
*/
function listResources() {
return [
{
uri: 'wms://query-examples',
name: 'Query Examples',
description: 'LINQ query examples and diagnostic recipes for WMS entities',
mimeType: 'text/markdown',
},
];
}
async function readResource(uri) {
let content;
switch (uri) {
case 'wms://query-examples':
content = getQueryExamples();
break;
default:
throw new Error(`Unknown query examples resource: ${uri}`);
}
return {
contents: [{
uri,
mimeType: 'text/markdown',
text: content,
}],
};
}
function getQueryExamples() {
return `# WMS LINQ Query Examples & Diagnostic Recipes
> **Reading model** — \`query_wms_entities\` / \`count_wms_entities\` use \`QueryExecute\`
> (QueryType=Reading). Status/enum fields are **strings** (enum names), never integers.
> Always verify enum values via \`docs://entities/\` or \`get_entity_metadata\` before filtering.
---
## Diagnostic Recipes
Recipes below were validated against a live WMS. Use them as-is, substituting the
\`X\` placeholders.
### OS incomplètes par classe d'expédition
Compter les ordres de sortie incomplets, actifs, d'une classe donnée
(\`OutboundClassCode\`). Fields verified on the \`OutboundOrder\` Reading entity:
\`OutboundClassCode\` (string), \`IncompleteOrder\` (bool), \`IsActive\` (bool).
\`\`\`
# Toutes classes confondues
count_wms_entities(
entity_type="OutboundOrders",
filter='z.IncompleteOrder == true && z.IsActive == true'
)
# Pour une classe précise
count_wms_entities(
entity_type="OutboundOrders",
filter='z.OutboundClassCode == "SHIPPING_GROUP_01" && z.IncompleteOrder == true && z.IsActive == true'
)
# Lister le détail des OS concernées
query_wms_entities(
entity_type="OutboundOrders",
filter='z.OutboundClassCode == "SHIPPING_GROUP_01" && z.IncompleteOrder == true && z.IsActive == true',
limit=200
)
\`\`\`
### Containers bloquants sur un emplacement
Identifier les conteneurs qui retiennent un emplacement parce qu'ils ont des tâches
en attente. Fields verified on the \`Container\` Reading entity:
\`LocationCode\` (string), \`NumContainerPendingTasks\` (long).
\`\`\`
# Combien de containers ont des tâches en attente sur l'emplacement
count_wms_entities(
entity_type="Containers",
filter='z.LocationCode == "QUAI_EXP_01" && z.NumContainerPendingTasks > 0'
)
# Lister ces containers (renvoie toutes les colonnes du container)
query_wms_entities(
entity_type="Containers",
filter='z.LocationCode == "QUAI_EXP_01" && z.NumContainerPendingTasks > 0',
limit=200
)
# Vue globale : tous les containers bloquants du WMS
count_wms_entities(
entity_type="Containers",
filter='z.NumContainerPendingTasks > 0'
)
\`\`\`
### Paramètres système d'un entrepôt
Pour lire les paramètres de configuration WMS et leurs valeurs par entrepôt,
utiliser l'outil dédié \`get_system_parameters\` plutôt qu'une requête LINQ :
\`\`\`
get_system_parameters(warehouse="DOMBASLE") # tous les paramètres
get_system_parameters(warehouse="DOMBASLE", param_class="Shipping")
get_system_parameters(search="CROSSDOCK")
\`\`\`
### Modèles d'expédition — suivi des exécutions
> ⚠️ L'API ne conserve que la **dernière** exécution de chaque modèle d'expédition
> (\`ShipmentTemplate.LastExecuteDate\`). L'historique complet des exécutions n'existe
> que dans les logs serveur \`ApplyShipmentTemplates\`, non exposés par ce MCP.
Fields verified on the \`ShipmentTemplate\` Reading entity: \`Code\`, \`Status\`,
\`IsEnabled\`, \`IsActive\`, \`LastExecuteDate\`, \`WarehouseCode\`, \`Priority\`,
\`DirectiveCode\`.
\`\`\`
# Tous les modèles d'un entrepôt + leur dernière exécution et leur statut
query_wms_entities(
entity_type="ShipmentTemplates",
filter='z.WarehouseCode == "DOMBASLE"',
limit=200
)
# Modèles activés mais jamais exécutés (LastExecuteDate null)
query_wms_entities(
entity_type="ShipmentTemplates",
filter='z.IsEnabled == true && z.LastExecuteDate == null',
limit=200
)
# Combien de modèles exécutés au moins une fois
count_wms_entities(
entity_type="ShipmentTemplates",
filter='z.LastExecuteDate != null'
)
# Modèles exécutés depuis une date (littéral DateTime obligatoire — voir Date filters)
count_wms_entities(
entity_type="ShipmentTemplates",
filter='z.LastExecuteDate >= new DateTime(2025, 1, 1)'
)
\`\`\`
---
## Counting (\`count_wms_entities\`)
Always prefer \`count_wms_entities\` for any "combien" / "how many" question — it uses
\`QueryScalarExecute\` and never materialises rows.
\`\`\`
count_wms_entities(entity_type="OutboundOrders")
count_wms_entities(entity_type="Tasks", filter='z.TaskStatus == "InProcess"')
\`\`\`
---
## Basic Queries
### Get rows (with limit)
\`\`\`
query_wms_entities(entity_type="Products", limit=100)
query_wms_entities(entity_type="Tasks", limit=50)
\`\`\`
> Note: the \`select_expression\` parameter (LINQ projections) is currently unreliable
> against \`QueryExecute\` — prefer querying full rows and reading the fields you need.
## Filtering Examples
### Status filters (string enum names)
\`\`\`
# Tâches en cours / en attente
query_wms_entities(entity_type="Tasks", filter='z.TaskStatus == "InProcess"', limit=100)
query_wms_entities(entity_type="Tasks", filter='z.TaskStatus == "Pending"', limit=100)
# Ordres de sortie lancés
query_wms_entities(entity_type="OutboundOrders", filter='z.OutboundOrderStatus == "Release"', limit=100)
\`\`\`
### Date filters
> ⚠️ \`AddDays()\` et les dates relatives (\`DateTime.Now\`, \`DateTime.Today\`) ne sont
> **pas traduisibles** par le moteur de requête — toujours utiliser un littéral
> \`new DateTime(année, mois, jour)\`. Le nom du champ date dépend de l'entité
> (\`LastExecuteDate\`, \`InternalInfo.CreationDate\`, …) — le vérifier via
> \`get_entity_metadata\` ou \`docs://entities/\`.
\`\`\`
# Éléments depuis une date donnée (littéral DateTime obligatoire)
count_wms_entities(
entity_type="ShipmentTemplates",
filter='z.LastExecuteDate >= new DateTime(2025, 1, 1)'
)
\`\`\`
### Numeric filters
\`\`\`
query_wms_entities(entity_type="Stocks", filter="z.Quantity > 0", limit=100)
\`\`\`
### String filters
\`\`\`
query_wms_entities(entity_type="Products", filter='z.Code.StartsWith("ABC")', limit=100)
query_wms_entities(entity_type="Products", filter='z.Code.Contains("test")', limit=100)
\`\`\`
## Complex Filters
### Multiple conditions (AND / OR)
\`\`\`
query_wms_entities(
entity_type="Tasks",
filter='z.TaskStatus == "Pending" && z.Priority > 50',
limit=100
)
query_wms_entities(
entity_type="OutboundOrders",
filter='z.OutboundOrderStatus == "Release" || z.OutboundOrderStatus == "Creating"',
limit=100
)
\`\`\`
## Common Patterns
### Find an entity by code
\`\`\`
query_wms_entities(entity_type="Products", filter='z.Code == "PROD123"', limit=1)
query_wms_entities(entity_type="OutboundOrders", filter='z.Code == "ORDER123"', limit=1)
\`\`\`
## Performance Tips
1. **Always use limits** — max 1000 rows per query.
2. **Use \`count_wms_entities\` for counts** — never fetch rows just to count them.
3. **Verify enum values first** — Reading model uses string enum names.
4. **Use specific filters** — narrow results at the API level.
---
**Note:** All queries respect the maximum limit of 1000 rows configured in the server.
`;
}
module.exports = {
listResources,
readResource,
};
+141
View File
@@ -0,0 +1,141 @@
/**
* WMS Entity Resources
* Provides overview of WMS entity types available via Query API
*/
function listResources() {
return [
{
uri: 'wms://entities',
name: 'WMS Entities Overview',
description: 'Overview of all WMS entity types available for querying',
mimeType: 'text/markdown',
},
];
}
async function readResource(uri) {
let content;
switch (uri) {
case 'wms://entities':
content = getEntitiesOverview();
break;
default:
throw new Error(`Unknown WMS entity resource: ${uri}`);
}
return {
contents: [{
uri,
mimeType: 'text/markdown',
text: content,
}],
};
}
function getEntitiesOverview() {
return `# WMS Entities — Reference Guide
## Tools to use
- **\`count_wms_entities\`** — count with optional filter (use for "combien", "nombre de")
- **\`query_wms_entities\`** — fetch rows with select/filter/limit
- **\`get_entity_schema\`** — discover field names by fetching one sample record
- **\`call_query_api\`** — raw LINQ query, full control
---
## Note importante : Reading model vs Writing model
Le \`QueryExecute\` (Context.*) interroge le **Reading model** — les champs de statut sont des **strings**, pas des entiers ni des enums C#.
---
## OutboundOrders — Ordres de sortie
**Reading model:** \`Mecalux.ITSW.EasyWMS.Modules.Expeditions.Reading.Domain.OutboundOrder\`
**Status field:** \`OutboundOrderStatus\` → **string**
| Statut | Filtre LINQ |
|---|---|
| Lancé | \`z.OutboundOrderStatus == "Launched"\` |
| En attente | \`z.OutboundOrderStatus == "Waiting"\` |
| En création | \`z.OutboundOrderStatus == "Creating"\` |
**Champs clés :** \`Code\`, \`OutboundOrderStatus\`, \`WarehouseCode\`, \`AccountCode\`, \`RouteCode\`, \`Priority\`, \`AssignedUser\`, \`NumPendingTasks\`, \`NumReleasedLines\`, \`HasTroubles\`, \`ShippingDeadline\`
**Exemples:**
\`\`\`
// Compter les ODS lancés
count_wms_entities(entity_type="OutboundOrders", filter='z.OutboundOrderStatus == "Launched"')
// Lister les ODS lancés avec infos clés
query_wms_entities(entity_type="OutboundOrders",
select_expression="z => new { z.Code, z.OutboundOrderStatus, z.AccountCode, z.NumPendingTasks, z.HasTroubles }",
filter='z.OutboundOrderStatus == "Launched"', limit=100)
\`\`\`
---
## InboundOrders — Ordres d'entrée
**Status field:** \`InboundStatus\` → **string**
| Statut | Filtre LINQ |
|---|---|
| Réception en attente | \`z.InboundStatus == "ReceptionPending"\` |
| Réception en cours | \`z.InboundStatus == "Receiving"\` |
| Complété | \`z.InboundStatus == "Completed"\` |
| Reçu partiellement | \`z.InboundStatus == "PartiallyReceived"\` |
| Annulé | \`z.InboundStatus == "Cancelled"\` |
| Fermeture | \`z.InboundStatus == "Closing"\` |
---
## Tasks — Tâches
**Status field:** \`TaskStatus\` → **string** (valeurs à confirmer via get_entity_schema)
\`\`\`
// Schéma exact avec valeurs d'exemple
get_entity_schema(entity_type="Tasks")
\`\`\`
---
## Kits
\`\`\`
count_wms_entities(entity_type="Kits", filter="z.IsEnable == true")
\`\`\`
---
## Autres entités disponibles (Reading model, 278 au total)
**Opérations :** Tasks, Stocks, ProductLocations, ContainerLock, CountOrder, CountOrderLine
**Entrepôt :** Location, Aisle, AisleType, Division, Container, ContainerType
**Entrées :** InboundOrders, Receptions, InboundClass
**Sorties :** OutboundOrders, Shipment, OutboundClass, Wave
**Référentiel :** Products, Accounts, Suppliers, Kits, Aliases, Agency, Route
**Pour connaître les champs exacts d'une entité :**
1. \`get_entity_metadata(entity_name="...")\` — métadonnées officielles via l'API
2. \`get_entity_schema(entity_type="...")\` — exemple live avec tous les champs
---
## Note sur \`Take()\`
Certaines entités (dont OutboundOrders) peuvent retourner HTTP 500 si \`Take()\` est ajouté.
- **count_wms_entities** n'utilise jamais \`Take()\` → toujours sûr
- **query_wms_entities** utilise \`Take(limit)\` → préférer une limite raisonnable (100-500)
`;
}
module.exports = {
listResources,
readResource,
};
+96
View File
@@ -0,0 +1,96 @@
/**
* Workflow Resources
* Provides context about workflows available via API
*/
function listResources() {
return [
{
uri: 'workflows://overview',
name: 'Workflow Overview',
description: 'Overview of workflow system and available categories',
mimeType: 'text/markdown',
},
];
}
async function readResource(uri) {
let content;
switch (uri) {
case 'workflows://overview':
content = getWorkflowOverview();
break;
default:
throw new Error(`Unknown workflow resource: ${uri}`);
}
return {
contents: [{
uri,
mimeType: 'text/markdown',
text: content,
}],
};
}
function getWorkflowOverview() {
return `# WMS Workflows
## Overview
Workflows are retrieved via the **Workflow API** (\`/AD/api/Workflow/GetByApplication\`).
**Total Workflows:** ~3712
**Data Source:** API endpoint (lazy loaded with 1-hour cache)
**Pagination:** Configurable page size (default: 5000)
## Available Tools
Use these tools to interact with workflows:
### \`search_workflows\`
Search workflows by name, description, or code.
- Supports category filtering
- Returns workflow metadata
- Workflows are cached after first request
### \`get_workflow_details\`
Get complete details of a specific workflow by ID or code.
### \`list_workflow_categories\`
List all available workflow categories with statistics.
## Common Workflow Categories
- **EasyWMS**: Core WMS workflows
- **CustomApplication**: Custom workflows
- **Deliveries**: Delivery and shipping workflows
- **AccountDirective**: Account management workflows
- **Notifications**: Notification workflows
- **LaborManagement**: Labor management workflows
## Usage Examples
\`\`\`
# Search for order-related workflows
search_workflows(query="Order", limit=20)
# Get workflow details
get_workflow_details(workflow_id="abc123")
# List all categories
list_workflow_categories()
\`\`\`
---
**Note:** Workflows are fetched from the API only when first requested, then cached for 1 hour to improve performance.
`;
}
module.exports = {
listResources,
readResource,
};