UNPKG

@siva-sub/mcp-public-transport

Version:

A Model Context Protocol server for Singapore transport data with real-time information and routing

121 lines (120 loc) 5.05 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BusStopsTool = 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 BusStopsInputSchema = zod_1.z.intersection(validation_js_1.LocationSchema, zod_1.z.object({ radius: zod_1.z.number().min(100).max(5000).default(500), limit: zod_1.z.number().min(1).max(50).default(10), })); class BusStopsTool extends base_js_1.BaseTool { constructor(ltaService, oneMapService) { super(); this.ltaService = ltaService; this.oneMapService = oneMapService; } getDefinitions() { return [ { name: 'find_bus_stops', description: 'Find bus stops by location name, coordinates, or road name', 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: 500, description: 'Search radius in meters', }, limit: { type: 'number', minimum: 1, maximum: 50, default: 10, description: 'Maximum number of results', }, }), }, ]; } canHandle(toolName) { return toolName === 'find_bus_stops'; } async execute(toolName, args) { try { const { location, lat, lng, radius, limit } = (0, validation_js_1.validateInput)(BusStopsInputSchema, 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: ${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 bus stops near ${searchLat}, ${searchLng}`, { radius, limit }); // Get all bus stops (cached) const allStops = await this.ltaService.getAllBusStops(); // Calculate distances and filter const nearbyStops = allStops .map(stop => ({ ...stop, distance: (0, haversine_distance_1.default)({ latitude: searchLat, longitude: searchLng }, { latitude: stop.latitude, longitude: stop.longitude }), })) .filter(stop => stop.distance <= (radius || 500)) .sort((a, b) => a.distance - b.distance) .slice(0, limit); return { searchLocation: { latitude: searchLat, longitude: searchLng, name: location, }, radius, totalFound: nearbyStops.length, stops: nearbyStops.map(stop => ({ busStopCode: stop.busStopCode, description: stop.description, roadName: stop.roadName, latitude: stop.latitude, longitude: stop.longitude, distanceMeters: Math.round(stop.distance), walkingTimeMinutes: Math.ceil(stop.distance / 80), // Assume 80m/min walking speed })), timestamp: new Date().toISOString(), }; } catch (error) { logger_js_1.logger.error(`Bus stops tool failed: ${toolName}`, error); return this.formatError(error, toolName); } } } exports.BusStopsTool = BusStopsTool;