version mise à jour par claude , à tester
This commit is contained in:
+283
@@ -0,0 +1,283 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* WMS MCP Server
|
||||
* Main entry point for the Model Context Protocol server
|
||||
*
|
||||
* Architecture: 100% API-based (no direct database access)
|
||||
* Data Access: All data retrieved via WMS REST APIs
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
|
||||
// Silence dotenv output to stdout (MCP requires stdout for JSON only)
|
||||
const originalStdoutWrite = process.stdout.write;
|
||||
process.stdout.write = process.stderr.write.bind(process.stderr);
|
||||
|
||||
require('dotenv').config({
|
||||
path: path.join(__dirname, '..', '.env')
|
||||
});
|
||||
|
||||
// Restore stdout
|
||||
process.stdout.write = originalStdoutWrite;
|
||||
|
||||
// Load WMS profiles from .env before any service is instantiated.
|
||||
// Services register onSwitch listeners at module load, so they must see
|
||||
// profile-manager in its final state — but since loadProfiles() mutates
|
||||
// the manager's internal state, it's safe to call it after requires too.
|
||||
const profileManager = require('./config/profile-manager');
|
||||
profileManager.loadProfiles();
|
||||
|
||||
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
||||
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
|
||||
const {
|
||||
CallToolRequestSchema,
|
||||
ListToolsRequestSchema,
|
||||
ListResourcesRequestSchema,
|
||||
ReadResourceRequestSchema,
|
||||
} = require('@modelcontextprotocol/sdk/types.js');
|
||||
|
||||
// Import resources
|
||||
const wmsEntitiesResources = require('./resources/wms-entities.js');
|
||||
const entitySchemasResources = require('./resources/entity-schemas.js');
|
||||
const queryExamplesResources = require('./resources/query-examples.js');
|
||||
const workflowsResources = require('./resources/workflows.js');
|
||||
const apisResources = require('./resources/apis.js');
|
||||
const logsResources = require('./resources/logs.js');
|
||||
|
||||
// Import tools
|
||||
const workflowTools = require('./tools/workflow-tools.js');
|
||||
const wmsQueryTools = require('./tools/wms-query-tools.js');
|
||||
const apiTools = require('./tools/api-tools.js');
|
||||
const logTools = require('./tools/log-tools.js');
|
||||
const adTools = require('./tools/ad-tools.js');
|
||||
const metadataTools = require('./tools/metadata-tools.js');
|
||||
const configTools = require('./tools/config-tools.js');
|
||||
const profileTools = require('./tools/profile-tools.js');
|
||||
|
||||
// Create MCP Server
|
||||
const server = new Server(
|
||||
{
|
||||
name: 'wms-mcp-server',
|
||||
version: '1.0.0',
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
resources: {},
|
||||
tools: {},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Handler: resources/list
|
||||
* List all available resources
|
||||
*/
|
||||
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
||||
const allResources = [
|
||||
...wmsEntitiesResources.listResources(),
|
||||
...entitySchemasResources.listResources(),
|
||||
...queryExamplesResources.listResources(),
|
||||
...workflowsResources.listResources(),
|
||||
...apisResources.listResources(),
|
||||
...logsResources.listResources(),
|
||||
];
|
||||
|
||||
return {
|
||||
resources: allResources,
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Handler: resources/read
|
||||
* Read a specific resource
|
||||
*/
|
||||
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
||||
const { uri } = request.params;
|
||||
|
||||
try {
|
||||
// Route to the appropriate handler based on URI
|
||||
if (uri.startsWith('wms://entities')) {
|
||||
return await wmsEntitiesResources.readResource(uri);
|
||||
} else if (uri.startsWith('wms://entity-schemas')) {
|
||||
return await entitySchemasResources.readResource(uri);
|
||||
} else if (uri.startsWith('wms://query-examples')) {
|
||||
return await queryExamplesResources.readResource(uri);
|
||||
} else if (uri.startsWith('workflows://')) {
|
||||
return await workflowsResources.readResource(uri);
|
||||
} else if (uri.startsWith('api://')) {
|
||||
return await apisResources.readResource(uri);
|
||||
} else if (uri.startsWith('logs://')) {
|
||||
return await logsResources.readResource(uri);
|
||||
} else {
|
||||
throw new Error(`Unknown resource URI: ${uri}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[Server] Error reading resource ${uri}:`, error.message);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri,
|
||||
mimeType: 'text/plain',
|
||||
text: `Error reading resource: ${error.message}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Handler: tools/list
|
||||
* List all available tools
|
||||
*/
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
const allTools = [
|
||||
...workflowTools.listTools(),
|
||||
...wmsQueryTools.listTools(),
|
||||
...apiTools.listTools(),
|
||||
...logTools.listTools(),
|
||||
...adTools.listTools(),
|
||||
...metadataTools.listTools(),
|
||||
...configTools.listTools(),
|
||||
...profileTools.listTools(),
|
||||
];
|
||||
|
||||
return {
|
||||
tools: allTools,
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Handler: tools/call
|
||||
* Execute a specific tool
|
||||
*/
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const { name, arguments: args } = request.params;
|
||||
|
||||
try {
|
||||
console.error(`[Server] Executing tool: ${name}`);
|
||||
|
||||
// Route to the appropriate handler based on tool name
|
||||
if (name.startsWith('search_workflows') ||
|
||||
name.startsWith('get_workflow_') ||
|
||||
name.startsWith('list_workflow_')) {
|
||||
return await workflowTools.executeTool(name, args);
|
||||
} else if (name.startsWith('query_wms_') ||
|
||||
name.startsWith('count_wms_') ||
|
||||
name.startsWith('get_entity_') ||
|
||||
name.startsWith('search_wms_')) {
|
||||
return await wmsQueryTools.executeTool(name, args);
|
||||
} else if (name.startsWith('call_query_api') ||
|
||||
name.startsWith('execute_command')) {
|
||||
return await apiTools.executeTool(name, args);
|
||||
} else if (name.includes('_logs')) {
|
||||
return await logTools.executeTool(name, args);
|
||||
} else if (name.startsWith('get_application_') ||
|
||||
name.startsWith('get_ad_') ||
|
||||
name.startsWith('search_ad_') ||
|
||||
name.startsWith('list_ad_')) {
|
||||
return await adTools.executeTool(name, args);
|
||||
} else if (name === 'get_entity_metadata' || name === 'generic_search') {
|
||||
return await metadataTools.executeTool(name, args);
|
||||
} else if (name === 'get_system_parameters') {
|
||||
return await configTools.executeTool(name, args);
|
||||
} else if (name === 'list_wms_profiles' ||
|
||||
name === 'get_current_wms_profile' ||
|
||||
name === 'switch_wms_profile') {
|
||||
return await profileTools.executeTool(name, args);
|
||||
} else {
|
||||
throw new Error(`Unknown tool: ${name}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[Server] Error executing tool ${name}:`, error.message);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: false,
|
||||
error: error.message,
|
||||
tool: name,
|
||||
},
|
||||
null,
|
||||
2
|
||||
),
|
||||
},
|
||||
],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Start the server
|
||||
*/
|
||||
async function main() {
|
||||
try {
|
||||
console.error('[Server] Starting WMS MCP Server...');
|
||||
console.error('[Server] Architecture: 100% API-based (no direct database access)');
|
||||
|
||||
// Validate shared environment variables
|
||||
const requiredSharedEnvVars = ['WMS_API_AUTH', 'WMS_PROFILES'];
|
||||
const missingShared = requiredSharedEnvVars.filter(v => !process.env[v]);
|
||||
if (missingShared.length > 0) {
|
||||
console.error('[Server] WARNING: Missing shared env vars:', missingShared.join(', '));
|
||||
}
|
||||
|
||||
// Validate that at least one profile is loaded
|
||||
const profiles = profileManager.listProfiles();
|
||||
if (profiles.length === 0) {
|
||||
console.error('[Server] WARNING: No WMS profile loaded. Define WMS_PROFILES + <NAME>_HOST/USERNAME/PASSWORD/TENANT in .env');
|
||||
} else {
|
||||
console.error(`[Server] Profiles available: ${profiles.join(', ')}`);
|
||||
const current = profileManager.getCurrentName();
|
||||
if (current) {
|
||||
console.error(`[Server] Active profile: ${current}`);
|
||||
} else {
|
||||
console.error('[Server] No active profile — Claude must call switch_wms_profile before any API call');
|
||||
}
|
||||
}
|
||||
|
||||
// Create stdio transport
|
||||
const transport = new StdioServerTransport();
|
||||
|
||||
// Connect server
|
||||
await server.connect(transport);
|
||||
|
||||
console.error('[Server] WMS MCP Server running on stdio');
|
||||
console.error('[Server] Server name: wms-mcp-server');
|
||||
console.error('[Server] Version: 1.0.0');
|
||||
console.error('[Server] Ready to accept requests from Claude Desktop');
|
||||
} catch (error) {
|
||||
console.error('[Server] Fatal error starting server:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle graceful shutdown
|
||||
*/
|
||||
process.on('SIGINT', async () => {
|
||||
console.error('\n[Server] Shutting down WMS MCP Server (SIGINT)...');
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
process.on('SIGTERM', async () => {
|
||||
console.error('\n[Server] Shutting down WMS MCP Server (SIGTERM)...');
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
// Handle uncaught errors
|
||||
process.on('uncaughtException', (error) => {
|
||||
console.error('[Server] Uncaught exception:', error.message);
|
||||
console.error(error.stack);
|
||||
});
|
||||
|
||||
process.on('unhandledRejection', (reason, promise) => {
|
||||
console.error('[Server] Unhandled rejection at:', promise);
|
||||
console.error('[Server] Reason:', reason);
|
||||
});
|
||||
|
||||
// Start the server
|
||||
main();
|
||||
Reference in New Issue
Block a user