MCP З нуля, частина 3: Підключення клієнта до вашого сервера
Створіть клієнт MCP stdio, який запускає hr_server.py, викликає функцію search_employee та повертає результати — без необхідності вручну запускати сервер.
У попередній частині залишився сервер MCP із єдиною функцією: надавати можливість пошуку в HR-системі.
HR MCP Server
↓
search_employee
Цей процес починався так:
python hr_server.py
Залишалося одне незрозуміле питання: хто насправді спілкується з сервером? Цю роль виконує клієнт.
Client
↓
MCP
↓
HR MCP Server
Розглядаймо ці поняття просто. Сервер пропонує можливості, а клієнт під’єднується та їх використовує.
Створимо наш клієнт
Окрім hr_server.py додайте ще один модуль:
hr_client.py
Структура проекту стає такою:
mcp-hr
│
├── hr_server.py
│
└── hr_client.py
Оскільки сервер вже написаний, увага зосереджується на клієнті.
Під’єднання до нашого сервера
Вставте наступний код у hr_client.py:
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())
Спочатку цей код здається складним. Вирішальною частиною є:
server = StdioServerParameters(
command="python",
args=["hr_server.py"]
)
Ці параметри наказують клієнту запустити та під’єднатися до hr_server.py. Клієнт запускає процес сервера та відкриває сеанс stdio з ним.
Тепер скличемо наш інструмент
У частині 2 був описаний інструмент під назвою:
search_employee
Клієнт може шукати Джона ось так:
await session.initialize()
result = await session.call_tool(
"search_employee",
{"name": "John"}
)
print(result.content[0].text)
Простими словами, клієнт просить сеанс виконати search_employee з ім’ям Джон. Повний скрипт клієнта є таким:
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())
Цей файл є повною клієнтською частиною демонстрації.
Запустимо його
У терміналі виконайте:
python hr_client.py
Корисна деталь: hr_server.py не потребує окремого ручного запуску. Клієнт запускає його через:
command="python",
args=["hr_server.py"]
а потім під’єднується до запущеного процесу.
Що відбувається?
Клієнт надсилає запит до інструменту у такому форматі:
Tool:
search_employee
Name:
John
Сервер отримує його та виконує:
search_employee("John")
Він розрішує:
John → Finance
і повертає цей результат тому, хто звернувся. Від початку до кінця шлях виглядає так:
hr_client.py
│
│ search_employee("John")
↓
hr_server.py
│
↓
Search employee list
│
↓
John → Finance
│
↓
hr_client.py
Обидві сторони протоколу зараз здійснюють справжню подорож туди й назад.
Повернення до нашого прикладу USB
Підключення клавіатури до комп’ютера є корисним порівнянням.
Keyboard
↓
USB
↓
Computer
Обидві сторони домовляються про спільний протокол кабелю. Тут клієнт використовує MCP, а сервер також MCP. Саме цей спільний контракт дозволяє їм співпрацювати.
Але чи обрав він інструмент?
Одне з обмежень легко пропустити. Розгляньмо місце виклику знову:
session.call_tool(
"search_employee",
{"name": "John"}
)
Хто обрав search_employee? Автор додатку — шляхом жорсткого введення назви інструменту. Клієнт ніколи не читав запитання мовою природи на кшталт «Чи працює Джон у відділі фінансів?» та не вирішував, яку функцію активувати. Наступною відсутньою складовою є автоматичний вибір інструменту.
Що далі?
Уявіть, що на сервері з’являється кілька нових інструментів:
search_employee
create_employee
get_leave_balance
list_departments
Коли користувач запитує, до якого відділу належить Джон, щось має вирішити, що правильною функцією буде:
search_employee
а не якийсь інший інструмент. Це рішення залежить від назв інструментів, їхніх описів та каталогу, який публікується. У наступному розділі розглядається, як додаток обирає серед інструментів MCP, коли їх стає багато.
До того часу важливий урок, який можна засвоїти з цього кроку, є механічним: клієнт stdio може запустити сервер, ініціалізувати сесію, викликати зазначений інструмент із аргументами та вивести структуровану відповідь — без необхідності ручного запуску окремого процесу сервера.