Разработка ИИ-агентов · Модуль 4 · Урок 4.3
Подключение агента к MCP-серверам
Хост, клиент и подключение
С другой стороны протокола — хост: ваше приложение-агент. Внутри него работает MCP-клиент, который устанавливает соединение с сервером. Для stdio это значит запустить сервер как подпроцесс и говорить через его stdin/stdout; для удалённого — открыть HTTP-соединение. Часто хост держит несколько клиентов — по одному на каждый подключённый сервер.
После соединения клиент выполняет рукопожатие initialize и запрашивает tools/list — узнаёт, какие инструменты предлагает сервер. Эти описания приходят уже в виде «имя + описание + JSON Schema» — то есть в точности том формате, который понимает модель.
Мост между MCP и tool calling модели
Ключевая идея подключения: инструменты MCP-серверов превращаются в обычные tool-схемы для модели. Хост собирает инструменты со всех серверов, объединяет их (следя за уникальностью имён — например, префиксуя именем сервера) и передаёт модели как её tools. Дальше работает знакомый агентный цикл из Модуля 1:
- Модель в ответ запрашивает вызов инструмента (
tool_calls). - Хост по имени понимает, какому серверу он принадлежит, и шлёт туда
tools/callс аргументами. - Сервер выполняет и возвращает результат; хост дозаписывает его как
tool-сообщение модели.
То есть MCP не меняет цикл агента — он лишь источник инструментов. Модель по-прежнему не знает о JSON-RPC; для неё это просто инструменты.
Безопасность и жизненный цикл
Подключать чужой MCP-сервер — это давать агенту новые возможности, в том числе потенциально опасные. Правила те же, что в Модуле 2–3, но усиленные: подключайте только доверенные серверы; помните про prompt injection — описание инструмента или его результат могут содержать вредоносные инструкции, поэтому к выводу MCP-инструмента относитесь как к недоверенным данным; держите программные gate'ы и human-in-the-loop на необратимых действиях, откуда бы инструмент ни пришёл.
Не забывайте про жизненный цикл соединения: корректно завершайте подпроцессы серверов, обрабатывайте их падения и переподключение, ставьте таймауты на вызовы. Подключённый сервер — это внешняя зависимость со всеми вытекающими: он может зависнуть, упасть или ответить медленно.
// mcpClient — упрощённый клиент: умеет ListTools и CallTool по JSON-RPC.
type mcpClient interface {
ListTools() ([]Tool, error)
CallTool(name string, argsJSON string) (string, error)
}
// collectTools собирает инструменты всех серверов и помнит, кто кому принадлежит.
func collectTools(clients map[string]mcpClient) ([]Tool, map[string]string, error) {
var all []Tool
owner := map[string]string{} // имя инструмента -> id сервера
for serverID, c := range clients {
tools, err := c.ListTools()
if err != nil {
return nil, nil, err
}
for _, t := range tools {
name := serverID + "__" + t.Function.Name // префикс для уникальности
t.Function.Name = name
owner[name] = serverID
all = append(all, t)
}
}
return all, owner, nil // all уходит модели как её tools
}
// При tool_calls от модели маршрутизируем вызов нужному серверу:
// serverID := owner[call.Name]
// result, _ := clients[serverID].CallTool(strings.TrimPrefix(call.Name, serverID+"__"), call.ArgsJSON)
// // дозаписываем result как сообщение роли "tool" (агентный цикл Модуля 1)Anti-patterns
| Анти-паттерн | Почему плохо | Как правильно |
|---|---|---|
| Подключать любой сервер без проверки доверия | Чужой код/инструкции получают доступ к агенту | Только доверенные серверы; принцип наименьших привилегий |
| Доверять выводу MCP-инструмента как факту | Prompt injection через описание/результат | Относиться к выводу как к недоверенным данным; gate на действия |
| Коллизии имён инструментов с разных серверов | Маршрутизация вызова ломается | Префиксовать имена сервером, хранить карту owner |
| Игнорировать падения/таймауты сервера | Зависший подпроцесс держит весь агент | Таймауты, обработка падения и переподключение, корректное завершение |
Практическое задание
- Подключите к агенту свой MCP-сервер из урока 4.2 (запуск подпроцессом, рукопожатие,
tools/list). - Преобразуйте полученные MCP-инструменты в tool-схемы модели, префиксуя имена сервером.
- В агентном цикле маршрутизируйте
tool_callsнужному серверу черезtools/callи дозаписывайте результат. - Поставьте таймаут на вызов инструмента и обработайте падение/недоступность сервера.
- Оставьте программный gate на необратимом действии независимо от того, с какого сервера пришёл инструмент.
Проверка знаний
Как инструменты MCP-сервера попадают к модели?
Верный ответ: B
B верно. MCP — источник инструментов: хост собирает их и отдаёт модели как tools, а tool_calls маршрутизирует серверам. Модель не знает о JSON-RPC (A неверно).
Зачем префиксовать имена инструментов идентификатором сервера?
Верный ответ: B
B верно. Разные серверы могут иметь инструменты с одинаковыми именами; префикс обеспечивает уникальность и позволяет по имени найти владельца.
Как относиться к результату, который вернул MCP-инструмент?
Верный ответ: B
B верно. Описание и вывод чужого инструмента могут нести вредоносные инструкции. Относитесь к ним как к недоверенному вводу и держите gate/human-in-the-loop на действиях.