UNPKG

crew-management-mcp-server

Version:

Crew management server handling crew records, certifications, scheduling, payroll, and vessel assignments with ERP access for data extraction

188 lines 7.81 kB
/** * Crew Management MCP Server * A low-level server implementation using Model Context Protocol */ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { ListResourcesRequestSchema, ReadResourceRequestSchema, ListToolsRequestSchema, CallToolRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourceTemplatesRequestSchema } from "@modelcontextprotocol/sdk/types.js"; import { ToolHandler } from "./tools/index.js"; import { config } from "./utils/config.js"; import { logger } from "./utils/logger.js"; import { toolDefinitions } from "./tools/schema.js"; import { testConnection, closeAllConnections } from "./utils/snowflake.js"; async function main() { logger.info("Starting Crew Management MCP server..."); // Test database connections on startup logger.info("Testing database connections..."); // Test Snowflake connection if credentials are provided if (config.snowflakeAccount && config.snowflakeUser && config.snowflakePassword) { logger.info("Testing Snowflake connection..."); const snowflakeConnected = await testConnection(); if (snowflakeConnected) { logger.info("✓ Snowflake connection successful"); } else { logger.warn("⚠ Snowflake connection failed - check configuration"); } } else { logger.info("⚠ Snowflake credentials not provided, skipping connection test"); } // Initialize company database and fetch IMO numbers for filtering if (config.companyName) { logger.info(`Company name configured: ${config.companyName}`); try { // Initialize company database connection const { initializeCompanyDatabase, fetchCompanyImoNumbers } = await import('./utils/imoUtils.js'); if (config.companyDbUri) { logger.info("Initializing company database connection..."); await initializeCompanyDatabase(); logger.info("✓ Company database connection established"); } // Fetch company IMO numbers logger.info(`Fetching IMO numbers for company: ${config.companyName}`); const imoNumbers = await fetchCompanyImoNumbers(config.companyName); logger.info(`✓ Successfully fetched ${imoNumbers.length} IMO numbers for company: ${config.companyName}`); if (imoNumbers.length > 0) { logger.debug(`Company IMO numbers: ${imoNumbers.slice(0, 5).join(', ')}${imoNumbers.length > 5 ? ` and ${imoNumbers.length - 5} more` : ''}`); } } catch (error) { logger.error("Failed to initialize company IMO filtering:", error.message); logger.warn("IMO filtering may be limited. Server will continue with reduced functionality."); } } else { logger.error("Company name is required for IMO filtering. Please provide it via --company-name option or COMPANY_NAME environment variable."); process.exit(1); } const server = new Server({ name: "crew-management-mcp-server", version: "1.0.8" }, { capabilities: { resources: { read: true, list: true, templates: true }, tools: { list: true, call: true }, prompts: { list: true, get: true } } }); const toolHandler = new ToolHandler(server); // Resources server.setRequestHandler(ListResourcesRequestSchema, async () => { const { resourceList } = await import("./resources/index.js"); return { resources: resourceList }; }); // Resource read server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const { readResource } = await import("./resources/index.js"); const result = await readResource(request.params.uri); return { contents: [{ type: "text", text: result }] }; }); // Empty resource templates server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => { return { templates: [] }; }); // Tools list server.setRequestHandler(ListToolsRequestSchema, async (request) => { logger.info("Handling ListToolsRequest", { request }); let tools = [...toolDefinitions]; const params = request.params || {}; const category = params.category; const search = params.search; const includeDeprecated = params.include_deprecated; // Apply category filter if provided if (category) { tools = tools.filter(tool => { const toolName = tool.name.toLowerCase(); return toolName.includes(category.toLowerCase()); }); } // Apply search filter if provided if (search) { const searchTerm = search.toLowerCase(); tools = tools.filter(tool => tool.name.toLowerCase().includes(searchTerm) || (tool.description?.toLowerCase() || '').includes(searchTerm)); } // Filter out deprecated tools unless explicitly requested if (!includeDeprecated) { tools = tools.filter(tool => !tool.name.includes('deprecated')); } return { tools }; }); // Tool call server.setRequestHandler(CallToolRequestSchema, async (request) => { const result = await toolHandler.handleCallTool(request.params.name, request.params.arguments || {}); return { content: result }; }); // Prompts list server.setRequestHandler(ListPromptsRequestSchema, async () => { const { promptList } = await import("./prompts/index.js"); return { prompts: promptList }; }); // Prompt get server.setRequestHandler(GetPromptRequestSchema, async (request) => { const { getPrompt } = await import("./prompts/index.js"); return getPrompt(request.params.name, request.params.arguments); }); // Setup graceful shutdown process.on('SIGINT', async () => { logger.info('Shutting down gracefully...'); // Close all database connections await closeAllConnections(); // Close company database connection try { const { closeCompanyDatabase } = await import('./utils/imoUtils.js'); await closeCompanyDatabase(); } catch (error) { logger.error('Error closing company database:', error); } process.exit(0); }); process.on('SIGTERM', async () => { logger.info('Shutting down gracefully...'); // Close all database connections await closeAllConnections(); // Close company database connection try { const { closeCompanyDatabase } = await import('./utils/imoUtils.js'); await closeCompanyDatabase(); } catch (error) { logger.error('Error closing company database:', error); } process.exit(0); }); // Connect to transport and start server const transport = new StdioServerTransport(); await server.connect(transport); } main().catch(async (error) => { logger.error("Fatal error:", error); await closeAllConnections(); // Close company database connection try { const { closeCompanyDatabase } = await import('./utils/imoUtils.js'); await closeCompanyDatabase(); } catch (cleanupError) { logger.error('Error during cleanup:', cleanupError); } process.exit(1); }); //# sourceMappingURL=index.js.map