#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { config } from 'dotenv';
// Load environment variables
config();
import { SFExpressClient } from './sf-express-client.js';
import { SFExpressConfig, SFExpressError } from './types.js';
// Tool imports
import { createOrderTool, handleCreateOrder } from './tools/create-order.js';
import { trackShipmentTool, handleTrackShipment } from './tools/track-shipment.js';
import { queryRoutesTool, handleQueryRoutes } from './tools/query-routes.js';
import { serviceInquiryTool, handleServiceInquiry } from './tools/service-inquiry.js';
import { logisticsServicesTool, handleLogisticsServices } from './tools/logistics-services.js';
class SFExpressMCPServer {
private server: Server;
private sfClient: SFExpressClient;
constructor() {
this.server = new Server(
{
name: 'sf-express-mcp-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
// Initialize SF Express client with configuration from environment variables
const config: SFExpressConfig = {
apiUrl: process.env.SF_EXPRESS_API_URL || 'https://open.sf-express.com',
partnerID: process.env.SF_EXPRESS_PARTNER_ID || '',
requestID: process.env.SF_EXPRESS_REQUEST_ID || '',
checkWord: process.env.SF_EXPRESS_CHECK_WORD || '',
timeout: parseInt(process.env.SF_EXPRESS_TIMEOUT || '30000')
};
// Validate required configuration
if (!config.partnerID || !config.requestID || !config.checkWord) {
console.error('Error: Missing required SF Express API configuration.');
console.error('Please set the following environment variables:');
console.error('- SF_EXPRESS_PARTNER_ID');
console.error('- SF_EXPRESS_REQUEST_ID');
console.error('- SF_EXPRESS_CHECK_WORD');
process.exit(1);
}
this.sfClient = new SFExpressClient(config);
this.setupHandlers();
}
private setupHandlers(): void {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
createOrderTool,
trackShipmentTool,
queryRoutesTool,
serviceInquiryTool,
logisticsServicesTool
]
};
});
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'sf_express_create_order':
return {
content: [
{
type: 'text',
text: JSON.stringify(await handleCreateOrder(args, this.sfClient), null, 2)
}
]
};
case 'sf_express_track_shipment':
return {
content: [
{
type: 'text',
text: JSON.stringify(await handleTrackShipment(args, this.sfClient), null, 2)
}
]
};
case 'sf_express_query_routes':
return {
content: [
{
type: 'text',
text: JSON.stringify(await handleQueryRoutes(args, this.sfClient), null, 2)
}
]
};
case 'sf_express_service_inquiry':
return {
content: [
{
type: 'text',
text: JSON.stringify(await handleServiceInquiry(args, this.sfClient), null, 2)
}
]
};
case 'sf_express_logistics_services':
return {
content: [
{
type: 'text',
text: JSON.stringify(await handleLogisticsServices(args, this.sfClient), null, 2)
}
]
};
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
// Log error for debugging
console.error(`Error handling tool call ${name}:`, error);
// Return structured error response
const errorResponse = {
success: false,
error: {
code: 'TOOL_EXECUTION_ERROR',
message: error instanceof Error ? error.message : 'Unknown error occurred',
tool: name,
timestamp: new Date().toISOString()
}
};
return {
content: [
{
type: 'text',
text: JSON.stringify(errorResponse, null, 2)
}
]
};
}
});
// Add error handler
this.server.onerror = (error) => {
console.error('[MCP Error]', error);
};
process.on('SIGINT', async () => {
await this.server.close();
process.exit(0);
});
}
async run(): Promise<void> {
console.log('SF Express MCP Server starting...');
// Test connection to SF Express API
try {
const isConnected = await this.sfClient.testConnection();
if (isConnected) {
console.log('✅ Successfully connected to SF Express API');
} else {
console.log('⚠️ Could not verify SF Express API connection');
}
} catch (error) {
console.log('⚠️ SF Express API connection test failed:', error instanceof Error ? error.message : 'Unknown error');
}
const transport = new StdioServerTransport();
console.log('🚀 SF Express MCP Server is running on stdio transport');
console.log('Available tools:');
console.log(' - sf_express_create_order: Create new shipping orders');
console.log(' - sf_express_track_shipment: Track shipment status');
console.log(' - sf_express_query_routes: Query available routes and pricing');
console.log(' - sf_express_service_inquiry: Inquire about service availability');
console.log(' - sf_express_logistics_services: Query logistics services');
await this.server.connect(transport);
}
}
// Create and run the server
async function main() {
const server = new SFExpressMCPServer();
await server.run();
}
// Handle unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
process.exit(1);
});
// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error);
process.exit(1);
});
if (import.meta.url === `file://${process.argv[1]}`) {
main().catch((error) => {
console.error('Failed to start SF Express MCP Server:', error);
process.exit(1);
});
}