"""FastMCP integration tests — tool calls against the real server, HTTP mocked.""" import json import httpx import respx from fastmcp import Client import mcgibs.server as server_module from mcgibs.client import GIBSClient from mcgibs.server import mcp async def _init_mock_client(capabilities_xml: str) -> GIBSClient: """Create and initialize a GIBSClient with mocked capabilities.""" client = GIBSClient() await client.initialize() return client @respx.mock async def test_search_tool(capabilities_xml): """search_gibs_layers finds the sea ice layer by keyword.""" respx.get(url__regex=r".*WMTSCapabilities\.xml").mock( return_value=httpx.Response(200, text=capabilities_xml) ) server_module._client = await _init_mock_client(capabilities_xml) try: async with Client(mcp) as client: result = await client.call_tool("search_gibs_layers", {"query": "sea ice"}) text = result.content[0].text assert "AMSR2" in text assert "Sea Ice" in text # Should not match unrelated layers assert "Surface Air Temperature" not in text finally: await server_module._client.close() server_module._client = None @respx.mock async def test_get_layer_info_tool(capabilities_xml, layer_metadata_json): """get_layer_info returns enriched JSON for the true color layer.""" respx.get(url__regex=r".*WMTSCapabilities\.xml").mock( return_value=httpx.Response(200, text=capabilities_xml) ) layer_id = "MODIS_Terra_CorrectedReflectance_TrueColor" respx.get(url__regex=rf".*layer-metadata.*/{layer_id}\.json").mock( return_value=httpx.Response(200, text=layer_metadata_json) ) server_module._client = await _init_mock_client(capabilities_xml) try: async with Client(mcp) as client: result = await client.call_tool("get_layer_info", {"layer_id": layer_id}) text = result.content[0].text info = json.loads(text) assert info["identifier"] == layer_id assert info["instrument"] == "MODIS" assert info["platform"] == "Terra" assert info["ongoing"] is True assert "time" in info assert info["time"]["start"] == "2000-02-24" finally: await server_module._client.close() server_module._client = None @respx.mock async def test_resolve_place_tool(capabilities_xml): """resolve_place geocodes a place name via mocked Nominatim.""" respx.get(url__regex=r".*WMTSCapabilities\.xml").mock( return_value=httpx.Response(200, text=capabilities_xml) ) nominatim_response = [ { "display_name": "Tokyo, Japan", "lat": "35.6762", "lon": "139.6503", "boundingbox": ["35.5190", "35.8178", "138.9428", "139.9200"], "osm_type": "relation", "importance": 0.82, } ] respx.get(url__regex=r".*nominatim.*search.*").mock( return_value=httpx.Response(200, json=nominatim_response) ) server_module._client = await _init_mock_client(capabilities_xml) try: async with Client(mcp) as client: result = await client.call_tool("resolve_place", {"place": "Tokyo"}) text = result.content[0].text data = json.loads(text) assert data["display_name"] == "Tokyo, Japan" assert abs(data["lat"] - 35.6762) < 0.01 assert abs(data["lon"] - 139.6503) < 0.01 assert "bbox" in data assert data["bbox"]["west"] < data["bbox"]["east"] finally: await server_module._client.close() server_module._client = None @respx.mock async def test_build_tile_url_tool(capabilities_xml): """build_tile_url returns a properly formatted WMTS tile URL.""" respx.get(url__regex=r".*WMTSCapabilities\.xml").mock( return_value=httpx.Response(200, text=capabilities_xml) ) server_module._client = await _init_mock_client(capabilities_xml) try: async with Client(mcp) as client: result = await client.call_tool( "build_tile_url", { "layer_id": "MODIS_Terra_CorrectedReflectance_TrueColor", "date": "2025-06-01", "zoom": 3, "row": 2, "col": 4, }, ) url = result.content[0].text assert "MODIS_Terra_CorrectedReflectance_TrueColor" in url assert "2025-06-01" in url assert "epsg4326" in url # True color layer uses JPEG and 250m matrix set assert url.endswith(".jpg") assert "/250m/" in url finally: await server_module._client.close() server_module._client = None @respx.mock async def test_list_tools(capabilities_xml): """All expected tools are registered on the MCP server.""" respx.get(url__regex=r".*WMTSCapabilities\.xml").mock( return_value=httpx.Response(200, text=capabilities_xml) ) server_module._client = await _init_mock_client(capabilities_xml) try: async with Client(mcp) as client: tools = await client.list_tools() tool_names = {t.name for t in tools} expected = { "search_gibs_layers", "get_layer_info", "list_measurements", "check_layer_dates", "get_imagery", "compare_dates", "get_imagery_composite", "explain_layer_colormap", "get_legend", "resolve_place", "build_tile_url", } for name in expected: assert name in tool_names, f"Missing tool: {name}" finally: await server_module._client.close() server_module._client = None