noaa-tidesandcurrents-mcp

by RyanCardin15
Verified
  • src
import axios from 'axios'; // Base URLs for the different NOAA APIs const DATA_API_BASE_URL = 'https://api.tidesandcurrents.noaa.gov/api/prod/datagetter'; const METADATA_API_BASE_URL = 'https://api.tidesandcurrents.noaa.gov/mdapi/prod/webapi'; /** * Configuration options for the NOAA service */ export interface NoaaConfig { applicationName?: string; } /** * Service for interacting with NOAA Tides and Currents APIs */ export class NoaaService { private config: NoaaConfig; constructor(config: NoaaConfig = {}) { this.config = config; } /** * Build parameters for the API request * @param params Parameters for the request * @returns URL-encoded parameters string */ private buildParams(params: Record<string, any>): string { // Add application name if provided in config if (this.config.applicationName) { params.application = this.config.applicationName; } // Remove undefined and null values const filteredParams = Object.entries(params) .filter(([_, value]) => value !== undefined && value !== null) .reduce((acc, [key, value]) => { acc[key] = value; return acc; }, {} as Record<string, any>); // Convert to URL parameters return new URLSearchParams(filteredParams as Record<string, string>).toString(); } /** * Make a request to the Data API * @param params Parameters for the request * @returns Response data */ async fetchDataApi(params: Record<string, any>): Promise<any> { try { const queryParams = this.buildParams(params); const url = `${DATA_API_BASE_URL}?${queryParams}`; const response = await axios.get(url); return response.data; } catch (error) { if (axios.isAxiosError(error) && error.response) { throw new Error(`NOAA API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`); } throw error; } } /** * Make a request to the Metadata API * @param endpoint Endpoint path * @param params Parameters for the request * @returns Response data */ async fetchMetadataApi(endpoint: string, params: Record<string, any> = {}): Promise<any> { try { const queryParams = this.buildParams(params); const url = `${METADATA_API_BASE_URL}${endpoint}${queryParams ? '?' + queryParams : ''}`; const response = await axios.get(url); return response.data; } catch (error) { if (axios.isAxiosError(error) && error.response) { throw new Error(`NOAA API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`); } throw error; } } /** * Get water level data */ async getWaterLevels(params: Record<string, any>): Promise<any> { return this.fetchDataApi({ ...params, product: 'water_level' }); } /** * Get tide predictions */ async getTidePredictions(params: Record<string, any>): Promise<any> { return this.fetchDataApi({ ...params, product: 'predictions' }); } /** * Get currents data */ async getCurrents(params: Record<string, any>): Promise<any> { return this.fetchDataApi({ ...params, product: 'currents' }); } /** * Get current predictions */ async getCurrentPredictions(params: Record<string, any>): Promise<any> { return this.fetchDataApi({ ...params, product: 'currents_predictions' }); } /** * Get meteorological data (air_temperature, wind, etc.) */ async getMeteorologicalData(params: Record<string, any>): Promise<any> { const { product, ...rest } = params; return this.fetchDataApi({ ...rest, product }); } /** * Get list of stations */ async getStations(params: Record<string, any>): Promise<any> { const { type, ...rest } = params; const endpoint = '/stations.' + (rest.format || 'json'); const queryParams = type ? { type, ...rest } : rest; return this.fetchMetadataApi(endpoint, queryParams); } /** * Get station details */ async getStationDetails(params: Record<string, any>): Promise<any> { const { station, ...rest } = params; const endpoint = `/stations/${station}/details.` + (rest.format || 'json'); return this.fetchMetadataApi(endpoint, rest); } }