Skip to main content
Glama
X-McKay
by X-McKay
test_mcp.py8.88 kB
#!/usr/bin/env python3 """ Comprehensive tests for the MCP Geocoding Server """ import json import os import sys from unittest.mock import AsyncMock, patch import pytest # type: ignore # Add the parent directory to the path so we can import the server sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from geocode_mcp.server import geocode_location, handle_call_tool, handle_list_tools class TestGeocodingServer: """Test cases for the geocoding server functionality.""" @pytest.mark.asyncio async def test_geocode_location_success(self) -> None: """Test successful geocoding with mocked HTTP response.""" mock_response_data = [ { "lat": "40.7127281", "lon": "-74.0060152", "display_name": "New York, United States", "place_id": 298085, "type": "city", "class": "place", "importance": 0.9756419939577, "boundingbox": [ "40.4960439", "40.9152414", "-74.2557349", "-73.7000091", ], } ] with patch("aiohttp.ClientSession.get") as mock_get: mock_response = AsyncMock() mock_response.ok = True mock_response.json = AsyncMock(return_value=mock_response_data) mock_get.return_value.__aenter__.return_value = mock_response result = await geocode_location("New York") assert result["query"] == "New York" assert result["results_count"] == 1 assert len(result["coordinates"]) == 1 assert result["coordinates"][0]["latitude"] == 40.7127281 assert result["coordinates"][0]["longitude"] == -74.0060152 @pytest.mark.asyncio async def test_geocode_location_not_found(self) -> None: """Test geocoding when no results are found.""" with patch("aiohttp.ClientSession.get") as mock_get: mock_response = AsyncMock() mock_response.ok = True mock_response.json = AsyncMock(return_value=[]) mock_get.return_value.__aenter__.return_value = mock_response result = await geocode_location("NonexistentPlace12345") assert "error" in result assert result["query"] == "NonexistentPlace12345" assert "suggestions" in result @pytest.mark.asyncio async def test_geocode_location_multiple_results(self) -> None: """Test geocoding with multiple results.""" mock_response_data = [ { "lat": "39.7817213", "lon": "-89.6501481", "display_name": "Springfield, Illinois, United States", "place_id": 123, "type": "city", "class": "place", "importance": 0.8, "boundingbox": ["39.7", "39.8", "-89.7", "-89.6"], }, { "lat": "42.1014831", "lon": "-72.589811", "display_name": "Springfield, Massachusetts, United States", "place_id": 456, "type": "city", "class": "place", "importance": 0.7, "boundingbox": ["42.0", "42.1", "-72.6", "-72.5"], }, ] with patch("aiohttp.ClientSession.get") as mock_get: mock_response = AsyncMock() mock_response.ok = True mock_response.json = AsyncMock(return_value=mock_response_data) mock_get.return_value.__aenter__.return_value = mock_response result = await geocode_location("Springfield", limit=2) assert result["results_count"] == 2 assert len(result["coordinates"]) == 2 @pytest.mark.asyncio async def test_geocode_location_network_error(self) -> None: """Test geocoding with network error.""" import aiohttp with patch("aiohttp.ClientSession.get") as mock_get: mock_get.side_effect = aiohttp.ClientError("Connection failed") with pytest.raises(Exception) as exc_info: await geocode_location("New York") assert "Network error" in str(exc_info.value) @pytest.mark.asyncio async def test_geocode_location_api_error(self) -> None: """Test geocoding with API error response.""" with patch("aiohttp.ClientSession.get") as mock_get: mock_response = AsyncMock() mock_response.ok = False mock_response.status = 500 mock_response.reason = "Internal Server Error" mock_get.return_value.__aenter__.return_value = mock_response with pytest.raises(Exception) as exc_info: await geocode_location("New York") assert "Nominatim API error" in str(exc_info.value) @pytest.mark.asyncio async def test_list_tools(self) -> None: """Test that the server lists available tools correctly.""" tools = await handle_list_tools() assert len(tools) == 1 assert tools[0].name == "get_coordinates" assert "latitude and longitude" in tools[0].description.lower() assert "location" in tools[0].inputSchema["properties"] assert "limit" in tools[0].inputSchema["properties"] @pytest.mark.asyncio async def test_call_tool_success(self) -> None: """Test successful tool call.""" mock_response_data = [ { "lat": "48.8566969", "lon": "2.3514616", "display_name": "Paris, France", "place_id": 789, "type": "city", "class": "place", "importance": 0.9, "boundingbox": ["48.8", "48.9", "2.3", "2.4"], } ] with patch("aiohttp.ClientSession.get") as mock_get: mock_response = AsyncMock() mock_response.ok = True mock_response.json = AsyncMock(return_value=mock_response_data) mock_get.return_value.__aenter__.return_value = mock_response result = await handle_call_tool( "get_coordinates", {"location": "Paris, France"} ) assert len(result) == 1 response_data = json.loads(result[0].text) assert response_data["query"] == "Paris, France" assert response_data["results_count"] == 1 @pytest.mark.asyncio async def test_call_tool_invalid_tool(self) -> None: """Test calling an invalid tool.""" with pytest.raises(ValueError) as exc_info: await handle_call_tool("invalid_tool", {"location": "Paris"}) assert "Unknown tool" in str(exc_info.value) @pytest.mark.asyncio async def test_call_tool_missing_location(self) -> None: """Test calling tool without required location parameter.""" result = await handle_call_tool("get_coordinates", {}) assert len(result) == 1 assert "Error:" in result[0].text assert "required" in result[0].text.lower() @pytest.mark.asyncio async def test_call_tool_empty_location(self) -> None: """Test calling tool with empty location parameter.""" result = await handle_call_tool("get_coordinates", {"location": ""}) assert len(result) == 1 assert "Error:" in result[0].text assert "cannot be empty" in result[0].text.lower() @pytest.mark.asyncio async def test_call_tool_with_limit(self) -> None: """Test calling tool with limit parameter.""" mock_response_data = [ { "lat": "40.7127281", "lon": "-74.0060152", "display_name": "New York, United States", "place_id": 298085, "type": "city", "class": "place", "importance": 0.9756419939577, "boundingbox": [ "40.4960439", "40.9152414", "-74.2557349", "-73.7000091", ], } ] with patch("aiohttp.ClientSession.get") as mock_get: mock_response = AsyncMock() mock_response.ok = True mock_response.json = AsyncMock(return_value=mock_response_data) mock_get.return_value.__aenter__.return_value = mock_response result = await handle_call_tool( "get_coordinates", {"location": "New York", "limit": 5} ) assert len(result) == 1 response_data = json.loads(result[0].text) assert response_data["query"] == "New York" def main() -> None: pytest.main([__file__, "-v"]) if __name__ == "__main__": main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/X-McKay/geocode-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server