UNPKG

geoapify-mcp-server

Version:

Geoapify API MCP Server for location-based services - 一键部署的地理位置服务

203 lines (169 loc) 5.55 kB
const axios = require('axios'); const { logger } = require('../utils/logger.js'); const { CacheManager } = require('../utils/cache.js'); class GeoapifyService { constructor(apiKey) { if (!apiKey) { throw new Error('Geoapify API key is required'); } this.apiKey = apiKey; this.baseURL = 'https://api.geoapify.com'; this.cache = new CacheManager(); // 配置axios实例 this.client = axios.create({ baseURL: this.baseURL, timeout: 30000, headers: { 'User-Agent': 'Geoapify-MCP-Server/1.0.0' } }); // 请求拦截器 this.client.interceptors.request.use( (config) => { config.params = { ...config.params, apiKey: this.apiKey }; logger.debug(`API Request: ${config.method?.toUpperCase()} ${config.url}`, { params: config.params }); return config; }, (error) => { logger.error('Request interceptor error:', error); return Promise.reject(error); } ); // 响应拦截器 this.client.interceptors.response.use( (response) => { logger.debug(`API Response: ${response.status}`, { url: response.config.url, dataSize: JSON.stringify(response.data).length }); return response; }, (error) => { logger.error('API Error:', { url: error.config?.url, status: error.response?.status, message: error.response?.data?.message || error.message }); return Promise.reject(this.handleApiError(error)); } ); } handleApiError(error) { if (error.response) { const { status, data } = error.response; switch (status) { case 401: return new Error('Invalid API key'); case 403: return new Error('API key quota exceeded or access denied'); case 429: return new Error('Rate limit exceeded'); case 400: return new Error(`Bad request: ${data.message || 'Invalid parameters'}`); default: return new Error(`API error (${status}): ${data.message || 'Unknown error'}`); } } return error; } async geocode(address, options = {}) { const cacheKey = `geocode:${address}:${JSON.stringify(options)}`; const cached = await this.cache.get(cacheKey); if (cached) return cached; const params = { text: address, format: 'json', limit: 5, ...options }; const response = await this.client.get('/v1/geocode/search', { params }); const result = response.data; await this.cache.set(cacheKey, result, 3600); // 缓存1小时 return result; } async reverseGeocode(lat, lon, options = {}) { const cacheKey = `reverse:${lat}:${lon}:${JSON.stringify(options)}`; const cached = await this.cache.get(cacheKey); if (cached) return cached; const params = { lat, lon, format: 'json', ...options }; const response = await this.client.get('/v1/geocode/reverse', { params }); const result = response.data; await this.cache.set(cacheKey, result, 3600); return result; } async routing(waypoints, mode = 'drive', options = {}) { const waypointsStr = Array.isArray(waypoints) ? waypoints.join('|') : waypoints; const cacheKey = `routing:${waypointsStr}:${mode}:${JSON.stringify(options)}`; const cached = await this.cache.get(cacheKey); if (cached) return cached; const params = { waypoints: waypointsStr, mode, format: 'json', ...options }; const response = await this.client.get('/v1/routing', { params }); const result = response.data; await this.cache.set(cacheKey, result, 1800); // 缓存30分钟 return result; } async searchPlaces(categories, filter, options = {}) { const cacheKey = `places:${categories}:${filter}:${JSON.stringify(options)}`; const cached = await this.cache.get(cacheKey); if (cached) return cached; const params = { categories, filter, limit: 20, ...options }; const response = await this.client.get('/v2/places', { params }); const result = response.data; await this.cache.set(cacheKey, result, 1800); return result; } async autocomplete(text, options = {}) { const cacheKey = `autocomplete:${text}:${JSON.stringify(options)}`; const cached = await this.cache.get(cacheKey); if (cached) return cached; const params = { text, format: 'json', limit: 10, ...options }; const response = await this.client.get('/v1/geocode/autocomplete', { params }); const result = response.data; await this.cache.set(cacheKey, result, 600); // 缓存10分钟 return result; } async isoline(lat, lon, options = {}) { const params = { lat, lon, format: 'json', ...options }; const response = await this.client.get('/v1/isoline', { params }); return response.data; } async placeDetails(placeId, options = {}) { const cacheKey = `place_details:${placeId}:${JSON.stringify(options)}`; const cached = await this.cache.get(cacheKey); if (cached) return cached; const params = { id: placeId, ...options }; const response = await this.client.get('/v2/place-details', { params }); const result = response.data; await this.cache.set(cacheKey, result, 7200); // 缓存2小时 return result; } } module.exports = { GeoapifyService };