Быстрое напоминание: что такое MCP
Прежде чем про мультиагентность — короткий рефреш (детали в модуле 02). MCP (Model Context Protocol) — открытый стандарт, по которому LLM-приложение подключает внешние возможности единообразно, без кастомной интеграции под каждый источник. Две стороны:
- MCP-сервер — поставщик: выставляет tools (функции), resources (данные), prompts. Например, сервер файловой системы, БД, поисковика.
- MCP-клиент — потребитель: живёт внутри агента, подключается к серверам, узнаёт список их инструментов и вызывает их.
В модуле 02 картина была простая: агент = клиент, инструменты = серверы. Стрелка одна: агент → инструмент. В мультиагентных системах эта картина складывается: агент оказывается одновременно по обе стороны стрелки.
Держи в голове границу: MCP отвечает на вопрос «как агент подключает инструменты и данные» (агент → возможность). Общение агентов как равных — это A2A. Но, как увидим, через паттерн «агент-как-MCP-сервер» MCP частично заходит и на территорию межагентного взаимодействия. В конце разберём, где чья зона.
Две роли агента в MCP
Ключевая идея урока: в мультиагентной системе один агент играет обе MCP-роли одновременно. Смотри на агента с двух сторон:
① Агент как MCP-клиент (знакомая роль из модуля 02): внутри агент подключает MCP-серверы — поиск, файлы, БД — и вызывает их инструменты, чтобы выполнять работу.
② Агент как MCP-сервер (новая роль): агент оборачивает сам себя в MCP-сервер и выставляет одну-две «крупные» tools вроде research(topic). Для того, кто его вызывает (оркестратор или другой агент-клиент), он выглядит как обычный инструмент — но за этим инструментом стоит целый агент с собственным reasoning-циклом.
Это и есть главная сила паттерна: с точки зрения вызывающего нет разницы между «простым инструментом» и «инструментом, внутри которого агент». Оркестратор просто видит tool в списке и вызывает его. Значит, из агентов можно собирать агентов — фрактально, слоями, переиспользуя единый механизм MCP-инструментов вместо кастомной интеграции.
Роль 1: агент как MCP-клиент
Это база из модуля 02, освежим в мультиагентном контексте. Каждый специализированный агент подключает свой набор MCP-серверов — те инструменты, что нужны именно его роли. Исследователю — поиск, аналитику — БД и калькулятор, писателю — доступ к файлам.
# Агент-исследователь = MCP-КЛИЕНТ: подключает инструменты под свою роль
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def research_agent(topic: str) -> str:
# подключаемся к MCP-серверу веб-поиска
params = StdioServerParameters(command="mcp-server-websearch")
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools() # что умеет сервер
result = await session.call_tool( # вызываем инструмент
"search", {"query": topic}
)
# ... агент прогоняет результат через LLM, суммаризирует ...
return summarize(result)
Каждый агент изолированно решает, какие серверы ему нужны. Это даёт чистое разделение возможностей: у писателя нет доступа к продовой БД, потому что он к её MCP-серверу просто не подключён. Инструменты выдаются по ролям — привет принципу наименьших привилегий.
Роль 2: агент как MCP-сервер
А теперь новое. Возьмём того же исследователя и выставим его наружу как MCP-сервер с одним крупным инструментом research. Теперь любой MCP-совместимый оркестратор увидит его в списке tools и сможет вызвать — не зная, что внутри целый агент.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("research-agent")
@mcp.tool()
async def research(topic: str) -> str:
"""Найти информацию по теме и вернуть структурированную выжимку.
За этим 'инструментом' стоит ЦЕЛЫЙ агент: он сам ходит в веб-поиск,
гоняет результаты через LLM, при нужде вызывает другие инструменты.
Снаружи — обычный tool. Внутри — reasoning-цикл.
"""
return await run_research_agent(topic) # тут живёт агентная логика
if __name__ == "__main__":
mcp.run() # теперь агент доступен как MCP-сервер
Оркестратор при этом остаётся простым MCP-клиентом. Ему всё равно, что research — не однострочная функция, а автономный агент:
# Оркестратор = MCP-клиент. Для него research-agent — просто ещё один tool.
tools = await session.list_tools()
# → [research, write_report, analyze_numbers, ...] (агенты вперемешку с обычными tools)
# LLM оркестратора сама решает вызвать research — как любой инструмент
result = await session.call_tool("research", {"topic": "рынок EV 2025"})
# внутри развернулся целый агент, но оркестратор видит только результат
Переиспользование: написал агента-исследователя один раз — подключаешь в любой оркестратор как tool. Инкапсуляция: сложность агента спрятана за простым интерфейсом инструмента. Единый механизм: оркестратор одинаково работает и с примитивными tools, и с агентами — не нужен отдельный «протокол делегирования». Слои: агент-как-сервер сам может быть клиентом других агентов-серверов — иерархия любой глубины.
MCP-как-делегирование vs A2A
Возникает законный вопрос: если через «агент-как-MCP-сервер» один агент уже вызывает другого — зачем тогда A2A? Оба ведь дают межагентное взаимодействие. Разница — в модели отношений.
| MCP «агент-как-инструмент» | A2A | |
|---|---|---|
| Модель отношений | Иерархия: вызывающий → подчинённый инструмент | Равные: агент ↔ агент |
| Кто главный | Оркестратор рулит, агент-tool исполняет | Автономные пиры, каждый со своей волей |
| Взаимодействие | Вызов функции: запрос → результат | Задачи с жизненным циклом, диалог, уточнения |
| Обнаружение | list_tools у известного сервера | Agent Card, реестры |
| Когда уместно | Чёткая иерархия, агент как «умная функция» | Автономные сервисы разных вендоров, диалог |
Грубо: MCP — «вызвать возможность» (в т.ч. если возможность = агент), отношения вертикальные. A2A — «поговорить с равным», отношения горизонтальные. Часто они сочетаются: агент — A2A-сервис снаружи для пиров и одновременно MCP-клиент внутри для своих инструментов.
MCP вниз, A2A вбок. Подключаешь возможность/подчинённого — вниз по иерархии — это MCP. Общаешься с равным автономным агентом — вбок — это A2A. Один агент может делать и то, и другое сразу.
Подводные камни
Композиция агентов через MCP соблазнительна, но у неё есть цена:
- Скрытая стоимость и латентность. За «простым tool»
researchстоит целый LLM-агент: секунды работы, токены, деньги. Оркестратор этого не видит — легко недооценить бюджет. - Вложенные циклы reasoning. Агент внутри агента внутри агента — отладка усложняется, ошибки маскируются за интерфейсом инструмента. Нужна сквозная трассировка (модуль 03: LangSmith).
- Потеря контекста. Инструментный вызов
research(topic)отдаёт только результат — оркестратор не видит рассуждений агента внутри. Для диалога/уточнений это тесно (тут-то и нужен A2A). - Таймауты. Обычные tools быстрые, агенты — долгие. Клиент должен быть готов ждать (или стримить).
Паттерн «агент-как-инструмент» идеален, когда взаимодействие — «дай задачу, получи результат». Как только нужен диалог (агент уточняет, спорит, возвращается за данными по ходу) — интерфейс «вызов функции» становится тесным. Это сигнал перейти на A2A с его задачами и жизненным циклом. MCP — для делегирования, A2A — для разговора.
Шпаргалка
MCP: сервер = ПОСТАВЩИК (tools/resources/prompts) · клиент = ПОТРЕБИТЕЛЬ (в агенте)
В МУЛЬТИАГЕНТАХ агент играет ОБЕ роли сразу:
① как MCP-КЛИЕНТ → подключает инструменты под свою роль (поиск, БД, файлы)
② как MCP-СЕРВЕР → оборачивает СЕБЯ в tool (research(topic)) для оркестратора
«АГЕНТ-КАК-ИНСТРУМЕНТ»:
для вызывающего нет разницы «tool» vs «агент за tool»
→ фрактальная композиция: из агентов собираем агентов, слоями
плюсы: переиспользование · инкапсуляция · единый механизм · иерархия
MCP vs A2A:
MCP ВНИЗ — вызвать возможность/подчинённого (иерархия, запрос→результат)
A2A ВБОК — поговорить с равным (пиры, задачи с lifecycle, диалог)
часто вместе: A2A-сервис снаружи + MCP-клиент внутри
ГРАБЛИ:
• скрытая цена/латентность за «простым» tool (внутри целый LLM-агент)
• вложенные reasoning-циклы → нужна сквозная трассировка
• инструментный вызов теряет контекст рассуждений (нет диалога → бери A2A)
• таймауты: агенты долгие, готовь клиента ждать/стримить
ПРАВИЛО: «дай задачу → получи результат» = MCP · нужен диалог = A2A
Практическое задание
Задание: спроектируй композицию через MCP
- Возьми агента-аналитика данных. Опиши его как MCP-клиента: к каким MCP-серверам он подключается (БД, калькулятор, …) и почему именно к ним.
- Теперь оберни его как MCP-сервер: какой один крупный tool он выставит наружу? Напиши сигнатуру и docstring.
- Собери трёхслойную композицию: оркестратор → аналитик-как-tool → его внутренние инструменты. Нарисуй стрелки и подпиши, кто клиент, кто сервер на каждом стыке.
- Для двух сценариев выбери MCP или A2A и обоснуй: (а) «оркестратор делегирует: посчитай метрики и верни число»; (б) «два автономных агента разных команд согласуют бюджет, уточняя цифры друг у друга».
- Найди в своей композиции риск скрытой стоимости: где «простой вызов» на деле запускает дорогой LLM-цикл? Как это сделать видимым (трассировка/лимиты)?
- Со звёздочкой: подними FastMCP-сервер с одним tool, внутри которого мини-агент (пусть даже заглушка с LLM-вызовом), и вызови его из MCP-клиента. Замерь латентность.
Что дальше
И в A2A (skills в Agent Card), и в MCP (tools) агент декларирует, что он умеет, отдельными единицами возможностей. Следующий урок — про Skills: как правильно нарезать и описывать возможности агента, чтобы их находили и переиспользовали.