"""MCP resources: station catalog, station detail, nearby stations.""" import json from fastmcp import Context, FastMCP from noaa_tides.client import NOAAClient def register(mcp: FastMCP) -> None: @mcp.resource("noaa://stations") async def station_catalog(ctx: Context) -> str: """Full NOAA tide station catalog. ~301 stations with id, name, state, coordinates.""" noaa: NOAAClient = ctx.lifespan_context["noaa_client"] stations = await noaa.get_stations() return json.dumps( [s.model_dump() for s in stations], indent=2, ) @mcp.resource("noaa://stations/{station_id}") async def station_detail(station_id: str, ctx: Context) -> str: """Expanded metadata for a single station including sensors, datums, and products.""" noaa: NOAAClient = ctx.lifespan_context["noaa_client"] metadata = await noaa.get_station_metadata(station_id) return json.dumps(metadata, indent=2) @mcp.resource("noaa://stations/{station_id}/nearby") async def nearby_stations(station_id: str, ctx: Context) -> str: """Stations within 50 nm of the given station, sorted by distance.""" noaa: NOAAClient = ctx.lifespan_context["noaa_client"] stations = await noaa.get_stations() target = next((s for s in stations if s.id == station_id), None) if not target: return json.dumps({"error": f"Station {station_id} not found"}) nearby = noaa.find_nearest(target.lat, target.lng, limit=10, max_distance=50) # Exclude the station itself nearby = [(s, d) for s, d in nearby if s.id != station_id] return json.dumps( [{**s.model_dump(), "distance_nm": round(d, 1)} for s, d in nearby], indent=2, )