from __future__ import annotations import importlib import sys from types import ModuleType _MCP_MODULE_NAMES = ( "mcp", "mcp.server", "mcp.server.stdio", "mcp.types", ) def _build_mcp_sdk_stub() -> dict[str, ModuleType]: mcp_module = type(sys)("mcp") mcp_server_module = type(sys)("mcp.server") mcp_stdio_module = type(sys)("mcp.server.stdio") mcp_types_module = type(sys)("mcp.types") class DummyServer: def __init__(self, name: str) -> None: self.name = name def list_tools(self): return lambda fn: fn def call_tool(self): return lambda fn: fn def create_initialization_options(self): return {} class DummyTool: def __init__(self, **kwargs) -> None: self.kwargs = kwargs class DummyTextContent: def __init__(self, **kwargs) -> None: self.kwargs = kwargs async def dummy_stdio_server(): raise RuntimeError("stdio_server should not run in unit tests") mcp_server_module.Server = DummyServer mcp_stdio_module.stdio_server = dummy_stdio_server mcp_types_module.TextContent = DummyTextContent mcp_types_module.Tool = DummyTool return { "mcp": mcp_module, "mcp.server": mcp_server_module, "mcp.server.stdio": mcp_stdio_module, "mcp.types": mcp_types_module, } def import_module_with_mcp_stub(module_name: str): original_target_module = sys.modules.get(module_name) parent_name, _, child_name = module_name.rpartition(".") original_parent_module = sys.modules.get(parent_name) if parent_name else None original_parent_attr_exists = bool( original_parent_module and child_name and hasattr(original_parent_module, child_name) ) original_parent_attr = ( getattr(original_parent_module, child_name) if original_parent_attr_exists else None ) original_modules = {name: sys.modules.get(name) for name in _MCP_MODULE_NAMES} stub_modules = _build_mcp_sdk_stub() sys.modules.pop(module_name, None) for name, module in stub_modules.items(): sys.modules[name] = module try: return importlib.import_module(module_name) finally: if original_target_module is None: sys.modules.pop(module_name, None) else: sys.modules[module_name] = original_target_module if child_name: current_parent_module = sys.modules.get(parent_name) or original_parent_module if current_parent_module is not None: if original_parent_attr_exists: setattr(current_parent_module, child_name, original_parent_attr) else: try: delattr(current_parent_module, child_name) except AttributeError: pass for name, original_module in original_modules.items(): if original_module is None: sys.modules.pop(name, None) else: sys.modules[name] = original_module