"""Tests for MCP server tools and functionality.""" import json from unittest.mock import AsyncMock, MagicMock, patch import pytest from mcp.types import TextContent, Tool from src.mcp_server import MemberManagementServer class TestMCPServer: """Tests for MCP server initialization and tools.""" def test_mcp_server_initialization(self): """Test that MCP server initializes correctly.""" api_url = "http://127.0.0.1:8000/graphql" server = MemberManagementServer(api_url) assert server.graphql is not None def test_mcp_server_custom_api_url(self): """Test MCP server with custom API URL.""" custom_url = "http://localhost:3000/graphql" server = MemberManagementServer(custom_url) assert server.graphql is not None async def test_list_tools_returns_six_tools(self): """Test that MCP server registers 6 tools.""" server = MemberManagementServer("http://127.0.0.1:8000/graphql") # The server.server object has the registered tools # We can't directly test the decorator, but we can verify the server was initialized assert server.server is not None assert server.server.name == "clubber-mcp-server" class TestMCPToolExecution: """Tests for MCP tool execution.""" @pytest.fixture def mock_graphql_client(self): """Create a mock GraphQL client.""" mock = MagicMock() mock.query = AsyncMock() return mock async def test_list_members_tool(self, mock_graphql_client): """Test list_members tool execution.""" server = MemberManagementServer("http://127.0.0.1:8000/graphql") server.graphql = mock_graphql_client # Mock response mock_graphql_client.query.return_value = { "members": [ { "id": 1, "firstName": "Alice", "lastName": "Smith", "email": "alice@example.com", "phone": "+14155551234", "street": "123 Main St", "apartmentNumber": None, "zip": "12345", "city": "Springfield", "country": "USA", "createdAt": "2024-01-01T00:00:00", "updatedAt": "2024-01-01T00:00:00" } ] } result = await server._list_members() assert len(result) == 1 assert isinstance(result[0], TextContent) assert "Alice Smith" in result[0].text assert "alice@example.com" in result[0].text async def test_get_member_tool(self, mock_graphql_client): """Test get_member tool execution.""" server = MemberManagementServer("http://127.0.0.1:8000/graphql") server.graphql = mock_graphql_client # Mock response mock_graphql_client.query.return_value = { "member": { "id": 1, "firstName": "Bob", "lastName": "Johnson", "email": "bob@example.com", "phone": None, "street": None, "apartmentNumber": None, "zip": None, "city": None, "country": None, "createdAt": "2024-01-01T00:00:00", "updatedAt": "2024-01-01T00:00:00" } } result = await server._get_member(member_id=1) assert len(result) == 1 assert isinstance(result[0], TextContent) assert "Bob Johnson" in result[0].text assert "bob@example.com" in result[0].text async def test_get_member_not_found(self, mock_graphql_client): """Test get_member tool with non-existent ID.""" server = MemberManagementServer("http://127.0.0.1:8000/graphql") server.graphql = mock_graphql_client # Mock response for non-existent member mock_graphql_client.query.return_value = {"member": None} result = await server._get_member(member_id=999) assert len(result) == 1 assert "not found" in result[0].text.lower() async def test_create_member_tool(self, mock_graphql_client): """Test create_member tool execution.""" server = MemberManagementServer("http://127.0.0.1:8000/graphql") server.graphql = mock_graphql_client # Mock response mock_graphql_client.query.return_value = { "createMember": { "id": 1, "firstName": "Charlie", "lastName": "Brown", "email": "charlie@example.com", "phone": None, "street": None, "apartmentNumber": None, "zip": None, "city": None, "country": None, "createdAt": "2024-01-01T00:00:00", "updatedAt": "2024-01-01T00:00:00" } } result = await server._create_member( {"firstName": "Charlie", "lastName": "Brown", "email": "charlie@example.com"} ) assert len(result) == 1 assert "created successfully" in result[0].text.lower() assert "Charlie Brown" in result[0].text async def test_update_member_tool(self, mock_graphql_client): """Test update_member tool execution.""" server = MemberManagementServer("http://127.0.0.1:8000/graphql") server.graphql = mock_graphql_client # Mock response mock_graphql_client.query.return_value = { "updateMember": { "id": 1, "firstName": "David", "lastName": "Smith", "email": "updated@example.com", "phone": "+14155559999", "street": None, "apartmentNumber": None, "zip": None, "city": None, "country": None, "createdAt": "2024-01-01T00:00:00", "updatedAt": "2024-01-02T00:00:00" } } result = await server._update_member( {"id": 1, "email": "updated@example.com", "phone": "+14155559999"} ) assert len(result) == 1 assert "updated successfully" in result[0].text.lower() assert "updated@example.com" in result[0].text async def test_get_graphql_schema_tool(self, mock_graphql_client): """Test get_graphql_schema tool execution.""" server = MemberManagementServer("http://127.0.0.1:8000/graphql") server.graphql = mock_graphql_client # Mock introspection response mock_graphql_client.query.return_value = { "__schema": { "queryType": {"name": "Query"}, "mutationType": {"name": "Mutation"}, "types": [ { "kind": "OBJECT", "name": "Member", "description": None, "fields": [ { "name": "id", "description": None, "type": {"kind": "NON_NULL", "name": None, "ofType": {"kind": "SCALAR", "name": "ID"}}, "args": [] }, { "name": "firstName", "description": None, "type": {"kind": "NON_NULL", "name": None, "ofType": {"kind": "SCALAR", "name": "String"}}, "args": [] } ], "inputFields": None } ] } } result = await server._get_graphql_schema() assert len(result) == 1 assert "GraphQL Schema" in result[0].text assert "Member" in result[0].text async def test_execute_graphql_query_tool(self, mock_graphql_client): """Test execute_graphql_query tool with simple query.""" server = MemberManagementServer("http://127.0.0.1:8000/graphql") server.graphql = mock_graphql_client # Mock response mock_graphql_client.query.return_value = { "members": [ {"id": 1, "firstName": "Alice"}, {"id": 2, "firstName": "Bob"} ] } result = await server._execute_graphql_query( "{ members { id firstName } }" ) assert len(result) == 1 assert "Query executed successfully" in result[0].text # Should contain formatted JSON assert '"firstName": "Alice"' in result[0].text or "'firstName': 'Alice'" in result[0].text async def test_execute_graphql_query_with_variables(self, mock_graphql_client): """Test execute_graphql_query tool with variables.""" server = MemberManagementServer("http://127.0.0.1:8000/graphql") server.graphql = mock_graphql_client # Mock response mock_graphql_client.query.return_value = { "member": {"id": 5, "firstName": "Eve", "email": "eve@example.com"} } result = await server._execute_graphql_query( "query GetMember($id: Int!) { member(id: $id) { id firstName email } }", {"id": 5} ) assert len(result) == 1 assert "Query executed successfully" in result[0].text # Verify the mock was called with variables mock_graphql_client.query.assert_called_once() call_args = mock_graphql_client.query.call_args assert call_args[0][1] == {"id": 5} # Variables were passed async def test_error_handling_api_unavailable(self, mock_graphql_client): """Test error handling when GraphQL API is unavailable.""" server = MemberManagementServer("http://127.0.0.1:8000/graphql") server.graphql = mock_graphql_client # Mock connection error mock_graphql_client.query.side_effect = Exception("Connection refused") # The error should propagate (the handler doesn't catch it in private methods) with pytest.raises(Exception, match="Connection refused"): await server._list_members()