voyage-and-consumption-mcp-server
Version:
Voyage and consumption management server handling vessel voyages, fuel consumption, performance monitoring, and operational data with ERP access for data extraction
178 lines • 7.34 kB
JavaScript
import { MongoClient } from 'mongodb';
import { config } from './config.js';
import { logger } from './logger.js';
// Global cache for company IMO numbers
let companyImoNumbers = [];
/**
* Fetch company IMO numbers from the common_group_details collection
* @param companyName - Name of the company to fetch IMO numbers for
* @param companyDbUri - MongoDB connection URI for company database
* @param companyDbName - MongoDB database name for company data
* @returns Array of IMO numbers as strings
*/
export async function fetchCompanyImoNumbers(companyName, companyDbUri, companyDbName) {
let client = null;
try {
logger.info(`Connecting to company database for IMO fetching: ${companyDbName}`);
client = new MongoClient(companyDbUri);
await client.connect();
const db = client.db(companyDbName);
const collection = db.collection('common_group_details');
logger.info(`Fetching IMO numbers for company: ${companyName}`);
const result = await collection.findOne({ groupName: companyName }, { projection: { imo: 1, imoList: 1, groupImoList: 1, _id: 0 } });
if (!result) {
logger.warn(`No group details found for company: ${companyName}`);
return [];
}
// Combine IMO numbers from all three fields
const imoNumbers = [];
if (result.imo) {
imoNumbers.push(result.imo);
}
if (result.imoList && Array.isArray(result.imoList)) {
imoNumbers.push(...result.imoList);
}
if (result.groupImoList && Array.isArray(result.groupImoList)) {
imoNumbers.push(...result.groupImoList);
}
// Convert to strings and remove duplicates
const uniqueImoStrings = [...new Set(imoNumbers.map(imo => String(imo)))];
logger.info(`Successfully fetched ${uniqueImoStrings.length} unique IMO numbers for company: ${companyName}`);
logger.debug(`IMO numbers: ${uniqueImoStrings.slice(0, 10).join(', ')}${uniqueImoStrings.length > 10 ? '...' : ''}`);
return uniqueImoStrings;
}
catch (error) {
logger.error(`Failed to fetch IMO numbers for company ${companyName}:`, error.message);
throw new Error(`Failed to fetch company IMO numbers: ${error.message}`);
}
finally {
if (client) {
try {
await client.close();
logger.debug(`Closed company database connection`);
}
catch (closeError) {
logger.warn(`Error closing company database connection: ${closeError.message}`);
}
}
}
}
/**
* Set the cached company IMO numbers
* @param imoNumbers - Array of IMO numbers to cache
*/
export function setCompanyImoNumbers(imoNumbers) {
companyImoNumbers = [...imoNumbers];
logger.debug(`Cached ${companyImoNumbers.length} IMO numbers for filtering`);
}
/**
* Get the cached company IMO numbers
* @returns Array of cached IMO numbers
*/
export function getCompanyImoNumbers() {
return [...companyImoNumbers];
}
/**
* Check if a specific IMO number is valid for the company
* @param imoNumber - IMO number to validate (string or number)
* @returns Boolean indicating if IMO is authorized
*/
export function isValidImoForCompany(imoNumber) {
const companyImos = getCompanyImoNumbers();
// If no company IMOs are loaded, allow access (fallback behavior)
if (companyImos.length === 0) {
logger.debug(`No company IMOs loaded, allowing access to IMO: ${imoNumber}`);
return true;
}
const imoNum = Number(imoNumber);
const companyImosNum = companyImos.map(imo => Number(imo));
const isValid = companyImosNum.includes(imoNum);
if (!isValid) {
logger.debug(`IMO ${imoNumber} not found in company IMO list`);
}
return isValid;
}
/**
* Validate IMO number and provide detailed error message
* @param imoNumber - IMO number to validate
* @param companyName - Company name for error message
* @returns Validation result with error message if invalid
*/
export function validateImoNumber(imoNumber, companyName) {
// Check if IMO filtering should be bypassed for this company
if (shouldBypassImoFiltering(companyName)) {
logger.debug(`Bypassing IMO filtering for admin company: ${companyName}`);
return { isValid: true };
}
// Check if IMO is valid for the company
if (isValidImoForCompany(imoNumber)) {
return { isValid: true };
}
// Generate error message with available IMO numbers
const companyImos = getCompanyImoNumbers();
const displayLimit = 20;
const displayImos = companyImos.slice(0, displayLimit);
const moreCount = companyImos.length > displayLimit ? ` (and ${companyImos.length - displayLimit} more)` : '';
return {
isValid: false,
errorMessage: `IMO number ${imoNumber} is not associated with ${companyName}. Available IMO numbers: ${displayImos.join(', ')}${moreCount}`
};
}
/**
* Check if IMO filtering should be bypassed for admin companies
* @param companyName - Company name to check
* @returns Boolean indicating if filtering should be bypassed
*/
export function shouldBypassImoFiltering(companyName) {
const bypassCompanies = ['Synergy', 'Admin', 'SYIA', 'System'];
const shouldBypass = bypassCompanies.includes(companyName);
if (shouldBypass) {
logger.debug(`IMO filtering bypassed for admin company: ${companyName}`);
}
return shouldBypass;
}
/**
* Initialize company IMO numbers from configuration
* Should be called during server startup
*/
export async function initializeCompanyImoNumbers() {
const { companyName, companyDbUri, companyDbName } = config;
if (!companyName) {
logger.warn("No company name provided, IMO filtering will be disabled");
return;
}
if (shouldBypassImoFiltering(companyName)) {
logger.info(`Admin company detected (${companyName}), IMO filtering will be bypassed`);
setCompanyImoNumbers([]);
return;
}
if (!companyDbUri || !companyDbName) {
logger.warn("Company database configuration missing, IMO filtering will be limited");
return;
}
try {
const imoNumbers = await fetchCompanyImoNumbers(companyName, companyDbUri, companyDbName);
setCompanyImoNumbers(imoNumbers);
logger.info(`Successfully initialized IMO filtering for company: ${companyName} with ${imoNumbers.length} IMO numbers`);
}
catch (error) {
logger.error(`Failed to initialize company IMO numbers: ${error.message}`);
logger.warn("IMO filtering may be limited. Server will continue with reduced functionality.");
setCompanyImoNumbers([]);
}
}
/**
* Get current IMO filtering status for monitoring
* @returns Object with filtering status information
*/
export function getImoFilteringStatus() {
const { companyName } = config;
const companyImos = getCompanyImoNumbers();
return {
companyName: companyName || 'Not set',
isAdminCompany: companyName ? shouldBypassImoFiltering(companyName) : false,
imoCount: companyImos.length,
filteringEnabled: !!(companyName && !shouldBypassImoFiltering(companyName) && companyImos.length > 0)
};
}
//# sourceMappingURL=imoUtils.js.map