purchase-mcp-server
Version:
Purchase and budget management server handling requisitions, purchase orders, expenses, budgets, and vendor management with ERP access for data extraction
153 lines • 8.31 kB
JavaScript
// TODO: Replace with syia-mcp-utils import when imoCache is moved there
import { getCompanyImosWithFallback, shouldSkipImoValidation } from "../utils/imoCache.js";
import { logger } from "../index.js";
import { config } from "../config/index.js";
import { QAToolHandler } from "./handlers/qaTools.js";
import { UniversalToolHandler } from "./handlers/universalTools.js";
// import { SearchToolHandler } from "./handlers/searchTools.js";
import { ExportToolHandler } from "./handlers/exportTools.js";
import { VendorToolHandler } from "./handlers/vendorTools.js";
/**
* Main tool handler that coordinates different categories of tools
*/
export class ToolHandler {
constructor(server) {
this.qaToolHandler = new QAToolHandler();
this.universalToolHandler = new UniversalToolHandler();
// this.searchToolHandler = new SearchToolHandler();
this.exportToolHandler = new ExportToolHandler();
this.vendorToolHandler = new VendorToolHandler();
}
/**
* Get company IMO numbers for validation
*/
getCompanyImos() {
return getCompanyImosWithFallback();
}
/**
* Validate IMO numbers against company IMO list
*/
validateImoNumber(imo) {
// Skip validation for companies that don't require IMO validation
if (shouldSkipImoValidation(config.companyName)) {
logger.debug(`Skipping IMO validation for company: "${config.companyName}"`);
return null;
}
const companyImos = this.getCompanyImos();
if (companyImos.length === 0) {
logger.warn('No company IMOs available for validation, allowing request to proceed');
return null;
}
const imoNum = Number(imo);
const companyImosNum = companyImos.map(imo => Number(imo));
if (!companyImosNum.includes(imoNum)) {
return [{
type: "text",
text: `Error: IMO number ${imo} is not associated with the current company. Please provide a valid IMO number. Available IMO numbers: ${companyImos.join(", ")}`,
title: "Invalid IMO Number",
format: "json"
}];
}
return null;
}
/**
* Type-safe casting and validation of tool arguments
*/
processToolArguments(toolName, arguments_) {
// Validate IMO numbers
if (arguments_.imo) {
const error = this.validateImoNumber(arguments_.imo);
if (error)
return { args: arguments_, error };
}
if (arguments_.filters?.imo) {
const error = this.validateImoNumber(arguments_.filters.imo);
if (error)
return { args: arguments_, error };
}
// Runtime type casting - the schema validation ensures correctness
return { args: arguments_ };
}
/**
* Handles tool calls by routing them to appropriate specialized handlers
* @param name - The name of the tool to call
* @param arguments_ - The arguments for the tool
* @returns Promise resolving to the tool response
*/
async handleCallTool(name, arguments_) {
try {
// 🔒 AUTHORIZATION: Validate company IMO access before any tool execution
const authResult = this.processToolArguments(name, arguments_);
if (authResult.error) {
return authResult.error;
}
const validatedArgs = authResult.args;
switch (name) {
case "get_monthly_opex_budget_variance":
return await this.qaToolHandler.getMonthlyOpexBudgetVariance(validatedArgs);
case "get_current_year_committed_cost":
return await this.qaToolHandler.getCurrentYearCommittedCost(validatedArgs);
case "get_budget_status_summary_ytd":
return await this.qaToolHandler.getBudgetStatusSummaryYtd(validatedArgs);
case "get_purchase_orders_with_forwarders":
return await this.qaToolHandler.getPurchaseOrdersWithForwarders(validatedArgs);
case "purchase_orders_open_more_than_180_days":
return await this.qaToolHandler.purchaseOrdersOpenMoreThan180Days(validatedArgs);
// case "get_vessel_budget_data":
// return await this.searchToolHandler.getVesselBudgetData(validatedArgs as any);
case "universal_purchase_search":
return await this.universalToolHandler.universalPurchaseSearchHandler(validatedArgs);
case "universal_budget_search":
return await this.universalToolHandler.universalBudgetSearchHandler(validatedArgs);
case "universal_expense_search":
return await this.universalToolHandler.universalExpenseSearchHandler(validatedArgs);
// case "get_purchase_requisition_details":
// return await this.searchToolHandler.getPurchaseRequisitionDetails(validatedArgs as any);
// case "get_purchase_order_details":
// return await this.searchToolHandler.getPurchaseOrderDetails(validatedArgs as any);
// case "list_requisitions_by_status":
// return await this.searchToolHandler.listRequisitionsByStatus(validatedArgs as any);
// case "list_overdue_open_requisitions":
// return await this.searchToolHandler.listOverdueOpenRequisitions(validatedArgs as any);
// case "list_purchase_orders_by_status":
// return await this.searchToolHandler.listPurchaseOrdersByStatus(validatedArgs as any);
// case "list_requisitions_by_type_and_stage":
// return await this.searchToolHandler.listRequisitionsByTypeAndStage(validatedArgs as any);
// case "list_recent_requisitions_by_order_priority":
// return await this.searchToolHandler.listRecentRequisitionsByOrderPriority(validatedArgs as any);
// case "list_top_expenses_by_category":
// return await this.searchToolHandler.listTopExpensesByCategory(validatedArgs as any);
// case "list_committed_cost_expenses":
// return await this.searchToolHandler.listCommittedCostExpenses(validatedArgs as any);
// case "get_vessel_purchase_log_table":
// return await this.searchToolHandler.getVesselPurchaseLogTable(validatedArgs as any);
// case "list_recent_urgent_requisitions":
// return await this.searchToolHandler.listRecentUrgentRequisitions(validatedArgs as any);
case "find_relevant_vendors":
return await this.vendorToolHandler.findRelevantVendors(validatedArgs);
case "get_vendor_contact_details":
return await this.vendorToolHandler.getVendorContactInfo(validatedArgs);
// Fleet tools
case "get_fleet_purchase_log_table":
return await this.qaToolHandler.getFleetPurchaseLogTable(validatedArgs);
case "get_fleet_purchase_activities":
return await this.qaToolHandler.getFleetPurchaseActivities(validatedArgs);
case "get_fleet_budget_overviews":
return await this.qaToolHandler.getFleetBudgetOverviews(validatedArgs);
case "get_complete_vessel_purchase_requisition_data":
return await this.exportToolHandler.getCompleteVesselPurchaseRequisitionData(validatedArgs);
case "get_complete_vessel_expense_data":
return await this.exportToolHandler.getCompleteVesselExpenseData(validatedArgs);
case "get_complete_vessel_budget_data":
return await this.exportToolHandler.getCompleteVesselBudgetData(validatedArgs);
default:
throw new Error(`Unknown tool: ${name}`);
}
}
catch (error) {
logger.error(`Error calling tool ${name}:`, error);
throw error;
}
}
}
//# sourceMappingURL=index.js.map