MCPcopy Create free account
hub / github.com/agentforce314/clawcodex / McpRuntime

Class McpRuntime

src/server/mcp_runtime.py:54–162  ·  view source on GitHub ↗

Owns the background loop, the connected clients, and the wrapped tools.

Source from the content-addressed store, hash-verified

52
53
54class McpRuntime:
55 """Owns the background loop, the connected clients, and the wrapped tools."""
56
57 def __init__(self) -> None:
58 self._loop: asyncio.AbstractEventLoop | None = None
59 self._thread: threading.Thread | None = None
60 self.clients: dict[str, Any] = {}
61 self.servers: dict[str, list[str]] = {} # server name -> tool names
62 self.tools: list[Any] = [] # wrapped sync Tool objects (mcp__server__tool)
63
64 def _run(self, coro: Any, timeout: float) -> Any:
65 assert self._loop is not None
66 return asyncio.run_coroutine_threadsafe(coro, self._loop).result(timeout)
67
68 def start(self) -> bool:
69 """Connect all enabled, configured MCP servers. Returns True if at least
70 one tool was registered. Fully guarded: any failure leaves the runtime
71 empty and never raises."""
72 try:
73 from src.services.mcp.config import get_all_mcp_configs
74 except Exception: # noqa: BLE001
75 logger.debug("[mcp] config module unavailable", exc_info=True)
76 return False
77 try:
78 configs = get_all_mcp_configs()
79 except Exception: # noqa: BLE001
80 logger.debug("[mcp] reading configs failed", exc_info=True)
81 return False
82 enabled = {
83 name: scoped
84 for name, scoped in (configs or {}).items()
85 if getattr(getattr(scoped, "config", None), "enabled", True)
86 }
87 if not enabled:
88 return False
89
90 self._loop = asyncio.new_event_loop()
91 self._thread = threading.Thread(
92 target=self._loop.run_forever, daemon=True, name="mcp-loop"
93 )
94 self._thread.start()
95
96 from src.services.mcp.client import McpClient
97
98 for name, scoped in enabled.items():
99 try:
100 client = McpClient()
101 self._run(client.connect(name, scoped), _CONNECT_TIMEOUT_S)
102 mcp_tools = self._run(client.list_tools(), _CONNECT_TIMEOUT_S)
103 self.clients[name] = client
104 self.servers[name] = [t.name for t in mcp_tools]
105 for mt in mcp_tools:
106 self.tools.append(self._wrap(name, mt, client))
107 logger.info("[mcp] connected %s (%d tools)", name, len(mcp_tools))
108 except Exception: # noqa: BLE001 — one bad server must not sink the rest
109 logger.exception("[mcp] connect failed: %s", name)
110
111 if not self.tools:

Calls

no outgoing calls