#!/usr/bin/env python3
"""
Test Suite for Remote MCP Server Functionality
Tests the new remote MCP server deployment capabilities including:
- Remote server startup and configuration
- Transport switching (stdio, sse, streamable-http)
- OAuth authentication in remote mode
- Client connectivity testing
- Environment variable handling
"""
import importlib.util
import os
import sys
import unittest
from unittest.mock import patch
# Add project root to Python path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
class TestRemoteMCPServerConfig(unittest.TestCase):
"""Test remote MCP server configuration and environment handling."""
def setUp(self):
"""Set up test environment."""
self.original_env = os.environ.copy()
def tearDown(self):
"""Clean up test environment."""
os.environ.clear()
os.environ.update(self.original_env)
def test_remote_server_import(self):
"""Test that remote-mcp-server.py can be imported."""
# Get the path to remote-mcp-server.py
remote_script_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
"remote-mcp-server.py",
)
# Check file exists
self.assertTrue(os.path.exists(remote_script_path), "remote-mcp-server.py should exist")
try:
# Import the module using importlib
spec = importlib.util.spec_from_file_location("remote_mcp_server", remote_script_path)
remote_mcp_server = importlib.util.module_from_spec(spec)
spec.loader.exec_module(remote_mcp_server)
# Test that main function exists
self.assertTrue(
hasattr(remote_mcp_server, "main"),
"remote-mcp-server.py should have main function",
)
self.assertTrue(True, "Remote MCP server module imported successfully")
except Exception as e:
self.fail(f"Failed to import remote-mcp-server: {e}")
def test_transport_configuration(self):
"""Test transport configuration from environment variables."""
test_cases = [
{
"env": {"MCP_TRANSPORT": "streamable-http"},
"expected_transport": "streamable-http",
"expected_path": "/mcp",
},
{
"env": {"MCP_TRANSPORT": "sse"},
"expected_transport": "sse",
"expected_path": "/sse",
},
{
"env": {}, # No transport specified
"expected_transport": "streamable-http", # Default
"expected_path": "/mcp",
},
]
for case in test_cases:
with self.subTest(case=case):
# Set environment
for key, value in case["env"].items():
os.environ[key] = value
# Test configuration values
transport = os.getenv("MCP_TRANSPORT", "streamable-http")
path = os.getenv("MCP_PATH", "/mcp" if transport == "streamable-http" else "/sse")
self.assertEqual(transport, case["expected_transport"])
self.assertEqual(path, case["expected_path"])
# Clean up environment
for key in case["env"].keys():
os.environ.pop(key, None)
def test_oauth_configuration(self):
"""Test OAuth 2.1 generic configuration for remote deployment."""
oauth_env = {
"ENABLE_AUTH": "true",
"AUTH_ISSUER_URL": "https://login.microsoftonline.com/test-tenant-id/v2.0",
"AUTH_AUDIENCE": "test-client-id",
}
for key, value in oauth_env.items():
os.environ[key] = value
# Test that OAuth 2.1 is properly configured
self.assertEqual(os.getenv("ENABLE_AUTH"), "true")
self.assertEqual(
os.getenv("AUTH_ISSUER_URL"),
"https://login.microsoftonline.com/test-tenant-id/v2.0",
)
self.assertEqual(os.getenv("AUTH_AUDIENCE"), "test-client-id")
class TestRemoteMCPServerStartup(unittest.TestCase):
"""Test remote MCP server startup and transport initialization."""
def setUp(self):
"""Set up test environment."""
self.original_env = os.environ.copy()
def tearDown(self):
"""Clean up test environment."""
os.environ.clear()
os.environ.update(self.original_env)
def test_streamable_http_startup(self):
"""Test server startup with streamable-http transport."""
os.environ.update(
{
"MCP_TRANSPORT": "streamable-http",
"MCP_HOST": "0.0.0.0",
"MCP_PORT": "8000",
}
)
# Import remote server module
remote_script_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
"remote-mcp-server.py",
)
with patch("kafka_schema_registry_unified_mcp.mcp") as mock_mcp:
# Mock the run method to avoid actually starting server
mock_mcp.run.return_value = None
# Import and test
try:
spec = importlib.util.spec_from_file_location("remote_mcp_server", remote_script_path)
remote_mcp_server = importlib.util.module_from_spec(spec)
spec.loader.exec_module(remote_mcp_server)
# Test main function
result = remote_mcp_server.main()
# Verify mcp.run was called with correct transport
mock_mcp.run.assert_called_once_with(transport="streamable-http")
self.assertEqual(result, 0)
except Exception:
# If we can't test the startup, at least verify config is correct
transport = os.getenv("MCP_TRANSPORT", "streamable-http")
self.assertEqual(transport, "streamable-http")
def test_invalid_transport(self):
"""Test server startup with invalid transport."""
os.environ.update({"MCP_TRANSPORT": "invalid-transport"})
# Import remote server module
remote_script_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
"remote-mcp-server.py",
)
with patch("kafka_schema_registry_unified_mcp.mcp") as mock_mcp:
try:
spec = importlib.util.spec_from_file_location("remote_mcp_server", remote_script_path)
remote_mcp_server = importlib.util.module_from_spec(spec)
spec.loader.exec_module(remote_mcp_server)
result = remote_mcp_server.main()
# Should return error code for invalid transport
self.assertEqual(result, 1)
mock_mcp.run.assert_not_called()
except Exception:
# If we can't test the startup, at least verify config is invalid
transport = os.getenv("MCP_TRANSPORT", "streamable-http")
self.assertEqual(transport, "invalid-transport")
class TestRemoteMCPDockerIntegration(unittest.TestCase):
"""Test Docker integration for remote MCP deployment."""
def test_dockerfile_includes_remote_script(self):
"""Test that Dockerfile includes remote-mcp-server.py."""
dockerfile_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "Dockerfile")
self.assertTrue(os.path.exists(dockerfile_path), "Dockerfile should exist")
with open(dockerfile_path, "r") as f:
dockerfile_content = f.read()
# Check that remote-mcp-server.py is copied into the image
self.assertIn(
"remote-mcp-server.py",
dockerfile_content,
"Dockerfile should copy remote-mcp-server.py",
)
class TestRemoteMCPDocumentation(unittest.TestCase):
"""Test documentation for remote MCP deployment."""
def test_remote_deployment_guide_exists(self):
"""Test that remote deployment documentation exists."""
docs_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
"docs",
"remote-mcp-deployment.md",
)
self.assertTrue(os.path.exists(docs_path), "Remote MCP deployment guide should exist")
def run_remote_mcp_tests():
"""Run all remote MCP server tests."""
# Create test suite
loader = unittest.TestLoader()
suite = unittest.TestSuite()
# Add test classes
test_classes = [
TestRemoteMCPServerConfig,
TestRemoteMCPServerStartup,
TestRemoteMCPDockerIntegration,
TestRemoteMCPDocumentation,
]
for test_class in test_classes:
tests = loader.loadTestsFromTestCase(test_class)
suite.addTests(tests)
# Run tests
runner = unittest.TextTestRunner(verbosity=2)
result = runner.run(suite)
return result.wasSuccessful()
if __name__ == "__main__":
print("๐ Running Remote MCP Server Tests...")
print("=" * 60)
success = run_remote_mcp_tests()
print("=" * 60)
if success:
print("โ
All remote MCP server tests passed!")
sys.exit(0)
else:
print("โ Some remote MCP server tests failed!")
sys.exit(1)