diff --git a/jarvis_mcp/client.py b/jarvis_mcp/client.py index 26668dd..7020980 100644 --- a/jarvis_mcp/client.py +++ b/jarvis_mcp/client.py @@ -1,31 +1,54 @@ -# jarvis_mcp/client.py (oder wo du sie hast) - +# jarvis_mcp/client.py +import asyncio from mcp import ClientSession -from mcp.client.streamable_http import streamablehttp_client # wichtig: streamablehttp_client (ohne _) +from mcp.client.streamable_http import streamablehttp_client +from util.logger import get_logger + +logger = get_logger("MCP") class MCPClient: def __init__(self, url: str): - self.url = url + self.url = url.rstrip('/') + "/mcp/" # WICHTIG: /mcp Endpunkt self.session = None - self._client_context = None # Context Manager + self._client_context = None async def connect(self): - if self.session: + if self.session is not None: return - # Neuer Streamable HTTP Client (gibt 3 Werte zurück) - self._client_context = streamablehttp_client( - self.url, - terminate_on_close=False # wichtig für langlebige Verbindungen - ) + logger.info(f"Verbinde mit OpenHAB MCP: {self.url}") - read, write, _ = await self._client_context.__aenter__() + try: + self._client_context = streamablehttp_client( + self.url, + terminate_on_close=True + ) - self.session = ClientSession(read, write) - await self.session.initialize() + streams = await self._client_context.__aenter__() - print("✅ MCP Verbindung hergestellt") + # Manche Versionen geben 2, manche 3 Werte zurück + if isinstance(streams, tuple): + if len(streams) == 3: + read, write, _ = streams + else: + read, write = streams + else: + raise ValueError("Unerwartetes Format von streamablehttp_client") + + self.session = ClientSession(read, write) + + # Mit Timeout + await asyncio.wait_for(self.session.initialize(), timeout=8.0) + + logger.info("✅ OpenHAB MCP Verbindung erfolgreich") + + except asyncio.TimeoutError: + logger.error("❌ Timeout beim MCP Connect") + raise + except Exception as e: + logger.error(f"❌ MCP Connect Fehler: {e}") + raise async def list_tools(self): await self.connect() @@ -36,10 +59,23 @@ class MCPClient: return await self.session.call_tool(name, arguments) async def close(self): - if self._client_context: - await self._client_context.__aexit__(None, None, None) - self._client_context = None + """Sauberes Aufräumen""" + closed = False if self.session: - # Session schließen falls nötig - await self.session.close() - self.session = None \ No newline at end of file + try: + if hasattr(self.session, "close"): + await self.session.close() + closed = True + except Exception as e: + logger.warning(f"Session close Warning: {e}") + + if self._client_context: + try: + await self._client_context.__aexit__(None, None, None) + except Exception as e: + logger.warning(f"Context close Warning: {e}") + + self.session = None + self._client_context = None + if closed: + logger.info("MCP Verbindung geschlossen") \ No newline at end of file