@siva-sub/mcp-public-transport
Version:
A Model Context Protocol server for Singapore transport data with real-time information and routing
154 lines (153 loc) • 6.69 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TaxiAvailabilityTool = void 0;
const zod_1 = require("zod");
const base_js_1 = require("../base.js");
const validation_js_1 = require("../../utils/validation.js");
const logger_js_1 = require("../../utils/logger.js");
const haversine_distance_1 = __importDefault(require("haversine-distance"));
const TaxiAvailabilityInputSchema = zod_1.z.intersection(validation_js_1.LocationSchema, zod_1.z.object({
radius: zod_1.z.number().min(100).max(5000).default(1000),
}));
class TaxiAvailabilityTool extends base_js_1.BaseTool {
constructor(ltaService, oneMapService) {
super();
this.ltaService = ltaService;
this.oneMapService = oneMapService;
}
getDefinitions() {
return [
{
name: 'get_nearby_taxis',
description: 'Find available taxis near a specified location',
inputSchema: this.createSchema({
location: {
type: 'string',
description: 'Location name (e.g., "Marina Bay", "Orchard Road")',
},
lat: {
type: 'number',
description: 'Latitude coordinate',
},
lng: {
type: 'number',
description: 'Longitude coordinate',
},
radius: {
type: 'number',
minimum: 100,
maximum: 5000,
default: 1000,
description: 'Search radius in meters',
},
}),
},
];
}
canHandle(toolName) {
return toolName === 'get_nearby_taxis';
}
async execute(toolName, args) {
try {
const { location, lat, lng, radius } = (0, validation_js_1.validateInput)(TaxiAvailabilityInputSchema, args);
let searchLat = lat;
let searchLng = lng;
// Geocode location if coordinates not provided
if (!searchLat || !searchLng) {
if (!location) {
throw new Error('Either location name or coordinates must be provided');
}
logger_js_1.logger.info(`Geocoding location for taxi search: ${location}`);
const geocoded = await this.oneMapService.geocode(location);
if (!geocoded) {
return {
error: `Could not find coordinates for location: ${location}`,
timestamp: new Date().toISOString(),
};
}
searchLat = geocoded.latitude;
searchLng = geocoded.longitude;
}
logger_js_1.logger.info(`Finding taxis near ${searchLat}, ${searchLng}`, { radius });
// Get taxi availability data
const taxis = await this.ltaService.getTaxiAvailability();
// Filter taxis within radius
const nearbyTaxis = taxis
.map(taxi => ({
...taxi,
distance: (0, haversine_distance_1.default)({ latitude: searchLat, longitude: searchLng }, { latitude: taxi.coordinates[0], longitude: taxi.coordinates[1] }),
}))
.filter(taxi => taxi.distance <= (radius || 1000))
.sort((a, b) => a.distance - b.distance);
const closestTaxi = nearbyTaxis[0];
return {
searchLocation: {
latitude: searchLat,
longitude: searchLng,
name: location,
},
radius,
availableTaxis: nearbyTaxis.length,
closestTaxi: closestTaxi ? {
distanceMeters: Math.round(closestTaxi.distance),
estimatedWalkTime: `${Math.ceil(closestTaxi.distance / 80)} minutes`,
coordinates: closestTaxi.coordinates,
} : null,
taxiDensity: this.calculateTaxiDensity(nearbyTaxis.length, radius || 1000),
recommendations: this.generateTaxiRecommendations(nearbyTaxis.length, location),
timestamp: new Date().toISOString(),
};
}
catch (error) {
logger_js_1.logger.error(`Taxi availability tool failed: ${toolName}`, error);
return this.formatError(error, toolName);
}
}
calculateTaxiDensity(count, radius) {
const area = Math.PI * Math.pow(radius / 1000, 2); // km²
const density = count / area;
if (density > 10)
return 'very_high';
if (density > 5)
return 'high';
if (density > 2)
return 'moderate';
if (density > 0.5)
return 'low';
return 'very_low';
}
generateTaxiRecommendations(taxiCount, location) {
const recommendations = [];
if (taxiCount === 0) {
recommendations.push('No taxis available in this area');
recommendations.push('Consider using ride-hailing apps like Grab or ComfortDelGro');
recommendations.push('Check nearby MRT stations or bus stops for public transport');
}
else if (taxiCount < 3) {
recommendations.push('Limited taxi availability - consider booking in advance');
recommendations.push('Alternative: Use ride-hailing apps for better availability');
}
else if (taxiCount >= 10) {
recommendations.push('High taxi availability in this area');
recommendations.push('Good area for finding taxis quickly');
}
else {
recommendations.push('Moderate taxi availability');
}
// Location-specific recommendations
if (location) {
const locationLower = location.toLowerCase();
if (locationLower.includes('airport') || locationLower.includes('changi')) {
recommendations.push('Airport taxi queue available for departing passengers');
}
else if (locationLower.includes('orchard') || locationLower.includes('cbd')) {
recommendations.push('Peak hours may have longer wait times in this busy area');
}
}
return recommendations;
}
}
exports.TaxiAvailabilityTool = TaxiAvailabilityTool;