Startseite / Artikel / MCP Von Grund auf Teil 3: Einen Client mit Ihrem Server verbinden

MCP Von Grund auf Teil 3: Einen Client mit Ihrem Server verbinden

Erstellen Sie einen MCP-stdio-Client, der hr_server.py startet, search_employee aufruft und die Ergebnisse zurückgibt – ohne den Server manuell zu starten.

804 Wörter

Der vorherige Teil ließ einen MCP-Server mit einer einzigen Aufgabe zurück: die Möglichkeit zur Suche in Personalangelegenheiten bereitzustellen.

HR MCP Server
      ↓
search_employee

Der Prozess begann mit:

python hr_server.py

Eine Frage blieb offen: Wer spricht eigentlich mit dem Server? Diese Rolle obliegt dem Client.

Client
   ↓
MCP
   ↓
HR MCP Server

Betrachten wir die Begriffe einfach. Der Server bietet Funktionen an. Der Client verbindet sich und nutzt sie.

Lassen Sie uns unseren Client erstellen

Neben hr_server.py fügen Sie ein weiteres Modul hinzu:

hr_client.py

Die Projektstruktur sieht dann so aus:

mcp-hr
│
├── hr_server.py
│
└── hr_client.py

Nun, da der Server bereits geschrieben wurde, konzentriert sich die Aufmerksamkeit auf den Client.

Verbinden mit unserem Server

Fügen Sie Folgendes in hr_client.py ein:

import asyncio

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def main():
    server = StdioServerParameters(
        command="python",
        args=["hr_server.py"]
    )
    async with stdio_client(server) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()

asyncio.run(main())

Zu Beginn wirkt die Auflistung dicht. Der entscheidende Teil ist:

server = StdioServerParameters(
    command="python",
    args=["hr_server.py"]
)

Diese Parameter weisen den Client an, hr_server.py zu starten und sich daran anzuschließen. Der Client startet den Serverprozess und öffnet eine stdio-Sitzung dazu.

Lassen Sie uns nun unser Tool aufrufen

In Teil 2 wurde ein Tool mit dem Namen definiert:

search_employee

Der Client kann nach John wie folgt suchen:

await session.initialize()
result = await session.call_tool(
    "search_employee",
    {"name": "John"}
)

print(result.content[0].text)

In einfachen Worten bittet der Client die Sitzung, search_employee mit dem Namen John auszuführen. Der vollständige Client-Script lautet:

import asyncio

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def main():
    server = StdioServerParameters(
        command="python3",
        args=["hr_server.py"]
    )
    async with stdio_client(server) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool(
                "search_employee",
                {"name": "John"}
            )
            print(result.content[0].text)

asyncio.run(main())

Dieses Datei enthält die gesamte Client-Seite der Demo.

Lassen Sie uns es ausführen

Von einer Terminalzeile aus führen Sie Folgendes aus:

python hr_client.py

Ein nützlicher Hinweis: hr_server.py benötigt keine separate manuelle Startung. Der Client startet es über:

command="python",
args=["hr_server.py"]

und schließt sich anschließend dem laufenden Prozess an.

Was passiert?

Der Client sendet eine Tool-Anfrage in folgender Form:

Tool:
  search_employee
Name:
  John

Der Server empfängt es und führt aus:

search_employee("John")

Er löst auf:

John → Finance

und gibt dieses Ergebnis an den Aufrufer zurück. Von Anfang bis Ende sieht der Pfad so aus:

hr_client.py
     │
     │  search_employee("John")
     ↓
hr_server.py
     │
     ↓
Search employee list
     │
     ↓
John → Finance
     │
     ↓
hr_client.py

Sowohl Seiten des Protokolls führen nun eine echte Hin- und Rückreise durch.

Zurück zu unserem USB-Beispiel

Das Anschließen einer Tastatur an einen Computer bietet einen nützlichen Vergleich.

Keyboard
   ↓
USB
   ↓
Computer

Sowohl die Endgeräte als auch der gemeinsame Kabelprotokoll sind sich einig. Hier spricht der Client MCP und der Server ebenfalls MCP. Genau dieses gemeinsame Abkommen ermöglicht ihre Zusammenarbeit.

Aber hat es das Werkzeug ausgewählt?

Eine Einschränkung fällt leicht übersehen. Betrachten wir erneut den Aufrufort:

session.call_tool(
    "search_employee",
    {"name": "John"}
)

Wer hat search_employee ausgewählt? Der Anwendungsentwickler, indem er den Namen des Tools hardcodete. Der Client hat niemals eine Frage in natürlicher Sprache wie „Arbeitet John im Finanzbereich?“ gelesen und entschieden, welche Funktionalität aufgerufen werden soll. Das nächste fehlende Element ist die automatische Auswahl des Tools.

Was kommt als Nächstes?

Stellen Sie sich vor, der Server erhält mehrere Tools:

search_employee
create_employee
get_leave_balance
list_departments

Wenn ein Benutzer fragt, zu welchem Department John gehört, muss etwas entscheiden, welche passende Funktionalität verwendet werden soll – und nicht irgendein anderes Tool. Diese Entscheidung hängt von den Toolnamen, Beschreibungen sowie dem angezeigten Katalog ab. Im folgenden Teil wird erläutert, wie eine Anwendung unter mehreren verfügbaren MCP-Tools auswählt.

search_employee

Bis dahin ist die wichtige Lektion aus diesem Schritt mechanischer Natur: Ein stdio-Client kann den Server starten, eine Sitzung initialisieren, ein benanntes Tool mit Argumenten aufrufen und die strukturierte Antwort ausgeben – ohne dass ein separater Serverprozess manuell gestartet werden muss.