Spaces:
Sleeping
Sleeping
Download backend/mcp_sync.py from EnvironmentalAI/WaterScopeAI-Search: direct link, hf CLI and curl.
- Browser
- Download file 2.43 kB
-
https://huggingface.co/spaces/EnvironmentalAI/WaterScopeAI-Search/resolve/main/backend/mcp_sync.py
- Command line
-
hf download hf://spaces/EnvironmentalAI/WaterScopeAI-Search/backend/mcp_sync.py
-
curl -L -o mcp_sync.py https://huggingface.co/spaces/EnvironmentalAI/WaterScopeAI-Search/resolve/main/backend/mcp_sync.py
2.43 kB
| """Synchronous MCP client for Flask (stdio subprocess).""" | |
| from __future__ import annotations | |
| import asyncio | |
| import atexit | |
| import os | |
| import threading | |
| from typing import Any | |
| from backend.mcp_client import PaperMCPClient | |
| _client: PaperMCPClient | None = None | |
| _connect_lock = threading.Lock() | |
| _shutdown_registered = False | |
| _loop: asyncio.AbstractEventLoop | None = None | |
| _loop_thread: threading.Thread | None = None | |
| _loop_ready = threading.Event() | |
| def use_mcp() -> bool: | |
| return os.getenv("USE_MCP", "1").lower() in {"1", "true", "yes"} | |
| def _start_loop_thread() -> asyncio.AbstractEventLoop: | |
| global _loop, _loop_thread | |
| if _loop is not None and _loop.is_running(): | |
| return _loop | |
| def _runner() -> None: | |
| global _loop | |
| loop = asyncio.new_event_loop() | |
| asyncio.set_event_loop(loop) | |
| _loop = loop | |
| _loop_ready.set() | |
| loop.run_forever() | |
| _loop_ready.clear() | |
| _loop_thread = threading.Thread(target=_runner, daemon=True, name="mcp-async-loop") | |
| _loop_thread.start() | |
| _loop_ready.wait() | |
| if _loop is None: | |
| raise RuntimeError("MCP event loop failed to start.") | |
| return _loop | |
| def _run_async(coro, *, timeout: float = 600): | |
| loop = _start_loop_thread() | |
| future = asyncio.run_coroutine_threadsafe(coro, loop) | |
| return future.result(timeout=timeout) | |
| def ensure_mcp_connected() -> PaperMCPClient: | |
| global _client, _shutdown_registered | |
| if _client is not None and _client._session is not None: | |
| return _client | |
| with _connect_lock: | |
| if _client is not None and _client._session is not None: | |
| return _client | |
| client = PaperMCPClient() | |
| _run_async(client.connect()) | |
| _client = client | |
| if not _shutdown_registered: | |
| atexit.register(shutdown_mcp) | |
| _shutdown_registered = True | |
| return _client | |
| def shutdown_mcp() -> None: | |
| global _client, _loop | |
| if _client is None: | |
| return | |
| try: | |
| _run_async(_client.close(), timeout=30) | |
| except Exception: | |
| pass | |
| _client = None | |
| if _loop is not None and _loop.is_running(): | |
| _loop.call_soon_threadsafe(_loop.stop) | |
| def call_mcp_tool(name: str, arguments: dict[str, Any] | None = None) -> Any: | |
| client = ensure_mcp_connected() | |
| return _run_async(client.call_tool(name, arguments)) | |