Wird geladen

Implementierung eines Clients

Lektion 547 Min.

Jetzt, da unser MCP-Server funktioniert, ist es Zeit, die Client-Seite zu bauen. Der Client ist das, was es unserer Anwendung ermöglicht, mit dem MCP-Server zu kommunizieren und auf seine Funktionalität zuzugreifen.

Die Client-Architektur verstehen

Bevor wir in den Code eintauchen, lass uns einen wichtigen Punkt zu MCP-Projekten klären. Normalerweise würdest du entweder einen MCP-Client oder einen MCP-Server implementieren - nicht beides. Wir bauen in diesem Projekt beides, nur damit du sehen kannst, wie sie zusammenarbeiten.

Diagramm unseres Servers, der den MCP-Client enthält, welcher sich in beide Richtungen mit einem separaten MCP-Server verbindet.

Der MCP-Client besteht aus zwei Hauptkomponenten:

  • MCP Client - Eine benutzerdefinierte Klasse, die wir erstellen, um die Nutzung der Session einfacher zu machen
  • Client Session - Die eigentliche Verbindung zum Server (Teil des MCP Python SDK)

Diagramm von mcp_client.py, das den MCP Client und die Client Session enthält, welche sich mit einem separaten MCP-Server verbindet.

Die Client Session erfordert eine Ressourcenbereinigung, wenn wir mit ihr fertig sind, weshalb wir sie in unsere benutzerdefinierte Klasse einwickeln. Dies übernimmt das Verbindungsmanagement und die Bereinigung automatisch.

Wie der Client in unsere Anwendung passt

Erinnerst du dich an unseren Anwendungsablauf? Unser CLI-Code muss auf zwei wesentliche Arten mit Claude interagieren:

Sequenzdiagramm des Anwendungsablaufs, das hervorhebt, wo unser CLI-Code den Client verwendet, um Tools aufzulisten und ein Tool aufzurufen.

Der Client ermöglicht beide dieser Interaktionen, indem er die Funktionalität des Servers für unsere Codebasis verfügbar macht.

Implementierung der Kernfunktionen des Clients

Wir müssen zwei wesentliche Funktionen implementieren: list_tools und call_tool.

List Tools Funktion

Diese Funktion holt alle verfügbaren Tools vom Server:

python
async def list_tools(self) -> list[types.Tool]:
    result = await self.session().list_tools()
    return result.tools

Es ist unkompliziert - wir greifen auf unsere Session zu (die Verbindung zum MCP-Server), rufen die eingebaute Funktion list_tools auf und geben die Tools aus dem Ergebnis zurück.

Call Tool Funktion

Diese Funktion führt ein bestimmtes Tool auf dem Server aus:

python
async def call_tool(
    self, tool_name: str, tool_input: dict
) -> types.CallToolResult | None:
    return await self.session().call_tool(tool_name, tool_input)

Wir übergeben den Tool-Namen und die Eingabeparameter (bereitgestellt von Claude) an den Server und geben das Ergebnis zurück.

Den Client testen

Um zu überprüfen, dass unsere Implementierung funktioniert, können wir sie direkt testen. Die Client-Datei enthält ein Test-Harness, das sich mit dem MCP-Server verbindet und Befehle gegen ihn ausführt. Lass es list_tools() aufrufen und das Ergebnis ausgeben:

python
async with MCPClient(
    command="uv", args=["run", "mcp_server.py"]
) as client:
    result = await client.list_tools()
    print(result)

Das Ausführen von uv run mcp_client.py sollte eine Liste der verfügbaren Tools mit ihren Beschreibungen und Eingabeschemas zurückgeben. Du solltest Tools wie read_doc_contents und edit_document sehen, die wir in unserem Server definiert haben.

End-to-End-Testing

Jetzt, da sowohl der Client als auch der Server funktionieren, können wir den kompletten Ablauf testen. Wenn wir unsere Hauptanwendung ausführen und Claude fragen "Was ist der Inhalt des Dokuments report.pdf?", sollte Folgendes passieren:

  1. Die Liste der verfügbaren Tools wird an Claude gesendet
  2. Claude entscheidet sich, das Tool read_doc_contents zu verwenden
  3. Unser Client ruft das Tool auf dem Server auf
  4. Der Server gibt den Dokumentinhalt zurück
  5. Claude antwortet mit den Informationen

Der Client fungiert als Brücke zwischen deinem Anwendungscode und dem MCP-Server und macht es einfach, auf die Funktionalität des Servers zuzugreifen, ohne direkt mit den Low-Level-Verbindungsdetails umgehen zu müssen.