mcp-name-cheap/tests/test_mcp_server.py
Claude Code f5e63c888d Initial commit: MCP Name Cheap server implementation
- Production-ready MCP server for Name Cheap API integration
- Domain management (registration, renewal, availability checking)
- DNS management (records, nameserver configuration)
- SSL certificate management and monitoring
- Account information and balance checking
- Smart identifier resolution for improved UX
- Comprehensive error handling with specific exception types
- 80%+ test coverage with unit, integration, and MCP tests
- CLI and MCP server interfaces
- FastMCP 2.10.5+ implementation with full MCP spec compliance

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-20 03:43:11 -06:00

266 lines
12 KiB
Python

"""Test MCP server functionality using FastMCP testing patterns."""
import pytest
from unittest.mock import patch, Mock
from fastmcp import testing
from mcp_namecheap.fastmcp_server import mcp_server
from .conftest import create_mock_response
class TestMCPServer:
"""Test MCP server tools and resources."""
@pytest.fixture
def mcp_client(self):
"""Create FastMCP test client."""
return testing.create_client(mcp_server)
@pytest.mark.mcp
async def test_list_domains_tool(self, mcp_client, sample_domains_response):
"""Test list domains tool."""
with patch('mcp_namecheap.domains.get_client') as mock_get_client:
mock_client = Mock()
mock_client.list_domains.return_value = sample_domains_response["DomainGetListResult"]["Domain"]
mock_get_client.return_value = mock_client
result = await mcp_client.call_tool("list_domains")
assert result["success"] is True
assert len(result["data"]) == 2
assert result["data"][0]["@Name"] == "example.com"
@pytest.mark.mcp
async def test_get_domain_info_tool(self, mcp_client, sample_domain_info_response):
"""Test get domain info tool."""
with patch('mcp_namecheap.domains.get_client') as mock_get_client:
mock_client = Mock()
mock_client.get_domain_info.return_value = sample_domain_info_response
mock_get_client.return_value = mock_client
result = await mcp_client.call_tool("get_domain_info", domain_identifier="example.com")
assert result["success"] is True
assert result["data"]["DomainGetInfoResult"]["@DomainName"] == "example.com"
@pytest.mark.mcp
async def test_check_domain_availability_tool(self, mcp_client, sample_domain_check_response):
"""Test check domain availability tool."""
with patch('mcp_namecheap.domains.get_client') as mock_get_client:
mock_client = Mock()
mock_client.check_domain_availability.return_value = sample_domain_check_response["DomainCheckResult"]
mock_get_client.return_value = mock_client
result = await mcp_client.call_tool("check_domain_availability", {
"domains": ["available-domain.com", "taken-domain.com"]
})
assert result["success"] is True
assert len(result["data"]) == 2
assert result["data"][0]["@Available"] == "true"
assert result["data"][1]["@Available"] == "false"
@pytest.mark.mcp
async def test_get_dns_records_tool(self, mcp_client, sample_dns_records_response):
"""Test get DNS records tool."""
with patch('mcp_namecheap.dns.get_client') as mock_get_client:
mock_client = Mock()
mock_client.get_dns_records.return_value = sample_dns_records_response["DomainDNSGetHostsResult"]["host"]
mock_get_client.return_value = mock_client
result = await mcp_client.call_tool("get_dns_records", domain_identifier="example.com")
assert result["success"] is True
assert len(result["data"]) == 2
assert result["data"][0]["@Type"] == "A"
assert result["data"][1]["@Type"] == "CNAME"
@pytest.mark.mcp
async def test_set_dns_records_tool(self, mcp_client):
"""Test set DNS records tool."""
with patch('mcp_namecheap.dns.get_client') as mock_get_client:
mock_client = Mock()
mock_client.set_dns_records.return_value = {"Status": "OK"}
mock_get_client.return_value = mock_client
result = await mcp_client.call_tool("set_dns_records", {
"domain_identifier": "example.com",
"records": [
{
"hostname": "@",
"record_type": "A",
"address": "192.168.1.1",
"ttl": 1800
}
]
})
assert result["success"] is True
@pytest.mark.mcp
async def test_list_ssl_certificates_tool(self, mcp_client, sample_ssl_certificates_response):
"""Test list SSL certificates tool."""
with patch('mcp_namecheap.ssl.get_client') as mock_get_client:
mock_client = Mock()
mock_client.list_ssl_certificates.return_value = sample_ssl_certificates_response["SSLListResult"]["SSL"]
mock_get_client.return_value = mock_client
result = await mcp_client.call_tool("list_ssl_certificates")
assert result["success"] is True
assert len(result["data"]) == 1
assert result["data"][0]["@HostName"] == "example.com"
@pytest.mark.mcp
async def test_get_account_info_tool(self, mcp_client, sample_account_info_response):
"""Test get account info tool."""
with patch('mcp_namecheap.account.get_client') as mock_get_client:
mock_client = Mock()
mock_client.get_account_info.return_value = sample_account_info_response
mock_get_client.return_value = mock_client
result = await mcp_client.call_tool("get_account_info")
assert result["success"] is True
assert result["data"]["UserGetAccountResult"]["@UserName"] == "test_user"
@pytest.mark.mcp
async def test_get_account_balance_tool(self, mcp_client, sample_balance_response):
"""Test get account balance tool."""
with patch('mcp_namecheap.account.get_client') as mock_get_client:
mock_client = Mock()
mock_client.get_account_balance.return_value = sample_balance_response
mock_get_client.return_value = mock_client
result = await mcp_client.call_tool("get_account_balance")
assert result["success"] is True
assert result["data"]["UserGetBalancesResult"]["@AccountBalance"] == "100.00"
@pytest.mark.mcp
async def test_domains_resource(self, mcp_client, sample_domains_response):
"""Test domains resource."""
with patch('mcp_namecheap.domains.get_client') as mock_get_client:
mock_client = Mock()
mock_client.list_domains.return_value = sample_domains_response["DomainGetListResult"]["Domain"]
mock_get_client.return_value = mock_client
result = await mcp_client.read_resource("namecheap://domains")
assert "Domains in Account:" in result
assert "example.com" in result
assert "test.org" in result
@pytest.mark.mcp
async def test_domain_resource(self, mcp_client, sample_domain_info_response):
"""Test individual domain resource."""
with patch('mcp_namecheap.domains.get_client') as mock_get_client:
mock_client = Mock()
mock_client.get_domain_info.return_value = sample_domain_info_response
mock_get_client.return_value = mock_client
result = await mcp_client.read_resource("namecheap://domain/example.com")
assert "Domain Information: example.com" in result
assert "test_user" in result
@pytest.mark.mcp
async def test_dns_resource(self, mcp_client, sample_dns_records_response):
"""Test DNS records resource."""
with patch('mcp_namecheap.dns.get_client') as mock_get_client:
mock_client = Mock()
mock_client.get_dns_records.return_value = sample_dns_records_response["DomainDNSGetHostsResult"]["host"]
mock_get_client.return_value = mock_client
result = await mcp_client.read_resource("namecheap://dns/example.com")
assert "DNS Records for example.com" in result
assert "192.168.1.1" in result
@pytest.mark.mcp
async def test_ssl_resource(self, mcp_client, sample_ssl_certificates_response):
"""Test SSL certificates resource."""
with patch('mcp_namecheap.ssl.get_client') as mock_get_client:
mock_client = Mock()
mock_client.list_ssl_certificates.return_value = sample_ssl_certificates_response["SSLListResult"]["SSL"]
mock_get_client.return_value = mock_client
result = await mcp_client.read_resource("namecheap://ssl")
assert "SSL Certificates in Account:" in result
assert "example.com" in result
@pytest.mark.mcp
async def test_account_resource(self, mcp_client, sample_account_info_response):
"""Test account resource."""
with patch('mcp_namecheap.account.get_client') as mock_get_client:
mock_client = Mock()
mock_client.get_account_info.return_value = sample_account_info_response
mock_get_client.return_value = mock_client
result = await mcp_client.read_resource("namecheap://account")
assert "Account Information" in result
assert "test_user" in result
@pytest.mark.mcp
async def test_balance_resource(self, mcp_client, sample_balance_response):
"""Test balance resource."""
with patch('mcp_namecheap.account.get_client') as mock_get_client:
mock_client = Mock()
mock_client.get_account_balance.return_value = sample_balance_response
mock_get_client.return_value = mock_client
result = await mcp_client.read_resource("namecheap://balance")
assert "Account Balance" in result
assert "100.00" in result
class TestMCPErrorHandling:
"""Test MCP server error handling."""
@pytest.fixture
def mcp_client(self):
"""Create FastMCP test client."""
return testing.create_client(mcp_server)
@pytest.mark.mcp
async def test_domain_not_found_error(self, mcp_client):
"""Test domain not found error handling."""
from mcp_namecheap.server import NameCheapNotFoundError
with patch('mcp_namecheap.domains.get_client') as mock_get_client:
mock_client = Mock()
mock_client.get_domain_info.side_effect = NameCheapNotFoundError("Domain not found")
mock_get_client.return_value = mock_client
result = await mcp_client.call_tool("get_domain_info", domain_identifier="nonexistent.com")
assert result["success"] is False
assert "Domain not found" in result["error"]
@pytest.mark.mcp
async def test_validation_error(self, mcp_client):
"""Test validation error handling."""
from pydantic import ValidationError
with pytest.raises(ValidationError):
await mcp_client.call_tool("check_domain_availability", {
"domains": [] # Empty list should fail validation
})
@pytest.mark.mcp
async def test_api_error_handling(self, mcp_client):
"""Test API error handling."""
from mcp_namecheap.server import NameCheapAPIError
with patch('mcp_namecheap.domains.get_client') as mock_get_client:
mock_client = Mock()
mock_client.list_domains.side_effect = NameCheapAPIError("API Error")
mock_get_client.return_value = mock_client
result = await mcp_client.call_tool("list_domains")
assert result["success"] is False
assert "API Error" in result["error"]