31 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Goal: Create an MCP (Model Context Protocol) server that allows Claude to interact with a WMS (Warehouse Management System) for debugging and analysis purposes.
Current Status: ✅ Implementation complete and functional - API-only architecture
Implementation Progress:
- ✅ Project planning completed
- ✅ CLAUDE.md documentation created
- ✅ Node.js and npm installed on system
- ✅ Architecture finalized (100% API, no direct Oracle access)
- ✅ Services and tools implemented
- ✅ API connectivity tested and validated
- ✅ OAuth authentication working (with tenant_code fix)
- ✅ Workflow fetching operational (entities extraction fix)
- ✅ Application Dictionary API implemented (20 element types, 38,765 elements)
- ✅ AD API endpoints validated with curl (17/19 working, 2 removed)
- ✅ Claude Desktop integration successful
Required Information:
- 🌐 WMS API Configuration:
- Server IP address:
10.255.255.2 - Tenant code (configurable in .env)
- Username and password for API access
- Server IP address:
- 📁 File Paths:
- Log files directory path (e.g.,
C:\WMS\Logs) - Deployment directory on VM (e.g.,
C:\WMS\mcp)
- Log files directory path (e.g.,
Target Architecture:
- MCP Server: Node.js executable running on Windows Server VM
- Data Access: 100% via WMS REST APIs (no direct Oracle connection)
- Query API:
/ApplicationService/api/QueryExecute(LINQ queries) - Command API:
/ApplicationService/api/CommandExecute(WMS commands) - Workflow API:
/AD/api/Workflow/GetByApplication(workflows with pagination) - Application Dictionary API:
/AD/api/{ElementType}/GetByApplication(20 element types: Commands, Queries, Dialogs, Views, Entities, Events, etc.)
- Query API:
- Authentication: OAuth 2.0 with automatic token refresh
- Connection: Claude Desktop (PC) → Local or SSH → MCP Server
Quick Start
1. Install Dependencies
npm install
2. Configure Environment
Copy .env.example to .env and configure. The server supports multiple WMS profiles (AD, LIMAGRAIN, etc.) and Claude switches between them at runtime:
# Shared settings (same for all profiles)
WMS_API_AUTH=Basic R05BOklFNGU3aXFoZHQ=
WMS_APPLICATION=EasyWMS
WMS_API_PATH=/ApplicationService/api
WMS_TOKEN_PATH=/EasySTS/OAuth/Token
WORKFLOW_API_PATH=/AD/api
# Profile registry
WMS_PROFILES=AD,LIMAGRAIN
DEFAULT_WMS_PROFILE=AD
# Profile: AD (on-premise — logs accessible)
AD_HOST=10.255.255.2
AD_USERNAME=your-ad-username
AD_PASSWORD=your-ad-password
AD_TENANT=AD
AD_SAAS=false
# Profile: LIMAGRAIN (on-premise — logs accessible)
LIMAGRAIN_HOST=10.255.255.2
LIMAGRAIN_USERNAME=your-limagrain-username
LIMAGRAIN_PASSWORD=your-limagrain-password
LIMAGRAIN_TENANT=LIMAGRAI2512
LIMAGRAIN_SAAS=false
# Logs — {host} is substituted with the active profile's HOST
LOGS_PATH=\\{host}\inetpub\logs\LogFiles\Mecalux;\\{host}\ProgramData\Mecalux\ETLLogs
WORKFLOW_PAGE_SIZE=5000
Adding a new profile:
- Add its name to
WMS_PROFILES(comma-separated). - Define
<NAME>_HOST,<NAME>_USERNAME,<NAME>_PASSWORD,<NAME>_TENANT. - The full URLs are built as
https://<HOST><WMS_API_PATH>etc. — no need to repeat URLs per profile.
Switching profiles at runtime (in Claude Desktop):
- "Quels WMS sont configurés ?" → calls
list_wms_profiles - "Connecte-toi au WMS LIMAGRAIN" → calls
switch_wms_profilewithprofile: "LIMAGRAIN" - The OAuth token is reset and workflow/AD caches cleared automatically on switch.
3. Configure Claude Desktop
Edit %APPDATA%\Claude\claude_desktop_config.json:
{
"mcpServers": {
"wms": {
"command": "node",
"args": [
"c:\\path\\to\\wms-mcp-server\\src\\index.js"
]
}
}
}
4. Restart Claude Desktop
Close and reopen Claude Desktop completely. The MCP server will start automatically.
5. Test
In Claude Desktop, try:
- Workflows: "Search for workflows containing 'Order'"
- WMS Queries: "Query the last 10 products"
- AD Elements: "Get all Query elements" or "Search Commands containing 'Product'"
- Logs: "Show me recent log entries"
- Summary: "Get application summary" (shows cached AD element counts)
Existing Files
- CLAUDE.md - This file (project guidance and implementation plan)
- [queries api.php](queries api.php) - Reference PHP file showing WMS API interaction patterns
Understanding the WMS API from queries api.php
The PHP file demonstrates the EasyWMS API structure:
Authentication:
- OAuth 2.0 token-based authentication
- Endpoint:
https://{ip}/EasySTS/OAuth/Token - Supports both password and refresh_token grant types
- Token refresh required after ~1000 seconds (hardcoded in PHP)
Query API:
- Endpoint:
https://{ip}/ApplicationService/api/QueryExecute - Uses LINQ-like expression syntax:
Context.{Type}.Select(z => z.Id) - Supported entity types: Containers, Stocks, ProductLocations, Tasks, Products, Accounts, Suppliers, Kits, Aliases, InboundOrders, Receptions, OutboundOrders
Command API:
- Endpoint:
https://{ip}/ApplicationService/api/CommandExecute - Command structure includes fully qualified .NET class names
- Example:
Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.ProductRemoveCommand
Workflow API:
- Endpoint:
POST https://{ip}/AD/api/Workflow/GetByApplication - Request body:
["EasyWMS", "AD", 5000, 0](application, tenant, pageSize, offset) - Returns workflow definitions with pagination
- Total workflows: ~3712 (can be fetched with higher page size to reduce API calls)
- Lazy loading: Workflows are only fetched when MCP receives a workflow-related request
Application Dictionary API:
- Endpoint pattern:
POST https://{ip}/AD/api/{ElementType}/GetByApplication - Request body:
["EasyWMS", "AD", pageSize, offset] - Response structure:
{entities: [...]} - Supported element types (20): Command, Query, Dialog, View, Entity, Event, FieldType, Hook, List, Record, Relationship, Report, Resource, Subscription, TimelineTemplate, Toggle, Validator, ViewGroup, Workflow, Dashboard
- Total elements: ~38,765 across all types
- Validated with curl: 17/19 types working (WorkflowAction and WritingModel return 404)
- Lazy loading + caching: Each element type loaded on first request, cached for 1 hour
- Test results: See AD_API_TEST_RESULTS.md for detailed validation
Project Structure
wms-mcp-server/
├── src/
│ ├── index.js # Main MCP server entry point
│ ├── resources/ # MCP resources (read-only data)
│ │ ├── wms-entities.js # WMS entities catalog
│ │ ├── entity-schemas.js # Entity schemas details
│ │ ├── query-examples.js # LINQ query examples + diagnostic recipes
│ │ ├── workflows.js # Workflow catalog overview
│ │ ├── apis.js # API documentation
│ │ └── logs.js # Log file guide
│ ├── tools/ # MCP tools (actions)
│ │ ├── wms-query-tools.js # query_wms_entities, count_wms_entities, get_entity_schema, search_wms_data
│ │ ├── workflow-tools.js # search_workflows, get_workflow_details, list_workflow_categories
│ │ ├── ad-tools.js # get_ad_elements, search_ad_elements, get_ad_element_details (5 tools)
│ │ ├── api-tools.js # call_query_api, execute_command
│ │ ├── metadata-tools.js # get_entity_metadata, generic_search
│ │ ├── config-tools.js # get_system_parameters (Parameter + ParamValue merge)
│ │ ├── profile-tools.js # list_wms_profiles, get_current_wms_profile, switch_wms_profile
│ │ └── log-tools.js # read_recent_logs, list_log_files, search_logs
│ ├── services/ # Business logic
│ │ ├── api-service.js # OAuth + HTTP client (ApplicationService + AD APIs)
│ │ ├── workflow-service.js # Workflow fetching with cache (lazy loading)
│ │ ├── ad-service.js # Application Dictionary elements (20 types, lazy loading + cache)
│ │ ├── wms-query-service.js # LINQ query builder helper
│ │ └── log-service.js # Log file reading & searching
│ └── config/
│ ├── constants.js # Constants and entity type definitions
│ └── profile-manager.js # Multi-profile registry (AD, LIMAGRAIN, ...) + runtime switching
├── .env.example
├── package.json
└── README.md
Development Setup
Initial Setup
# Initialize project
npm init -y
# Install dependencies
npm install @modelcontextprotocol/sdk dotenv axios
npm install --save-dev @types/node typescript
Environment Configuration
Create .env file (use .env.example as template):
# Logs Configuration
LOGS_PATH=C:\WMS\Logs
LOG_FILE_PATTERN=application*.log
# WMS API Configuration
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_AUTH=Basic R05BOklFNGU3aXFoZHQ=
WMS_API_USERNAME=your_username
WMS_API_PASSWORD=your_password
WMS_API_TENANT=AD
# Workflow API Configuration
WORKFLOW_API_BASE=https://10.255.255.2/AD/api
WORKFLOW_APPLICATION=EasyWMS
WORKFLOW_PAGE_SIZE=5000
# Cache Configuration
WORKFLOW_CACHE_TTL=3600
Common Commands
# Run MCP server locally
npm start
# Test API connection
node test-api.js
# Build Windows executable
npm run build
# or
pkg . --targets node18-win-x64 --output dist/mcp-server.exe
# Run tests (once implemented)
npm test
Implementation Guide
Phase 1: API Service (src/services/api-service.js)
Required Methods:
authenticate()- Get OAuth token with username/passwordrefreshToken()- Refresh OAuth token before expirationpost(endpoint, data)- Generic POST request with automatic token managementget(endpoint, params)- Generic GET request with automatic token management
Token Management Strategy:
- Check token age before each request
- Auto-refresh if age > 1000 seconds (token lifetime ~1200s)
- Support both password and refresh_token grant types
Test Script:
// test-api.js
const apiService = require('./src/services/api-service');
async function test() {
await apiService.authenticate();
const result = await apiService.post('/QueryExecute', {
Application: "EasyWMS",
QueryType: 1,
Expression: "Context.Products.Select(z => new { z.Id }).Take(1)"
});
console.log('API connection OK:', result);
}
test();
Phase 2: MCP Resources (Read-Only Context for Claude)
Resources provide Claude with background knowledge without explicit queries:
wms://entities- List of WMS entities available via Query API (Containers, Stocks, Tasks, etc.)wms://entity-schemas- Detailed schemas for top 15 critical entitieswms://query-examples- LINQ query examples for common use casesworkflows://overview- Workflow statistics, categories, and top workflowsworkflows://categories- Complete list of workflow categoriesapi://catalog- List of available WMS APIs with parameterslogs://guide- Log file format, locations, common error patterns
All resources should return markdown-formatted content.
Phase 3: MCP Tools (Executable Actions)
WMS Query Tools:
query_wms_entities(entity_type, select_expression, filter, limit)- Query WMS entities via LINQ (max 1000 rows)count_wms_entities(entity_type, filter)- Count entities via QueryScalarExecute (preferred for "how many")get_entity_schema(entity_type)- Get available fields for an entitysearch_wms_data(keyword, entity_types, limit)- Search across multiple entities
Workflow Tools:
search_workflows(query, category, limit)- Search workflows (lazy loaded with cache)get_workflow_details(workflow_id)- Retrieve full workflow JSONlist_workflow_categories()- List all workflow categories
API Tools:
call_query_api(entity_type, expression, filter, limit)- Execute custom LINQ queriesexecute_command(command_name, properties)- Execute WMS commands
Metadata Tools:
get_entity_metadata(entity_name)- List queryable entities + their field names/typesgeneric_search(query, categories, limit)- Full-text search across indexed WMS documents
Config Tools:
get_system_parameters(warehouse, param_class, search, only_overridden)- WMS configuration parameters with per-warehouse effective values (mergesParameter+ParamValueReading entities)
Log Tools:
read_recent_logs(count, log_file)- Tail recent log entrieslist_log_files()- List available log filessearch_logs(keyword, max_results)- Search logs with context
Phase 4: Main Server (src/index.js)
Use the MCP SDK to create the server:
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = new Server({
name: 'wms-mcp-server',
version: '1.0.0',
}, {
capabilities: {
resources: {},
tools: {},
},
});
// Implement handlers for:
// - resources/list
// - resources/read
// - tools/list
// - tools/call
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('WMS MCP Server running'); // Use stderr, not stdout
}
main();
Critical: Use console.error() for all logging. Stdout is reserved for MCP protocol communication.
Phase 5: Workflow Service (src/services/workflow-service.js)
Lazy Loading Strategy:
let workflowCache = null;
let cacheTimestamp = null;
const CACHE_TTL = process.env.WORKFLOW_CACHE_TTL || 3600000; // 1 hour
async function fetchAllWorkflows() {
// Check cache validity
const now = Date.now();
if (workflowCache && (now - cacheTimestamp) < CACHE_TTL) {
console.error('[Workflow] Using cached data');
return workflowCache;
}
// Fetch from API with high page size to minimize calls
console.error('[Workflow] Fetching from API...');
const apiService = require('./api-service');
let allWorkflows = [];
let offset = 0;
const pageSize = parseInt(process.env.WORKFLOW_PAGE_SIZE) || 5000;
while (true) {
const endpoint = '/AD/api/Workflow/GetByApplication';
const body = [
process.env.WORKFLOW_APPLICATION || "EasyWMS",
process.env.WMS_API_TENANT || "AD",
pageSize,
offset
];
const response = await apiService.post(endpoint, body, true); // true = use AD API base
if (!response || response.length === 0) break;
allWorkflows = allWorkflows.concat(response);
console.error(`[Workflow] Fetched ${response.length} workflows (total: ${allWorkflows.length})`);
if (response.length < pageSize) break; // Last page
offset += pageSize;
}
// Cache results
workflowCache = allWorkflows;
cacheTimestamp = now;
console.error(`[Workflow] Cached ${allWorkflows.length} workflows`);
return allWorkflows;
}
Key Features:
- Only fetches workflows when needed (first workflow-related request)
- Uses high page size (5000) to reduce API calls
- Caches results for 1 hour (configurable)
- Automatic pagination if needed
Phase 6: WMS API Client Details (src/services/api-service.js)
Based on the PHP reference file:
Token Management:
async function refreshToken() {
// Check if token age > 1000 seconds
// If < 1190s: use refresh_token grant
// If >= 1190s: use password grant
// Store new token and refresh_token
}
Query Execution:
async function executeQuery(entityType, expression) {
await ensureTokenValid();
const query = {
Application: "EasyWMS",
QueryType: 1,
Expression: `Context.${entityType}.Select(${expression})`
};
// POST to /api/QueryExecute with Bearer token
}
Command Execution:
async function executeCommand(commandName, properties) {
await ensureTokenValid();
const command = [{
Name: `${commandName}, Mecalux.ITSW.EasyWMS.Modules.Contracts`,
Properties: properties
}];
// POST to /api/CommandExecute with Bearer token
}
Phase 7: Error Handling
Wrapper for All Tools:
async function safeToolCall(toolFn, args) {
try {
const result = await toolFn(args);
return {
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }]
};
} catch (error) {
console.error('Tool error:', error);
return {
content: [{ type: 'text', text: `Error: ${error.message}` }],
isError: true
};
}
}
Deployment
Build Windows Executable
Add to package.json:
{
"bin": "src/index.js",
"pkg": {
"targets": ["node18-win-x64"],
"outputPath": "dist"
}
}
Build:
npm install -g pkg
pkg . --output dist/mcp-server.exe
SSH Configuration
On Windows Server VM:
# Install OpenSSH Server
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'
New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server' `
-Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
# Configure authorized_keys
mkdir C:\Users\YourUser\.ssh
# Copy public key to C:\Users\YourUser\.ssh\authorized_keys
icacls C:\Users\YourUser\.ssh\authorized_keys /inheritance:r
icacls C:\Users\YourUser\.ssh\authorized_keys /grant:r "YourUser:F"
On Development PC:
# Generate SSH key
ssh-keygen -t ed25519 -C "claude-mcp"
# Add to ~/.ssh/config
Host vm-wms
HostName 192.168.x.x
User your-username
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 60
ServerAliveCountMax 3
# Test connection
ssh vm-wms echo "Connection OK"
Deploy to VM
- Copy
mcp-server.exetoC:\WMS\mcp\ - Create
C:\WMS\mcp\.envwith production credentials - Test:
ssh vm-wms "C:\WMS\mcp\mcp-server.exe"
Claude Desktop Configuration
Edit %APPDATA%\Claude\claude_desktop_config.json:
{
"mcpServers": {
"wms": {
"command": "ssh",
"args": ["vm-wms", "C:\\WMS\\mcp\\mcp-server.exe"]
}
}
}
Restart Claude Desktop after configuration changes.
Testing
Manual Tests (After Implementation)
- List resources: "Show me available resources"
- Read WMS entities: "What entities are available in the WMS?"
- Search workflows: "Find workflows related to orders"
- Query WMS data: "Query the last 10 products"
- Read logs: "Show me the last 50 log lines"
- Check workflow cache: "Search for workflows containing 'picking'"
Debugging
MCP Server Logs:
- All
console.error()output appears in Claude Desktop logs - Location:
%APPDATA%\Claude\logs\
Manual MCP Testing:
# Test server directly via SSH
ssh vm-wms "C:\WMS\mcp\mcp-server.exe" < test-request.json
# Test API connectivity
curl -X POST "https://10.255.255.2/EasySTS/OAuth/Token" \
-H "Authorization: Basic R05BOklFNGU3aXFoZHQ=" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password&username=XXX&password=XXX"
Multi-Profile Architecture
The server connects to different WMS backends (tenants/customers) via profiles defined in .env. Each profile has its own host, credentials, and tenant. Claude selects which profile to use at runtime.
.env layout
Shared settings (same across all profiles):
WMS_API_AUTH— OAuth client Basic auth headerWMS_APPLICATION— Application name (e.g.EasyWMS)WMS_API_PATH,WMS_TOKEN_PATH,WORKFLOW_API_PATH— URL path components
Profile registry:
WMS_PROFILES— comma-separated profile names (e.g.AD,LIMAGRAIN)DEFAULT_WMS_PROFILE— profile active at startup (optional)
Per profile (prefixed by profile name):
<NAME>_HOST— hostname or IP (e.g.10.255.255.2,p4swms.mss.mecalux.com)<NAME>_USERNAME,<NAME>_PASSWORD,<NAME>_TENANT<NAME>_SAAS—true/false(defaultfalse). Whentrue, the WMS is cloud-hosted and log filesystem tools are disabled (they return an error pointing to the API tools instead).
URLs are assembled as https://<HOST><PATH> — only the host varies per profile.
Logs path template: LOGS_PATH supports the {host} placeholder, substituted with the active profile's HOST at each call. Example:
LOGS_PATH=\\{host}\inetpub\logs\LogFiles\Mecalux;\\{host}\ProgramData\Mecalux\ETLLogs
Runtime behavior
- At startup,
profile-manager.loadProfiles()parses.envand activatesDEFAULT_WMS_PROFILEif valid. - If no default is set, any WMS API call throws a structured error that tells Claude to call
switch_wms_profilefirst — Claude Desktop reads this and asks the user which WMS to use. - On
switch_wms_profile:api-serviceresets its OAuth tokenworkflow-serviceclears its workflow cachead-serviceinvalidates all element-type caches- Next API call re-authenticates against the new host with the new tenant.
- SaaS profiles (
<NAME>_SAAS=true): log tools (read_recent_logs,search_logs,list_log_files) throw an error because the cloud filesystem is unreachable. Only WMS APIs (query/command/workflow/AD) work. On-premise profiles (SAAS=false, default) scanLOGS_PATHwith{host}substituted by the profile's host.
Profile tools
list_wms_profiles— list all configured profiles + currently active oneget_current_wms_profile— return active profile details (host, tenant, URLs)switch_wms_profile({ profile })— change active profile
Files
- src/config/profile-manager.js — profile registry, switching, listener API
- src/tools/profile-tools.js — the 3 MCP tools above
Services (api-service, workflow-service, ad-service) register onSwitch listeners so cache/token invalidation is automatic — never call these invalidations manually from other code.
Key Technical Constraints
- API Access Only: No direct Oracle access. All data retrieval via WMS REST APIs.
- Performance: Limit result sets to 1000 rows maximum, implement query timeouts (30s).
- Error Handling: All tools must return structured errors, never crash the server.
- Logging: Use
console.error()for logs (stdout reserved for MCP protocol). - Windows: File paths use backslashes, executable must be .exe format.
- Token Management: Implement automatic token refresh before expiration (~1200s lifetime).
- Lazy Loading: Workflows are only fetched when needed (not at startup).
- Caching: Cache workflows for 1 hour to minimize API calls.
- Pagination: Use high page sizes (5000) to reduce workflow API calls.
Implementation Checklist
Phase 1-2: Foundation
- Project initialized with dependencies (axios, @modelcontextprotocol/sdk, dotenv)
- Directory structure created
- API service implemented (OAuth + HTTP client)
- Workflow service implemented (lazy loading + cache)
- WMS query service implemented (LINQ helper)
- Log service implemented
Phase 3-4: MCP Core
- All 6 resources implemented (wms-entities, entity-schemas, query-examples, workflows, apis, logs)
- 23 tools implemented (wms-query, workflow, ad, api, metadata, config, profile, log tools)
- Main server with request routing
- Error handling wrapper for all tools
Phase 5-6: Deployment
- Build to .exe validated (pkg configuration ready)
- SSH configured on VM (pending deployment)
- Key-based auth working (pending deployment)
- Server deployed to C:\WMS\mcp\ (pending deployment)
- .env configured with production credentials
Phase 7: Integration
- Claude Desktop config updated
- Basic functionality tests passed
- Workflow lazy loading validated
- API token refresh tested
- Performance validated (query limits, timeouts)
Critical Fixes Applied:
- OAuth authentication: Added missing
tenant_codeparameter - Workflow API: Extract
response.entitiesinstead of treating response as array - Property handling: Support both lowercase and uppercase property names (name/Name, id/Id)
- dotenv stdout: Redirect dotenv output to stderr to comply with MCP protocol
- .env path: Use absolute path to ensure .env is loaded from project root
WMS Entity Types Reference
Based on [queries api.php](queries api.php), these entity types are supported:
Master Data: Containers, Products, Accounts, Suppliers, Kits, Aliases Operations: Tasks, Stocks, ProductLocations Inbound: InboundOrders, Receptions Outbound: OutboundOrders
Each has corresponding Command classes for operations (focus on Query API for debugging).
Troubleshooting
Common Issues and Solutions
1. "Unexpected token 'd', "[dotenv@17."... is not valid JSON"
Problem: dotenv writes version info to stdout, but MCP requires stdout to be reserved for JSON protocol only.
Solution:
// Redirect stdout to stderr during dotenv loading
const originalStdoutWrite = process.stdout.write;
process.stdout.write = process.stderr.write.bind(process.stderr);
require('dotenv').config({ path: path.join(__dirname, '..', '.env') });
process.stdout.write = originalStdoutWrite;
2. "Authentication failed: Request failed with status code 400"
Problem: Missing tenant_code parameter in OAuth request.
Solution: Add tenant_code to authentication request:
new URLSearchParams({
grant_type: 'password',
tenant_code: process.env.WMS_API_TENANT, // ← This was missing
username: process.env.WMS_API_USERNAME,
password: process.env.WMS_API_PASSWORD
})
3. "Successfully cached 0 workflows"
Problem: Workflow API returns {entities: [...]} but code expects direct array.
Solution: Extract entities from response:
const response = await apiService.post('/Workflow/GetByApplication', body, true);
const workflows = response?.entities || []; // ← Extract entities property
4. "Workflow not found" despite existing
Problem: API returns properties in lowercase (name, id) but code looks for uppercase (Name, Id).
Solution: Support both cases:
const name = (w.name || w.Name || '').toLowerCase();
const id = w.id || w.Id;
5. "Missing environment variables"
Problem: dotenv looks for .env in current working directory, not project root.
Solution: Specify absolute path:
require('dotenv').config({
path: path.join(__dirname, '..', '.env')
});
Application Dictionary Implementation
The MCP server supports the Application Dictionary (AD) API, providing access to 20 element types containing application definitions (commands, queries, dialogs, views, etc.).
Supported Element Types (20)
Working Types (17 validated with curl):
- Command (1,872 elements)
- Query (2,016 elements)
- Dialog (734 elements)
- View (373 elements)
- Entity (331 elements)
- Event (1,980 elements)
- FieldType (320 elements)
- Hook (60 elements)
- List (243 elements)
- Record (337 elements)
- Relationship (49 elements)
- Report (67 elements)
- Resource (29,374 elements - largest type)
- Subscription (500 elements)
- Validator (17 elements)
- ViewGroup (180 elements)
- Workflow (3,712 elements)
Empty Types (0 elements, but endpoints exist):
- Dashboard
- TimelineTemplate
- Toggle
Total Elements: 38,765
Architecture
The AD implementation follows the same pattern as workflow-service.js:
- Lazy Loading: Elements fetched only on first request (not at startup)
- Caching: 1-hour TTL per element type (configurable via
WORKFLOW_CACHE_TTL) - Pagination: Different page sizes per type (heavy types: 5000, light types: 100000)
- Property Flexibility: Supports both lowercase (
name,id) and uppercase (Name,Id)
Files:
- src/services/ad-service.js - Generic service for all 20 element types
- src/tools/ad-tools.js - 5 MCP tools for AD interaction
Available AD Tools
- get_application_summary - Shows cached element counts per type
- get_ad_elements - Get all elements of a specific type (with limit)
- search_ad_elements - Search elements by name/description/code
- get_ad_element_details - Get full details of specific element
- list_ad_types - List all 20 available element types
curl Testing
All 17 working element types were validated with curl. See AD_API_TEST_RESULTS.md for detailed results.
Test command:
powershell -ExecutionPolicy Bypass -File test-ad-api.ps1
Notes
- WorkflowAction and WritingModel removed (404 Not Found on API)
- Page sizes optimized per type (Resource: 15000, Workflow: 5000, View: 200, others: 100000)
- Same cache management as workflows (1-hour TTL)
System Parameters (config-tools.js)
The get_system_parameters tool exposes WMS configuration parameters.
- The Reading model has no
CommandParameterDataentity — the correct entities areParameter(definition +DefaultValue) andParamValue(per-warehouse overrides, linked byParameterId). - The tool fetches both entities fully (small datasets — ~200 / ~50 rows), merges
them client-side, and reports the effective value per warehouse (override if
present, otherwise default). No LINQ string injection — all filters
(
warehouse,param_class,search,only_overridden) are applied in JS. - Files: src/tools/config-tools.js.
Shipment Templates — scope note
Requests for shipment template execution history are only partially served:
- The
ShipmentTemplateReading entity (queryable viaquery_wms_entities) exposes only the last execution (LastExecuteDate) plusStatus/IsEnabled. - The full execution history lives exclusively in server-side
ApplyShipmentTemplatestext logs. Those logs are not present on the reachable host (10.255.255.2) — they sit on customer production / ETL servers — so no log-parsing tool was built. See thewms://query-examplesresource for the API-only recipes.
LINQ / QueryExecute gotchas (verified against live WMS)
- Relative dates fail:
DateTime.Now,DateTime.Today,AddDays()are NOT translatable by the query engine. Use a literalnew DateTime(year, month, day). select_expressionis unreliable: LINQ projections passed via theSelectAPI parameter raise compile errors. Prefer querying full rows. (Open issue.)- The
ApplicationService.logline format is:YYYY-MM-DD HH:MM:SS.ffff [thread] [Level] [Component] [message].
Removed code
The project is 100% API-based. Legacy direct-Oracle files
(src/services/oracle-service.js, src/resources/database.js,
src/tools/database-tools.js) were dead code (unwired, oracledb not even a
dependency) and have been removed. Do not reintroduce direct database access.
Future Enhancements
- Caching: Cache frequently accessed resources (workflow categories)
- Analytics: Tool to analyze error patterns across logs + workflows
- Suggestions: Tool to suggest fixes based on error analysis
- Metrics: Performance monitoring and query statistics
select_expressionfix: Investigate theSelectAPI parameter compile errors