Files
agent-platform/agent_platform/mcp_client.py
T
Leopold 64b840c94c feat: agent platform initial commit
- FastAPI + HTMX UI: dashboard, agents CRUD, chat, audit, tools
- SQLite schema: agents, conversations, messages, audit, sessions
- Code-agent sync (agents/*.py -> DB on startup)
- MCP client with health check
- Token auth (Bearer + session)
- LiteLLM integration via llm.py
- Docker Compose: agent-platform + mcp-tools services
- Smoke tests pass: /health 200, /api/agents 200, / 401
2026-07-05 22:18:00 +02:00

99 lines
3.0 KiB
Python

"""MCP-Client: Verbindung zum Tool-Server."""
from typing import List, Dict, Any, Optional
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
from config import settings
class MCPClient:
def __init__(self, server_url: str = None):
self.server_url = server_url or settings.MCP_SERVER_URL
self._session: Optional[ClientSession] = None
self._streams = None
self._ctx = None
async def connect(self):
"""Stellt Verbindung zum MCP-Server her (lazy + reconnect-fähig)."""
if self._session:
return
self._ctx = streamablehttp_client(url=self.server_url)
read, write, _ = await self._ctx.__aenter__()
self._session = ClientSession(read, write)
await self._session.__aenter__()
await self._session.initialize()
async def disconnect(self):
if self._session:
try:
await self._session.__aexit__(None, None, None)
except Exception:
pass
if self._ctx:
try:
await self._ctx.__aexit__(None, None, None)
except Exception:
pass
self._session = None
self._ctx = None
async def list_tools(self) -> List[Dict[str, Any]]:
await self.connect()
result = await self._session.list_tools()
tools = []
for tool in result.tools:
t = tool.model_dump() if hasattr(tool, "model_dump") else tool
tools.append(t)
return tools
async def call_tool(self, name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
await self.connect()
result = await self._session.call_tool(name, arguments)
return result.model_dump() if hasattr(result, "model_dump") else result
async def get_tools_for_llm(self, allowed: Optional[List[str]] = None) -> List[Dict[str, Any]]:
"""Konvertiert MCP-Tools in LiteLLM-Tool-Format.
Optional: Filter auf erlaubte Tool-Namen.
"""
tools = await self.list_tools()
result = []
for tool in tools:
name = tool.get("name")
if allowed and name not in allowed:
continue
result.append({
"type": "function",
"function": {
"name": name,
"description": tool.get("description", ""),
"parameters": tool.get("inputSchema", {"type": "object", "properties": {}}),
},
})
return result
async def health(self) -> bool:
"""Prüft ob MCP-Server erreichbar ist."""
try:
await self.connect()
return True
except Exception:
return False
_client: Optional[MCPClient] = None
def get_mcp_client() -> MCPClient:
global _client
if _client is None:
_client = MCPClient()
return _client
async def close_mcp_client():
global _client
if _client:
await _client.disconnect()
_client = None