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
JavaScript
/**
* 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